summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp4
-rw-r--r--Android.mk9
-rw-r--r--PREUPLOAD.cfg1
-rw-r--r--api/current.txt283
-rw-r--r--api/system-current.txt296
-rw-r--r--api/test-current.txt327
-rw-r--r--cmds/am/src/com/android/commands/am/Instrument.java10
-rwxr-xr-xcmds/appwidget/appwidget1
-rwxr-xr-xcmds/bmgr/bmgr1
-rwxr-xr-xcmds/bu/bu1
-rwxr-xr-xcmds/content/content1
-rwxr-xr-xcmds/dpm/dpm1
-rwxr-xr-xcmds/ime/ime1
-rw-r--r--cmds/incident_helper/src/ih_util.cpp273
-rw-r--r--cmds/incident_helper/src/ih_util.h58
-rw-r--r--cmds/incident_helper/src/main.cpp6
-rw-r--r--cmds/incident_helper/src/parsers/CpuInfoParser.cpp161
-rw-r--r--cmds/incident_helper/src/parsers/CpuInfoParser.h36
-rw-r--r--cmds/incident_helper/src/parsers/KernelWakesParser.cpp8
-rw-r--r--cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp24
-rw-r--r--cmds/incident_helper/src/parsers/ProcrankParser.cpp8
-rw-r--r--cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp89
-rw-r--r--cmds/incident_helper/src/parsers/SystemPropertiesParser.h35
-rw-r--r--cmds/incident_helper/testdata/cpuinfo.txt15
-rw-r--r--cmds/incident_helper/testdata/system_properties.txt14
-rw-r--r--cmds/incident_helper/tests/CpuInfoParser_test.cpp158
-rw-r--r--cmds/incident_helper/tests/SystemPropertiesParser_test.cpp95
-rw-r--r--cmds/incident_helper/tests/ih_util_test.cpp91
-rw-r--r--cmds/incidentd/tests/FdBuffer_test.cpp12
-rw-r--r--cmds/incidentd/tests/PrivacyBuffer_test.cpp2
-rw-r--r--cmds/incidentd/tests/Section_test.cpp12
-rwxr-xr-xcmds/input/input1
-rwxr-xr-xcmds/locksettings/locksettings1
-rwxr-xr-xcmds/media/media1
-rwxr-xr-xcmds/pm/pm1
-rwxr-xr-xcmds/requestsync/requestsync1
-rwxr-xr-xcmds/sm/sm1
-rw-r--r--cmds/sm/src/com/android/commands/sm/Sm.java53
-rw-r--r--cmds/statsd/Android.bp2
-rw-r--r--cmds/statsd/Android.mk34
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp83
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h3
-rw-r--r--cmds/statsd/src/StatsService.cpp98
-rw-r--r--cmds/statsd/src/StatsService.h25
-rw-r--r--cmds/statsd/src/anomaly/AnomalyMonitor.h10
-rw-r--r--cmds/statsd/src/anomaly/DiscreteAnomalyTracker.cpp153
-rw-r--r--cmds/statsd/src/anomaly/DiscreteAnomalyTracker.h91
-rw-r--r--cmds/statsd/src/atoms.proto (renamed from cmds/statsd/src/stats_events.proto)129
-rw-r--r--cmds/statsd/src/atoms_copy.proto910
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.cpp34
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.h5
-rw-r--r--cmds/statsd/src/condition/ConditionTracker.h15
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.cpp228
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.h29
-rw-r--r--cmds/statsd/src/condition/condition_util.cpp1
-rw-r--r--cmds/statsd/src/condition/condition_util.h1
-rw-r--r--cmds/statsd/src/config/ConfigListener.h1
-rw-r--r--cmds/statsd/src/config/ConfigManager.cpp94
-rw-r--r--cmds/statsd/src/config/ConfigManager.h19
-rw-r--r--cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp90
-rw-r--r--cmds/statsd/src/external/CpuTimePerUidFreqPuller.h41
-rw-r--r--cmds/statsd/src/external/CpuTimePerUidPuller.cpp82
-rw-r--r--cmds/statsd/src/external/CpuTimePerUidPuller.h41
-rw-r--r--cmds/statsd/src/external/ResourcePowerManagerPuller.cpp168
-rw-r--r--cmds/statsd/src/external/ResourcePowerManagerPuller.h (renamed from cmds/statsd/src/external/KernelWakelockPuller.h)10
-rw-r--r--cmds/statsd/src/external/StatsCompanionServicePuller.cpp (renamed from cmds/statsd/src/external/KernelWakelockPuller.cpp)28
-rw-r--r--cmds/statsd/src/external/StatsCompanionServicePuller.h33
-rw-r--r--cmds/statsd/src/external/StatsPuller.h3
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp189
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.h82
-rw-r--r--cmds/statsd/src/external/StatsPullerManagerImpl.cpp183
-rw-r--r--cmds/statsd/src/external/StatsPullerManagerImpl.h87
-rw-r--r--cmds/statsd/src/logd/LogEvent.cpp2
-rw-r--r--cmds/statsd/src/logd/LogEvent.h6
-rw-r--r--cmds/statsd/src/main.cpp2
-rw-r--r--cmds/statsd/src/matchers/CombinationLogMatchingTracker.h1
-rw-r--r--cmds/statsd/src/matchers/LogMatchingTracker.h1
-rw-r--r--cmds/statsd/src/matchers/SimpleLogMatchingTracker.h1
-rw-r--r--cmds/statsd/src/matchers/matcher_util.cpp11
-rw-r--r--cmds/statsd/src/metrics/CountAnomalyTracker.cpp129
-rw-r--r--cmds/statsd/src/metrics/CountAnomalyTracker.h87
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.cpp154
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.h35
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp133
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.h16
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.cpp55
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.h19
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.cpp298
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.h106
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.cpp19
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h17
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.cpp31
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h3
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp369
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.h42
-rw-r--r--cmds/statsd/src/metrics/duration_helper/DurationTracker.h14
-rw-r--r--cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp23
-rw-r--r--cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h4
-rw-r--r--cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp18
-rw-r--r--cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h4
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.cpp135
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.h2
-rw-r--r--cmds/statsd/src/packages/PackageInfoListener.h2
-rw-r--r--cmds/statsd/src/packages/UidMap.cpp35
-rw-r--r--cmds/statsd/src/packages/UidMap.h13
-rw-r--r--cmds/statsd/src/stats_events_copy.proto467
-rw-r--r--cmds/statsd/src/stats_log.proto4
-rw-r--r--cmds/statsd/src/stats_util.h13
-rw-r--r--cmds/statsd/src/statsd_config.proto132
-rw-r--r--cmds/statsd/tests/ConfigManager_test.cpp24
-rw-r--r--cmds/statsd/tests/LogEntryMatcher_test.cpp41
-rw-r--r--cmds/statsd/tests/MetricsManager_test.cpp13
-rw-r--r--cmds/statsd/tests/UidMap_test.cpp28
-rw-r--r--cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp239
-rw-r--r--cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp (renamed from cmds/statsd/tests/ConditionTracker_test.cpp)3
-rw-r--r--cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp481
-rw-r--r--cmds/statsd/tests/metrics/CountMetricProducer_test.cpp183
-rw-r--r--cmds/statsd/tests/metrics/EventMetricProducer_test.cpp130
-rw-r--r--cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp (renamed from cmds/statsd/tests/MaxDurationTracker_test.cpp)33
-rw-r--r--cmds/statsd/tests/metrics/OringDurationTracker_test.cpp (renamed from cmds/statsd/tests/OringDurationTracker_test.cpp)30
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp299
-rw-r--r--cmds/statsd/tests/metrics/metrics_test_helper.h43
-rwxr-xr-xcmds/svc/svc1
-rwxr-xr-xcmds/telecom/telecom1
-rwxr-xr-xcmds/uiautomator/cmds/uiautomator/uiautomator1
-rwxr-xr-xcmds/vr/vr1
-rwxr-xr-xcmds/wm/wm1
-rw-r--r--config/compiled-classes-phone13
-rw-r--r--config/preloaded-classes5
-rw-r--r--core/java/Android.bp5
-rw-r--r--core/java/android/animation/ValueAnimator.java31
-rw-r--r--core/java/android/app/Activity.java27
-rw-r--r--core/java/android/app/ActivityThread.java35
-rw-r--r--core/java/android/app/DexLoadReporter.java24
-rw-r--r--core/java/android/app/DialogFragment.java3
-rw-r--r--core/java/android/app/Fragment.java12
-rw-r--r--core/java/android/app/FragmentBreadCrumbs.java3
-rw-r--r--core/java/android/app/FragmentContainer.java3
-rw-r--r--core/java/android/app/FragmentController.java3
-rw-r--r--core/java/android/app/FragmentHostCallback.java3
-rw-r--r--core/java/android/app/FragmentManager.java12
-rw-r--r--core/java/android/app/FragmentManagerNonConfig.java3
-rw-r--r--core/java/android/app/FragmentTransaction.java3
-rw-r--r--core/java/android/app/IActivityManager.aidl6
-rw-r--r--core/java/android/app/IAssistDataReceiver.aidl (renamed from core/java/com/android/internal/app/IAssistDataReceiver.aidl)2
-rw-r--r--core/java/android/app/Instrumentation.java44
-rw-r--r--core/java/android/app/ListFragment.java3
-rw-r--r--core/java/android/app/LoaderManager.java6
-rw-r--r--core/java/android/app/Notification.java311
-rw-r--r--core/java/android/app/NotificationManager.java6
-rw-r--r--core/java/android/app/SystemServiceRegistry.java41
-rw-r--r--core/java/android/app/TimePickerDialog.java3
-rw-r--r--core/java/android/app/WindowConfiguration.java9
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java7
-rw-r--r--core/java/android/app/job/JobInfo.java229
-rw-r--r--core/java/android/app/slice/Slice.java85
-rw-r--r--core/java/android/app/slice/SliceProvider.java78
-rw-r--r--core/java/android/app/slice/widget/GridView.java6
-rw-r--r--core/java/android/app/slice/widget/LargeTemplateView.java15
-rw-r--r--core/java/android/app/slice/widget/ShortcutView.java99
-rw-r--r--core/java/android/app/slice/widget/SliceView.java32
-rw-r--r--core/java/android/app/slice/widget/SliceViewUtil.java16
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java3
-rw-r--r--core/java/android/app/usage/UsageStatsManagerInternal.java10
-rw-r--r--core/java/android/bluetooth/BluetoothHidDevice.java36
-rw-r--r--core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java103
-rw-r--r--core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java20
-rw-r--r--core/java/android/bluetooth/BluetoothSocket.java4
-rw-r--r--core/java/android/content/AsyncTaskLoader.java3
-rw-r--r--core/java/android/content/ContentProviderClient.java13
-rw-r--r--core/java/android/content/Context.java17
-rw-r--r--core/java/android/content/CursorLoader.java3
-rw-r--r--core/java/android/content/Intent.java3
-rw-r--r--core/java/android/content/Loader.java12
-rw-r--r--core/java/android/content/SharedPreferences.java5
-rw-r--r--core/java/android/content/pm/LauncherApps.java12
-rw-r--r--core/java/android/content/pm/PackageInstaller.java10
-rw-r--r--core/java/android/content/pm/crossprofile/CrossProfileApps.java90
-rw-r--r--core/java/android/content/pm/crossprofile/ICrossProfileApps.aidl31
-rw-r--r--core/java/android/content/res/Configuration.java1
-rw-r--r--core/java/android/database/MergeCursor.java2
-rw-r--r--core/java/android/database/sqlite/SQLiteConnection.java26
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java72
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java14
-rw-r--r--core/java/android/database/sqlite/SQLiteGlobal.java1
-rw-r--r--core/java/android/database/sqlite/SQLiteOpenHelper.java51
-rw-r--r--core/java/android/database/sqlite/package.html2
-rw-r--r--core/java/android/hardware/camera2/CameraCaptureSession.java40
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java34
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java112
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java77
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java102
-rw-r--r--core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java14
-rw-r--r--core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java7
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java18
-rw-r--r--core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java10
-rw-r--r--core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java5
-rw-r--r--core/java/android/hardware/camera2/params/OutputConfiguration.java102
-rw-r--r--core/java/android/hardware/display/BrightnessChangeEvent.aidl19
-rw-r--r--core/java/android/hardware/display/BrightnessChangeEvent.java103
-rw-r--r--core/java/android/hardware/display/DisplayManager.java16
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java30
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl8
-rw-r--r--core/java/android/hardware/location/ContextHubManager.java55
-rw-r--r--core/java/android/hardware/location/ContextHubTransaction.java152
-rw-r--r--core/java/android/hardware/location/IContextHubTransactionCallback.aidl35
-rw-r--r--core/java/android/hardware/location/NanoAppBinary.java56
-rw-r--r--core/java/android/hardware/radio/ITuner.aidl12
-rw-r--r--core/java/android/hardware/radio/ITunerCallback.aidl5
-rw-r--r--core/java/android/hardware/radio/RadioTuner.java68
-rw-r--r--core/java/android/hardware/radio/TunerAdapter.java19
-rw-r--r--core/java/android/hardware/radio/TunerCallbackAdapter.java7
-rw-r--r--core/java/android/hardware/sidekick/SidekickInternal.java56
-rw-r--r--core/java/android/hardware/usb/AccessoryFilter.java145
-rw-r--r--core/java/android/hardware/usb/DeviceFilter.java313
-rw-r--r--core/java/android/net/ConnectivityManager.java29
-rw-r--r--core/java/android/net/ConnectivityMetricsEvent.java3
-rw-r--r--core/java/android/net/IIpConnectivityMetrics.aidl6
-rw-r--r--core/java/android/net/INetdEventCallback.aidl4
-rw-r--r--core/java/android/net/IpSecAlgorithm.java6
-rw-r--r--core/java/android/net/IpSecManager.java2
-rw-r--r--core/java/android/net/LocalSocketImpl.java18
-rw-r--r--core/java/android/net/MacAddress.java274
-rw-r--r--core/java/android/net/NetworkCapabilities.java119
-rw-r--r--core/java/android/net/NetworkIdentity.java4
-rw-r--r--core/java/android/net/NetworkInfo.java13
-rw-r--r--core/java/android/net/NetworkWatchlistManager.java75
-rw-r--r--core/java/android/net/SSLCertificateSocketFactory.java7
-rw-r--r--core/java/android/net/Uri.java6
-rw-r--r--core/java/android/net/metrics/ConnectStats.java3
-rw-r--r--core/java/android/net/metrics/DefaultNetworkEvent.java66
-rw-r--r--core/java/android/net/metrics/DnsEvent.java3
-rw-r--r--core/java/android/net/metrics/NetworkEvent.java14
-rw-r--r--core/java/android/net/metrics/WakeupEvent.java33
-rw-r--r--core/java/android/net/metrics/WakeupStats.java67
-rw-r--r--core/java/android/os/BatteryManager.java42
-rw-r--r--core/java/android/os/Binder.java13
-rw-r--r--core/java/android/os/Build.java2
-rw-r--r--core/java/android/os/ConfigUpdate.java7
-rw-r--r--core/java/android/os/Debug.java23
-rw-r--r--core/java/android/os/FileUtils.java13
-rw-r--r--core/java/android/os/HwBinder.java7
-rw-r--r--core/java/android/os/IStatsCompanionService.aidl3
-rw-r--r--core/java/android/os/IStatsManager.aidl23
-rw-r--r--core/java/android/os/IUserManager.aidl1
-rw-r--r--core/java/android/os/Parcel.java2
-rw-r--r--core/java/android/os/ParcelFileDescriptor.aidl2
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java2
-rw-r--r--core/java/android/os/ParcelUuid.aidl2
-rw-r--r--core/java/android/os/PowerManager.java46
-rw-r--r--core/java/android/os/PowerManagerInternal.java19
-rw-r--r--core/java/android/os/PowerSaveState.java2
-rw-r--r--core/java/android/os/Process.java3
-rw-r--r--core/java/android/os/RemoteCallbackList.java8
-rw-r--r--core/java/android/os/StrictMode.java926
-rw-r--r--core/java/android/os/SystemClock.java56
-rw-r--r--core/java/android/os/UpdateEngine.java1
-rw-r--r--core/java/android/os/UserHandle.java55
-rw-r--r--core/java/android/os/UserManager.java63
-rw-r--r--core/java/android/os/storage/IStorageManager.aidl7
-rw-r--r--core/java/android/os/storage/StorageManager.java29
-rw-r--r--core/java/android/os/strictmode/CleartextNetworkViolation.java (renamed from telephony/java/android/telephony/ims/feature/IRcsFeature.java)17
-rw-r--r--core/java/android/os/strictmode/ContentUriWithoutPermissionViolation.java30
-rw-r--r--core/java/android/os/strictmode/CustomViolation.java23
-rw-r--r--core/java/android/os/strictmode/DiskReadViolation.java23
-rw-r--r--core/java/android/os/strictmode/DiskWriteViolation.java23
-rw-r--r--core/java/android/os/strictmode/FileUriExposedViolation.java23
-rw-r--r--core/java/android/os/strictmode/InstanceCountViolation.java36
-rw-r--r--core/java/android/os/strictmode/IntentReceiverLeakedViolation.java24
-rw-r--r--core/java/android/os/strictmode/LeakedClosableViolation.java24
-rw-r--r--core/java/android/os/strictmode/NetworkViolation.java23
-rw-r--r--core/java/android/os/strictmode/ResourceMismatchViolation.java23
-rw-r--r--core/java/android/os/strictmode/ServiceConnectionLeakedViolation.java24
-rw-r--r--core/java/android/os/strictmode/SqliteObjectLeakedViolation.java25
-rw-r--r--core/java/android/os/strictmode/UnbufferedIoViolation.java28
-rw-r--r--core/java/android/os/strictmode/UntaggedSocketViolation.java28
-rw-r--r--core/java/android/os/strictmode/Violation.java24
-rw-r--r--core/java/android/os/strictmode/WebViewMethodCalledOnWrongThreadViolation.java24
-rw-r--r--core/java/android/preference/PreferenceFragment.java8
-rw-r--r--core/java/android/provider/MediaStore.java19
-rw-r--r--core/java/android/provider/SearchIndexableData.java2
-rw-r--r--[-rwxr-xr-x]core/java/android/provider/Settings.java151
-rw-r--r--core/java/android/security/KeystoreArguments.aidl2
-rw-r--r--core/java/android/security/keymaster/ExportResult.aidl2
-rw-r--r--core/java/android/security/keymaster/KeyCharacteristics.aidl2
-rw-r--r--core/java/android/security/keymaster/KeymasterArguments.aidl2
-rw-r--r--core/java/android/security/keymaster/KeymasterBlob.aidl2
-rw-r--r--core/java/android/security/keymaster/KeymasterCertificateChain.aidl2
-rw-r--r--core/java/android/security/keymaster/OperationResult.aidl2
-rw-r--r--core/java/android/service/autofill/FieldsDetection.java127
-rw-r--r--core/java/android/service/autofill/FillEventHistory.java57
-rw-r--r--core/java/android/service/autofill/FillResponse.java45
-rw-r--r--core/java/android/service/dreams/DreamService.java26
-rw-r--r--core/java/android/service/euicc/EuiccService.java9
-rw-r--r--core/java/android/service/notification/ConditionProviderService.java10
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java3
-rw-r--r--core/java/android/util/FeatureFlagUtils.java3
-rw-r--r--core/java/android/util/KeyValueListParser.java14
-rw-r--r--core/java/android/util/StatsManager.java134
-rw-r--r--core/java/android/util/TimeUtils.java8
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java192
-rw-r--r--core/java/android/util/apk/ApkVerityBuilder.java351
-rw-r--r--core/java/android/util/apk/ByteBufferDataSource.java66
-rw-r--r--core/java/android/util/apk/ByteBufferFactory.java28
-rw-r--r--core/java/android/util/apk/DataDigester.java28
-rw-r--r--core/java/android/util/apk/DataSource.java38
-rw-r--r--core/java/android/util/apk/MemoryMappedFileDataSource.java105
-rw-r--r--core/java/android/util/apk/SignatureInfo.java49
-rw-r--r--core/java/android/view/Display.java29
-rw-r--r--core/java/android/view/DisplayFrames.java189
-rw-r--r--core/java/android/view/FocusFinder.java2
-rw-r--r--core/java/android/view/IWindowManager.aidl2
-rw-r--r--core/java/android/view/RenderNode.java7
-rw-r--r--core/java/android/view/SurfaceControl.java34
-rw-r--r--core/java/android/view/ThreadedRenderer.java7
-rw-r--r--core/java/android/view/View.java22
-rw-r--r--core/java/android/view/ViewRootImpl.java2
-rw-r--r--core/java/android/view/WindowManager.java17
-rw-r--r--core/java/android/view/WindowManagerGlobal.java3
-rw-r--r--core/java/android/view/WindowManagerInternal.java33
-rw-r--r--core/java/android/view/WindowManagerPolicy.java65
-rw-r--r--core/java/android/view/autofill/AutofillManager.java23
-rw-r--r--core/java/android/view/autofill/IAutoFillManager.aidl1
-rw-r--r--core/java/android/view/textclassifier/TextClassification.java28
-rw-r--r--core/java/android/view/textclassifier/TextClassifier.java84
-rw-r--r--core/java/android/view/textclassifier/TextClassifierImpl.java275
-rw-r--r--core/java/android/view/textclassifier/TextLinks.java252
-rw-r--r--core/java/android/view/textclassifier/TextSelection.java53
-rw-r--r--core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java179
-rw-r--r--core/java/android/webkit/WebView.java23
-rw-r--r--core/java/android/webkit/WebViewFragment.java3
-rw-r--r--core/java/android/widget/AbsListView.java9
-rw-r--r--core/java/android/widget/Editor.java14
-rw-r--r--core/java/android/widget/PopupWindow.java1
-rw-r--r--core/java/android/widget/SelectionActionModeHelper.java59
-rw-r--r--core/java/com/android/internal/app/ColorDisplayController.java (renamed from core/java/com/android/internal/app/NightDisplayController.java)10
-rw-r--r--core/java/com/android/internal/net/INetworkWatchlistManager.aidl26
-rw-r--r--core/java/com/android/internal/net/NetworkStatsFactory.java2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java12
-rw-r--r--core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java7
-rw-r--r--core/java/com/android/internal/os/KernelUidCpuTimeReader.java7
-rw-r--r--core/java/com/android/internal/util/RingBuffer.java11
-rw-r--r--core/java/com/android/internal/widget/ImageFloatingTextView.java4
-rw-r--r--core/java/com/android/internal/widget/MessagingGroup.java393
-rw-r--r--core/java/com/android/internal/widget/MessagingLayout.java444
-rw-r--r--core/java/com/android/internal/widget/MessagingLinearLayout.java217
-rw-r--r--core/java/com/android/internal/widget/MessagingMessage.java197
-rw-r--r--core/java/com/android/internal/widget/MessagingPropertyAnimator.java233
-rw-r--r--core/java/com/android/internal/widget/RemeasuringLinearLayout.java68
-rw-r--r--core/java/com/android/internal/widget/ViewClippingUtil.java108
-rw-r--r--core/jni/Android.bp4
-rw-r--r--core/jni/android/graphics/FontFamily.cpp18
-rw-r--r--core/jni/android/graphics/Paint.cpp23
-rw-r--r--core/jni/android/graphics/Typeface.cpp2
-rw-r--r--core/jni/android_opengl_EGL14.cpp1
-rw-r--r--core/jni/android_opengl_EGLExt.cpp1
-rw-r--r--core/jni/android_opengl_GLES10.cpp1
-rw-r--r--core/jni/android_opengl_GLES10Ext.cpp1
-rw-r--r--core/jni/android_opengl_GLES11.cpp1
-rw-r--r--core/jni/android_opengl_GLES11Ext.cpp1
-rw-r--r--core/jni/android_opengl_GLES20.cpp1
-rw-r--r--core/jni/android_opengl_GLES30.cpp1
-rw-r--r--core/jni/android_opengl_GLES31.cpp1
-rw-r--r--core/jni/android_opengl_GLES31Ext.cpp1
-rw-r--r--core/jni/android_opengl_GLES32.cpp1
-rw-r--r--core/jni/android_os_HwBinder.cpp14
-rw-r--r--core/jni/android_os_Parcel.cpp13
-rw-r--r--core/jni/android_text_StaticLayout.cpp56
-rw-r--r--core/jni/android_util_Binder.cpp1
-rw-r--r--core/jni/android_view_RenderNode.cpp5
-rw-r--r--core/jni/android_view_ThreadedRenderer.cpp9
-rw-r--r--core/jni/com_google_android_gles_jni_GLImpl.cpp1
-rw-r--r--core/jni/hwbinder/EphemeralStorage.cpp1
-rw-r--r--core/proto/android/os/cpuinfo.proto110
-rw-r--r--core/proto/android/os/incident.proto20
-rw-r--r--core/proto/android/os/kernelwake.proto2
-rw-r--r--core/proto/android/os/pagetypeinfo.proto2
-rw-r--r--core/proto/android/os/procrank.proto2
-rw-r--r--core/proto/android/os/system_properties.proto657
-rw-r--r--core/proto/android/providers/settings.proto124
-rw-r--r--core/proto/android/server/powermanagerservice.proto4
-rw-r--r--core/proto/android/server/windowmanagerservice.proto6
-rw-r--r--core/res/Android.mk3
-rw-r--r--core/res/AndroidManifest.xml32
-rw-r--r--core/res/res/anim/slide_out_micro.xml2
-rw-r--r--core/res/res/drawable-hdpi/ic_print.pngbin1050 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_print_error.pngbin852 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_print.pngbin799 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_print_error.pngbin658 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_print.pngbin1132 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/ic_print_error.pngbin1026 -> 0 bytes
-rw-r--r--core/res/res/drawable/ic_print.xml26
-rw-r--r--core/res/res/drawable/ic_print_error.xml26
-rw-r--r--core/res/res/drawable/ic_reply_notification_large.xml29
-rw-r--r--core/res/res/drawable/messaging_message_background.xml26
-rw-r--r--core/res/res/layout/chooser_row.xml3
-rw-r--r--core/res/res/layout/notification_material_action.xml1
-rw-r--r--core/res/res/layout/notification_material_action_tombstone.xml1
-rw-r--r--core/res/res/layout/notification_template_material_messaging.xml42
-rw-r--r--core/res/res/layout/notification_template_messaging_group.xml50
-rw-r--r--core/res/res/layout/notification_template_messaging_message.xml21
-rw-r--r--core/res/res/layout/notification_template_right_icon.xml4
-rw-r--r--core/res/res/values-be/strings.xml13
-rw-r--r--core/res/res/values-bn/strings.xml2
-rw-r--r--core/res/res/values-ca/strings.xml8
-rw-r--r--core/res/res/values-en-rAU/strings.xml39
-rw-r--r--core/res/res/values-en-rCA/strings.xml39
-rw-r--r--core/res/res/values-en-rGB/strings.xml39
-rw-r--r--core/res/res/values-en-rIN/strings.xml39
-rw-r--r--core/res/res/values-fi/strings.xml15
-rw-r--r--core/res/res/values-fr-rCA/strings.xml15
-rw-r--r--core/res/res/values-gl/strings.xml13
-rw-r--r--core/res/res/values-gu/strings.xml13
-rw-r--r--core/res/res/values-hi/strings.xml12
-rw-r--r--core/res/res/values-in/strings.xml18
-rw-r--r--core/res/res/values-kn/strings.xml13
-rw-r--r--core/res/res/values-ml/strings.xml13
-rw-r--r--core/res/res/values-mr/strings.xml109
-rw-r--r--core/res/res/values-ne/strings.xml4
-rw-r--r--core/res/res/values-pa/strings.xml13
-rw-r--r--core/res/res/values-pt-rBR/strings.xml13
-rw-r--r--core/res/res/values-pt/strings.xml13
-rw-r--r--core/res/res/values-ro/strings.xml13
-rw-r--r--core/res/res/values-sw/strings.xml13
-rw-r--r--core/res/res/values-ta/strings.xml4
-rw-r--r--core/res/res/values-te/strings.xml13
-rw-r--r--core/res/res/values-ur/strings.xml15
-rw-r--r--core/res/res/values-watch/styles_material.xml4
-rw-r--r--core/res/res/values-zh-rCN/strings.xml17
-rw-r--r--core/res/res/values/config.xml7
-rw-r--r--core/res/res/values/dimens.xml2
-rw-r--r--core/res/res/values/ids.xml21
-rw-r--r--core/res/res/values/strings.xml3
-rw-r--r--core/res/res/values/styles_material.xml11
-rw-r--r--core/res/res/values/symbols.xml20
-rw-r--r--core/tests/coretests/res/font/samplexmlfont.xml9
-rw-r--r--core/tests/coretests/res/font/samplexmlfontforparsing.xml10
-rw-r--r--core/tests/coretests/res/layout/add_column_in_table.xml1
-rw-r--r--core/tests/coretests/res/layout/baseline_0width_and_weight.xml1
-rw-r--r--core/tests/coretests/res/layout/focus_after_removal.xml1
-rw-r--r--core/tests/coretests/res/layout/linear_layout_edittext_then_button.xml1
-rw-r--r--core/tests/coretests/res/layout/visibility_callback.xml1
-rw-r--r--core/tests/coretests/src/android/content/res/FontResourcesParserTest.java4
-rw-r--r--core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java26
-rw-r--r--core/tests/coretests/src/android/net/UriTest.java5
-rw-r--r--core/tests/coretests/src/android/os/UserHandleTest.java120
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java3
-rw-r--r--core/tests/coretests/src/android/util/ListScenario.java55
-rw-r--r--core/tests/coretests/src/android/view/FocusFinderTest.java18
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java39
-rw-r--r--core/tests/coretests/src/android/widget/TextViewActivityTest.java52
-rw-r--r--core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java47
-rw-r--r--core/tests/coretests/src/android/widget/layout/linear/LLOfTwoFocusableInTouchMode.java5
-rw-r--r--core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java4
-rw-r--r--core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java11
-rw-r--r--core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java4
-rw-r--r--core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java94
-rw-r--r--core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java13
-rw-r--r--core/tests/webkit/apk_with_native_libs/Android.mk3
-rw-r--r--core/tests/webkit/apk_with_native_libs/jni/WebViewTestJniOnLoad.cpp2
-rw-r--r--data/etc/privapp-permissions-platform.xml8
-rw-r--r--data/keyboards/Vendor_045e_Product_02e0.kl59
-rw-r--r--docs/html/reference/images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.pngbin0 -> 25603 bytes
-rw-r--r--docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.pngbin0 -> 12983 bytes
-rw-r--r--docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.pngbin0 -> 15443 bytes
-rw-r--r--docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.pngbin0 -> 15839 bytes
-rw-r--r--docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.pngbin0 -> 72941 bytes
-rw-r--r--docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/red_shading.pngbin0 -> 12787 bytes
-rw-r--r--docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.pngbin0 -> 31494 bytes
-rw-r--r--docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.pngbin0 -> 22690 bytes
-rw-r--r--docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.pngbin0 -> 21822 bytes
-rw-r--r--docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.pngbin0 -> 32384 bytes
-rw-r--r--docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.pngbin0 -> 32315 bytes
-rw-r--r--graphics/java/android/graphics/Paint.java16
-rw-r--r--graphics/java/android/graphics/Rect.java13
-rw-r--r--keystore/java/android/security/IKeyChainService.aidl2
-rw-r--r--keystore/java/android/security/KeyStore.java54
-rw-r--r--legacy-test/Android.mk1
-rw-r--r--legacy-test/src/com/android/internal/util/Predicate.java1
-rw-r--r--libs/androidfw/Android.bp3
-rw-r--r--libs/androidfw/ResourceTypes.cpp80
-rw-r--r--libs/androidfw/ZipUtils.cpp235
-rw-r--r--libs/androidfw/include/androidfw/ZipUtils.h2
-rw-r--r--libs/androidfw/libandroidfw_blacklist.txt1
-rw-r--r--libs/hwui/.clang-format10
-rw-r--r--libs/hwui/AmbientShadow.cpp99
-rw-r--r--libs/hwui/AmbientShadow.h14
-rw-r--r--libs/hwui/Android.bp3
-rw-r--r--libs/hwui/AnimationContext.cpp23
-rw-r--r--libs/hwui/AnimationContext.h8
-rw-r--r--libs/hwui/Animator.cpp177
-rw-r--r--libs/hwui/Animator.h36
-rw-r--r--libs/hwui/AnimatorManager.cpp27
-rw-r--r--libs/hwui/AnimatorManager.h5
-rw-r--r--libs/hwui/BakedOpDispatcher.cpp302
-rw-r--r--libs/hwui/BakedOpDispatcher.h15
-rw-r--r--libs/hwui/BakedOpRenderer.cpp62
-rw-r--r--libs/hwui/BakedOpRenderer.h25
-rw-r--r--libs/hwui/BakedOpState.cpp60
-rw-r--r--libs/hwui/BakedOpState.h70
-rw-r--r--libs/hwui/Caches.cpp68
-rw-r--r--libs/hwui/Caches.h35
-rw-r--r--libs/hwui/CanvasProperty.h2
-rw-r--r--libs/hwui/CanvasState.cpp39
-rw-r--r--libs/hwui/CanvasState.h44
-rw-r--r--libs/hwui/ClipArea.cpp192
-rw-r--r--libs/hwui/ClipArea.h82
-rw-r--r--libs/hwui/DamageAccumulator.cpp51
-rw-r--r--libs/hwui/DamageAccumulator.h3
-rw-r--r--libs/hwui/Debug.h6
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp18
-rw-r--r--libs/hwui/DeferredLayerUpdater.h31
-rw-r--r--libs/hwui/DeviceInfo.cpp5
-rw-r--r--libs/hwui/DeviceInfo.h3
-rw-r--r--libs/hwui/DisplayList.cpp13
-rw-r--r--libs/hwui/DisplayList.h24
-rw-r--r--libs/hwui/Extensions.cpp14
-rw-r--r--libs/hwui/Extensions.h8
-rw-r--r--libs/hwui/FboCache.cpp7
-rw-r--r--libs/hwui/FboCache.h8
-rw-r--r--libs/hwui/FloatColor.h25
-rw-r--r--libs/hwui/FontRenderer.cpp149
-rw-r--r--libs/hwui/FontRenderer.h104
-rw-r--r--libs/hwui/FrameBuilder.cpp289
-rw-r--r--libs/hwui/FrameBuilder.h107
-rw-r--r--libs/hwui/FrameInfo.cpp40
-rw-r--r--libs/hwui/FrameInfo.h46
-rw-r--r--libs/hwui/FrameInfoVisualizer.cpp49
-rw-r--r--libs/hwui/FrameMetricsObserver.h4
-rw-r--r--libs/hwui/FrameMetricsReporter.h17
-rw-r--r--libs/hwui/GammaFontRenderer.cpp6
-rw-r--r--libs/hwui/GammaFontRenderer.h14
-rw-r--r--libs/hwui/GlFunctorLifecycleListener.h4
-rw-r--r--libs/hwui/GlLayer.cpp15
-rw-r--r--libs/hwui/GlLayer.h40
-rw-r--r--libs/hwui/Glop.h56
-rw-r--r--libs/hwui/GlopBuilder.cpp350
-rw-r--r--libs/hwui/GlopBuilder.h47
-rw-r--r--libs/hwui/GpuMemoryTracker.cpp29
-rw-r--r--libs/hwui/GpuMemoryTracker.h14
-rw-r--r--libs/hwui/GradientCache.cpp43
-rw-r--r--libs/hwui/GradientCache.h38
-rw-r--r--libs/hwui/IProfileRenderer.h2
-rw-r--r--libs/hwui/Image.cpp12
-rw-r--r--libs/hwui/Image.h16
-rw-r--r--libs/hwui/Interpolator.cpp36
-rw-r--r--libs/hwui/Interpolator.h12
-rw-r--r--libs/hwui/JankTracker.cpp44
-rw-r--r--libs/hwui/JankTracker.h3
-rw-r--r--libs/hwui/Layer.cpp6
-rw-r--r--libs/hwui/Layer.h48
-rw-r--r--libs/hwui/LayerBuilder.cpp121
-rw-r--r--libs/hwui/LayerBuilder.h64
-rw-r--r--libs/hwui/LayerUpdateQueue.cpp4
-rw-r--r--libs/hwui/LayerUpdateQueue.h15
-rw-r--r--libs/hwui/Matrix.cpp202
-rw-r--r--libs/hwui/Matrix.h60
-rw-r--r--libs/hwui/NinePatchUtils.h8
-rw-r--r--libs/hwui/OpDumper.cpp15
-rw-r--r--libs/hwui/OpDumper.h4
-rw-r--r--libs/hwui/OpenGLReadback.cpp95
-rw-r--r--libs/hwui/OpenGLReadback.h19
-rw-r--r--libs/hwui/Outline.h54
-rw-r--r--libs/hwui/Patch.cpp29
-rw-r--r--libs/hwui/Patch.h23
-rw-r--r--libs/hwui/PatchCache.cpp28
-rw-r--r--libs/hwui/PatchCache.h69
-rw-r--r--libs/hwui/PathCache.cpp61
-rw-r--r--libs/hwui/PathCache.h74
-rw-r--r--libs/hwui/PathParser.cpp85
-rw-r--r--libs/hwui/PathParser.h13
-rw-r--r--libs/hwui/PathTessellator.cpp356
-rw-r--r--libs/hwui/PathTessellator.h81
-rw-r--r--libs/hwui/PixelBuffer.cpp29
-rw-r--r--libs/hwui/PixelBuffer.h45
-rw-r--r--libs/hwui/ProfileData.cpp18
-rw-r--r--libs/hwui/ProfileData.h7
-rw-r--r--libs/hwui/ProfileDataContainer.cpp15
-rw-r--r--libs/hwui/ProfileDataContainer.h1
-rw-r--r--libs/hwui/ProfileRenderer.cpp2
-rw-r--r--libs/hwui/ProfileRenderer.h4
-rw-r--r--libs/hwui/Program.cpp6
-rw-r--r--libs/hwui/Program.h86
-rw-r--r--libs/hwui/ProgramCache.cpp260
-rw-r--r--libs/hwui/ProgramCache.h8
-rw-r--r--libs/hwui/Properties.cpp40
-rw-r--r--libs/hwui/Properties.h43
-rw-r--r--libs/hwui/PropertyValuesAnimatorSet.cpp35
-rw-r--r--libs/hwui/PropertyValuesAnimatorSet.h18
-rw-r--r--libs/hwui/PropertyValuesHolder.cpp26
-rw-r--r--libs/hwui/PropertyValuesHolder.h53
-rw-r--r--libs/hwui/Readback.h9
-rw-r--r--libs/hwui/RecordedOp.h223
-rw-r--r--libs/hwui/RecordingCanvas.cpp270
-rw-r--r--libs/hwui/RecordingCanvas.h124
-rw-r--r--libs/hwui/Rect.h125
-rw-r--r--libs/hwui/RenderBuffer.h39
-rw-r--r--libs/hwui/RenderBufferCache.cpp41
-rw-r--r--libs/hwui/RenderBufferCache.h36
-rw-r--r--libs/hwui/RenderNode.cpp85
-rw-r--r--libs/hwui/RenderNode.h129
-rw-r--r--libs/hwui/RenderProperties.cpp70
-rw-r--r--libs/hwui/RenderProperties.h268
-rw-r--r--libs/hwui/ResourceCache.cpp27
-rw-r--r--libs/hwui/ResourceCache.h14
-rw-r--r--libs/hwui/RevealClip.h13
-rw-r--r--libs/hwui/ShadowTessellator.cpp62
-rw-r--r--libs/hwui/ShadowTessellator.h28
-rw-r--r--libs/hwui/SkiaCanvas.cpp153
-rw-r--r--libs/hwui/SkiaCanvas.h99
-rw-r--r--libs/hwui/SkiaCanvasProxy.cpp193
-rw-r--r--libs/hwui/SkiaCanvasProxy.h19
-rw-r--r--libs/hwui/SkiaShader.cpp97
-rw-r--r--libs/hwui/SkiaShader.h14
-rw-r--r--libs/hwui/Snapshot.cpp25
-rw-r--r--libs/hwui/Snapshot.h24
-rw-r--r--libs/hwui/SpotShadow.cpp186
-rw-r--r--libs/hwui/SpotShadow.h42
-rw-r--r--libs/hwui/SwapBehavior.h8
-rw-r--r--libs/hwui/TessellationCache.cpp118
-rw-r--r--libs/hwui/TessellationCache.h74
-rw-r--r--libs/hwui/TextDropShadowCache.cpp24
-rw-r--r--libs/hwui/TextDropShadowCache.h58
-rw-r--r--libs/hwui/Texture.cpp218
-rw-r--r--libs/hwui/Texture.h86
-rw-r--r--libs/hwui/TextureCache.cpp40
-rw-r--r--libs/hwui/TextureCache.h14
-rw-r--r--libs/hwui/TreeInfo.h8
-rw-r--r--libs/hwui/UvMapper.h17
-rw-r--r--libs/hwui/Vector.h61
-rw-r--r--libs/hwui/VectorDrawable.cpp206
-rw-r--r--libs/hwui/VectorDrawable.h300
-rw-r--r--libs/hwui/Vertex.h38
-rw-r--r--libs/hwui/VertexBuffer.h17
-rw-r--r--libs/hwui/VkLayer.cpp4
-rw-r--r--libs/hwui/VkLayer.h28
-rw-r--r--libs/hwui/debug/DefaultGlesDriver.cpp6
-rw-r--r--libs/hwui/debug/DefaultGlesDriver.h9
-rw-r--r--libs/hwui/debug/FatalBaseDriver.cpp12
-rw-r--r--libs/hwui/debug/FatalBaseDriver.h8
-rw-r--r--libs/hwui/debug/GlesDriver.cpp6
-rw-r--r--libs/hwui/debug/GlesDriver.h8
-rw-r--r--libs/hwui/debug/GlesErrorCheckWrapper.cpp57
-rw-r--r--libs/hwui/debug/GlesErrorCheckWrapper.h8
-rw-r--r--libs/hwui/debug/MockGlesDriver.h11
-rw-r--r--libs/hwui/debug/NullGlesDriver.cpp114
-rw-r--r--libs/hwui/debug/NullGlesDriver.h163
-rw-r--r--libs/hwui/debug/ScopedReplaceDriver.h11
-rw-r--r--libs/hwui/debug/gles_redefine.h3
-rw-r--r--libs/hwui/debug/nullegl.cpp55
-rw-r--r--libs/hwui/font/CacheTexture.cpp51
-rw-r--r--libs/hwui/font/CacheTexture.h80
-rw-r--r--libs/hwui/font/CachedGlyphInfo.h6
-rw-r--r--libs/hwui/font/Font.cpp159
-rw-r--r--libs/hwui/font/Font.h82
-rw-r--r--libs/hwui/font/FontCacheHistoryTracker.cpp12
-rw-r--r--libs/hwui/font/FontCacheHistoryTracker.h5
-rw-r--r--libs/hwui/font/FontUtil.h10
-rw-r--r--libs/hwui/hwui/Bitmap.cpp141
-rw-r--r--libs/hwui/hwui/Bitmap.h26
-rw-r--r--libs/hwui/hwui/Canvas.cpp73
-rw-r--r--libs/hwui/hwui/Canvas.h132
-rw-r--r--libs/hwui/hwui/MinikinSkia.cpp47
-rw-r--r--libs/hwui/hwui/MinikinSkia.h18
-rw-r--r--libs/hwui/hwui/MinikinUtils.cpp65
-rw-r--r--libs/hwui/hwui/MinikinUtils.h21
-rw-r--r--libs/hwui/hwui/Paint.h71
-rw-r--r--libs/hwui/hwui/PaintImpl.cpp59
-rw-r--r--libs/hwui/hwui/Typeface.cpp31
-rw-r--r--libs/hwui/hwui/Typeface.h24
-rw-r--r--libs/hwui/pipeline/skia/AnimatedDrawables.h34
-rw-r--r--libs/hwui/pipeline/skia/DumpOpsCanvas.h41
-rw-r--r--libs/hwui/pipeline/skia/GLFunctorDrawable.cpp18
-rw-r--r--libs/hwui/pipeline/skia/GLFunctorDrawable.h23
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.cpp16
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.h22
-rw-r--r--libs/hwui/pipeline/skia/RenderNodeDrawable.cpp71
-rw-r--r--libs/hwui/pipeline/skia/RenderNodeDrawable.h12
-rw-r--r--libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp60
-rw-r--r--libs/hwui/pipeline/skia/ReorderBarrierDrawables.h16
-rw-r--r--libs/hwui/pipeline/skia/ShaderCache.cpp139
-rw-r--r--libs/hwui/pipeline/skia/ShaderCache.h148
-rw-r--r--libs/hwui/pipeline/skia/SkiaDisplayList.cpp31
-rw-r--r--libs/hwui/pipeline/skia/SkiaDisplayList.h36
-rw-r--r--libs/hwui/pipeline/skia/SkiaLayer.h4
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp175
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h17
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp58
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLReadback.h4
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp111
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.h29
-rw-r--r--libs/hwui/pipeline/skia/SkiaProfileRenderer.cpp4
-rw-r--r--libs/hwui/pipeline/skia/SkiaProfileRenderer.h3
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp96
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.h45
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp64
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.h17
-rw-r--r--libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp40
-rw-r--r--libs/hwui/pipeline/skia/VectorDrawableAtlas.h23
-rw-r--r--libs/hwui/private/hwui/DrawGlInfo.h8
-rw-r--r--libs/hwui/protos/ProtoHelpers.h6
-rw-r--r--libs/hwui/renderstate/Blend.cpp70
-rw-r--r--libs/hwui/renderstate/Blend.h12
-rw-r--r--libs/hwui/renderstate/MeshState.cpp39
-rw-r--r--libs/hwui/renderstate/MeshState.h14
-rw-r--r--libs/hwui/renderstate/OffscreenBufferPool.cpp49
-rw-r--r--libs/hwui/renderstate/OffscreenBufferPool.h40
-rw-r--r--libs/hwui/renderstate/PixelBufferState.cpp5
-rw-r--r--libs/hwui/renderstate/PixelBufferState.h5
-rw-r--r--libs/hwui/renderstate/RenderState.cpp99
-rw-r--r--libs/hwui/renderstate/RenderState.h16
-rw-r--r--libs/hwui/renderstate/Scissor.cpp22
-rw-r--r--libs/hwui/renderstate/Scissor.h4
-rw-r--r--libs/hwui/renderstate/Stencil.cpp4
-rw-r--r--libs/hwui/renderstate/Stencil.h26
-rw-r--r--libs/hwui/renderstate/TextureState.cpp23
-rw-r--r--libs/hwui/renderstate/TextureState.h7
-rw-r--r--libs/hwui/renderthread/CacheManager.cpp32
-rw-r--r--libs/hwui/renderthread/CacheManager.h8
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp122
-rw-r--r--libs/hwui/renderthread/CanvasContext.h40
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.cpp11
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.h4
-rw-r--r--libs/hwui/renderthread/EglManager.cpp201
-rw-r--r--libs/hwui/renderthread/EglManager.h2
-rw-r--r--libs/hwui/renderthread/Frame.h7
-rw-r--r--libs/hwui/renderthread/IRenderPipeline.h27
-rw-r--r--libs/hwui/renderthread/OpenGLPipeline.cpp136
-rw-r--r--libs/hwui/renderthread/OpenGLPipeline.h26
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp150
-rw-r--r--libs/hwui/renderthread/RenderProxy.h23
-rw-r--r--libs/hwui/renderthread/RenderTask.h6
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp73
-rw-r--r--libs/hwui/renderthread/RenderThread.h6
-rw-r--r--libs/hwui/renderthread/TimeLord.cpp5
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp227
-rw-r--r--libs/hwui/renderthread/VulkanManager.h25
-rw-r--r--libs/hwui/service/GraphicsStatsService.cpp95
-rw-r--r--libs/hwui/service/GraphicsStatsService.h8
-rw-r--r--libs/hwui/tests/common/BitmapAllocationTestUtils.h44
-rw-r--r--libs/hwui/tests/common/LeakChecker.cpp18
-rw-r--r--libs/hwui/tests/common/LeakChecker.h2
-rw-r--r--libs/hwui/tests/common/TestContext.cpp46
-rw-r--r--libs/hwui/tests/common/TestContext.h17
-rw-r--r--libs/hwui/tests/common/TestListViewSceneBase.cpp26
-rw-r--r--libs/hwui/tests/common/TestListViewSceneBase.h15
-rw-r--r--libs/hwui/tests/common/TestScene.h16
-rw-r--r--libs/hwui/tests/common/TestUtils.cpp38
-rw-r--r--libs/hwui/tests/common/TestUtils.h224
-rw-r--r--libs/hwui/tests/common/scenes/BitmapFillrate.cpp25
-rw-r--r--libs/hwui/tests/common/scenes/BitmapShaders.cpp48
-rw-r--r--libs/hwui/tests/common/scenes/ClippingAnimation.cpp12
-rw-r--r--libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp22
-rw-r--r--libs/hwui/tests/common/scenes/HwBitmap565.cpp30
-rw-r--r--libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp25
-rw-r--r--libs/hwui/tests/common/scenes/HwLayerAnimation.cpp14
-rw-r--r--libs/hwui/tests/common/scenes/HwLayerSizeAnimation.cpp20
-rw-r--r--libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp17
-rw-r--r--libs/hwui/tests/common/scenes/ListViewAnimation.cpp26
-rw-r--r--libs/hwui/tests/common/scenes/MagnifierAnimation.cpp79
-rw-r--r--libs/hwui/tests/common/scenes/OpPropAnimation.cpp17
-rw-r--r--libs/hwui/tests/common/scenes/OvalAnimation.cpp10
-rw-r--r--libs/hwui/tests/common/scenes/PartialDamageAnimation.cpp31
-rw-r--r--libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp12
-rw-r--r--libs/hwui/tests/common/scenes/RecentsAnimation.cpp37
-rw-r--r--libs/hwui/tests/common/scenes/RectGridAnimation.cpp17
-rw-r--r--libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp42
-rw-r--r--libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp34
-rw-r--r--libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp17
-rw-r--r--libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp25
-rw-r--r--libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp25
-rw-r--r--libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp38
-rw-r--r--libs/hwui/tests/common/scenes/ShapeAnimation.cpp128
-rw-r--r--libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp65
-rw-r--r--libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp38
-rw-r--r--libs/hwui/tests/common/scenes/TextAnimation.cpp12
-rw-r--r--libs/hwui/tests/common/scenes/TvApp.cpp180
-rw-r--r--libs/hwui/tests/macrobench/TestSceneRunner.cpp43
-rw-r--r--libs/hwui/tests/macrobench/main.cpp211
-rw-r--r--libs/hwui/tests/microbench/DisplayListCanvasBench.cpp7
-rw-r--r--libs/hwui/tests/microbench/FontBench.cpp4
-rw-r--r--libs/hwui/tests/microbench/FrameBuilderBench.cpp66
-rw-r--r--libs/hwui/tests/microbench/PathParserBench.cpp4
-rw-r--r--libs/hwui/tests/microbench/RenderNodeBench.cpp1
-rw-r--r--libs/hwui/tests/microbench/ShadowBench.cpp28
-rw-r--r--libs/hwui/tests/microbench/TaskManagerBench.cpp21
-rw-r--r--libs/hwui/tests/unit/BakedOpDispatcherTests.cpp101
-rw-r--r--libs/hwui/tests/unit/BakedOpRendererTests.cpp12
-rw-r--r--libs/hwui/tests/unit/BakedOpStateTests.cpp141
-rw-r--r--libs/hwui/tests/unit/CacheManagerTests.cpp3
-rw-r--r--libs/hwui/tests/unit/CanvasContextTests.cpp4
-rw-r--r--libs/hwui/tests/unit/CanvasStateTests.cpp32
-rw-r--r--libs/hwui/tests/unit/ClipAreaTests.cpp26
-rw-r--r--libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp1
-rw-r--r--libs/hwui/tests/unit/FatVectorTests.cpp5
-rw-r--r--libs/hwui/tests/unit/FatalTestCanvas.h42
-rw-r--r--libs/hwui/tests/unit/FontRendererTests.cpp12
-rw-r--r--libs/hwui/tests/unit/FrameBuilderTests.cpp2048
-rw-r--r--libs/hwui/tests/unit/GlopBuilderTests.cpp26
-rw-r--r--libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp11
-rw-r--r--libs/hwui/tests/unit/GradientCacheTests.cpp6
-rw-r--r--libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp16
-rw-r--r--libs/hwui/tests/unit/LayerUpdateQueueTests.cpp5
-rw-r--r--libs/hwui/tests/unit/LeakCheckTests.cpp20
-rw-r--r--libs/hwui/tests/unit/LinearAllocatorTests.cpp5
-rw-r--r--libs/hwui/tests/unit/MatrixTests.cpp6
-rw-r--r--libs/hwui/tests/unit/MeshStateTests.cpp5
-rw-r--r--libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp11
-rw-r--r--libs/hwui/tests/unit/OpDumperTests.cpp2
-rw-r--r--libs/hwui/tests/unit/PathInterpolatorTests.cpp76
-rw-r--r--libs/hwui/tests/unit/RecordingCanvasTests.cpp319
-rw-r--r--libs/hwui/tests/unit/RenderNodeDrawableTests.cpp831
-rw-r--r--libs/hwui/tests/unit/RenderNodeTests.cpp87
-rw-r--r--libs/hwui/tests/unit/ShaderCacheTests.cpp176
-rw-r--r--libs/hwui/tests/unit/SkiaBehaviorTests.cpp16
-rw-r--r--libs/hwui/tests/unit/SkiaCanvasTests.cpp4
-rw-r--r--libs/hwui/tests/unit/SkiaDisplayListTests.cpp34
-rw-r--r--libs/hwui/tests/unit/SkiaPipelineTests.cpp257
-rw-r--r--libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp137
-rw-r--r--libs/hwui/tests/unit/SnapshotTests.cpp8
-rw-r--r--libs/hwui/tests/unit/StringUtilsTests.cpp2
-rw-r--r--libs/hwui/tests/unit/TestUtilsTests.cpp2
-rw-r--r--libs/hwui/tests/unit/TextDropShadowCacheTests.cpp8
-rw-r--r--libs/hwui/tests/unit/ThreadBaseTests.cpp35
-rw-r--r--libs/hwui/tests/unit/TypefaceTests.cpp309
-rw-r--r--libs/hwui/tests/unit/VectorDrawableAtlasTests.cpp59
-rw-r--r--libs/hwui/tests/unit/VectorDrawableTests.cpp474
-rw-r--r--libs/hwui/tests/unit/main.cpp16
-rw-r--r--libs/hwui/thread/Barrier.h11
-rw-r--r--libs/hwui/thread/Future.h15
-rw-r--r--libs/hwui/thread/Signal.h11
-rw-r--r--libs/hwui/thread/Task.h32
-rw-r--r--libs/hwui/thread/TaskManager.cpp6
-rw-r--r--libs/hwui/thread/TaskManager.h19
-rw-r--r--libs/hwui/thread/TaskProcessor.h24
-rw-r--r--libs/hwui/thread/ThreadBase.h25
-rw-r--r--libs/hwui/thread/WorkQueue.h31
-rw-r--r--libs/hwui/utils/Blur.cpp59
-rw-r--r--libs/hwui/utils/Blur.h16
-rw-r--r--libs/hwui/utils/Color.cpp19
-rw-r--r--libs/hwui/utils/Color.h168
-rw-r--r--libs/hwui/utils/FatVector.h34
-rw-r--r--libs/hwui/utils/GLUtils.cpp32
-rw-r--r--libs/hwui/utils/GLUtils.h15
-rw-r--r--libs/hwui/utils/LinearAllocator.cpp52
-rw-r--r--libs/hwui/utils/LinearAllocator.h42
-rw-r--r--libs/hwui/utils/Macros.h22
-rw-r--r--libs/hwui/utils/MathUtils.h24
-rw-r--r--libs/hwui/utils/PaintUtils.h17
-rw-r--r--libs/hwui/utils/Pair.h40
-rw-r--r--libs/hwui/utils/RingBuffer.h22
-rw-r--r--libs/hwui/utils/StringUtils.cpp4
-rw-r--r--libs/hwui/utils/StringUtils.h13
-rw-r--r--libs/hwui/utils/TestWindowContext.cpp70
-rw-r--r--libs/hwui/utils/TestWindowContext.h4
-rw-r--r--libs/hwui/utils/TimeUtils.h6
-rw-r--r--libs/hwui/utils/Timing.h10
-rw-r--r--libs/hwui/utils/TraceUtils.h10
-rw-r--r--libs/hwui/utils/VectorDrawableUtils.cpp504
-rw-r--r--libs/hwui/utils/VectorDrawableUtils.h10
-rw-r--r--media/java/android/media/AudioAttributes.java1
-rw-r--r--media/java/android/media/AudioManager.java26
-rw-r--r--media/java/android/media/BufferingParams.java384
-rw-r--r--media/java/android/media/MediaDrm.java2
-rw-r--r--media/java/android/media/MediaPlayer.java180
-rw-r--r--media/jni/Android.bp1
-rw-r--r--media/jni/android_media_BufferingParams.h50
-rw-r--r--media/jni/android_media_MediaDrm.cpp4
-rw-r--r--media/jni/android_media_MediaPlayer.cpp63
-rw-r--r--obex/javax/obex/ObexHelper.java18
-rw-r--r--packages/ExtServices/src/android/ext/services/notification/Assistant.java190
-rw-r--r--packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java49
-rw-r--r--packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java142
-rw-r--r--packages/ExtServices/tests/src/android/ext/services/notification/ChannelImpressionsTest.java26
-rw-r--r--packages/MtpDocumentsProvider/res/values-mr/strings.xml2
-rw-r--r--packages/PrintSpooler/res/drawable/ic_print.xml19
-rw-r--r--packages/PrintSpooler/res/values-mr/strings.xml6
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java2
-rw-r--r--packages/SettingsLib/Android.mk8
-rw-r--r--packages/SettingsLib/common.mk4
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml17
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-en-rCA/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-en-rXC/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml7
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml19
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-hi/arrays.xml12
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml29
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml37
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml15
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml15
-rw-r--r--packages/SettingsLib/res/values/strings.xml12
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java61
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/Utils.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java118
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java87
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/lifecycle/LifecycleObserver.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservableActivity.java28
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservableDialogFragment.java38
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservableFragment.java37
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservablePreferenceFragment.java38
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnAttach.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnCreate.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnDestroy.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnPause.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnResume.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnStart.java8
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnStop.java8
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java15
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractSerialNumberPreferenceController.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/UserAdapter.java2
-rwxr-xr-xpackages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java19
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java (renamed from packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawable/UserIconDrawableTest.java)15
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java12
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/DeviceInfoUtilsTest.java75
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java4
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java113
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/PreferenceControllerTest.java178
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java19
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java15
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java3
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java44
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java6
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java17
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java21
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java378
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java4
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java8
-rw-r--r--packages/SystemUI/AndroidManifest.xml8
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml2
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml1
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml1
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml61
-rw-r--r--packages/SystemUI/res-keyguard/values-be/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-en-rAU/strings.xml1
-rw-r--r--packages/SystemUI/res-keyguard/values-en-rCA/strings.xml1
-rw-r--r--packages/SystemUI/res-keyguard/values-en-rGB/strings.xml1
-rw-r--r--packages/SystemUI/res-keyguard/values-en-rIN/strings.xml1
-rw-r--r--packages/SystemUI/res-keyguard/values-fi/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-gl/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-gu/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-kn/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-ml/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-mr/strings.xml29
-rw-r--r--packages/SystemUI/res-keyguard/values-pa/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-pt/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-ro/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-sw/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-te/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-ur/strings.xml3
-rw-r--r--packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml3
-rw-r--r--packages/SystemUI/res/layout/volume_dialog.xml73
-rw-r--r--packages/SystemUI/res/layout/volume_dialog_row.xml12
-rw-r--r--packages/SystemUI/res/layout/volume_zen_footer.xml127
-rw-r--r--packages/SystemUI/res/values-be/config.xml1
-rw-r--r--packages/SystemUI/res/values-be/strings.xml18
-rw-r--r--packages/SystemUI/res/values-bn/config.xml1
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml18
-rw-r--r--packages/SystemUI/res/values-ca/config.xml1
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml18
-rw-r--r--packages/SystemUI/res/values-en-rAU/config.xml1
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml15
-rw-r--r--packages/SystemUI/res/values-en-rCA/config.xml1
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml15
-rw-r--r--packages/SystemUI/res/values-en-rGB/config.xml1
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml15
-rw-r--r--packages/SystemUI/res/values-en-rIN/config.xml1
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml15
-rw-r--r--packages/SystemUI/res/values-en-rXC/config.xml1
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml12
-rw-r--r--packages/SystemUI/res/values-fi/config.xml1
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml20
-rw-r--r--packages/SystemUI/res/values-fr-rCA/config.xml1
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml20
-rw-r--r--packages/SystemUI/res/values-gl/config.xml1
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml18
-rw-r--r--packages/SystemUI/res/values-gu/config.xml1
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml18
-rw-r--r--packages/SystemUI/res/values-hi/config.xml1
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml18
-rw-r--r--packages/SystemUI/res/values-in/config.xml2
-rw-r--r--packages/SystemUI/res/values-in/strings.xml10
-rw-r--r--packages/SystemUI/res/values-iw/config.xml1
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml18
-rw-r--r--packages/SystemUI/res/values-kn/config.xml1
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml18
-rw-r--r--packages/SystemUI/res/values-ml/config.xml1
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml18
-rw-r--r--packages/SystemUI/res/values-mr/config.xml1
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml26
-rw-r--r--packages/SystemUI/res/values-ne/config.xml1
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml18
-rw-r--r--packages/SystemUI/res/values-nl/config.xml1
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml12
-rw-r--r--packages/SystemUI/res/values-pa/config.xml1
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml18
-rw-r--r--packages/SystemUI/res/values-pt-rBR/config.xml1
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml12
-rw-r--r--packages/SystemUI/res/values-pt/config.xml1
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ro/config.xml1
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml12
-rw-r--r--packages/SystemUI/res/values-sw/config.xml1
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml18
-rw-r--r--packages/SystemUI/res/values-ta/config.xml1
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml18
-rw-r--r--packages/SystemUI/res/values-te/config.xml1
-rw-r--r--packages/SystemUI/res/values-te/strings.xml18
-rw-r--r--packages/SystemUI/res/values-ur/config.xml1
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml18
-rw-r--r--packages/SystemUI/res/values-zh-rCN/config.xml1
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml18
-rw-r--r--packages/SystemUI/res/values/config.xml3
-rw-r--r--packages/SystemUI/res/values/dimens.xml6
-rw-r--r--packages/SystemUI/res/values/ids.xml3
-rw-r--r--packages/SystemUI/res/values/strings.xml14
-rw-r--r--packages/SystemUI/res/xml/tuner_prefs.xml7
-rw-r--r--packages/SystemUI/shared/Android.mk4
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl25
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl32
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java19
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java3
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java26
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AppTrace.java73
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AnimateableViewBounds.java (renamed from packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java)36
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecCompat.java41
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecsFuture.java21
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java34
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java133
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiverCompat.java28
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/BackgroundExecutor.java16
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ChoreographerCompat.java37
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.aidl19
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.java64
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java4
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java12
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java45
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java160
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java44
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/OverviewProxyService.java223
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenStatePreventingAdapter.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeService.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java159
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionComposer.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java66
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java355
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java245
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java79
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java411
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java137
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java612
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java143
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/SystemUIInterpolators.java78
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java431
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java317
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java180
-rw-r--r--packages/SystemUI/tests/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java108
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTest.java69
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java28
-rw-r--r--packages/VpnDialogs/res/values-ta/strings.xml2
-rw-r--r--proto/src/ipconnectivity.proto56
-rw-r--r--proto/src/metrics_constants.proto495
-rw-r--r--proto/src/wifi.proto63
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java2
-rw-r--r--services/art-profile44
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java10
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java35
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java161
-rw-r--r--services/autofill/java/com/android/server/autofill/ViewState.java6
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java2
-rw-r--r--services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java2
-rw-r--r--services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java21
-rw-r--r--services/core/java/com/android/server/BatteryService.java445
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java4
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java51
-rw-r--r--services/core/java/com/android/server/ForceAppStandbyTracker.java386
-rw-r--r--services/core/java/com/android/server/MountServiceIdler.java10
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java43
-rw-r--r--services/core/java/com/android/server/RescueParty.java8
-rw-r--r--services/core/java/com/android/server/ServiceThread.java8
-rw-r--r--services/core/java/com/android/server/ServiceWatcher.java25
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java109
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java30
-rw-r--r--services/core/java/com/android/server/VibratorService.java2
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java4
-rw-r--r--services/core/java/com/android/server/am/ActivityDisplay.java87
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerDebugConfig.java1
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java292
-rw-r--r--services/core/java/com/android/server/am/ActivityMetricsLogger.java91
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java33
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java224
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java98
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java30
-rw-r--r--services/core/java/com/android/server/am/AssistDataReceiverProxy.java35
-rw-r--r--services/core/java/com/android/server/am/AssistDataRequester.java84
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java2
-rw-r--r--services/core/java/com/android/server/am/KeyguardController.java47
-rw-r--r--services/core/java/com/android/server/am/TaskChangeNotificationController.java8
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java35
-rw-r--r--services/core/java/com/android/server/am/UserController.java38
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java200
-rw-r--r--services/core/java/com/android/server/broadcastradio/Tuner.java31
-rw-r--r--services/core/java/com/android/server/broadcastradio/TunerCallback.java8
-rw-r--r--services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java117
-rw-r--r--services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java36
-rw-r--r--services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java113
-rw-r--r--services/core/java/com/android/server/connectivity/NetdEventListenerService.java110
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkMonitor.java6
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java63
-rw-r--r--services/core/java/com/android/server/display/BrightnessTracker.java639
-rw-r--r--services/core/java/com/android/server/display/ColorDisplayService.java (renamed from services/core/java/com/android/server/display/NightDisplayService.java)20
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java41
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java21
-rw-r--r--services/core/java/com/android/server/display/DisplayTransformManager.java8
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java37
-rw-r--r--services/core/java/com/android/server/job/JobPackageTracker.java30
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java57
-rw-r--r--services/core/java/com/android/server/job/JobServiceContext.java19
-rw-r--r--services/core/java/com/android/server/job/JobStore.java103
-rw-r--r--services/core/java/com/android/server/job/controllers/AppIdleController.java2
-rw-r--r--services/core/java/com/android/server/job/controllers/BackgroundJobsController.java284
-rw-r--r--services/core/java/com/android/server/job/controllers/BatteryController.java9
-rw-r--r--services/core/java/com/android/server/job/controllers/ConnectivityController.java45
-rw-r--r--services/core/java/com/android/server/job/controllers/IdleController.java9
-rw-r--r--services/core/java/com/android/server/job/controllers/JobStatus.java95
-rw-r--r--services/core/java/com/android/server/job/controllers/StorageController.java7
-rw-r--r--services/core/java/com/android/server/job/controllers/TimeController.java15
-rw-r--r--services/core/java/com/android/server/location/ActivityRecognitionProxy.java90
-rw-r--r--services/core/java/com/android/server/location/FusedProxy.java22
-rw-r--r--services/core/java/com/android/server/location/GeocoderProxy.java50
-rw-r--r--services/core/java/com/android/server/location/GeofenceProxy.java18
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java32
-rw-r--r--services/core/java/com/android/server/location/LocationProviderProxy.java237
-rw-r--r--services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java21
-rw-r--r--services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java35
-rw-r--r--services/core/java/com/android/server/media/AudioPlaybackMonitor.java289
-rw-r--r--services/core/java/com/android/server/media/AudioPlayerStateMonitor.java327
-rw-r--r--services/core/java/com/android/server/media/MediaRouterService.java74
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java28
-rw-r--r--services/core/java/com/android/server/media/MediaSessionStack.java14
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java4
-rw-r--r--services/core/java/com/android/server/net/watchlist/DigestUtils.java54
-rw-r--r--services/core/java/com/android/server/net/watchlist/HarmfulDigests.java55
-rw-r--r--services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java267
-rw-r--r--services/core/java/com/android/server/net/watchlist/ReportWatchlistJobService.java76
-rw-r--r--services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java298
-rw-r--r--services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java203
-rw-r--r--services/core/java/com/android/server/net/watchlist/WatchlistSettings.java284
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java12
-rw-r--r--services/core/java/com/android/server/notification/RankingHelper.java40
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java11
-rw-r--r--services/core/java/com/android/server/pm/KeySetManagerService.java37
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java12
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java8
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java552
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java13
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java342
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java10
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java37
-rw-r--r--services/core/java/com/android/server/pm/UserDataPreparer.java4
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java17
-rw-r--r--services/core/java/com/android/server/pm/UserRestrictionsUtils.java15
-rw-r--r--services/core/java/com/android/server/pm/crossprofile/CrossProfileAppsService.java34
-rw-r--r--services/core/java/com/android/server/pm/crossprofile/CrossProfileAppsServiceImpl.java264
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java6
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java101
-rw-r--r--services/core/java/com/android/server/policy/BurnInProtectionHelper.java3
-rw-r--r--services/core/java/com/android/server/policy/GlobalActions.java2
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java1319
-rw-r--r--services/core/java/com/android/server/power/BatterySaverPolicy.java305
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java79
-rw-r--r--services/core/java/com/android/server/power/ShutdownThread.java10
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySaverController.java239
-rw-r--r--services/core/java/com/android/server/power/batterysaver/FileUpdater.java55
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java68
-rw-r--r--services/core/java/com/android/server/updates/TzDataInstallReceiver.java58
-rw-r--r--services/core/java/com/android/server/vr/VrManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java60
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java44
-rw-r--r--services/core/java/com/android/server/wm/DragDropController.java430
-rw-r--r--services/core/java/com/android/server/wm/DragInputEventReceiver.java116
-rw-r--r--services/core/java/com/android/server/wm/DragState.java191
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java4
-rw-r--r--services/core/java/com/android/server/wm/PinnedStackController.java3
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java2
-rw-r--r--services/core/java/com/android/server/wm/StackWindowController.java12
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java59
-rw-r--r--services/core/java/com/android/server/wm/TaskWindowContainerController.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java113
-rw-r--r--services/core/jni/BroadcastRadio/Tuner.cpp61
-rw-r--r--services/core/jni/BroadcastRadio/TunerCallback.cpp8
-rw-r--r--services/core/jni/BroadcastRadio/convert.cpp47
-rw-r--r--services/core/jni/BroadcastRadio/convert.h2
-rw-r--r--services/core/jni/com_android_server_SystemServer.cpp2
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp7
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java6
-rw-r--r--services/java/com/android/server/SystemServer.java37
-rw-r--r--services/net/java/android/net/apf/ApfFilter.java31
-rw-r--r--services/net/java/android/net/ip/IpClient.java18
-rw-r--r--services/net/java/android/net/ip/IpManager.java10
-rw-r--r--services/print/java/com/android/server/print/UserState.java11
-rw-r--r--services/robotests/Android.mk16
-rw-r--r--services/tests/notification/src/com/android/server/notification/RankingHelperTest.java28
-rw-r--r--services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java31
-rw-r--r--services/tests/servicestests/Android.mk3
-rw-r--r--services/tests/servicestests/AndroidManifest.xml4
-rw-r--r--services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_settings_test1.xml27
-rw-r--r--services/tests/servicestests/res/values/strings.xml4
-rw-r--r--services/tests/servicestests/src/com/android/server/BatteryServiceTest.java60
-rw-r--r--services/tests/servicestests/src/com/android/server/ColorDisplayServiceTest.java (renamed from services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java)46
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java189
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java118
-rw-r--r--services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java94
-rw-r--r--services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java640
-rw-r--r--services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/job/JobStoreTest.java176
-rw-r--r--services/tests/servicestests/src/com/android/server/net/watchlist/HarmfulDigestsTests.java63
-rw-r--r--services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java217
-rw-r--r--services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java61
-rw-r--r--services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java195
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java64
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/crossprofile/CrossProfileAppsServiceImplTest.java449
-rw-r--r--services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java76
-rw-r--r--services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java30
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java28
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java30
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java321
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java47
-rw-r--r--services/usage/java/com/android/server/usage/AppIdleHistory.java9
-rw-r--r--services/usage/java/com/android/server/usage/AppStandbyController.java69
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java2
-rw-r--r--services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java403
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java2
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java20
-rw-r--r--telecomm/java/android/telecom/Call.java66
-rw-r--r--telecomm/java/android/telecom/CallAudioState.java90
-rw-r--r--telecomm/java/android/telecom/Connection.java50
-rw-r--r--telecomm/java/android/telecom/ConnectionService.java77
-rw-r--r--telecomm/java/android/telecom/ConnectionServiceAdapter.java9
-rw-r--r--telecomm/java/android/telecom/ConnectionServiceAdapterServant.java10
-rw-r--r--telecomm/java/android/telecom/InCallAdapter.java35
-rw-r--r--telecomm/java/android/telecom/InCallService.java18
-rw-r--r--telecomm/java/android/telecom/Phone.java14
-rw-r--r--telecomm/java/android/telecom/PhoneAccount.java10
-rw-r--r--telecomm/java/android/telecom/RemoteConnectionService.java3
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java35
-rw-r--r--telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl3
-rw-r--r--telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl5
-rw-r--r--telecomm/java/com/android/internal/telecom/ITelecomService.aidl5
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java38
-rw-r--r--telephony/java/android/telephony/PhoneStateListener.java27
-rw-r--r--telephony/java/android/telephony/SmsManager.java8
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java36
-rw-r--r--telephony/java/android/telephony/Telephony.java85
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java23
-rw-r--r--telephony/java/android/telephony/TelephonyScanManager.java4
-rw-r--r--telephony/java/android/telephony/euicc/DownloadableSubscription.java19
-rw-r--r--telephony/java/android/telephony/ims/ImsServiceProxy.java335
-rw-r--r--telephony/java/android/telephony/ims/ImsServiceProxyCompat.java183
-rw-r--r--telephony/java/android/telephony/ims/feature/IMMTelFeature.java187
-rw-r--r--telephony/java/android/telephony/ims/feature/MMTelFeature.java135
-rw-r--r--telephony/java/android/telephony/ims/feature/RcsFeature.java4
-rw-r--r--telephony/java/android/telephony/mbms/DownloadStateCallback.java2
-rw-r--r--telephony/java/android/telephony/mbms/FileInfo.java23
-rw-r--r--telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java11
-rw-r--r--telephony/java/android/telephony/mbms/UriPathPair.java2
-rw-r--r--telephony/java/android/telephony/mbms/vendor/VendorUtils.java2
-rw-r--r--telephony/java/com/android/ims/internal/IImsServiceController.aidl2
-rw-r--r--telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl1
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl11
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl1
-rw-r--r--test-mock/Android.mk144
-rw-r--r--test-mock/api/android-test-mock-current.txt (renamed from test-runner/api/android-test-mock-current.txt)0
-rw-r--r--test-mock/api/android-test-mock-removed.txt (renamed from test-runner/api/android-test-mock-removed.txt)0
-rw-r--r--test-mock/api/apicheck_msg_android_test_mock.txt (renamed from test-runner/api/apicheck_msg_android_test_mock.txt)0
-rw-r--r--test-mock/src/android/test/mock/MockApplication.java (renamed from test-runner/src/android/test/mock/MockApplication.java)0
-rw-r--r--test-mock/src/android/test/mock/MockContentProvider.java (renamed from test-runner/src/android/test/mock/MockContentProvider.java)0
-rw-r--r--test-mock/src/android/test/mock/MockContentResolver.java (renamed from test-runner/src/android/test/mock/MockContentResolver.java)0
-rw-r--r--test-mock/src/android/test/mock/MockContext.java (renamed from test-runner/src/android/test/mock/MockContext.java)0
-rw-r--r--test-mock/src/android/test/mock/MockCursor.java (renamed from test-runner/src/android/test/mock/MockCursor.java)0
-rw-r--r--test-mock/src/android/test/mock/MockDialogInterface.java (renamed from test-runner/src/android/test/mock/MockDialogInterface.java)0
-rw-r--r--test-mock/src/android/test/mock/MockIContentProvider.java (renamed from test-runner/src/android/test/mock/MockIContentProvider.java)0
-rw-r--r--test-mock/src/android/test/mock/MockPackageManager.java (renamed from test-runner/src/android/test/mock/MockPackageManager.java)0
-rw-r--r--test-mock/src/android/test/mock/MockResources.java (renamed from test-runner/src/android/test/mock/MockResources.java)0
-rw-r--r--test-mock/src/android/test/mock/package.html (renamed from test-runner/src/android/test/mock/package.html)0
-rw-r--r--test-runner/Android.mk129
-rw-r--r--tests/FeatureSplit/feature1/Android.mk2
-rw-r--r--tests/FeatureSplit/feature1/AndroidManifest.xml4
-rw-r--r--tests/FeatureSplit/feature1/res/values/values.xml2
-rw-r--r--tests/FeatureSplit/feature2/Android.mk2
-rw-r--r--tests/FeatureSplit/feature2/AndroidManifest.xml2
-rw-r--r--tests/FeatureSplit/feature2/res/values/values.xml2
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml9
-rw-r--r--tests/HwAccelerationTest/res/layout/colored_shadows_activity.xml32
-rw-r--r--tests/HwAccelerationTest/res/layout/colored_shadows_row.xml57
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/ColoredShadowsActivity.java55
-rw-r--r--tests/UiBench/Android.mk24
-rw-r--r--tests/UiBench/AndroidManifest.xml9
-rw-r--r--tests/UiBench/src/com/android/test/uibench/TrivialAnimationActivityWideGamut.java18
-rw-r--r--tests/net/java/android/net/MacAddressTest.java208
-rw-r--r--tests/net/java/android/net/NetworkCapabilitiesTest.java25
-rw-r--r--tests/net/java/android/net/apf/ApfTest.java95
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java83
-rw-r--r--tests/net/java/com/android/server/IpSecServiceParameterizedTest.java13
-rw-r--r--tests/net/java/com/android/server/IpSecServiceTest.java119
-rw-r--r--tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java64
-rw-r--r--tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java222
-rw-r--r--tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java171
-rw-r--r--tests/net/java/com/android/server/connectivity/VpnTest.java101
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsServiceTest.java9
-rw-r--r--tools/aapt2/Android.bp2
-rw-r--r--tools/aapt2/Android.mk7
-rw-r--r--tools/aapt2/ConfigDescription.cpp5
-rw-r--r--tools/aapt2/ConfigDescription.h2
-rw-r--r--tools/aapt2/Debug.cpp254
-rw-r--r--tools/aapt2/Debug.h7
-rw-r--r--tools/aapt2/LoadedApk.cpp149
-rw-r--r--tools/aapt2/LoadedApk.h43
-rw-r--r--tools/aapt2/Main.cpp5
-rw-r--r--tools/aapt2/Resource.cpp25
-rw-r--r--tools/aapt2/Resource.h58
-rw-r--r--tools/aapt2/ResourceValues.cpp248
-rw-r--r--tools/aapt2/ResourceValues.h13
-rw-r--r--tools/aapt2/Source.h23
-rw-r--r--tools/aapt2/cmd/Compile.cpp2
-rw-r--r--tools/aapt2/cmd/Convert.cpp381
-rw-r--r--tools/aapt2/cmd/Diff.cpp5
-rw-r--r--tools/aapt2/cmd/Dump.cpp56
-rw-r--r--tools/aapt2/cmd/Link.cpp219
-rw-r--r--tools/aapt2/cmd/Optimize.cpp15
-rw-r--r--tools/aapt2/cmd/Util.cpp93
-rw-r--r--tools/aapt2/cmd/Util.h3
-rw-r--r--tools/aapt2/cmd/Util_test.cpp9
-rw-r--r--tools/aapt2/compile/InlineXmlFormatParser.cpp2
-rw-r--r--tools/aapt2/format/binary/BinaryResourceParser.cpp115
-rw-r--r--tools/aapt2/format/binary/BinaryResourceParser.h4
-rw-r--r--tools/aapt2/format/binary/TableFlattener.cpp27
-rw-r--r--tools/aapt2/format/binary/TableFlattener_test.cpp5
-rw-r--r--tools/aapt2/format/proto/ProtoDeserialize.cpp35
-rw-r--r--tools/aapt2/format/proto/ProtoDeserialize.h11
-rw-r--r--tools/aapt2/format/proto/ProtoSerialize.cpp8
-rw-r--r--tools/aapt2/format/proto/ProtoSerialize_test.cpp18
-rw-r--r--tools/aapt2/integration-tests/NamespaceTest/App/Android.mk1
-rw-r--r--tools/aapt2/io/FileStream.cpp14
-rw-r--r--tools/aapt2/io/FileStream.h20
-rw-r--r--tools/aapt2/io/FileStream_test.cpp8
-rw-r--r--tools/aapt2/io/Util.cpp26
-rw-r--r--tools/aapt2/io/Util.h4
-rw-r--r--tools/aapt2/java/JavaClassGenerator.cpp4
-rw-r--r--tools/aapt2/java/ProguardRules.cpp9
-rw-r--r--tools/aapt2/java/ProguardRules_test.cpp6
-rw-r--r--tools/aapt2/link/ManifestFixer.cpp4
-rw-r--r--tools/aapt2/link/TableMerger.cpp71
-rw-r--r--tools/aapt2/link/TableMerger.h25
-rw-r--r--tools/aapt2/link/TableMerger_test.cpp27
-rw-r--r--tools/aapt2/optimize/MultiApkGenerator.cpp8
-rw-r--r--tools/aapt2/optimize/MultiApkGenerator_test.cpp6
-rw-r--r--tools/aapt2/process/SymbolTable.cpp2
-rw-r--r--tools/aapt2/test/Builders.cpp20
-rw-r--r--tools/aapt2/test/Builders.h9
-rw-r--r--tools/aapt2/text/Printer.cpp92
-rw-r--r--tools/aapt2/text/Printer.h53
-rw-r--r--tools/aapt2/text/Printer_test.cpp67
-rw-r--r--tools/aapt2/text/Unicode.cpp3
-rw-r--r--tools/aapt2/text/Unicode_test.cpp5
-rw-r--r--tools/aapt2/util/Files.cpp23
-rw-r--r--tools/aapt2/util/Util.cpp84
-rw-r--r--tools/aapt2/util/Util.h189
-rw-r--r--tools/aapt2/util/Util_test.cpp32
-rw-r--r--tools/aapt2/xml/XmlActionExecutor.cpp25
-rw-r--r--tools/aapt2/xml/XmlActionExecutor.h46
-rw-r--r--tools/aapt2/xml/XmlActionExecutor_test.cpp8
-rw-r--r--tools/aapt2/xml/XmlDom.cpp54
-rw-r--r--tools/aapt2/xml/XmlDom.h20
-rw-r--r--tools/aapt2/xml/XmlDom_test.cpp3
-rw-r--r--tools/apilint/apilint.py10
-rwxr-xr-xtools/apilint/apilint_sha.sh4
-rw-r--r--tools/stats_log_api_gen/Android.bp8
-rw-r--r--tools/stats_log_api_gen/main.cpp14
-rw-r--r--tools/stats_log_api_gen/test.proto2
-rw-r--r--tools/streaming_proto/cpp/main.cpp27
-rw-r--r--tools/streaming_proto/stream.proto14
-rw-r--r--tools/streaming_proto/string_utils.cpp11
-rw-r--r--tools/streaming_proto/string_utils.h9
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl38
-rw-r--r--wifi/java/android/net/wifi/WifiInfo.java3
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java55
-rw-r--r--wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl7
-rw-r--r--wifi/java/android/net/wifi/rtt/WifiRttManager.java51
-rw-r--r--wifi/tests/src/android/net/wifi/WifiManagerTest.java30
-rw-r--r--wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java8
1476 files changed, 49584 insertions, 27085 deletions
diff --git a/Android.bp b/Android.bp
index 5c1ccb7cc639..24a9bca1844c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -58,9 +58,11 @@ cc_library {
// runtime, as well as the only protos that are actually
// needed by the device.
srcs: [
+ "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",
],
@@ -81,9 +83,11 @@ gensrcs {
],
srcs: [
+ "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",
],
// Append protoc-gen-cppstream tool's PATH otherwise aprotoc can't find the plugin tool
diff --git a/Android.mk b/Android.mk
index 1ed8a2506600..2e65074cee9a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -79,6 +79,7 @@ LOCAL_SRC_FILES += \
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 \
@@ -137,6 +138,7 @@ LOCAL_SRC_FILES += \
../../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 \
@@ -158,6 +160,7 @@ LOCAL_SRC_FILES += \
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 \
@@ -218,6 +221,7 @@ LOCAL_SRC_FILES += \
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 \
@@ -380,7 +384,6 @@ LOCAL_SRC_FILES += \
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/IAssistDataReceiver.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 \
@@ -397,6 +400,7 @@ LOCAL_SRC_FILES += \
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 \
@@ -927,7 +931,7 @@ non_base_dirs := \
../opt/net/voip/src/java/android/net/sip
framework_base_android_test_mock_src_files := \
- $(call all-java-files-under, test-runner/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))
@@ -1554,6 +1558,7 @@ LOCAL_PROTOC_FLAGS := \
LOCAL_SOURCE_FILES_ALL_GENERATED := true
LOCAL_SRC_FILES := \
tools/streaming_proto/stream.proto \
+ cmds/am/proto/instrumentation_data.proto \
$(call all-proto-files-under, core/proto) \
$(call all-proto-files-under, libs/incident/proto)
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 50a597407e58..711c12d20a84 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -7,3 +7,4 @@ checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPL
services/print/
services/usb/
+api_lint_hook = ${REPO_ROOT}/frameworks/base/tools/apilint/apilint_sha.sh ${PREUPLOAD_COMMIT}
diff --git a/api/current.txt b/api/current.txt
index a0abc1a330de..06163ccee9d6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3609,11 +3609,11 @@ package android.app {
method public android.transition.Scene getContentScene();
method public android.transition.TransitionManager getContentTransitionManager();
method public android.view.View getCurrentFocus();
- method public android.app.FragmentManager getFragmentManager();
+ method public deprecated android.app.FragmentManager getFragmentManager();
method public android.content.Intent getIntent();
method public java.lang.Object getLastNonConfigurationInstance();
method public android.view.LayoutInflater getLayoutInflater();
- method public android.app.LoaderManager getLoaderManager();
+ method public deprecated android.app.LoaderManager getLoaderManager();
method public java.lang.String getLocalClassName();
method public int getMaxNumPictureInPictureActions();
method public final android.media.session.MediaController getMediaController();
@@ -3653,7 +3653,7 @@ package android.app {
method public void onActionModeStarted(android.view.ActionMode);
method public void onActivityReenter(int, android.content.Intent);
method protected void onActivityResult(int, int, android.content.Intent);
- method public void onAttachFragment(android.app.Fragment);
+ method public deprecated void onAttachFragment(android.app.Fragment);
method public void onAttachedToWindow();
method public void onBackPressed();
method protected void onChildTitleChanged(android.app.Activity, java.lang.CharSequence);
@@ -3795,8 +3795,8 @@ package android.app {
method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
method public void startActivityFromChild(android.app.Activity, android.content.Intent, int);
method public void startActivityFromChild(android.app.Activity, android.content.Intent, int, android.os.Bundle);
- method public void startActivityFromFragment(android.app.Fragment, android.content.Intent, int);
- method public void startActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
+ method public deprecated void startActivityFromFragment(android.app.Fragment, android.content.Intent, int);
+ method public deprecated void startActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
method public boolean startActivityIfNeeded(android.content.Intent, int);
method public boolean startActivityIfNeeded(android.content.Intent, int, android.os.Bundle);
method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
@@ -4455,7 +4455,7 @@ package android.app {
method public void unregisterForContextMenu(android.view.View);
}
- public class DialogFragment extends android.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+ public deprecated class DialogFragment extends android.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
ctor public DialogFragment();
method public void dismiss();
method public void dismissAllowingStateLoss();
@@ -4573,7 +4573,7 @@ package android.app {
method public void setSelectedGroup(int);
}
- public class Fragment implements android.content.ComponentCallbacks2 android.view.View.OnCreateContextMenuListener {
+ public deprecated class Fragment implements android.content.ComponentCallbacks2 android.view.View.OnCreateContextMenuListener {
ctor public Fragment();
method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method public final boolean equals(java.lang.Object);
@@ -4589,7 +4589,7 @@ package android.app {
method public final java.lang.Object getHost();
method public final int getId();
method public final android.view.LayoutInflater getLayoutInflater();
- method public android.app.LoaderManager getLoaderManager();
+ method public deprecated android.app.LoaderManager getLoaderManager();
method public final android.app.Fragment getParentFragment();
method public android.transition.Transition getReenterTransition();
method public final android.content.res.Resources getResources();
@@ -4684,11 +4684,11 @@ package android.app {
method public void unregisterForContextMenu(android.view.View);
}
- public static class Fragment.InstantiationException extends android.util.AndroidRuntimeException {
+ public static deprecated class Fragment.InstantiationException extends android.util.AndroidRuntimeException {
ctor public Fragment.InstantiationException(java.lang.String, java.lang.Exception);
}
- public static class Fragment.SavedState implements android.os.Parcelable {
+ public static deprecated class Fragment.SavedState implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.ClassLoaderCreator<android.app.Fragment.SavedState> CREATOR;
@@ -4707,17 +4707,17 @@ package android.app {
method public void setTitle(java.lang.CharSequence, java.lang.CharSequence);
}
- public static abstract interface FragmentBreadCrumbs.OnBreadCrumbClickListener {
+ public static abstract deprecated interface FragmentBreadCrumbs.OnBreadCrumbClickListener {
method public abstract boolean onBreadCrumbClick(android.app.FragmentManager.BackStackEntry, int);
}
- public abstract class FragmentContainer {
+ public abstract deprecated class FragmentContainer {
ctor public FragmentContainer();
method public abstract <T extends android.view.View> T onFindViewById(int);
method public abstract boolean onHasView();
}
- public class FragmentController {
+ public deprecated class FragmentController {
method public void attachHost(android.app.Fragment);
method public static final android.app.FragmentController createController(android.app.FragmentHostCallback<?>);
method public void dispatchActivityCreated();
@@ -4760,7 +4760,7 @@ package android.app {
method public android.os.Parcelable saveAllState();
}
- public abstract class FragmentHostCallback<E> extends android.app.FragmentContainer {
+ public abstract deprecated class FragmentHostCallback<E> extends android.app.FragmentContainer {
ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
method public void onAttachFragment(android.app.Fragment);
method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
@@ -4778,7 +4778,7 @@ package android.app {
method public boolean onUseFragmentManagerInflaterFactory();
}
- public abstract class FragmentManager {
+ public abstract deprecated class FragmentManager {
ctor public FragmentManager();
method public abstract void addOnBackStackChangedListener(android.app.FragmentManager.OnBackStackChangedListener);
method public abstract android.app.FragmentTransaction beginTransaction();
@@ -4809,7 +4809,7 @@ package android.app {
field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
}
- public static abstract interface FragmentManager.BackStackEntry {
+ public static abstract deprecated interface FragmentManager.BackStackEntry {
method public abstract java.lang.CharSequence getBreadCrumbShortTitle();
method public abstract int getBreadCrumbShortTitleRes();
method public abstract java.lang.CharSequence getBreadCrumbTitle();
@@ -4818,7 +4818,7 @@ package android.app {
method public abstract java.lang.String getName();
}
- public static abstract class FragmentManager.FragmentLifecycleCallbacks {
+ public static abstract deprecated class FragmentManager.FragmentLifecycleCallbacks {
ctor public FragmentManager.FragmentLifecycleCallbacks();
method public void onFragmentActivityCreated(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
method public void onFragmentAttached(android.app.FragmentManager, android.app.Fragment, android.content.Context);
@@ -4836,14 +4836,14 @@ package android.app {
method public void onFragmentViewDestroyed(android.app.FragmentManager, android.app.Fragment);
}
- public static abstract interface FragmentManager.OnBackStackChangedListener {
+ public static abstract deprecated interface FragmentManager.OnBackStackChangedListener {
method public abstract void onBackStackChanged();
}
- public class FragmentManagerNonConfig {
+ public deprecated class FragmentManagerNonConfig {
}
- public abstract class FragmentTransaction {
+ public abstract deprecated class FragmentTransaction {
ctor public FragmentTransaction();
method public abstract android.app.FragmentTransaction add(android.app.Fragment, java.lang.String);
method public abstract android.app.FragmentTransaction add(int, android.app.Fragment);
@@ -4943,6 +4943,7 @@ package android.app {
method public void setInTouchMode(boolean);
method public void start();
method public android.app.Activity startActivitySync(android.content.Intent);
+ method public android.app.Activity startActivitySync(android.content.Intent, android.os.Bundle);
method public deprecated void startAllocCounting();
method public void startPerformanceSnapshot();
method public void startProfiling();
@@ -5048,7 +5049,7 @@ package android.app {
method public void setSelection(int);
}
- public class ListFragment extends android.app.Fragment {
+ public deprecated class ListFragment extends android.app.Fragment {
ctor public ListFragment();
method public android.widget.ListAdapter getListAdapter();
method public android.widget.ListView getListView();
@@ -5062,7 +5063,7 @@ package android.app {
method public void setSelection(int);
}
- public abstract class LoaderManager {
+ public abstract deprecated class LoaderManager {
ctor public LoaderManager();
method public abstract void destroyLoader(int);
method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
@@ -5072,7 +5073,7 @@ package android.app {
method public abstract <D> android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
}
- public static abstract interface LoaderManager.LoaderCallbacks<D> {
+ public static abstract deprecated interface LoaderManager.LoaderCallbacks<D> {
method public abstract android.content.Loader<D> onCreateLoader(int, android.os.Bundle);
method public abstract void onLoadFinished(android.content.Loader<D>, D);
method public abstract void onLoaderReset(android.content.Loader<D>);
@@ -6541,6 +6542,7 @@ package android.app.admin {
field public static final int LOCK_TASK_FEATURE_NOTIFICATIONS = 2; // 0x2
field public static final int LOCK_TASK_FEATURE_RECENTS = 8; // 0x8
field public static final int LOCK_TASK_FEATURE_SYSTEM_INFO = 1; // 0x1
+ field public static final int MAKE_USER_EPHEMERAL = 2; // 0x2
field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning";
field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000
field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000
@@ -6846,7 +6848,8 @@ package android.app.job {
method public static final long getMinFlexMillis();
method public long getMinLatencyMillis();
method public static final long getMinPeriodMillis();
- method public int getNetworkType();
+ method public deprecated int getNetworkType();
+ method public android.net.NetworkRequest getRequiredNetwork();
method public android.content.ComponentName getService();
method public android.os.Bundle getTransientExtras();
method public long getTriggerContentMaxDelay();
@@ -6866,7 +6869,8 @@ package android.app.job {
field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L
field public static final int NETWORK_BYTES_UNKNOWN = -1; // 0xffffffff
field public static final int NETWORK_TYPE_ANY = 1; // 0x1
- field public static final int NETWORK_TYPE_METERED = 4; // 0x4
+ field public static final int NETWORK_TYPE_CELLULAR = 4; // 0x4
+ field public static final deprecated int NETWORK_TYPE_METERED = 4; // 0x4
field public static final int NETWORK_TYPE_NONE = 0; // 0x0
field public static final int NETWORK_TYPE_NOT_ROAMING = 3; // 0x3
field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2
@@ -6885,6 +6889,7 @@ package android.app.job {
method public android.app.job.JobInfo.Builder setPeriodic(long);
method public android.app.job.JobInfo.Builder setPeriodic(long, long);
method public android.app.job.JobInfo.Builder setPersisted(boolean);
+ method public android.app.job.JobInfo.Builder setRequiredNetwork(android.net.NetworkRequest);
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
method public android.app.job.JobInfo.Builder setRequiresBatteryNotLow(boolean);
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
@@ -6969,6 +6974,7 @@ package android.app.slice {
public final class Slice implements android.os.Parcelable {
ctor protected Slice(android.os.Parcel);
method public static android.app.slice.Slice bindSlice(android.content.ContentResolver, android.net.Uri);
+ method public static android.app.slice.Slice bindSlice(android.content.Context, android.content.Intent);
method public int describeContents();
method public java.util.List<java.lang.String> getHints();
method public java.util.List<android.app.slice.SliceItem> getItems();
@@ -7037,6 +7043,7 @@ package android.app.slice {
method public final java.lang.String getType(android.net.Uri);
method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
method public abstract android.app.slice.Slice onBindSlice(android.net.Uri);
+ method public android.net.Uri onMapIntentToUri(android.content.Intent);
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
@@ -8528,7 +8535,7 @@ package android.content {
ctor public AsyncQueryHandler.WorkerHandler(android.os.Looper);
}
- public abstract class AsyncTaskLoader<D> extends android.content.Loader {
+ public abstract deprecated class AsyncTaskLoader<D> extends android.content.Loader {
ctor public AsyncTaskLoader(android.content.Context);
method public void cancelLoadInBackground();
method public boolean isLoadInBackgroundCanceled();
@@ -9101,6 +9108,7 @@ package android.content {
field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
field public static final int CONTEXT_INCLUDE_CODE = 1; // 0x1
field public static final int CONTEXT_RESTRICTED = 4; // 0x4
+ field public static final java.lang.String CROSS_PROFILE_APPS_SERVICE = "crossprofileapps";
field public static final java.lang.String DEVICE_POLICY_SERVICE = "device_policy";
field public static final java.lang.String DISPLAY_SERVICE = "display";
field public static final java.lang.String DOWNLOAD_SERVICE = "download";
@@ -9267,7 +9275,7 @@ package android.content {
method public void unregisterReceiver(android.content.BroadcastReceiver);
}
- public class CursorLoader extends android.content.AsyncTaskLoader {
+ public deprecated class CursorLoader extends android.content.AsyncTaskLoader {
ctor public CursorLoader(android.content.Context);
ctor public CursorLoader(android.content.Context, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
method public void deliverResult(android.database.Cursor);
@@ -9873,7 +9881,7 @@ package android.content {
ctor public IntentSender.SendIntentException(java.lang.Exception);
}
- public class Loader<D> {
+ public deprecated class Loader<D> {
ctor public Loader(android.content.Context);
method public void abandon();
method public boolean cancelLoad();
@@ -9906,15 +9914,15 @@ package android.content {
method public void unregisterOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
}
- public final class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
+ public final deprecated class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
ctor public Loader.ForceLoadContentObserver();
}
- public static abstract interface Loader.OnLoadCanceledListener<D> {
+ public static abstract deprecated interface Loader.OnLoadCanceledListener<D> {
method public abstract void onLoadCanceled(android.content.Loader<D>);
}
- public static abstract interface Loader.OnLoadCompleteListener<D> {
+ public static abstract deprecated interface Loader.OnLoadCompleteListener<D> {
method public abstract void onLoadComplete(android.content.Loader<D>, D);
}
@@ -10568,6 +10576,7 @@ package android.content.pm {
field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
field public static final int FLAG_MATCH_PINNED = 2; // 0x2
+ field public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1024; // 0x400
}
public class PackageInfo implements android.os.Parcelable {
@@ -11222,6 +11231,15 @@ package android.content.pm {
}
+package android.content.pm.crossprofile {
+
+ public class CrossProfileApps {
+ 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);
+ }
+
+}
+
package android.content.res {
public class AssetFileDescriptor implements java.io.Closeable android.os.Parcelable {
@@ -12121,9 +12139,11 @@ package android.database.sqlite {
method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
method public android.database.DatabaseErrorHandler getErrorHandler();
method public long getIdleConnectionTimeout();
+ method public java.lang.String getJournalMode();
method public int getLookasideSlotCount();
method public int getLookasideSlotSize();
method public int getOpenFlags();
+ method public java.lang.String getSynchronousMode();
}
public static final class SQLiteDatabase.OpenParams.Builder {
@@ -12135,8 +12155,10 @@ package android.database.sqlite {
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(android.database.DatabaseErrorHandler);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(long);
+ method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setJournalMode(java.lang.String);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(int, int);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
+ method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setSynchronousMode(java.lang.String);
}
public class SQLiteDatabaseCorruptException extends android.database.sqlite.SQLiteException {
@@ -12183,6 +12205,7 @@ package android.database.sqlite {
public abstract class SQLiteOpenHelper {
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
+ ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, int, android.database.sqlite.SQLiteDatabase.OpenParams);
method public synchronized void close();
method public java.lang.String getDatabaseName();
method public android.database.sqlite.SQLiteDatabase getReadableDatabase();
@@ -15263,6 +15286,7 @@ package android.hardware.camera2 {
method public abstract int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract int setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException;
+ method public void updateOutputConfiguration(android.hardware.camera2.params.OutputConfiguration) throws android.hardware.camera2.CameraAccessException;
}
public static abstract class CameraCaptureSession.CaptureCallback {
@@ -15904,9 +15928,11 @@ package android.hardware.camera2.params {
method public void addSurface(android.view.Surface);
method public int describeContents();
method public void enableSurfaceSharing();
+ method public static int getMaxSharedSurfaceCount();
method public android.view.Surface getSurface();
method public int getSurfaceGroupId();
method public java.util.List<android.view.Surface> getSurfaces();
+ method public void removeSurface(android.view.Surface);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff
@@ -18272,11 +18298,13 @@ package android.icu.text {
method public synchronized void applyLocalizedPattern(java.lang.String);
method public synchronized void applyPattern(java.lang.String);
method public synchronized boolean areSignificantDigitsUsed();
+ method public synchronized boolean equals(java.lang.Object);
method public java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(java.math.BigInteger, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(java.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(android.icu.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
+ method public synchronized android.icu.util.Currency getCurrency();
method public synchronized android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
method public synchronized android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
method public synchronized android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
@@ -18284,8 +18312,12 @@ package android.icu.text {
method public synchronized int getGroupingSize();
method public synchronized java.math.MathContext getMathContext();
method public synchronized android.icu.math.MathContext getMathContextICU();
+ method public synchronized int getMaximumFractionDigits();
+ method public synchronized int getMaximumIntegerDigits();
method public synchronized int getMaximumSignificantDigits();
method public synchronized byte getMinimumExponentDigits();
+ method public synchronized int getMinimumFractionDigits();
+ method public synchronized int getMinimumIntegerDigits();
method public synchronized int getMinimumSignificantDigits();
method public synchronized int getMultiplier();
method public synchronized java.lang.String getNegativePrefix();
@@ -18296,13 +18328,19 @@ package android.icu.text {
method public synchronized java.lang.String getPositivePrefix();
method public synchronized java.lang.String getPositiveSuffix();
method public synchronized java.math.BigDecimal getRoundingIncrement();
+ method public synchronized int getRoundingMode();
method public synchronized int getSecondaryGroupingSize();
+ method public synchronized int hashCode();
method public synchronized boolean isDecimalPatternMatchRequired();
method public synchronized boolean isDecimalSeparatorAlwaysShown();
method public synchronized boolean isExponentSignAlwaysShown();
+ method public synchronized boolean isGroupingUsed();
method public synchronized boolean isParseBigDecimal();
+ method public synchronized boolean isParseIntegerOnly();
+ method public synchronized boolean isParseStrict();
method public synchronized boolean isScientificNotation();
method public java.lang.Number parse(java.lang.String, java.text.ParsePosition);
+ method public synchronized void setCurrency(android.icu.util.Currency);
method public synchronized void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
method public synchronized void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
method public synchronized void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
@@ -18311,10 +18349,15 @@ package android.icu.text {
method public synchronized void setExponentSignAlwaysShown(boolean);
method public synchronized void setFormatWidth(int);
method public synchronized void setGroupingSize(int);
+ method public synchronized void setGroupingUsed(boolean);
method public synchronized void setMathContext(java.math.MathContext);
method public synchronized void setMathContextICU(android.icu.math.MathContext);
+ method public synchronized void setMaximumFractionDigits(int);
+ method public synchronized void setMaximumIntegerDigits(int);
method public synchronized void setMaximumSignificantDigits(int);
method public synchronized void setMinimumExponentDigits(byte);
+ method public synchronized void setMinimumFractionDigits(int);
+ method public synchronized void setMinimumIntegerDigits(int);
method public synchronized void setMinimumSignificantDigits(int);
method public synchronized void setMultiplier(int);
method public synchronized void setNegativePrefix(java.lang.String);
@@ -18322,12 +18365,15 @@ package android.icu.text {
method public synchronized void setPadCharacter(char);
method public synchronized void setPadPosition(int);
method public synchronized void setParseBigDecimal(boolean);
+ method public synchronized void setParseIntegerOnly(boolean);
method public deprecated void setParseMaxDigits(int);
+ method public synchronized void setParseStrict(boolean);
method public synchronized void setPositivePrefix(java.lang.String);
method public synchronized void setPositiveSuffix(java.lang.String);
method public synchronized void setRoundingIncrement(java.math.BigDecimal);
method public synchronized void setRoundingIncrement(android.icu.math.BigDecimal);
method public synchronized void setRoundingIncrement(double);
+ method public synchronized void setRoundingMode(int);
method public synchronized void setScientificNotation(boolean);
method public synchronized void setSecondaryGroupingSize(int);
method public synchronized void setSignificantDigitsUsed(boolean);
@@ -23008,8 +23054,9 @@ package android.media {
field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
}
- public class MediaPlayer implements android.media.VolumeAutomation {
+ public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation {
ctor public MediaPlayer();
+ method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(java.io.FileDescriptor, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -23031,6 +23078,8 @@ package android.media {
method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
method public android.os.PersistableBundle getMetrics();
method public android.media.PlaybackParams getPlaybackParams();
+ method public android.media.AudioDeviceInfo getPreferredDevice();
+ method public android.media.AudioDeviceInfo getRoutedDevice();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
method public android.media.SyncParams getSyncParams();
method public android.media.MediaTimestamp getTimestamp();
@@ -23046,6 +23095,7 @@ package android.media {
method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
method public void release();
method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
+ method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public void reset();
method public void restoreKeys(byte[]) throws android.media.MediaPlayer.NoDrmSchemeException;
method public void seekTo(long, int);
@@ -23082,6 +23132,7 @@ package android.media {
method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener);
method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener);
method public void setPlaybackParams(android.media.PlaybackParams);
+ method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
method public void setScreenOnWhilePlaying(boolean);
method public void setSurface(android.view.Surface);
method public void setSyncParams(android.media.SyncParams);
@@ -25970,6 +26021,7 @@ package android.net {
field public static final int NET_CAPABILITY_MMS = 0; // 0x0
field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
+ field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
field public static final int NET_CAPABILITY_RCS = 8; // 0x8
field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
@@ -26000,7 +26052,7 @@ package android.net {
method public boolean isConnected();
method public boolean isConnectedOrConnecting();
method public boolean isFailover();
- method public boolean isRoaming();
+ method public deprecated boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
}
@@ -31009,6 +31061,7 @@ package android.os {
}
public final class Debug {
+ method public static void attachJvmtiAgent(java.lang.String, java.lang.String) throws java.io.IOException;
method public static deprecated void changeDebugPort(int);
method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
method public static boolean dumpService(java.lang.String, java.io.FileDescriptor, java.lang.String[]);
@@ -31809,6 +31862,14 @@ package android.os {
method public static void setVmPolicy(android.os.StrictMode.VmPolicy);
}
+ public static abstract interface StrictMode.OnThreadViolationListener {
+ method public abstract void onThreadViolation(android.os.strictmode.Violation);
+ }
+
+ public static abstract interface StrictMode.OnVmViolationListener {
+ method public abstract void onVmViolation(android.os.strictmode.Violation);
+ }
+
public static final class StrictMode.ThreadPolicy {
field public static final android.os.StrictMode.ThreadPolicy LAX;
}
@@ -31829,6 +31890,7 @@ package android.os {
method public android.os.StrictMode.ThreadPolicy.Builder penaltyDialog();
method public android.os.StrictMode.ThreadPolicy.Builder penaltyDropBox();
method public android.os.StrictMode.ThreadPolicy.Builder penaltyFlashScreen();
+ method public android.os.StrictMode.ThreadPolicy.Builder penaltyListener(android.os.StrictMode.OnThreadViolationListener, java.util.concurrent.Executor);
method public android.os.StrictMode.ThreadPolicy.Builder penaltyLog();
method public android.os.StrictMode.ThreadPolicy.Builder permitAll();
method public android.os.StrictMode.ThreadPolicy.Builder permitCustomSlowCalls();
@@ -31860,6 +31922,7 @@ package android.os {
method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnFileUriExposure();
method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox();
+ method public android.os.StrictMode.VmPolicy.Builder penaltyListener(android.os.StrictMode.OnVmViolationListener, java.util.concurrent.Executor);
method public android.os.StrictMode.VmPolicy.Builder penaltyLog();
method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(java.lang.Class, int);
}
@@ -31867,10 +31930,12 @@ package android.os {
public final class SystemClock {
method public static long currentThreadTimeMillis();
method public static long elapsedRealtime();
+ method public static java.time.Clock elapsedRealtimeClock();
method public static long elapsedRealtimeNanos();
method public static boolean setCurrentTimeMillis(long);
method public static void sleep(long);
method public static long uptimeMillis();
+ method public static java.time.Clock uptimeMillisClock();
}
public class TestLooperManager {
@@ -31952,6 +32017,7 @@ package android.os {
field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
field public static final java.lang.String DISALLOW_CONFIG_DATE_TIME = "no_config_date_time";
+ field public static final java.lang.String DISALLOW_CONFIG_LOCALE = "no_config_locale";
field public static final java.lang.String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
field public static final java.lang.String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
field public static final java.lang.String DISALLOW_CONFIG_VPN = "no_config_vpn";
@@ -31980,6 +32046,7 @@ package android.os {
field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
field public static final java.lang.String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
+ field public static final java.lang.String DISALLOW_USER_SWITCH = "no_user_switch";
field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1
@@ -32220,6 +32287,62 @@ package android.os.storage {
}
+package android.os.strictmode {
+
+ public final class CleartextNetworkViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class ContentUriWithoutPermissionViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class CustomViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class DiskReadViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class DiskWriteViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class FileUriExposedViolation extends android.os.strictmode.Violation {
+ }
+
+ public class InstanceCountViolation extends android.os.strictmode.Violation {
+ method public long getNumberOfInstances();
+ }
+
+ public final class IntentReceiverLeakedViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class LeakedClosableViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class NetworkViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class ResourceMismatchViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class ServiceConnectionLeakedViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class SqliteObjectLeakedViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class UnbufferedIoViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class UntaggedSocketViolation extends android.os.strictmode.Violation {
+ }
+
+ public abstract class Violation extends java.lang.Throwable {
+ }
+
+ public final class WebViewMethodCalledOnWrongThreadViolation extends android.os.strictmode.Violation {
+ }
+
+}
+
package android.preference {
public class CheckBoxPreference extends android.preference.TwoStatePreference {
@@ -32506,7 +32629,7 @@ package android.preference {
method public default void putStringSet(java.lang.String, java.util.Set<java.lang.String>);
}
- public abstract class PreferenceFragment extends android.app.Fragment {
+ public abstract deprecated class PreferenceFragment extends android.app.Fragment {
ctor public PreferenceFragment();
method public void addPreferencesFromIntent(android.content.Intent);
method public void addPreferencesFromResource(int);
@@ -32517,7 +32640,7 @@ package android.preference {
method public void setPreferenceScreen(android.preference.PreferenceScreen);
}
- public static abstract interface PreferenceFragment.OnPreferenceStartFragmentCallback {
+ public static abstract deprecated interface PreferenceFragment.OnPreferenceStartFragmentCallback {
method public abstract boolean onPreferenceStartFragment(android.preference.PreferenceFragment, android.preference.Preference);
}
@@ -35170,6 +35293,7 @@ package android.provider {
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
+ field public static final java.lang.String EXTRA_SUB_ID = "android.provider.extra.SUB_ID";
field public static final java.lang.String INTENT_CATEGORY_USAGE_ACCESS_CONFIG = "android.intent.category.USAGE_ACCESS_CONFIG";
field public static final java.lang.String METADATA_USAGE_ACCESS_REASON = "android.settings.metadata.USAGE_ACCESS_REASON";
}
@@ -38421,6 +38545,16 @@ package android.system {
field public final int errno;
}
+ public class Int32Ref {
+ ctor public Int32Ref(int);
+ field public int value;
+ }
+
+ public class Int64Ref {
+ ctor public Int64Ref(long);
+ field public long value;
+ }
+
public final class Os {
method public static java.io.FileDescriptor accept(java.io.FileDescriptor, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
method public static boolean access(java.lang.String, int) throws android.system.ErrnoException;
@@ -38490,7 +38624,8 @@ package android.system {
method public static void remove(java.lang.String) throws android.system.ErrnoException;
method public static void removexattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
- method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+ method public static deprecated long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+ method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.system.Int64Ref, long) throws android.system.ErrnoException;
method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
method public static void setegid(int) throws android.system.ErrnoException;
@@ -38515,7 +38650,8 @@ package android.system {
method public static int umask(int);
method public static android.system.StructUtsname uname();
method public static void unsetenv(java.lang.String) throws android.system.ErrnoException;
- method public static int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+ method public static deprecated int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+ method public static int waitpid(int, android.system.Int32Ref, int) throws android.system.ErrnoException;
method public static int write(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
method public static int write(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
method public static int writev(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
@@ -39091,6 +39227,7 @@ package android.telecom {
method public android.telecom.Call.RttCall getRttCall();
method public int getState();
method public android.telecom.InCallService.VideoCall getVideoCall();
+ method public void handoverTo(android.telecom.PhoneAccountHandle, int, android.os.Bundle);
method public void hold();
method public boolean isRttActive();
method public void mergeConference();
@@ -39135,6 +39272,8 @@ package android.telecom {
method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
+ method public void onHandoverComplete(android.telecom.Call);
+ method public void onHandoverFailed(android.telecom.Call, int);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
method public void onRttInitiationFailure(android.telecom.Call, int);
@@ -39143,6 +39282,10 @@ package android.telecom {
method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
method public void onStateChanged(android.telecom.Call, int);
method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
+ field public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1; // 0x1
+ 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
}
public static class Call.Details {
@@ -39211,7 +39354,9 @@ package android.telecom {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
method public int describeContents();
+ method public android.bluetooth.BluetoothDevice getActiveBluetoothDevice();
method public int getRoute();
+ method public java.util.Collection<android.bluetooth.BluetoothDevice> getSupportedBluetoothDevices();
method public int getSupportedRouteMask();
method public boolean isMuted();
method public void writeToParcel(android.os.Parcel, int);
@@ -39343,6 +39488,7 @@ package android.telecom {
method public final void putExtras(android.os.Bundle);
method public final void removeExtras(java.util.List<java.lang.String>);
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 setActive();
method public final void setAddress(android.net.Uri, int);
@@ -39474,8 +39620,11 @@ package android.telecom {
method public void onConference(android.telecom.Connection, android.telecom.Connection);
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);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public void onHandoverFailed(android.telecom.ConnectionRequest, int);
method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
@@ -39533,6 +39682,7 @@ package android.telecom {
method public void onCanAddCallChanged(boolean);
method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public void onSilenceRinger();
+ method public final void requestBluetoothAudio(java.lang.String);
method public final void setAudioRoute(int);
method public final void setMuted(boolean);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
@@ -39597,6 +39747,9 @@ package android.telecom {
field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
+ field public static final java.lang.String EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
+ field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_FROM = "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
+ field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_TO = "android.telecom.extra.SUPPORTS_HANDOVER_TO";
field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
field public static final java.lang.String SCHEME_SIP = "sip";
@@ -39757,6 +39910,7 @@ package android.telecom {
}
public class TelecomManager {
+ method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
method public void acceptRingingCall();
method public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
@@ -39925,8 +40079,8 @@ package android.telephony {
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
- field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
+ field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
@@ -40409,6 +40563,7 @@ package android.telephony {
method public void sendMultimediaMessage(android.content.Context, android.net.Uri, java.lang.String, android.os.Bundle, android.app.PendingIntent);
method public void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
method public void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
+ method public void sendTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
field public static final java.lang.String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
field public static final java.lang.String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
field public static final java.lang.String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
@@ -44552,6 +44707,7 @@ package android.view {
field public static final int STATE_DOZE_SUSPEND = 4; // 0x4
field public static final int STATE_OFF = 1; // 0x1
field public static final int STATE_ON = 2; // 0x2
+ field public static final int STATE_ON_SUSPEND = 6; // 0x6
field public static final int STATE_UNKNOWN = 0; // 0x0
field public static final int STATE_VR = 5; // 0x5
}
@@ -48956,14 +49112,23 @@ package android.view.textclassifier {
method public android.view.textclassifier.TextClassification.Builder setText(java.lang.String);
}
+ public static final class TextClassification.Options {
+ ctor public TextClassification.Options();
+ method public android.os.LocaleList getDefaultLocales();
+ method public android.view.textclassifier.TextClassification.Options setDefaultLocales(android.os.LocaleList);
+ }
+
public final class TextClassificationManager {
method public android.view.textclassifier.TextClassifier getTextClassifier();
method public void setTextClassifier(android.view.textclassifier.TextClassifier);
}
public abstract interface TextClassifier {
- method public abstract android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
- method public abstract android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
+ 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, 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.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, 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";
@@ -48972,6 +49137,36 @@ package android.view.textclassifier {
field public static final java.lang.String TYPE_URL = "url";
}
+ public final class TextLinks {
+ method public boolean apply(android.text.SpannableString, java.util.function.Function<android.view.textclassifier.TextLinks.TextLink, android.text.style.ClickableSpan>);
+ method public java.util.Collection<android.view.textclassifier.TextLinks.TextLink> getLinks();
+ }
+
+ public static final class TextLinks.Builder {
+ ctor public TextLinks.Builder(java.lang.String);
+ method public android.view.textclassifier.TextLinks.Builder addLink(android.view.textclassifier.TextLinks.TextLink);
+ method public android.view.textclassifier.TextLinks build();
+ }
+
+ public static final class 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);
+ }
+
+ public static final class TextLinks.TextLink {
+ ctor public TextLinks.TextLink(java.lang.String, int, int, java.util.Map<java.lang.String, java.lang.Float>);
+ method public float getConfidenceScore(java.lang.String);
+ method public int getEnd();
+ method public java.lang.String getEntity(int);
+ method public int getEntityCount();
+ method public int getStart();
+ }
+
public final class TextSelection {
method public float getConfidenceScore(java.lang.String);
method public java.lang.String getEntity(int);
@@ -48986,6 +49181,12 @@ package android.view.textclassifier {
method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
}
+ public static final class TextSelection.Options {
+ ctor public TextSelection.Options();
+ method public android.os.LocaleList getDefaultLocales();
+ method public android.view.textclassifier.TextSelection.Options setDefaultLocales(android.os.LocaleList);
+ }
+
}
package android.view.textservice {
@@ -49815,7 +50016,7 @@ package android.webkit {
method public abstract void setHttpAuthUsernamePassword(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
}
- public class WebViewFragment extends android.app.Fragment {
+ public deprecated class WebViewFragment extends android.app.Fragment {
ctor public WebViewFragment();
method public android.webkit.WebView getWebView();
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 9a5968ed3eda..808f222b62b7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -88,6 +88,7 @@ package android {
field public static final java.lang.String CAPTURE_SECURE_VIDEO_OUTPUT = "android.permission.CAPTURE_SECURE_VIDEO_OUTPUT";
field public static final java.lang.String CAPTURE_TV_INPUT = "android.permission.CAPTURE_TV_INPUT";
field public static final java.lang.String CAPTURE_VIDEO_OUTPUT = "android.permission.CAPTURE_VIDEO_OUTPUT";
+ field public static final java.lang.String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
field public static final java.lang.String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE";
field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
field public static final java.lang.String CHANGE_DEVICE_IDLE_TEMP_WHITELIST = "android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST";
@@ -3753,11 +3754,11 @@ package android.app {
method public android.transition.Scene getContentScene();
method public android.transition.TransitionManager getContentTransitionManager();
method public android.view.View getCurrentFocus();
- method public android.app.FragmentManager getFragmentManager();
+ method public deprecated android.app.FragmentManager getFragmentManager();
method public android.content.Intent getIntent();
method public java.lang.Object getLastNonConfigurationInstance();
method public android.view.LayoutInflater getLayoutInflater();
- method public android.app.LoaderManager getLoaderManager();
+ method public deprecated android.app.LoaderManager getLoaderManager();
method public java.lang.String getLocalClassName();
method public int getMaxNumPictureInPictureActions();
method public final android.media.session.MediaController getMediaController();
@@ -3798,7 +3799,7 @@ package android.app {
method public void onActionModeStarted(android.view.ActionMode);
method public void onActivityReenter(int, android.content.Intent);
method protected void onActivityResult(int, int, android.content.Intent);
- method public void onAttachFragment(android.app.Fragment);
+ method public deprecated void onAttachFragment(android.app.Fragment);
method public void onAttachedToWindow();
method public void onBackPressed();
method public deprecated void onBackgroundVisibleBehindChanged(boolean);
@@ -3942,8 +3943,8 @@ package android.app {
method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
method public void startActivityFromChild(android.app.Activity, android.content.Intent, int);
method public void startActivityFromChild(android.app.Activity, android.content.Intent, int, android.os.Bundle);
- method public void startActivityFromFragment(android.app.Fragment, android.content.Intent, int);
- method public void startActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
+ method public deprecated void startActivityFromFragment(android.app.Fragment, android.content.Intent, int);
+ method public deprecated void startActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
method public boolean startActivityIfNeeded(android.content.Intent, int);
method public boolean startActivityIfNeeded(android.content.Intent, int, android.os.Bundle);
method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
@@ -4627,7 +4628,7 @@ package android.app {
method public void unregisterForContextMenu(android.view.View);
}
- public class DialogFragment extends android.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+ public deprecated class DialogFragment extends android.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
ctor public DialogFragment();
method public void dismiss();
method public void dismissAllowingStateLoss();
@@ -4746,7 +4747,7 @@ package android.app {
method public void setSelectedGroup(int);
}
- public class Fragment implements android.content.ComponentCallbacks2 android.view.View.OnCreateContextMenuListener {
+ public deprecated class Fragment implements android.content.ComponentCallbacks2 android.view.View.OnCreateContextMenuListener {
ctor public Fragment();
method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method public final boolean equals(java.lang.Object);
@@ -4762,7 +4763,7 @@ package android.app {
method public final java.lang.Object getHost();
method public final int getId();
method public final android.view.LayoutInflater getLayoutInflater();
- method public android.app.LoaderManager getLoaderManager();
+ method public deprecated android.app.LoaderManager getLoaderManager();
method public final android.app.Fragment getParentFragment();
method public android.transition.Transition getReenterTransition();
method public final android.content.res.Resources getResources();
@@ -4857,11 +4858,11 @@ package android.app {
method public void unregisterForContextMenu(android.view.View);
}
- public static class Fragment.InstantiationException extends android.util.AndroidRuntimeException {
+ public static deprecated class Fragment.InstantiationException extends android.util.AndroidRuntimeException {
ctor public Fragment.InstantiationException(java.lang.String, java.lang.Exception);
}
- public static class Fragment.SavedState implements android.os.Parcelable {
+ public static deprecated class Fragment.SavedState implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.ClassLoaderCreator<android.app.Fragment.SavedState> CREATOR;
@@ -4880,17 +4881,17 @@ package android.app {
method public void setTitle(java.lang.CharSequence, java.lang.CharSequence);
}
- public static abstract interface FragmentBreadCrumbs.OnBreadCrumbClickListener {
+ public static abstract deprecated interface FragmentBreadCrumbs.OnBreadCrumbClickListener {
method public abstract boolean onBreadCrumbClick(android.app.FragmentManager.BackStackEntry, int);
}
- public abstract class FragmentContainer {
+ public abstract deprecated class FragmentContainer {
ctor public FragmentContainer();
method public abstract <T extends android.view.View> T onFindViewById(int);
method public abstract boolean onHasView();
}
- public class FragmentController {
+ public deprecated class FragmentController {
method public void attachHost(android.app.Fragment);
method public static final android.app.FragmentController createController(android.app.FragmentHostCallback<?>);
method public void dispatchActivityCreated();
@@ -4933,7 +4934,7 @@ package android.app {
method public android.os.Parcelable saveAllState();
}
- public abstract class FragmentHostCallback<E> extends android.app.FragmentContainer {
+ public abstract deprecated class FragmentHostCallback<E> extends android.app.FragmentContainer {
ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
method public void onAttachFragment(android.app.Fragment);
method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
@@ -4951,7 +4952,7 @@ package android.app {
method public boolean onUseFragmentManagerInflaterFactory();
}
- public abstract class FragmentManager {
+ public abstract deprecated class FragmentManager {
ctor public FragmentManager();
method public abstract void addOnBackStackChangedListener(android.app.FragmentManager.OnBackStackChangedListener);
method public abstract android.app.FragmentTransaction beginTransaction();
@@ -4982,7 +4983,7 @@ package android.app {
field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
}
- public static abstract interface FragmentManager.BackStackEntry {
+ public static abstract deprecated interface FragmentManager.BackStackEntry {
method public abstract java.lang.CharSequence getBreadCrumbShortTitle();
method public abstract int getBreadCrumbShortTitleRes();
method public abstract java.lang.CharSequence getBreadCrumbTitle();
@@ -4991,7 +4992,7 @@ package android.app {
method public abstract java.lang.String getName();
}
- public static abstract class FragmentManager.FragmentLifecycleCallbacks {
+ public static abstract deprecated class FragmentManager.FragmentLifecycleCallbacks {
ctor public FragmentManager.FragmentLifecycleCallbacks();
method public void onFragmentActivityCreated(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
method public void onFragmentAttached(android.app.FragmentManager, android.app.Fragment, android.content.Context);
@@ -5009,14 +5010,14 @@ package android.app {
method public void onFragmentViewDestroyed(android.app.FragmentManager, android.app.Fragment);
}
- public static abstract interface FragmentManager.OnBackStackChangedListener {
+ public static abstract deprecated interface FragmentManager.OnBackStackChangedListener {
method public abstract void onBackStackChanged();
}
- public class FragmentManagerNonConfig {
+ public deprecated class FragmentManagerNonConfig {
}
- public abstract class FragmentTransaction {
+ public abstract deprecated class FragmentTransaction {
ctor public FragmentTransaction();
method public abstract android.app.FragmentTransaction add(android.app.Fragment, java.lang.String);
method public abstract android.app.FragmentTransaction add(int, android.app.Fragment);
@@ -5128,6 +5129,7 @@ package android.app {
method public void setInTouchMode(boolean);
method public void start();
method public android.app.Activity startActivitySync(android.content.Intent);
+ method public android.app.Activity startActivitySync(android.content.Intent, android.os.Bundle);
method public deprecated void startAllocCounting();
method public void startPerformanceSnapshot();
method public void startProfiling();
@@ -5233,7 +5235,7 @@ package android.app {
method public void setSelection(int);
}
- public class ListFragment extends android.app.Fragment {
+ public deprecated class ListFragment extends android.app.Fragment {
ctor public ListFragment();
method public android.widget.ListAdapter getListAdapter();
method public android.widget.ListView getListView();
@@ -5247,7 +5249,7 @@ package android.app {
method public void setSelection(int);
}
- public abstract class LoaderManager {
+ public abstract deprecated class LoaderManager {
ctor public LoaderManager();
method public abstract void destroyLoader(int);
method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
@@ -5257,7 +5259,7 @@ package android.app {
method public abstract <D> android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
}
- public static abstract interface LoaderManager.LoaderCallbacks<D> {
+ public static abstract deprecated interface LoaderManager.LoaderCallbacks<D> {
method public abstract android.content.Loader<D> onCreateLoader(int, android.os.Bundle);
method public abstract void onLoadFinished(android.content.Loader<D>, D);
method public abstract void onLoaderReset(android.content.Loader<D>);
@@ -6787,6 +6789,7 @@ package android.app.admin {
field public static final int LOCK_TASK_FEATURE_NOTIFICATIONS = 2; // 0x2
field public static final int LOCK_TASK_FEATURE_RECENTS = 8; // 0x8
field public static final int LOCK_TASK_FEATURE_SYSTEM_INFO = 1; // 0x1
+ field public static final int MAKE_USER_EPHEMERAL = 2; // 0x2
field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning";
field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000
field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000
@@ -7288,7 +7291,8 @@ package android.app.job {
method public static final long getMinFlexMillis();
method public long getMinLatencyMillis();
method public static final long getMinPeriodMillis();
- method public int getNetworkType();
+ method public deprecated int getNetworkType();
+ method public android.net.NetworkRequest getRequiredNetwork();
method public android.content.ComponentName getService();
method public android.os.Bundle getTransientExtras();
method public long getTriggerContentMaxDelay();
@@ -7308,7 +7312,8 @@ package android.app.job {
field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L
field public static final int NETWORK_BYTES_UNKNOWN = -1; // 0xffffffff
field public static final int NETWORK_TYPE_ANY = 1; // 0x1
- field public static final int NETWORK_TYPE_METERED = 4; // 0x4
+ field public static final int NETWORK_TYPE_CELLULAR = 4; // 0x4
+ field public static final deprecated int NETWORK_TYPE_METERED = 4; // 0x4
field public static final int NETWORK_TYPE_NONE = 0; // 0x0
field public static final int NETWORK_TYPE_NOT_ROAMING = 3; // 0x3
field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2
@@ -7327,6 +7332,7 @@ package android.app.job {
method public android.app.job.JobInfo.Builder setPeriodic(long);
method public android.app.job.JobInfo.Builder setPeriodic(long, long);
method public android.app.job.JobInfo.Builder setPersisted(boolean);
+ method public android.app.job.JobInfo.Builder setRequiredNetwork(android.net.NetworkRequest);
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
method public android.app.job.JobInfo.Builder setRequiresBatteryNotLow(boolean);
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
@@ -7412,6 +7418,7 @@ package android.app.slice {
public final class Slice implements android.os.Parcelable {
ctor protected Slice(android.os.Parcel);
method public static android.app.slice.Slice bindSlice(android.content.ContentResolver, android.net.Uri);
+ method public static android.app.slice.Slice bindSlice(android.content.Context, android.content.Intent);
method public int describeContents();
method public java.util.List<java.lang.String> getHints();
method public java.util.List<android.app.slice.SliceItem> getItems();
@@ -7480,6 +7487,7 @@ package android.app.slice {
method public final java.lang.String getType(android.net.Uri);
method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
method public abstract android.app.slice.Slice onBindSlice(android.net.Uri);
+ method public android.net.Uri onMapIntentToUri(android.content.Intent);
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
@@ -7677,6 +7685,7 @@ package android.app.usage {
method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long);
method public android.app.usage.UsageEvents queryEvents(long, long);
method public java.util.List<android.app.usage.UsageStats> queryUsageStats(int, long, long);
+ method public void setAppStandbyBucket(java.lang.String, int);
method public void whitelistAppTemporarily(java.lang.String, long, android.os.UserHandle);
field public static final int INTERVAL_BEST = 4; // 0x4
field public static final int INTERVAL_DAILY = 0; // 0x0
@@ -9038,7 +9047,7 @@ package android.content {
ctor public AsyncQueryHandler.WorkerHandler(android.os.Looper);
}
- public abstract class AsyncTaskLoader<D> extends android.content.Loader {
+ public abstract deprecated class AsyncTaskLoader<D> extends android.content.Loader {
ctor public AsyncTaskLoader(android.content.Context);
method public void cancelLoadInBackground();
method public boolean isLoadInBackgroundCanceled();
@@ -9620,6 +9629,7 @@ package android.content {
field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
field public static final int CONTEXT_INCLUDE_CODE = 1; // 0x1
field public static final int CONTEXT_RESTRICTED = 4; // 0x4
+ field public static final java.lang.String CROSS_PROFILE_APPS_SERVICE = "crossprofileapps";
field public static final java.lang.String DEVICE_POLICY_SERVICE = "device_policy";
field public static final java.lang.String DISPLAY_SERVICE = "display";
field public static final java.lang.String DOWNLOAD_SERVICE = "download";
@@ -9660,6 +9670,7 @@ package android.content {
field public static final java.lang.String SEARCH_SERVICE = "search";
field public static final java.lang.String SENSOR_SERVICE = "sensor";
field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
+ field public static final java.lang.String STATS_MANAGER = "stats";
field public static final java.lang.String STORAGE_SERVICE = "storage";
field public static final java.lang.String STORAGE_STATS_SERVICE = "storagestats";
field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
@@ -9799,7 +9810,7 @@ package android.content {
method public void unregisterReceiver(android.content.BroadcastReceiver);
}
- public class CursorLoader extends android.content.AsyncTaskLoader {
+ public deprecated class CursorLoader extends android.content.AsyncTaskLoader {
ctor public CursorLoader(android.content.Context);
ctor public CursorLoader(android.content.Context, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
method public void deliverResult(android.database.Cursor);
@@ -10434,7 +10445,7 @@ package android.content {
ctor public IntentSender.SendIntentException(java.lang.Exception);
}
- public class Loader<D> {
+ public deprecated class Loader<D> {
ctor public Loader(android.content.Context);
method public void abandon();
method public boolean cancelLoad();
@@ -10467,15 +10478,15 @@ package android.content {
method public void unregisterOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
}
- public final class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
+ public final deprecated class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
ctor public Loader.ForceLoadContentObserver();
}
- public static abstract interface Loader.OnLoadCanceledListener<D> {
+ public static abstract deprecated interface Loader.OnLoadCanceledListener<D> {
method public abstract void onLoadCanceled(android.content.Loader<D>);
}
- public static abstract interface Loader.OnLoadCompleteListener<D> {
+ public static abstract deprecated interface Loader.OnLoadCompleteListener<D> {
method public abstract void onLoadComplete(android.content.Loader<D>, D);
}
@@ -11184,6 +11195,7 @@ package android.content.pm {
field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
field public static final int FLAG_MATCH_PINNED = 2; // 0x2
+ field public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1024; // 0x400
}
public class PackageInfo implements android.os.Parcelable {
@@ -11953,6 +11965,15 @@ package android.content.pm {
}
+package android.content.pm.crossprofile {
+
+ public class CrossProfileApps {
+ 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);
+ }
+
+}
+
package android.content.pm.permission {
public final class RuntimePermissionPresentationInfo implements android.os.Parcelable {
@@ -12866,9 +12887,11 @@ package android.database.sqlite {
method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
method public android.database.DatabaseErrorHandler getErrorHandler();
method public long getIdleConnectionTimeout();
+ method public java.lang.String getJournalMode();
method public int getLookasideSlotCount();
method public int getLookasideSlotSize();
method public int getOpenFlags();
+ method public java.lang.String getSynchronousMode();
}
public static final class SQLiteDatabase.OpenParams.Builder {
@@ -12880,8 +12903,10 @@ package android.database.sqlite {
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(android.database.DatabaseErrorHandler);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(long);
+ method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setJournalMode(java.lang.String);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(int, int);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
+ method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setSynchronousMode(java.lang.String);
}
public class SQLiteDatabaseCorruptException extends android.database.sqlite.SQLiteException {
@@ -12928,6 +12953,7 @@ package android.database.sqlite {
public abstract class SQLiteOpenHelper {
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
+ ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, int, android.database.sqlite.SQLiteDatabase.OpenParams);
method public synchronized void close();
method public java.lang.String getDatabaseName();
method public android.database.sqlite.SQLiteDatabase getReadableDatabase();
@@ -16016,6 +16042,7 @@ package android.hardware.camera2 {
method public abstract int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract int setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException;
+ method public void updateOutputConfiguration(android.hardware.camera2.params.OutputConfiguration) throws android.hardware.camera2.CameraAccessException;
}
public static abstract class CameraCaptureSession.CaptureCallback {
@@ -16663,10 +16690,12 @@ package android.hardware.camera2.params {
method public void addSurface(android.view.Surface);
method public int describeContents();
method public void enableSurfaceSharing();
+ method public static int getMaxSharedSurfaceCount();
method public int getRotation();
method public android.view.Surface getSurface();
method public int getSurfaceGroupId();
method public java.util.List<android.view.Surface> getSurfaces();
+ method public void removeSurface(android.view.Surface);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
field public static final int ROTATION_0 = 0; // 0x0
@@ -19829,11 +19858,13 @@ package android.icu.text {
method public synchronized void applyLocalizedPattern(java.lang.String);
method public synchronized void applyPattern(java.lang.String);
method public synchronized boolean areSignificantDigitsUsed();
+ method public synchronized boolean equals(java.lang.Object);
method public java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(java.math.BigInteger, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(java.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(android.icu.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
+ method public synchronized android.icu.util.Currency getCurrency();
method public synchronized android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
method public synchronized android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
method public synchronized android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
@@ -19841,8 +19872,12 @@ package android.icu.text {
method public synchronized int getGroupingSize();
method public synchronized java.math.MathContext getMathContext();
method public synchronized android.icu.math.MathContext getMathContextICU();
+ method public synchronized int getMaximumFractionDigits();
+ method public synchronized int getMaximumIntegerDigits();
method public synchronized int getMaximumSignificantDigits();
method public synchronized byte getMinimumExponentDigits();
+ method public synchronized int getMinimumFractionDigits();
+ method public synchronized int getMinimumIntegerDigits();
method public synchronized int getMinimumSignificantDigits();
method public synchronized int getMultiplier();
method public synchronized java.lang.String getNegativePrefix();
@@ -19853,13 +19888,19 @@ package android.icu.text {
method public synchronized java.lang.String getPositivePrefix();
method public synchronized java.lang.String getPositiveSuffix();
method public synchronized java.math.BigDecimal getRoundingIncrement();
+ method public synchronized int getRoundingMode();
method public synchronized int getSecondaryGroupingSize();
+ method public synchronized int hashCode();
method public synchronized boolean isDecimalPatternMatchRequired();
method public synchronized boolean isDecimalSeparatorAlwaysShown();
method public synchronized boolean isExponentSignAlwaysShown();
+ method public synchronized boolean isGroupingUsed();
method public synchronized boolean isParseBigDecimal();
+ method public synchronized boolean isParseIntegerOnly();
+ method public synchronized boolean isParseStrict();
method public synchronized boolean isScientificNotation();
method public java.lang.Number parse(java.lang.String, java.text.ParsePosition);
+ method public synchronized void setCurrency(android.icu.util.Currency);
method public synchronized void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
method public synchronized void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
method public synchronized void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
@@ -19868,10 +19909,15 @@ package android.icu.text {
method public synchronized void setExponentSignAlwaysShown(boolean);
method public synchronized void setFormatWidth(int);
method public synchronized void setGroupingSize(int);
+ method public synchronized void setGroupingUsed(boolean);
method public synchronized void setMathContext(java.math.MathContext);
method public synchronized void setMathContextICU(android.icu.math.MathContext);
+ method public synchronized void setMaximumFractionDigits(int);
+ method public synchronized void setMaximumIntegerDigits(int);
method public synchronized void setMaximumSignificantDigits(int);
method public synchronized void setMinimumExponentDigits(byte);
+ method public synchronized void setMinimumFractionDigits(int);
+ method public synchronized void setMinimumIntegerDigits(int);
method public synchronized void setMinimumSignificantDigits(int);
method public synchronized void setMultiplier(int);
method public synchronized void setNegativePrefix(java.lang.String);
@@ -19879,12 +19925,15 @@ package android.icu.text {
method public synchronized void setPadCharacter(char);
method public synchronized void setPadPosition(int);
method public synchronized void setParseBigDecimal(boolean);
+ method public synchronized void setParseIntegerOnly(boolean);
method public deprecated void setParseMaxDigits(int);
+ method public synchronized void setParseStrict(boolean);
method public synchronized void setPositivePrefix(java.lang.String);
method public synchronized void setPositiveSuffix(java.lang.String);
method public synchronized void setRoundingIncrement(java.math.BigDecimal);
method public synchronized void setRoundingIncrement(android.icu.math.BigDecimal);
method public synchronized void setRoundingIncrement(double);
+ method public synchronized void setRoundingMode(int);
method public synchronized void setScientificNotation(boolean);
method public synchronized void setSecondaryGroupingSize(int);
method public synchronized void setSignificantDigitsUsed(boolean);
@@ -24899,8 +24948,9 @@ package android.media {
field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
}
- public class MediaPlayer implements android.media.VolumeAutomation {
+ public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation {
ctor public MediaPlayer();
+ method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(java.io.FileDescriptor, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -24922,6 +24972,8 @@ package android.media {
method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
method public android.os.PersistableBundle getMetrics();
method public android.media.PlaybackParams getPlaybackParams();
+ method public android.media.AudioDeviceInfo getPreferredDevice();
+ method public android.media.AudioDeviceInfo getRoutedDevice();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
method public android.media.SyncParams getSyncParams();
method public android.media.MediaTimestamp getTimestamp();
@@ -24937,6 +24989,7 @@ package android.media {
method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
method public void release();
method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
+ method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public void reset();
method public void restoreKeys(byte[]) throws android.media.MediaPlayer.NoDrmSchemeException;
method public void seekTo(long, int);
@@ -24973,6 +25026,7 @@ package android.media {
method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener);
method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener);
method public void setPlaybackParams(android.media.PlaybackParams);
+ method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
method public void setScreenOnWhilePlaying(boolean);
method public void setSurface(android.view.Surface);
method public void setSyncParams(android.media.SyncParams);
@@ -28215,6 +28269,7 @@ package android.net {
field public static final int NET_CAPABILITY_MMS = 0; // 0x0
field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
+ field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
field public static final int NET_CAPABILITY_RCS = 8; // 0x8
field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
@@ -28245,7 +28300,7 @@ package android.net {
method public boolean isConnected();
method public boolean isConnectedOrConnecting();
method public boolean isFailover();
- method public boolean isRoaming();
+ method public deprecated boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
}
@@ -33720,7 +33775,6 @@ package android.os {
field public static final java.lang.String ACTION_UPDATE_PINS = "android.intent.action.UPDATE_PINS";
field public static final java.lang.String ACTION_UPDATE_SMART_SELECTION = "android.intent.action.UPDATE_SMART_SELECTION";
field public static final java.lang.String ACTION_UPDATE_SMS_SHORT_CODES = "android.intent.action.UPDATE_SMS_SHORT_CODES";
- field public static final java.lang.String ACTION_UPDATE_TZDATA = "android.intent.action.UPDATE_TZDATA";
}
public abstract class CountDownTimer {
@@ -33749,6 +33803,7 @@ package android.os {
}
public final class Debug {
+ method public static void attachJvmtiAgent(java.lang.String, java.lang.String) throws java.io.IOException;
method public static deprecated void changeDebugPort(int);
method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
method public static boolean dumpService(java.lang.String, java.io.FileDescriptor, java.lang.String[]);
@@ -34597,6 +34652,14 @@ package android.os {
method public static void setVmPolicy(android.os.StrictMode.VmPolicy);
}
+ public static abstract interface StrictMode.OnThreadViolationListener {
+ method public abstract void onThreadViolation(android.os.strictmode.Violation);
+ }
+
+ public static abstract interface StrictMode.OnVmViolationListener {
+ method public abstract void onVmViolation(android.os.strictmode.Violation);
+ }
+
public static final class StrictMode.ThreadPolicy {
field public static final android.os.StrictMode.ThreadPolicy LAX;
}
@@ -34617,6 +34680,7 @@ package android.os {
method public android.os.StrictMode.ThreadPolicy.Builder penaltyDialog();
method public android.os.StrictMode.ThreadPolicy.Builder penaltyDropBox();
method public android.os.StrictMode.ThreadPolicy.Builder penaltyFlashScreen();
+ method public android.os.StrictMode.ThreadPolicy.Builder penaltyListener(android.os.StrictMode.OnThreadViolationListener, java.util.concurrent.Executor);
method public android.os.StrictMode.ThreadPolicy.Builder penaltyLog();
method public android.os.StrictMode.ThreadPolicy.Builder permitAll();
method public android.os.StrictMode.ThreadPolicy.Builder permitCustomSlowCalls();
@@ -34648,6 +34712,7 @@ package android.os {
method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnFileUriExposure();
method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox();
+ method public android.os.StrictMode.VmPolicy.Builder penaltyListener(android.os.StrictMode.OnVmViolationListener, java.util.concurrent.Executor);
method public android.os.StrictMode.VmPolicy.Builder penaltyLog();
method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(java.lang.Class, int);
}
@@ -34655,10 +34720,12 @@ package android.os {
public final class SystemClock {
method public static long currentThreadTimeMillis();
method public static long elapsedRealtime();
+ method public static java.time.Clock elapsedRealtimeClock();
method public static long elapsedRealtimeNanos();
method public static boolean setCurrentTimeMillis(long);
method public static void sleep(long);
method public static long uptimeMillis();
+ method public static java.time.Clock uptimeMillisClock();
}
public class TestLooperManager {
@@ -34718,6 +34785,7 @@ package android.os {
field public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11; // 0xb
field public static final int POST_INSTALL_RUNNER_ERROR = 5; // 0x5
field public static final int SUCCESS = 0; // 0x0
+ field public static final int UPDATED_BUT_NOT_ACTIVE = 52; // 0x34
}
public static final class UpdateEngine.UpdateStatusConstants {
@@ -34773,11 +34841,13 @@ package android.os {
method public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(java.lang.String, android.os.UserHandle);
method public android.os.Bundle getUserRestrictions();
method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
+ method public boolean hasRestrictedProfiles();
method public boolean hasUserRestriction(java.lang.String);
method public boolean isDemoUser();
method public boolean isManagedProfile();
method public boolean isManagedProfile(int);
method public boolean isQuietModeEnabled(android.os.UserHandle);
+ method public boolean isRestrictedProfile();
method public boolean isSystemUser();
method public boolean isUserAGoat();
method public boolean isUserRunning(android.os.UserHandle);
@@ -34802,6 +34872,7 @@ package android.os {
field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
field public static final java.lang.String DISALLOW_CONFIG_DATE_TIME = "no_config_date_time";
+ field public static final java.lang.String DISALLOW_CONFIG_LOCALE = "no_config_locale";
field public static final java.lang.String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
field public static final java.lang.String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
field public static final java.lang.String DISALLOW_CONFIG_VPN = "no_config_vpn";
@@ -34831,6 +34902,7 @@ package android.os {
field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
field public static final java.lang.String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
+ field public static final java.lang.String DISALLOW_USER_SWITCH = "no_user_switch";
field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
field public static final int RESTRICTION_NOT_SET = 0; // 0x0
@@ -35090,6 +35162,62 @@ package android.os.storage {
}
+package android.os.strictmode {
+
+ public final class CleartextNetworkViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class ContentUriWithoutPermissionViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class CustomViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class DiskReadViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class DiskWriteViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class FileUriExposedViolation extends android.os.strictmode.Violation {
+ }
+
+ public class InstanceCountViolation extends android.os.strictmode.Violation {
+ method public long getNumberOfInstances();
+ }
+
+ public final class IntentReceiverLeakedViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class LeakedClosableViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class NetworkViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class ResourceMismatchViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class ServiceConnectionLeakedViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class SqliteObjectLeakedViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class UnbufferedIoViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class UntaggedSocketViolation extends android.os.strictmode.Violation {
+ }
+
+ public abstract class Violation extends java.lang.Throwable {
+ }
+
+ public final class WebViewMethodCalledOnWrongThreadViolation extends android.os.strictmode.Violation {
+ }
+
+}
+
package android.permissionpresenterservice {
public abstract class RuntimePermissionPresenterService extends android.app.Service {
@@ -35388,7 +35516,7 @@ package android.preference {
method public default void putStringSet(java.lang.String, java.util.Set<java.lang.String>);
}
- public abstract class PreferenceFragment extends android.app.Fragment {
+ public abstract deprecated class PreferenceFragment extends android.app.Fragment {
ctor public PreferenceFragment();
method public void addPreferencesFromIntent(android.content.Intent);
method public void addPreferencesFromResource(int);
@@ -35399,7 +35527,7 @@ package android.preference {
method public void setPreferenceScreen(android.preference.PreferenceScreen);
}
- public static abstract interface PreferenceFragment.OnPreferenceStartFragmentCallback {
+ public static abstract deprecated interface PreferenceFragment.OnPreferenceStartFragmentCallback {
method public abstract boolean onPreferenceStartFragment(android.preference.PreferenceFragment, android.preference.Preference);
}
@@ -38235,6 +38363,7 @@ package android.provider {
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
+ field public static final java.lang.String EXTRA_SUB_ID = "android.provider.extra.SUB_ID";
field public static final java.lang.String INTENT_CATEGORY_USAGE_ACCESS_CONFIG = "android.intent.category.USAGE_ACCESS_CONFIG";
field public static final java.lang.String METADATA_USAGE_ACCESS_REASON = "android.settings.metadata.USAGE_ACCESS_REASON";
}
@@ -41720,6 +41849,16 @@ package android.system {
field public final int errno;
}
+ public class Int32Ref {
+ ctor public Int32Ref(int);
+ field public int value;
+ }
+
+ public class Int64Ref {
+ ctor public Int64Ref(long);
+ field public long value;
+ }
+
public final class Os {
method public static java.io.FileDescriptor accept(java.io.FileDescriptor, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
method public static boolean access(java.lang.String, int) throws android.system.ErrnoException;
@@ -41789,7 +41928,8 @@ package android.system {
method public static void remove(java.lang.String) throws android.system.ErrnoException;
method public static void removexattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
- method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+ method public static deprecated long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+ method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.system.Int64Ref, long) throws android.system.ErrnoException;
method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
method public static void setegid(int) throws android.system.ErrnoException;
@@ -41814,7 +41954,8 @@ package android.system {
method public static int umask(int);
method public static android.system.StructUtsname uname();
method public static void unsetenv(java.lang.String) throws android.system.ErrnoException;
- method public static int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+ method public static deprecated int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+ method public static int waitpid(int, android.system.Int32Ref, int) throws android.system.ErrnoException;
method public static int write(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
method public static int write(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
method public static int writev(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
@@ -42409,6 +42550,7 @@ package android.telecom {
method public android.telecom.Call.RttCall getRttCall();
method public int getState();
method public android.telecom.InCallService.VideoCall getVideoCall();
+ method public void handoverTo(android.telecom.PhoneAccountHandle, int, android.os.Bundle);
method public void hold();
method public boolean isRttActive();
method public void mergeConference();
@@ -42455,6 +42597,8 @@ package android.telecom {
method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
+ method public void onHandoverComplete(android.telecom.Call);
+ method public void onHandoverFailed(android.telecom.Call, int);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
method public void onRttInitiationFailure(android.telecom.Call, int);
@@ -42463,6 +42607,10 @@ package android.telecom {
method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
method public void onStateChanged(android.telecom.Call, int);
method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
+ field public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1; // 0x1
+ 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
}
public static class Call.Details {
@@ -42535,7 +42683,9 @@ package android.telecom {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
method public int describeContents();
+ method public android.bluetooth.BluetoothDevice getActiveBluetoothDevice();
method public int getRoute();
+ method public java.util.Collection<android.bluetooth.BluetoothDevice> getSupportedBluetoothDevices();
method public int getSupportedRouteMask();
method public boolean isMuted();
method public void writeToParcel(android.os.Parcel, int);
@@ -42674,6 +42824,7 @@ package android.telecom {
method public final void putExtras(android.os.Bundle);
method public final void removeExtras(java.util.List<java.lang.String>);
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 setActive();
method public final void setAddress(android.net.Uri, int);
@@ -42805,8 +42956,11 @@ package android.telecom {
method public void onConference(android.telecom.Connection, android.telecom.Connection);
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);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public void onHandoverFailed(android.telecom.ConnectionRequest, int);
method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
@@ -42867,6 +43021,7 @@ package android.telecom {
method public deprecated void onPhoneCreated(android.telecom.Phone);
method public deprecated void onPhoneDestroyed(android.telecom.Phone);
method public void onSilenceRinger();
+ method public final void requestBluetoothAudio(java.lang.String);
method public final void setAudioRoute(int);
method public final void setMuted(boolean);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
@@ -43005,6 +43160,7 @@ package android.telecom {
method public final android.telecom.CallAudioState getCallAudioState();
method public final java.util.List<android.telecom.Call> getCalls();
method public final void removeListener(android.telecom.Phone.Listener);
+ method public void requestBluetoothAudio(java.lang.String);
method public final void setAudioRoute(int);
method public final void setMuted(boolean);
}
@@ -43052,6 +43208,9 @@ package android.telecom {
field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
+ field public static final java.lang.String EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
+ field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_FROM = "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
+ field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_TO = "android.telecom.extra.SUPPORTS_HANDOVER_TO";
field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
field public static final java.lang.String SCHEME_SIP = "sip";
@@ -43253,6 +43412,7 @@ package android.telecom {
}
public class TelecomManager {
+ method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
method public void acceptRingingCall();
method public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
@@ -43442,8 +43602,8 @@ package android.telephony {
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
- field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
+ field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
@@ -48035,6 +48195,12 @@ package android.util {
field public static final int[] WILD_CARD;
}
+ public final class StatsManager {
+ method public byte[] getData(java.lang.String);
+ method public boolean addConfiguration(java.lang.String, byte[], java.lang.String, java.lang.String);
+ method public boolean removeConfiguration(java.lang.String);
+ }
+
public class StringBuilderPrinter implements android.util.Printer {
ctor public StringBuilderPrinter(java.lang.StringBuilder);
method public void println(java.lang.String);
@@ -48286,6 +48452,7 @@ package android.view {
field public static final int STATE_DOZE_SUSPEND = 4; // 0x4
field public static final int STATE_OFF = 1; // 0x1
field public static final int STATE_ON = 2; // 0x2
+ field public static final int STATE_ON_SUSPEND = 6; // 0x6
field public static final int STATE_UNKNOWN = 0; // 0x0
field public static final int STATE_VR = 5; // 0x5
}
@@ -52694,14 +52861,23 @@ package android.view.textclassifier {
method public android.view.textclassifier.TextClassification.Builder setText(java.lang.String);
}
+ public static final class TextClassification.Options {
+ ctor public TextClassification.Options();
+ method public android.os.LocaleList getDefaultLocales();
+ method public android.view.textclassifier.TextClassification.Options setDefaultLocales(android.os.LocaleList);
+ }
+
public final class TextClassificationManager {
method public android.view.textclassifier.TextClassifier getTextClassifier();
method public void setTextClassifier(android.view.textclassifier.TextClassifier);
}
public abstract interface TextClassifier {
- method public abstract android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
- method public abstract android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
+ 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, 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.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, 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";
@@ -52710,6 +52886,36 @@ package android.view.textclassifier {
field public static final java.lang.String TYPE_URL = "url";
}
+ public final class TextLinks {
+ method public boolean apply(android.text.SpannableString, java.util.function.Function<android.view.textclassifier.TextLinks.TextLink, android.text.style.ClickableSpan>);
+ method public java.util.Collection<android.view.textclassifier.TextLinks.TextLink> getLinks();
+ }
+
+ public static final class TextLinks.Builder {
+ ctor public TextLinks.Builder(java.lang.String);
+ method public android.view.textclassifier.TextLinks.Builder addLink(android.view.textclassifier.TextLinks.TextLink);
+ method public android.view.textclassifier.TextLinks build();
+ }
+
+ public static final class 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);
+ }
+
+ public static final class TextLinks.TextLink {
+ ctor public TextLinks.TextLink(java.lang.String, int, int, java.util.Map<java.lang.String, java.lang.Float>);
+ method public float getConfidenceScore(java.lang.String);
+ method public int getEnd();
+ method public java.lang.String getEntity(int);
+ method public int getEntityCount();
+ method public int getStart();
+ }
+
public final class TextSelection {
method public float getConfidenceScore(java.lang.String);
method public java.lang.String getEntity(int);
@@ -52724,6 +52930,12 @@ package android.view.textclassifier {
method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
}
+ public static final class TextSelection.Options {
+ ctor public TextSelection.Options();
+ method public android.os.LocaleList getDefaultLocales();
+ method public android.view.textclassifier.TextSelection.Options setDefaultLocales(android.os.LocaleList);
+ }
+
}
package android.view.textservice {
@@ -53739,7 +53951,7 @@ package android.webkit {
method public abstract void setWebContentsDebuggingEnabled(boolean);
}
- public class WebViewFragment extends android.app.Fragment {
+ public deprecated class WebViewFragment extends android.app.Fragment {
ctor public WebViewFragment();
method public android.webkit.WebView getWebView();
}
diff --git a/api/test-current.txt b/api/test-current.txt
index d645b26e9347..da59056d50ec 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3611,11 +3611,11 @@ package android.app {
method public android.transition.Scene getContentScene();
method public android.transition.TransitionManager getContentTransitionManager();
method public android.view.View getCurrentFocus();
- method public android.app.FragmentManager getFragmentManager();
+ method public deprecated android.app.FragmentManager getFragmentManager();
method public android.content.Intent getIntent();
method public java.lang.Object getLastNonConfigurationInstance();
method public android.view.LayoutInflater getLayoutInflater();
- method public android.app.LoaderManager getLoaderManager();
+ method public deprecated android.app.LoaderManager getLoaderManager();
method public java.lang.String getLocalClassName();
method public int getMaxNumPictureInPictureActions();
method public final android.media.session.MediaController getMediaController();
@@ -3655,7 +3655,7 @@ package android.app {
method public void onActionModeStarted(android.view.ActionMode);
method public void onActivityReenter(int, android.content.Intent);
method protected void onActivityResult(int, int, android.content.Intent);
- method public void onAttachFragment(android.app.Fragment);
+ method public deprecated void onAttachFragment(android.app.Fragment);
method public void onAttachedToWindow();
method public void onBackPressed();
method protected void onChildTitleChanged(android.app.Activity, java.lang.CharSequence);
@@ -3797,8 +3797,8 @@ package android.app {
method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
method public void startActivityFromChild(android.app.Activity, android.content.Intent, int);
method public void startActivityFromChild(android.app.Activity, android.content.Intent, int, android.os.Bundle);
- method public void startActivityFromFragment(android.app.Fragment, android.content.Intent, int);
- method public void startActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
+ method public deprecated void startActivityFromFragment(android.app.Fragment, android.content.Intent, int);
+ method public deprecated void startActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
method public boolean startActivityIfNeeded(android.content.Intent, int);
method public boolean startActivityIfNeeded(android.content.Intent, int, android.os.Bundle);
method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
@@ -4484,7 +4484,7 @@ package android.app {
method public void unregisterForContextMenu(android.view.View);
}
- public class DialogFragment extends android.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+ public deprecated class DialogFragment extends android.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
ctor public DialogFragment();
method public void dismiss();
method public void dismissAllowingStateLoss();
@@ -4602,7 +4602,7 @@ package android.app {
method public void setSelectedGroup(int);
}
- public class Fragment implements android.content.ComponentCallbacks2 android.view.View.OnCreateContextMenuListener {
+ public deprecated class Fragment implements android.content.ComponentCallbacks2 android.view.View.OnCreateContextMenuListener {
ctor public Fragment();
method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method public final boolean equals(java.lang.Object);
@@ -4618,7 +4618,7 @@ package android.app {
method public final java.lang.Object getHost();
method public final int getId();
method public final android.view.LayoutInflater getLayoutInflater();
- method public android.app.LoaderManager getLoaderManager();
+ method public deprecated android.app.LoaderManager getLoaderManager();
method public final android.app.Fragment getParentFragment();
method public android.transition.Transition getReenterTransition();
method public final android.content.res.Resources getResources();
@@ -4713,11 +4713,11 @@ package android.app {
method public void unregisterForContextMenu(android.view.View);
}
- public static class Fragment.InstantiationException extends android.util.AndroidRuntimeException {
+ public static deprecated class Fragment.InstantiationException extends android.util.AndroidRuntimeException {
ctor public Fragment.InstantiationException(java.lang.String, java.lang.Exception);
}
- public static class Fragment.SavedState implements android.os.Parcelable {
+ public static deprecated class Fragment.SavedState implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.ClassLoaderCreator<android.app.Fragment.SavedState> CREATOR;
@@ -4736,17 +4736,17 @@ package android.app {
method public void setTitle(java.lang.CharSequence, java.lang.CharSequence);
}
- public static abstract interface FragmentBreadCrumbs.OnBreadCrumbClickListener {
+ public static abstract deprecated interface FragmentBreadCrumbs.OnBreadCrumbClickListener {
method public abstract boolean onBreadCrumbClick(android.app.FragmentManager.BackStackEntry, int);
}
- public abstract class FragmentContainer {
+ public abstract deprecated class FragmentContainer {
ctor public FragmentContainer();
method public abstract <T extends android.view.View> T onFindViewById(int);
method public abstract boolean onHasView();
}
- public class FragmentController {
+ public deprecated class FragmentController {
method public void attachHost(android.app.Fragment);
method public static final android.app.FragmentController createController(android.app.FragmentHostCallback<?>);
method public void dispatchActivityCreated();
@@ -4789,7 +4789,7 @@ package android.app {
method public android.os.Parcelable saveAllState();
}
- public abstract class FragmentHostCallback<E> extends android.app.FragmentContainer {
+ public abstract deprecated class FragmentHostCallback<E> extends android.app.FragmentContainer {
ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
method public void onAttachFragment(android.app.Fragment);
method public void onDump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
@@ -4807,7 +4807,7 @@ package android.app {
method public boolean onUseFragmentManagerInflaterFactory();
}
- public abstract class FragmentManager {
+ public abstract deprecated class FragmentManager {
ctor public FragmentManager();
method public abstract void addOnBackStackChangedListener(android.app.FragmentManager.OnBackStackChangedListener);
method public abstract android.app.FragmentTransaction beginTransaction();
@@ -4838,7 +4838,7 @@ package android.app {
field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
}
- public static abstract interface FragmentManager.BackStackEntry {
+ public static abstract deprecated interface FragmentManager.BackStackEntry {
method public abstract java.lang.CharSequence getBreadCrumbShortTitle();
method public abstract int getBreadCrumbShortTitleRes();
method public abstract java.lang.CharSequence getBreadCrumbTitle();
@@ -4847,7 +4847,7 @@ package android.app {
method public abstract java.lang.String getName();
}
- public static abstract class FragmentManager.FragmentLifecycleCallbacks {
+ public static abstract deprecated class FragmentManager.FragmentLifecycleCallbacks {
ctor public FragmentManager.FragmentLifecycleCallbacks();
method public void onFragmentActivityCreated(android.app.FragmentManager, android.app.Fragment, android.os.Bundle);
method public void onFragmentAttached(android.app.FragmentManager, android.app.Fragment, android.content.Context);
@@ -4865,14 +4865,14 @@ package android.app {
method public void onFragmentViewDestroyed(android.app.FragmentManager, android.app.Fragment);
}
- public static abstract interface FragmentManager.OnBackStackChangedListener {
+ public static abstract deprecated interface FragmentManager.OnBackStackChangedListener {
method public abstract void onBackStackChanged();
}
- public class FragmentManagerNonConfig {
+ public deprecated class FragmentManagerNonConfig {
}
- public abstract class FragmentTransaction {
+ public abstract deprecated class FragmentTransaction {
ctor public FragmentTransaction();
method public abstract android.app.FragmentTransaction add(android.app.Fragment, java.lang.String);
method public abstract android.app.FragmentTransaction add(int, android.app.Fragment);
@@ -4972,6 +4972,7 @@ package android.app {
method public void setInTouchMode(boolean);
method public void start();
method public android.app.Activity startActivitySync(android.content.Intent);
+ method public android.app.Activity startActivitySync(android.content.Intent, android.os.Bundle);
method public deprecated void startAllocCounting();
method public void startPerformanceSnapshot();
method public void startProfiling();
@@ -5077,7 +5078,7 @@ package android.app {
method public void setSelection(int);
}
- public class ListFragment extends android.app.Fragment {
+ public deprecated class ListFragment extends android.app.Fragment {
ctor public ListFragment();
method public android.widget.ListAdapter getListAdapter();
method public android.widget.ListView getListView();
@@ -5091,7 +5092,7 @@ package android.app {
method public void setSelection(int);
}
- public abstract class LoaderManager {
+ public abstract deprecated class LoaderManager {
ctor public LoaderManager();
method public abstract void destroyLoader(int);
method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
@@ -5101,7 +5102,7 @@ package android.app {
method public abstract <D> android.content.Loader<D> restartLoader(int, android.os.Bundle, android.app.LoaderManager.LoaderCallbacks<D>);
}
- public static abstract interface LoaderManager.LoaderCallbacks<D> {
+ public static abstract deprecated interface LoaderManager.LoaderCallbacks<D> {
method public abstract android.content.Loader<D> onCreateLoader(int, android.os.Bundle);
method public abstract void onLoadFinished(android.content.Loader<D>, D);
method public abstract void onLoaderReset(android.content.Loader<D>);
@@ -6615,6 +6616,7 @@ package android.app.admin {
field public static final int LOCK_TASK_FEATURE_NOTIFICATIONS = 2; // 0x2
field public static final int LOCK_TASK_FEATURE_RECENTS = 8; // 0x8
field public static final int LOCK_TASK_FEATURE_SYSTEM_INFO = 1; // 0x1
+ field public static final int MAKE_USER_EPHEMERAL = 2; // 0x2
field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning";
field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000
field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000
@@ -6920,7 +6922,8 @@ package android.app.job {
method public static final long getMinFlexMillis();
method public long getMinLatencyMillis();
method public static final long getMinPeriodMillis();
- method public int getNetworkType();
+ method public deprecated int getNetworkType();
+ method public android.net.NetworkRequest getRequiredNetwork();
method public android.content.ComponentName getService();
method public android.os.Bundle getTransientExtras();
method public long getTriggerContentMaxDelay();
@@ -6940,7 +6943,8 @@ package android.app.job {
field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L
field public static final int NETWORK_BYTES_UNKNOWN = -1; // 0xffffffff
field public static final int NETWORK_TYPE_ANY = 1; // 0x1
- field public static final int NETWORK_TYPE_METERED = 4; // 0x4
+ field public static final int NETWORK_TYPE_CELLULAR = 4; // 0x4
+ field public static final deprecated int NETWORK_TYPE_METERED = 4; // 0x4
field public static final int NETWORK_TYPE_NONE = 0; // 0x0
field public static final int NETWORK_TYPE_NOT_ROAMING = 3; // 0x3
field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2
@@ -6959,6 +6963,7 @@ package android.app.job {
method public android.app.job.JobInfo.Builder setPeriodic(long);
method public android.app.job.JobInfo.Builder setPeriodic(long, long);
method public android.app.job.JobInfo.Builder setPersisted(boolean);
+ method public android.app.job.JobInfo.Builder setRequiredNetwork(android.net.NetworkRequest);
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
method public android.app.job.JobInfo.Builder setRequiresBatteryNotLow(boolean);
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
@@ -7043,6 +7048,7 @@ package android.app.slice {
public final class Slice implements android.os.Parcelable {
ctor protected Slice(android.os.Parcel);
method public static android.app.slice.Slice bindSlice(android.content.ContentResolver, android.net.Uri);
+ method public static android.app.slice.Slice bindSlice(android.content.Context, android.content.Intent);
method public int describeContents();
method public java.util.List<java.lang.String> getHints();
method public java.util.List<android.app.slice.SliceItem> getItems();
@@ -7111,6 +7117,7 @@ package android.app.slice {
method public final java.lang.String getType(android.net.Uri);
method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
method public abstract android.app.slice.Slice onBindSlice(android.net.Uri);
+ method public android.net.Uri onMapIntentToUri(android.content.Intent);
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
@@ -8603,7 +8610,7 @@ package android.content {
ctor public AsyncQueryHandler.WorkerHandler(android.os.Looper);
}
- public abstract class AsyncTaskLoader<D> extends android.content.Loader {
+ public abstract deprecated class AsyncTaskLoader<D> extends android.content.Loader {
ctor public AsyncTaskLoader(android.content.Context);
method public void cancelLoadInBackground();
method public boolean isLoadInBackgroundCanceled();
@@ -9178,6 +9185,7 @@ package android.content {
field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
field public static final int CONTEXT_INCLUDE_CODE = 1; // 0x1
field public static final int CONTEXT_RESTRICTED = 4; // 0x4
+ field public static final java.lang.String CROSS_PROFILE_APPS_SERVICE = "crossprofileapps";
field public static final java.lang.String DEVICE_POLICY_SERVICE = "device_policy";
field public static final java.lang.String DISPLAY_SERVICE = "display";
field public static final java.lang.String DOWNLOAD_SERVICE = "download";
@@ -9345,7 +9353,7 @@ package android.content {
method public void unregisterReceiver(android.content.BroadcastReceiver);
}
- public class CursorLoader extends android.content.AsyncTaskLoader {
+ public deprecated class CursorLoader extends android.content.AsyncTaskLoader {
ctor public CursorLoader(android.content.Context);
ctor public CursorLoader(android.content.Context, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
method public void deliverResult(android.database.Cursor);
@@ -9951,7 +9959,7 @@ package android.content {
ctor public IntentSender.SendIntentException(java.lang.Exception);
}
- public class Loader<D> {
+ public deprecated class Loader<D> {
ctor public Loader(android.content.Context);
method public void abandon();
method public boolean cancelLoad();
@@ -9984,15 +9992,15 @@ package android.content {
method public void unregisterOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
}
- public final class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
+ public final deprecated class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
ctor public Loader.ForceLoadContentObserver();
}
- public static abstract interface Loader.OnLoadCanceledListener<D> {
+ public static abstract deprecated interface Loader.OnLoadCanceledListener<D> {
method public abstract void onLoadCanceled(android.content.Loader<D>);
}
- public static abstract interface Loader.OnLoadCompleteListener<D> {
+ public static abstract deprecated interface Loader.OnLoadCompleteListener<D> {
method public abstract void onLoadComplete(android.content.Loader<D>, D);
}
@@ -10647,10 +10655,10 @@ package android.content.pm {
method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>);
field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
- field public static final int FLAG_MATCH_ALL_PINNED = 1024; // 0x400
field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
field public static final int FLAG_MATCH_PINNED = 2; // 0x2
+ field public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1024; // 0x400
}
public class PackageInfo implements android.os.Parcelable {
@@ -11311,6 +11319,15 @@ package android.content.pm {
}
+package android.content.pm.crossprofile {
+
+ public class CrossProfileApps {
+ 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);
+ }
+
+}
+
package android.content.res {
public class AssetFileDescriptor implements java.io.Closeable android.os.Parcelable {
@@ -12211,9 +12228,11 @@ package android.database.sqlite {
method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
method public android.database.DatabaseErrorHandler getErrorHandler();
method public long getIdleConnectionTimeout();
+ method public java.lang.String getJournalMode();
method public int getLookasideSlotCount();
method public int getLookasideSlotSize();
method public int getOpenFlags();
+ method public java.lang.String getSynchronousMode();
}
public static final class SQLiteDatabase.OpenParams.Builder {
@@ -12225,8 +12244,10 @@ package android.database.sqlite {
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(android.database.DatabaseErrorHandler);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(long);
+ method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setJournalMode(java.lang.String);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setLookasideConfig(int, int);
method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
+ method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setSynchronousMode(java.lang.String);
}
public class SQLiteDatabaseCorruptException extends android.database.sqlite.SQLiteException {
@@ -12308,6 +12329,7 @@ package android.database.sqlite {
method public static int getWALAutoCheckpoint();
method public static int getWALConnectionPoolSize();
method public static java.lang.String getWALSyncMode();
+ method public static boolean isCompatibilityWalSupported();
method public static int releaseMemory();
}
@@ -12319,6 +12341,7 @@ package android.database.sqlite {
public abstract class SQLiteOpenHelper {
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
+ ctor public SQLiteOpenHelper(android.content.Context, java.lang.String, int, android.database.sqlite.SQLiteDatabase.OpenParams);
method public synchronized void close();
method public java.lang.String getDatabaseName();
method public android.database.sqlite.SQLiteDatabase getReadableDatabase();
@@ -15404,6 +15427,7 @@ package android.hardware.camera2 {
method public abstract int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract int setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException;
+ method public void updateOutputConfiguration(android.hardware.camera2.params.OutputConfiguration) throws android.hardware.camera2.CameraAccessException;
}
public static abstract class CameraCaptureSession.CaptureCallback {
@@ -16049,9 +16073,11 @@ package android.hardware.camera2.params {
method public void addSurface(android.view.Surface);
method public int describeContents();
method public void enableSurfaceSharing();
+ method public static int getMaxSharedSurfaceCount();
method public android.view.Surface getSurface();
method public int getSurfaceGroupId();
method public java.util.List<android.view.Surface> getSurfaces();
+ method public void removeSurface(android.view.Surface);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff
@@ -18417,11 +18443,13 @@ package android.icu.text {
method public synchronized void applyLocalizedPattern(java.lang.String);
method public synchronized void applyPattern(java.lang.String);
method public synchronized boolean areSignificantDigitsUsed();
+ method public synchronized boolean equals(java.lang.Object);
method public java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(java.math.BigInteger, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(java.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(android.icu.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
+ method public synchronized android.icu.util.Currency getCurrency();
method public synchronized android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
method public synchronized android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
method public synchronized android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
@@ -18429,8 +18457,12 @@ package android.icu.text {
method public synchronized int getGroupingSize();
method public synchronized java.math.MathContext getMathContext();
method public synchronized android.icu.math.MathContext getMathContextICU();
+ method public synchronized int getMaximumFractionDigits();
+ method public synchronized int getMaximumIntegerDigits();
method public synchronized int getMaximumSignificantDigits();
method public synchronized byte getMinimumExponentDigits();
+ method public synchronized int getMinimumFractionDigits();
+ method public synchronized int getMinimumIntegerDigits();
method public synchronized int getMinimumSignificantDigits();
method public synchronized int getMultiplier();
method public synchronized java.lang.String getNegativePrefix();
@@ -18441,13 +18473,19 @@ package android.icu.text {
method public synchronized java.lang.String getPositivePrefix();
method public synchronized java.lang.String getPositiveSuffix();
method public synchronized java.math.BigDecimal getRoundingIncrement();
+ method public synchronized int getRoundingMode();
method public synchronized int getSecondaryGroupingSize();
+ method public synchronized int hashCode();
method public synchronized boolean isDecimalPatternMatchRequired();
method public synchronized boolean isDecimalSeparatorAlwaysShown();
method public synchronized boolean isExponentSignAlwaysShown();
+ method public synchronized boolean isGroupingUsed();
method public synchronized boolean isParseBigDecimal();
+ method public synchronized boolean isParseIntegerOnly();
+ method public synchronized boolean isParseStrict();
method public synchronized boolean isScientificNotation();
method public java.lang.Number parse(java.lang.String, java.text.ParsePosition);
+ method public synchronized void setCurrency(android.icu.util.Currency);
method public synchronized void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
method public synchronized void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
method public synchronized void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
@@ -18456,10 +18494,15 @@ package android.icu.text {
method public synchronized void setExponentSignAlwaysShown(boolean);
method public synchronized void setFormatWidth(int);
method public synchronized void setGroupingSize(int);
+ method public synchronized void setGroupingUsed(boolean);
method public synchronized void setMathContext(java.math.MathContext);
method public synchronized void setMathContextICU(android.icu.math.MathContext);
+ method public synchronized void setMaximumFractionDigits(int);
+ method public synchronized void setMaximumIntegerDigits(int);
method public synchronized void setMaximumSignificantDigits(int);
method public synchronized void setMinimumExponentDigits(byte);
+ method public synchronized void setMinimumFractionDigits(int);
+ method public synchronized void setMinimumIntegerDigits(int);
method public synchronized void setMinimumSignificantDigits(int);
method public synchronized void setMultiplier(int);
method public synchronized void setNegativePrefix(java.lang.String);
@@ -18467,12 +18510,15 @@ package android.icu.text {
method public synchronized void setPadCharacter(char);
method public synchronized void setPadPosition(int);
method public synchronized void setParseBigDecimal(boolean);
+ method public synchronized void setParseIntegerOnly(boolean);
method public deprecated void setParseMaxDigits(int);
+ method public synchronized void setParseStrict(boolean);
method public synchronized void setPositivePrefix(java.lang.String);
method public synchronized void setPositiveSuffix(java.lang.String);
method public synchronized void setRoundingIncrement(java.math.BigDecimal);
method public synchronized void setRoundingIncrement(android.icu.math.BigDecimal);
method public synchronized void setRoundingIncrement(double);
+ method public synchronized void setRoundingMode(int);
method public synchronized void setScientificNotation(boolean);
method public synchronized void setSecondaryGroupingSize(int);
method public synchronized void setSignificantDigitsUsed(boolean);
@@ -23211,8 +23257,9 @@ package android.media {
field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
}
- public class MediaPlayer implements android.media.VolumeAutomation {
+ public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation {
ctor public MediaPlayer();
+ method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(java.io.FileDescriptor, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -23234,6 +23281,8 @@ package android.media {
method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
method public android.os.PersistableBundle getMetrics();
method public android.media.PlaybackParams getPlaybackParams();
+ method public android.media.AudioDeviceInfo getPreferredDevice();
+ method public android.media.AudioDeviceInfo getRoutedDevice();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
method public android.media.SyncParams getSyncParams();
method public android.media.MediaTimestamp getTimestamp();
@@ -23249,6 +23298,7 @@ package android.media {
method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
method public void release();
method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
+ method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public void reset();
method public void restoreKeys(byte[]) throws android.media.MediaPlayer.NoDrmSchemeException;
method public void seekTo(long, int);
@@ -23285,6 +23335,7 @@ package android.media {
method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener);
method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener);
method public void setPlaybackParams(android.media.PlaybackParams);
+ method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
method public void setScreenOnWhilePlaying(boolean);
method public void setSurface(android.view.Surface);
method public void setSyncParams(android.media.SyncParams);
@@ -26173,6 +26224,7 @@ package android.net {
field public static final int NET_CAPABILITY_MMS = 0; // 0x0
field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
+ field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
field public static final int NET_CAPABILITY_RCS = 8; // 0x8
field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
@@ -26203,7 +26255,7 @@ package android.net {
method public boolean isConnected();
method public boolean isConnectedOrConnecting();
method public boolean isFailover();
- method public boolean isRoaming();
+ method public deprecated boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
}
@@ -31212,6 +31264,7 @@ package android.os {
}
public final class Debug {
+ method public static void attachJvmtiAgent(java.lang.String, java.lang.String) throws java.io.IOException;
method public static deprecated void changeDebugPort(int);
method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
method public static boolean dumpService(java.lang.String, java.io.FileDescriptor, java.lang.String[]);
@@ -32050,6 +32103,14 @@ package android.os {
field public static final int DETECT_VM_UNTAGGED_SOCKET = -2147483648; // 0x80000000
}
+ public static abstract interface StrictMode.OnThreadViolationListener {
+ method public abstract void onThreadViolation(android.os.strictmode.Violation);
+ }
+
+ public static abstract interface StrictMode.OnVmViolationListener {
+ method public abstract void onVmViolation(android.os.strictmode.Violation);
+ }
+
public static final class StrictMode.ThreadPolicy {
field public static final android.os.StrictMode.ThreadPolicy LAX;
}
@@ -32070,6 +32131,7 @@ package android.os {
method public android.os.StrictMode.ThreadPolicy.Builder penaltyDialog();
method public android.os.StrictMode.ThreadPolicy.Builder penaltyDropBox();
method public android.os.StrictMode.ThreadPolicy.Builder penaltyFlashScreen();
+ method public android.os.StrictMode.ThreadPolicy.Builder penaltyListener(android.os.StrictMode.OnThreadViolationListener, java.util.concurrent.Executor);
method public android.os.StrictMode.ThreadPolicy.Builder penaltyLog();
method public android.os.StrictMode.ThreadPolicy.Builder permitAll();
method public android.os.StrictMode.ThreadPolicy.Builder permitCustomSlowCalls();
@@ -32081,13 +32143,13 @@ package android.os {
}
public static final class StrictMode.ViolationInfo implements android.os.Parcelable {
- ctor public StrictMode.ViolationInfo();
- ctor public StrictMode.ViolationInfo(java.lang.Throwable, int);
ctor public StrictMode.ViolationInfo(android.os.Parcel);
ctor public StrictMode.ViolationInfo(android.os.Parcel, boolean);
method public int describeContents();
method public void dump(android.util.Printer, java.lang.String);
+ method public int getPolicyMask();
method public java.lang.String getStackTrace();
+ method public int getViolationBit();
method public java.lang.String getViolationDetails();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.os.StrictMode.ViolationInfo> CREATOR;
@@ -32095,7 +32157,6 @@ package android.os {
field public int durationMillis;
field public int numAnimationsRunning;
field public long numInstances;
- field public final int policy;
field public java.lang.String[] tags;
field public int violationNumThisLoop;
field public long violationUptimeMillis;
@@ -32126,6 +32187,7 @@ package android.os {
method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnFileUriExposure();
method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox();
+ method public android.os.StrictMode.VmPolicy.Builder penaltyListener(android.os.StrictMode.OnVmViolationListener, java.util.concurrent.Executor);
method public android.os.StrictMode.VmPolicy.Builder penaltyLog();
method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(java.lang.Class, int);
}
@@ -32133,10 +32195,12 @@ package android.os {
public final class SystemClock {
method public static long currentThreadTimeMillis();
method public static long elapsedRealtime();
+ method public static java.time.Clock elapsedRealtimeClock();
method public static long elapsedRealtimeNanos();
method public static boolean setCurrentTimeMillis(long);
method public static void sleep(long);
method public static long uptimeMillis();
+ method public static java.time.Clock uptimeMillisClock();
}
public class TestLooperManager {
@@ -32221,6 +32285,7 @@ package android.os {
field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
field public static final java.lang.String DISALLOW_CONFIG_DATE_TIME = "no_config_date_time";
+ field public static final java.lang.String DISALLOW_CONFIG_LOCALE = "no_config_locale";
field public static final java.lang.String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
field public static final java.lang.String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
field public static final java.lang.String DISALLOW_CONFIG_VPN = "no_config_vpn";
@@ -32249,6 +32314,7 @@ package android.os {
field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
field public static final java.lang.String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
+ field public static final java.lang.String DISALLOW_USER_SWITCH = "no_user_switch";
field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1
@@ -32489,6 +32555,62 @@ package android.os.storage {
}
+package android.os.strictmode {
+
+ public final class CleartextNetworkViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class ContentUriWithoutPermissionViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class CustomViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class DiskReadViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class DiskWriteViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class FileUriExposedViolation extends android.os.strictmode.Violation {
+ }
+
+ public class InstanceCountViolation extends android.os.strictmode.Violation {
+ method public long getNumberOfInstances();
+ }
+
+ public final class IntentReceiverLeakedViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class LeakedClosableViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class NetworkViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class ResourceMismatchViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class ServiceConnectionLeakedViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class SqliteObjectLeakedViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class UnbufferedIoViolation extends android.os.strictmode.Violation {
+ }
+
+ public final class UntaggedSocketViolation extends android.os.strictmode.Violation {
+ }
+
+ public abstract class Violation extends java.lang.Throwable {
+ }
+
+ public final class WebViewMethodCalledOnWrongThreadViolation extends android.os.strictmode.Violation {
+ }
+
+}
+
package android.preference {
public class CheckBoxPreference extends android.preference.TwoStatePreference {
@@ -32775,7 +32897,7 @@ package android.preference {
method public default void putStringSet(java.lang.String, java.util.Set<java.lang.String>);
}
- public abstract class PreferenceFragment extends android.app.Fragment {
+ public abstract deprecated class PreferenceFragment extends android.app.Fragment {
ctor public PreferenceFragment();
method public void addPreferencesFromIntent(android.content.Intent);
method public void addPreferencesFromResource(int);
@@ -32786,7 +32908,7 @@ package android.preference {
method public void setPreferenceScreen(android.preference.PreferenceScreen);
}
- public static abstract interface PreferenceFragment.OnPreferenceStartFragmentCallback {
+ public static abstract deprecated interface PreferenceFragment.OnPreferenceStartFragmentCallback {
method public abstract boolean onPreferenceStartFragment(android.preference.PreferenceFragment, android.preference.Preference);
}
@@ -35443,6 +35565,7 @@ package android.provider {
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
+ field public static final java.lang.String EXTRA_SUB_ID = "android.provider.extra.SUB_ID";
field public static final java.lang.String INTENT_CATEGORY_USAGE_ACCESS_CONFIG = "android.intent.category.USAGE_ACCESS_CONFIG";
field public static final java.lang.String METADATA_USAGE_ACCESS_REASON = "android.settings.metadata.USAGE_ACCESS_REASON";
}
@@ -35538,6 +35661,7 @@ package android.provider {
field public static final java.lang.String ALLOWED_GEOLOCATION_ORIGINS = "allowed_geolocation_origins";
field public static final deprecated java.lang.String ALLOW_MOCK_LOCATION = "mock_location";
field public static final java.lang.String ANDROID_ID = "android_id";
+ field public static final java.lang.String AUTOFILL_FEATURE_FIELD_DETECTION = "autofill_field_detection";
field public static final java.lang.String AUTOFILL_SERVICE = "autofill_service";
field public static final deprecated java.lang.String BACKGROUND_DATA = "background_data";
field public static final deprecated java.lang.String BLUETOOTH_ON = "bluetooth_on";
@@ -37593,6 +37717,13 @@ package android.service.autofill {
method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, java.util.regex.Pattern, android.widget.RemoteViews);
}
+ public final class FieldsDetection implements android.os.Parcelable {
+ ctor public FieldsDetection(android.view.autofill.AutofillId, java.lang.String, java.lang.String);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.FieldsDetection> CREATOR;
+ }
+
public final class FillCallback {
method public void onFailure(java.lang.CharSequence);
method public void onSuccess(android.service.autofill.FillResponse);
@@ -37618,6 +37749,7 @@ package android.service.autofill {
method public java.util.Map<android.view.autofill.AutofillId, java.lang.String> getChangedFields();
method public android.os.Bundle getClientState();
method public java.lang.String getDatasetId();
+ method public java.util.Map<java.lang.String, java.lang.Integer> getDetectedFields();
method public java.util.Set<java.lang.String> getIgnoredDatasetIds();
method public java.util.Map<android.view.autofill.AutofillId, java.util.Set<java.lang.String>> getManuallyEnteredField();
method public java.util.Set<java.lang.String> getSelectedDatasetIds();
@@ -37655,6 +37787,7 @@ package android.service.autofill {
method public android.service.autofill.FillResponse.Builder disableAutofill(long);
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 setFieldsDetection(android.service.autofill.FieldsDetection);
method public android.service.autofill.FillResponse.Builder setFlags(int);
method public android.service.autofill.FillResponse.Builder setIgnoredIds(android.view.autofill.AutofillId...);
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
@@ -38023,6 +38156,7 @@ package android.service.notification {
public abstract class ConditionProviderService extends android.app.Service {
ctor public ConditionProviderService();
+ method public boolean isBound();
method public final void notifyCondition(android.service.notification.Condition);
method public final void notifyConditions(android.service.notification.Condition...);
method public android.os.IBinder onBind(android.content.Intent);
@@ -38802,6 +38936,16 @@ package android.system {
field public final int errno;
}
+ public class Int32Ref {
+ ctor public Int32Ref(int);
+ field public int value;
+ }
+
+ public class Int64Ref {
+ ctor public Int64Ref(long);
+ field public long value;
+ }
+
public final class Os {
method public static java.io.FileDescriptor accept(java.io.FileDescriptor, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
method public static boolean access(java.lang.String, int) throws android.system.ErrnoException;
@@ -38871,7 +39015,8 @@ package android.system {
method public static void remove(java.lang.String) throws android.system.ErrnoException;
method public static void removexattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
- method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+ method public static deprecated long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+ method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.system.Int64Ref, long) throws android.system.ErrnoException;
method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
method public static void setegid(int) throws android.system.ErrnoException;
@@ -38896,7 +39041,8 @@ package android.system {
method public static int umask(int);
method public static android.system.StructUtsname uname();
method public static void unsetenv(java.lang.String) throws android.system.ErrnoException;
- method public static int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+ method public static deprecated int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+ method public static int waitpid(int, android.system.Int32Ref, int) throws android.system.ErrnoException;
method public static int write(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
method public static int write(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
method public static int writev(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
@@ -39472,6 +39618,7 @@ package android.telecom {
method public android.telecom.Call.RttCall getRttCall();
method public int getState();
method public android.telecom.InCallService.VideoCall getVideoCall();
+ method public void handoverTo(android.telecom.PhoneAccountHandle, int, android.os.Bundle);
method public void hold();
method public boolean isRttActive();
method public void mergeConference();
@@ -39516,6 +39663,8 @@ package android.telecom {
method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
+ method public void onHandoverComplete(android.telecom.Call);
+ method public void onHandoverFailed(android.telecom.Call, int);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
method public void onRttInitiationFailure(android.telecom.Call, int);
@@ -39524,6 +39673,10 @@ package android.telecom {
method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
method public void onStateChanged(android.telecom.Call, int);
method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
+ field public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1; // 0x1
+ 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
}
public static class Call.Details {
@@ -39592,7 +39745,9 @@ package android.telecom {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
method public int describeContents();
+ method public android.bluetooth.BluetoothDevice getActiveBluetoothDevice();
method public int getRoute();
+ method public java.util.Collection<android.bluetooth.BluetoothDevice> getSupportedBluetoothDevices();
method public int getSupportedRouteMask();
method public boolean isMuted();
method public void writeToParcel(android.os.Parcel, int);
@@ -39727,6 +39882,7 @@ package android.telecom {
method public final void putExtras(android.os.Bundle);
method public final void removeExtras(java.util.List<java.lang.String>);
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);
@@ -39871,8 +40027,11 @@ package android.telecom {
method public void onConference(android.telecom.Connection, android.telecom.Connection);
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);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method public void onHandoverFailed(android.telecom.ConnectionRequest, int);
method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
@@ -39930,6 +40089,7 @@ package android.telecom {
method public void onCanAddCallChanged(boolean);
method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public void onSilenceRinger();
+ method public final void requestBluetoothAudio(java.lang.String);
method public final void setAudioRoute(int);
method public final void setMuted(boolean);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
@@ -39994,6 +40154,9 @@ package android.telecom {
field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
+ field public static final java.lang.String EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
+ field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_FROM = "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
+ field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_TO = "android.telecom.extra.SUPPORTS_HANDOVER_TO";
field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
field public static final java.lang.String SCHEME_SIP = "sip";
@@ -40154,6 +40317,7 @@ package android.telecom {
}
public class TelecomManager {
+ method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
method public void acceptRingingCall();
method public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
@@ -40322,8 +40486,8 @@ package android.telephony {
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
- field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
+ field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
@@ -40808,6 +40972,7 @@ package android.telephony {
method public void sendMultimediaMessage(android.content.Context, android.net.Uri, java.lang.String, android.os.Bundle, android.app.PendingIntent);
method public void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
method public void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
+ method public void sendTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
field public static final java.lang.String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
field public static final java.lang.String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
field public static final java.lang.String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
@@ -41318,6 +41483,7 @@ package android.telephony.mbms {
}
public final class FileInfo implements android.os.Parcelable {
+ ctor public FileInfo(android.net.Uri, java.lang.String);
method public int describeContents();
method public java.lang.String getMimeType();
method public android.net.Uri getUri();
@@ -41431,6 +41597,14 @@ package android.telephony.mbms {
field public static final android.os.Parcelable.Creator<android.telephony.mbms.StreamingServiceInfo> CREATOR;
}
+ public final class UriPathPair implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.net.Uri getContentUri();
+ method public android.net.Uri getFilePathUri();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.mbms.UriPathPair> CREATOR;
+ }
+
}
package android.telephony.mbms.vendor {
@@ -41462,6 +41636,23 @@ package android.telephony.mbms.vendor {
method public void stopStreaming(int, java.lang.String) throws android.os.RemoteException;
}
+ public class VendorUtils {
+ ctor public VendorUtils();
+ method public static android.content.ComponentName getAppReceiverFromPackageName(android.content.Context, java.lang.String);
+ field public static final java.lang.String ACTION_CLEANUP = "android.telephony.mbms.action.CLEANUP";
+ field public static final java.lang.String ACTION_DOWNLOAD_RESULT_INTERNAL = "android.telephony.mbms.action.DOWNLOAD_RESULT_INTERNAL";
+ field public static final java.lang.String ACTION_FILE_DESCRIPTOR_REQUEST = "android.telephony.mbms.action.FILE_DESCRIPTOR_REQUEST";
+ field public static final java.lang.String EXTRA_FD_COUNT = "android.telephony.mbms.extra.FD_COUNT";
+ field public static final java.lang.String EXTRA_FINAL_URI = "android.telephony.mbms.extra.FINAL_URI";
+ field public static final java.lang.String EXTRA_FREE_URI_LIST = "android.telephony.mbms.extra.FREE_URI_LIST";
+ field public static final java.lang.String EXTRA_PAUSED_LIST = "android.telephony.mbms.extra.PAUSED_LIST";
+ field public static final java.lang.String EXTRA_PAUSED_URI_LIST = "android.telephony.mbms.extra.PAUSED_URI_LIST";
+ field public static final java.lang.String EXTRA_SERVICE_ID = "android.telephony.mbms.extra.SERVICE_ID";
+ field public static final java.lang.String EXTRA_TEMP_FILES_IN_USE = "android.telephony.mbms.extra.TEMP_FILES_IN_USE";
+ field public static final java.lang.String EXTRA_TEMP_FILE_ROOT = "android.telephony.mbms.extra.TEMP_FILE_ROOT";
+ field public static final java.lang.String EXTRA_TEMP_LIST = "android.telephony.mbms.extra.TEMP_LIST";
+ }
+
}
package android.test {
@@ -45165,6 +45356,7 @@ package android.view {
field public static final int STATE_DOZE_SUSPEND = 4; // 0x4
field public static final int STATE_OFF = 1; // 0x1
field public static final int STATE_ON = 2; // 0x2
+ field public static final int STATE_ON_SUSPEND = 6; // 0x6
field public static final int STATE_UNKNOWN = 0; // 0x0
field public static final int STATE_VR = 5; // 0x5
}
@@ -49594,14 +49786,23 @@ package android.view.textclassifier {
method public android.view.textclassifier.TextClassification.Builder setText(java.lang.String);
}
+ public static final class TextClassification.Options {
+ ctor public TextClassification.Options();
+ method public android.os.LocaleList getDefaultLocales();
+ method public android.view.textclassifier.TextClassification.Options setDefaultLocales(android.os.LocaleList);
+ }
+
public final class TextClassificationManager {
method public android.view.textclassifier.TextClassifier getTextClassifier();
method public void setTextClassifier(android.view.textclassifier.TextClassifier);
}
public abstract interface TextClassifier {
- method public abstract android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
- method public abstract android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
+ 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, 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.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, 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";
@@ -49610,6 +49811,36 @@ package android.view.textclassifier {
field public static final java.lang.String TYPE_URL = "url";
}
+ public final class TextLinks {
+ method public boolean apply(android.text.SpannableString, java.util.function.Function<android.view.textclassifier.TextLinks.TextLink, android.text.style.ClickableSpan>);
+ method public java.util.Collection<android.view.textclassifier.TextLinks.TextLink> getLinks();
+ }
+
+ public static final class TextLinks.Builder {
+ ctor public TextLinks.Builder(java.lang.String);
+ method public android.view.textclassifier.TextLinks.Builder addLink(android.view.textclassifier.TextLinks.TextLink);
+ method public android.view.textclassifier.TextLinks build();
+ }
+
+ public static final class 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);
+ }
+
+ public static final class TextLinks.TextLink {
+ ctor public TextLinks.TextLink(java.lang.String, int, int, java.util.Map<java.lang.String, java.lang.Float>);
+ method public float getConfidenceScore(java.lang.String);
+ method public int getEnd();
+ method public java.lang.String getEntity(int);
+ method public int getEntityCount();
+ method public int getStart();
+ }
+
public final class TextSelection {
method public float getConfidenceScore(java.lang.String);
method public java.lang.String getEntity(int);
@@ -49624,6 +49855,12 @@ package android.view.textclassifier {
method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
}
+ public static final class TextSelection.Options {
+ ctor public TextSelection.Options();
+ method public android.os.LocaleList getDefaultLocales();
+ method public android.view.textclassifier.TextSelection.Options setDefaultLocales(android.os.LocaleList);
+ }
+
}
package android.view.textservice {
@@ -50453,7 +50690,7 @@ package android.webkit {
method public abstract void setHttpAuthUsernamePassword(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
}
- public class WebViewFragment extends android.app.Fragment {
+ public deprecated class WebViewFragment extends android.app.Fragment {
ctor public WebViewFragment();
method public android.webkit.WebView getWebView();
}
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index 93b9f58d51d3..d79b1a61eb5b 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -47,6 +47,16 @@ import java.util.Locale;
/**
* Runs the am instrument command
+ *
+ * Test Result Code:
+ * 1 - Test running
+ * 0 - Test passed
+ * -2 - assertion failure
+ * -1 - other exceptions
+ *
+ * Session Result Code:
+ * -1: Success
+ * other: Failure
*/
public class Instrument {
public static final String DEFAULT_LOG_DIR = "instrument-logs";
diff --git a/cmds/appwidget/appwidget b/cmds/appwidget/appwidget
index 610500929519..26ab1730250f 100755
--- a/cmds/appwidget/appwidget
+++ b/cmds/appwidget/appwidget
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "appwidget" on the device, which has a very rudimentary shell.
base=/system
export CLASSPATH=$base/framework/appwidget.jar
diff --git a/cmds/bmgr/bmgr b/cmds/bmgr/bmgr
index 6b4bbe2d9032..60b5833e7696 100755
--- a/cmds/bmgr/bmgr
+++ b/cmds/bmgr/bmgr
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "bmgr" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/bu/bu b/cmds/bu/bu
index e8dbc318818f..e50b53da4325 100755
--- a/cmds/bu/bu
+++ b/cmds/bu/bu
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "bu" on the device
#
base=/system
diff --git a/cmds/content/content b/cmds/content/content
index a8e056d04d69..f1bfe1737c5a 100755
--- a/cmds/content/content
+++ b/cmds/content/content
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "content" on the device, which has a very rudimentary shell.
base=/system
export CLASSPATH=$base/framework/content.jar
diff --git a/cmds/dpm/dpm b/cmds/dpm/dpm
index c2e5cbb61c18..e0efdc15a706 100755
--- a/cmds/dpm/dpm
+++ b/cmds/dpm/dpm
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "dpm" on the device
#
base=/system
diff --git a/cmds/ime/ime b/cmds/ime/ime
index 96c56d3bde0a..1a1fdd96da6e 100755
--- a/cmds/ime/ime
+++ b/cmds/ime/ime
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "pm" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/incident_helper/src/ih_util.cpp b/cmds/incident_helper/src/ih_util.cpp
index c7d1ca231a03..db4f586c7e31 100644
--- a/cmds/incident_helper/src/ih_util.cpp
+++ b/cmds/incident_helper/src/ih_util.cpp
@@ -22,23 +22,36 @@
#include <sstream>
#include <unistd.h>
-const ssize_t BUFFER_SIZE = 16 * 1024; // 4KB
-
+bool isValidChar(char c) {
+ uint8_t v = (uint8_t)c;
+ return (v >= (uint8_t)'a' && v <= (uint8_t)'z')
+ || (v >= (uint8_t)'A' && v <= (uint8_t)'Z')
+ || (v >= (uint8_t)'0' && v <= (uint8_t)'9')
+ || (v == (uint8_t)'_');
+}
-static std::string trim(const std::string& s) {
- const auto head = s.find_first_not_of(DEFAULT_WHITESPACE);
+std::string trim(const std::string& s, const std::string& charset) {
+ const auto head = s.find_first_not_of(charset);
if (head == std::string::npos) return "";
- const auto tail = s.find_last_not_of(DEFAULT_WHITESPACE);
+ const auto tail = s.find_last_not_of(charset);
return s.substr(head, tail - head + 1);
}
-static std::string trimHeader(const std::string& s) {
- std::string res = trim(s);
+static inline std::string toLowerStr(const std::string& s) {
+ std::string res(s);
std::transform(res.begin(), res.end(), res.begin(), ::tolower);
return res;
}
+static inline std::string trimDefault(const std::string& s) {
+ return trim(s, DEFAULT_WHITESPACE);
+}
+
+static inline std::string trimHeader(const std::string& s) {
+ return toLowerStr(trimDefault(s));
+}
+
// This is similiar to Split in android-base/file.h, but it won't add empty string
static void split(const std::string& line, std::vector<std::string>& words,
const trans_func& func, const std::string& delimiters) {
@@ -68,22 +81,68 @@ header_t parseHeader(const std::string& line, const std::string& delimiters) {
record_t parseRecord(const std::string& line, const std::string& delimiters) {
record_t record;
- trans_func f = &trim;
+ trans_func f = &trimDefault;
split(line, record, f, delimiters);
return record;
}
-bool hasPrefix(std::string* line, const char* key) {
+record_t parseRecordByColumns(const std::string& line, const std::vector<int>& indices, const std::string& delimiters) {
+ record_t record;
+ int lastIndex = 0;
+ int lineSize = (int)line.size();
+ for (std::vector<int>::const_iterator it = indices.begin(); it != indices.end(); ++it) {
+ int idx = *it;
+ if (lastIndex > idx || idx > lineSize) {
+ record.clear(); // The indices is wrong, return empty;
+ return record;
+ }
+ while (idx < lineSize && delimiters.find(line[idx++]) == std::string::npos);
+ record.push_back(trimDefault(line.substr(lastIndex, idx - lastIndex)));
+ lastIndex = idx;
+ }
+ record.push_back(trimDefault(line.substr(lastIndex, lineSize - lastIndex)));
+ return record;
+}
+
+bool stripPrefix(std::string* line, const char* key, bool endAtDelimiter) {
const auto head = line->find_first_not_of(DEFAULT_WHITESPACE);
if (head == std::string::npos) return false;
- auto i = 0;
- auto j = head;
+ int len = (int)line->length();
+ int i = 0;
+ int j = head;
while (key[i] != '\0') {
- if (j >= line->size() || key[i++] != line->at(j++)) {
+ if (j >= len || key[i++] != line->at(j++)) {
+ return false;
+ }
+ }
+
+ if (endAtDelimiter) {
+ // this means if the line only have prefix or no delimiter, we still return false.
+ if (j == len || isValidChar(line->at(j))) return false;
+ }
+
+ line->assign(trimDefault(line->substr(j)));
+ return true;
+}
+
+bool stripSuffix(std::string* line, const char* key, bool endAtDelimiter) {
+ const auto tail = line->find_last_not_of(DEFAULT_WHITESPACE);
+ if (tail == std::string::npos) return false;
+ int i = 0;
+ while (key[++i] != '\0'); // compute the size of the key
+ int j = tail;
+ while (i > 0) {
+ if (j < 0 || key[--i] != line->at(j--)) {
return false;
}
}
- line->assign(trim(line->substr(j)));
+
+ if (endAtDelimiter) {
+ // this means if the line only have suffix or no delimiter, we still return false.
+ if (j < 0 || isValidChar(line->at(j))) return false;
+ }
+
+ line->assign(trimDefault(line->substr(0, j+1)));
return true;
}
@@ -95,65 +154,36 @@ long long toLongLong(const std::string& s) {
return atoll(s.c_str());
}
-// ==============================================================================
-Reader::Reader(const int fd) : Reader(fd, BUFFER_SIZE) {};
+double toDouble(const std::string& s) {
+ return atof(s.c_str());
+}
-Reader::Reader(const int fd, const size_t capacity)
- : mFd(fd), mMaxSize(capacity), mBufSize(0), mRead(0), mFlushed(0)
+// ==============================================================================
+Reader::Reader(const int fd)
{
- mBuf = capacity > 0 ? (char*)malloc(capacity * sizeof(char)) : NULL;
- mStatus = mFd < 0 ? "Negative fd" : (capacity == 0 ? "Zero buffer capacity" : "");
+ mFile = fdopen(fd, "r");
+ mStatus = mFile == NULL ? "Invalid fd " + std::to_string(fd) : "";
}
Reader::~Reader()
{
- free(mBuf);
-}
-
-bool Reader::readLine(std::string* line, const char newline) {
- if (!ok(line)) return false; // bad status
- line->clear();
- std::stringstream ss;
- while (!EOR()) {
- // read if available
- if (mFd != -1 && mBufSize != mMaxSize) {
- ssize_t amt = 0;
- if (mRead >= mFlushed) {
- amt = ::read(mFd, mBuf + mRead, mMaxSize - mRead);
- } else {
- amt = ::read(mFd, mBuf + mRead, mFlushed - mRead);
- }
- if (amt < 0) {
- mStatus = "Fail to read from fd";
- return false;
- } else if (amt == 0) {
- close(mFd);
- mFd = -1;
- }
- mRead += amt;
- mBufSize += amt;
- }
-
- bool meetsNewLine = false;
- if (mBufSize > 0) {
- int start = mFlushed;
- int end = mFlushed < mRead ? mRead : mMaxSize;
- while (mFlushed < end && mBuf[mFlushed++] != newline && mBufSize > 0) mBufSize--;
- meetsNewLine = (mBuf[mFlushed-1] == newline);
- if (meetsNewLine) mBufSize--; // deduct the new line character
- size_t len = meetsNewLine ? mFlushed - start - 1 : mFlushed - start;
- ss.write(mBuf + start, len);
- }
+ if (mFile != NULL) fclose(mFile);
+}
- if (mRead >= (int) mMaxSize) mRead = 0;
- if (mFlushed >= (int) mMaxSize) mFlushed = 0;
+bool Reader::readLine(std::string* line) {
+ if (mFile == NULL) return false;
- if (EOR() || meetsNewLine) {
- line->assign(ss.str());
- return true;
- }
+ char* buf = NULL;
+ size_t len = 0;
+ ssize_t read = getline(&buf, &len, mFile);
+ if (read != -1) {
+ std::string s(buf);
+ line->assign(trim(s, DEFAULT_NEWLINE));
+ } else if (errno == EINVAL) {
+ mStatus = "Bad Argument";
}
- return false;
+ free(buf);
+ return read != -1;
}
bool Reader::ok(std::string* error) {
@@ -163,51 +193,104 @@ bool Reader::ok(std::string* error) {
// ==============================================================================
Table::Table(const char* names[], const uint64_t ids[], const int count)
- :mFieldNames(names),
- mFieldIds(ids),
- mFieldCount(count)
+ :mEnums(),
+ mEnumValuesByName()
{
+ map<std::string, uint64_t> fields;
+ for (int i = 0; i < count; i++) {
+ fields[names[i]] = ids[i];
+ }
+ mFields = fields;
}
Table::~Table()
{
}
-bool
-Table::insertField(ProtoOutputStream& proto, const std::string& name, const std::string& value)
+void
+Table::addEnumTypeMap(const char* field, const char* enumNames[], const int enumValues[], const int enumSize)
{
- uint64_t found = 0;
- for (int i=0; i<mFieldCount; i++) {
- if (strcmp(name.c_str(), mFieldNames[i]) == 0) {
- found = mFieldIds[i];
- break;
- }
+ if (mFields.find(field) == mFields.end()) return;
+
+ map<std::string, int> enu;
+ for (int i = 0; i < enumSize; i++) {
+ enu[enumNames[i]] = enumValues[i];
}
+ mEnums[field] = enu;
+}
+
+void
+Table::addEnumNameToValue(const char* enumName, const int enumValue)
+{
+ mEnumValuesByName[enumName] = enumValue;
+}
- switch (found & FIELD_TYPE_MASK) {
- case FIELD_TYPE_DOUBLE:
- case FIELD_TYPE_FLOAT:
- // TODO: support parse string to float/double
+bool
+Table::insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value)
+{
+ if (mFields.find(name) == mFields.end()) return false;
+
+ uint64_t found = mFields[name];
+ record_t repeats; // used for repeated fields
+ switch ((found & FIELD_COUNT_MASK) | (found & FIELD_TYPE_MASK)) {
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_DOUBLE:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_FLOAT:
+ proto->write(found, toDouble(value));
+ break;
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_STRING:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_BYTES:
+ proto->write(found, value);
+ break;
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_INT64:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_SINT64:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_UINT64:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED64:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED64:
+ proto->write(found, toLongLong(value));
+ break;
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_BOOL:
+ if (strcmp(toLowerStr(value).c_str(), "true") == 0 || strcmp(value.c_str(), "1") == 0) {
+ proto->write(found, true);
+ break;
+ }
+ if (strcmp(toLowerStr(value).c_str(), "false") == 0 || strcmp(value.c_str(), "0") == 0) {
+ proto->write(found, false);
+ break;
+ }
return false;
- case FIELD_TYPE_STRING:
- case FIELD_TYPE_BYTES:
- proto.write(found, value);
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_ENUM:
+ // if the field has its own enum mapping, use this, otherwise use general name to value mapping.
+ if (mEnums.find(name) != mEnums.end()) {
+ if (mEnums[name].find(value) != mEnums[name].end()) {
+ proto->write(found, mEnums[name][value]);
+ } else {
+ proto->write(found, 0); // TODO: should get the default enum value (Unknown)
+ }
+ } else if (mEnumValuesByName.find(value) != mEnumValuesByName.end()) {
+ proto->write(found, mEnumValuesByName[value]);
+ } else {
+ return false;
+ }
break;
- case FIELD_TYPE_INT64:
- case FIELD_TYPE_SINT64:
- case FIELD_TYPE_UINT64:
- case FIELD_TYPE_FIXED64:
- case FIELD_TYPE_SFIXED64:
- proto.write(found, toLongLong(value));
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_INT32:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_SINT32:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_UINT32:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED32:
+ case FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED32:
+ proto->write(found, toInt(value));
break;
- case FIELD_TYPE_BOOL:
- case FIELD_TYPE_ENUM:
- case FIELD_TYPE_INT32:
- case FIELD_TYPE_SINT32:
- case FIELD_TYPE_UINT32:
- case FIELD_TYPE_FIXED32:
- case FIELD_TYPE_SFIXED32:
- proto.write(found, toInt(value));
+ // REPEATED TYPE below:
+ case FIELD_COUNT_REPEATED | FIELD_TYPE_INT32:
+ repeats = parseRecord(value, COMMA_DELIMITER);
+ for (size_t i=0; i<repeats.size(); i++) {
+ proto->write(found, toInt(repeats[i]));
+ }
+ break;
+ case FIELD_COUNT_REPEATED | FIELD_TYPE_STRING:
+ repeats = parseRecord(value, COMMA_DELIMITER);
+ for (size_t i=0; i<repeats.size(); i++) {
+ proto->write(found, repeats[i]);
+ }
break;
default:
return false;
diff --git a/cmds/incident_helper/src/ih_util.h b/cmds/incident_helper/src/ih_util.h
index 86761e93f49c..4a5fe1dd7a42 100644
--- a/cmds/incident_helper/src/ih_util.h
+++ b/cmds/incident_helper/src/ih_util.h
@@ -17,9 +17,9 @@
#ifndef INCIDENT_HELPER_UTIL_H
#define INCIDENT_HELPER_UTIL_H
+#include <map>
#include <string>
#include <vector>
-#include <sstream>
#include <android/util/ProtoOutputStream.h>
@@ -29,8 +29,16 @@ typedef std::vector<std::string> header_t;
typedef std::vector<std::string> record_t;
typedef std::string (*trans_func) (const std::string&);
-const char DEFAULT_NEWLINE = '\n';
const std::string DEFAULT_WHITESPACE = " \t";
+const std::string DEFAULT_NEWLINE = "\r\n";
+const std::string TAB_DELIMITER = "\t";
+const std::string COMMA_DELIMITER = ",";
+
+// returns true if c is a-zA-Z0-9 or underscore _
+bool isValidChar(char c);
+
+// trim the string with the given charset
+std::string trim(const std::string& s, const std::string& charset);
/**
* When a text has a table format like this
@@ -47,19 +55,33 @@ header_t parseHeader(const std::string& line, const std::string& delimiters = DE
record_t parseRecord(const std::string& line, const std::string& delimiters = DEFAULT_WHITESPACE);
/**
- * When the line starts with the given key, the function returns true
- * as well as the line argument is changed to the rest part of the original.
+ * When a text-format table aligns by its vertical position, it is not possible to split them by purely delimiters.
+ * This function allows to parse record by its header's column position' indices, must in ascending order.
+ * At the same time, it still looks at the char at index, if it doesn't belong to delimiters, moves forward to find the delimiters.
+ */
+record_t parseRecordByColumns(const std::string& line, const std::vector<int>& indices, const std::string& delimiters = DEFAULT_WHITESPACE);
+
+/**
+ * When the line starts/ends with the given key, the function returns true
+ * as well as the line argument is changed to the rest trimmed part of the original.
* e.g. "ZRAM: 6828K physical used for 31076K in swap (524284K total swap)" becomes
* "6828K physical used for 31076K in swap (524284K total swap)" when given key "ZRAM:",
* otherwise the line is not changed.
+ *
+ * In order to prevent two values have same prefix which cause entering to incorrect conditions,
+ * stripPrefix and stripSuffix can turn on a flag that requires the ending char in the line must not be a valid
+ * character or digits, this feature is off by default.
+ * i.e. ABC%some value, ABCD%other value
*/
-bool hasPrefix(std::string* line, const char* key);
+bool stripPrefix(std::string* line, const char* key, bool endAtDelimiter = false);
+bool stripSuffix(std::string* line, const char* key, bool endAtDelimiter = false);
/**
* Converts string to the desired type
*/
int toInt(const std::string& s);
long long toLongLong(const std::string& s);
+double toDouble(const std::string& s);
/**
* Reader class reads data from given fd in streaming fashion.
@@ -69,23 +91,14 @@ class Reader
{
public:
Reader(const int fd);
- Reader(const int fd, const size_t capacity);
~Reader();
- bool readLine(std::string* line, const char newline = DEFAULT_NEWLINE);
+ bool readLine(std::string* line);
bool ok(std::string* error);
private:
- int mFd; // set mFd to -1 when read EOF()
- const size_t mMaxSize;
- size_t mBufSize;
- char* mBuf; // implements a circular buffer
-
- int mRead;
- int mFlushed;
+ FILE* mFile;
std::string mStatus;
- // end of read
- inline bool EOR() { return mFd == -1 && mBufSize == 0; };
};
/**
@@ -98,12 +111,17 @@ public:
Table(const char* names[], const uint64_t ids[], const int count);
~Table();
- bool insertField(ProtoOutputStream& proto, const std::string& name, const std::string& value);
+ // 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
+ void addEnumNameToValue(const char* enumName, const int enumValue);
+ bool insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value);
private:
- const char** mFieldNames;
- const uint64_t* mFieldIds;
- const int mFieldCount;
+ map<std::string, uint64_t> mFields;
+ map<std::string, map<std::string, int>> mEnums;
+ map<std::string, int> mEnumValuesByName;
};
#endif // INCIDENT_HELPER_UTIL_H
diff --git a/cmds/incident_helper/src/main.cpp b/cmds/incident_helper/src/main.cpp
index 3da87b9c801b..8239d8ec92ed 100644
--- a/cmds/incident_helper/src/main.cpp
+++ b/cmds/incident_helper/src/main.cpp
@@ -16,9 +16,11 @@
#define LOG_TAG "incident_helper"
+#include "parsers/CpuInfoParser.h"
#include "parsers/KernelWakesParser.h"
#include "parsers/PageTypeInfoParser.h"
#include "parsers/ProcrankParser.h"
+#include "parsers/SystemPropertiesParser.h"
#include <android-base/file.h>
#include <getopt.h>
@@ -48,12 +50,16 @@ static TextParserBase* selectParser(int section) {
return new ReverseParser();
/* ========================================================================= */
// IDs larger than 1 are section ids reserved in incident.proto
+ case 1000:
+ return new SystemPropertiesParser();
case 2000:
return new ProcrankParser();
case 2001:
return new PageTypeInfoParser();
case 2002:
return new KernelWakesParser();
+ case 2003:
+ return new CpuInfoParser();
default:
return NULL;
}
diff --git a/cmds/incident_helper/src/parsers/CpuInfoParser.cpp b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
new file mode 100644
index 000000000000..3faca00c1b88
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "incident_helper"
+
+#include <android/util/ProtoOutputStream.h>
+
+#include "frameworks/base/core/proto/android/os/cpuinfo.proto.h"
+#include "ih_util.h"
+#include "CpuInfoParser.h"
+
+using namespace android::os;
+
+static void writeSuffixLine(ProtoOutputStream* proto, uint64_t fieldId,
+ const string& line, const string& delimiter,
+ const int count, const char* names[], const uint64_t ids[])
+{
+ record_t record = parseRecord(line, delimiter);
+ long long token = proto->start(fieldId);
+ for (int i=0; i<(int)record.size(); i++) {
+ for (int j=0; j<count; j++) {
+ if (stripSuffix(&record[i], names[j], true)) {
+ proto->write(ids[j], toInt(record[i]));
+ break;
+ }
+ }
+ }
+ proto->end(token);
+}
+
+status_t
+CpuInfoParser::Parse(const int in, const int out) const
+{
+ Reader reader(in);
+ string line;
+ header_t header;
+ vector<int> columnIndices; // task table can't be split by purely delimiter, needs column positions.
+ record_t record;
+ int nline = 0;
+ bool nextToSwap = false;
+ bool nextToUsage = false;
+
+ ProtoOutputStream proto;
+ Table table(CpuInfo::Task::_FIELD_NAMES, CpuInfo::Task::_FIELD_IDS, CpuInfo::Task::_FIELD_COUNT);
+ table.addEnumTypeMap("s", CpuInfo::Task::_ENUM_STATUS_NAMES,
+ CpuInfo::Task::_ENUM_STATUS_VALUES, CpuInfo::Task::_ENUM_STATUS_COUNT);
+ table.addEnumTypeMap("pcy", CpuInfo::Task::_ENUM_POLICY_NAMES,
+ CpuInfo::Task::_ENUM_POLICY_VALUES, CpuInfo::Task::_ENUM_POLICY_COUNT);
+
+ // parse line by line
+ while (reader.readLine(&line)) {
+ if (line.empty()) continue;
+
+ nline++;
+
+ if (stripPrefix(&line, "Tasks:")) {
+ writeSuffixLine(&proto, CpuInfo::TASK_STATS, line, COMMA_DELIMITER,
+ CpuInfo::TaskStats::_FIELD_COUNT,
+ CpuInfo::TaskStats::_FIELD_NAMES,
+ CpuInfo::TaskStats::_FIELD_IDS);
+ continue;
+ }
+ if (stripPrefix(&line, "Mem:")) {
+ writeSuffixLine(&proto, CpuInfo::MEM, line, COMMA_DELIMITER,
+ CpuInfo::MemStats::_FIELD_COUNT,
+ CpuInfo::MemStats::_FIELD_NAMES,
+ CpuInfo::MemStats::_FIELD_IDS);
+ continue;
+ }
+ if (stripPrefix(&line, "Swap:")) {
+ writeSuffixLine(&proto, CpuInfo::SWAP, line, COMMA_DELIMITER,
+ CpuInfo::MemStats::_FIELD_COUNT,
+ CpuInfo::MemStats::_FIELD_NAMES,
+ CpuInfo::MemStats::_FIELD_IDS);
+ nextToSwap = true;
+ continue;
+ }
+
+ if (nextToSwap) {
+ writeSuffixLine(&proto, CpuInfo::CPU_USAGE, line, DEFAULT_WHITESPACE,
+ CpuInfo::CpuUsage::_FIELD_COUNT,
+ CpuInfo::CpuUsage::_FIELD_NAMES,
+ CpuInfo::CpuUsage::_FIELD_IDS);
+ nextToUsage = true;
+ nextToSwap = false;
+ continue;
+ }
+
+ // Header of tasks must be next to usage line
+ if (nextToUsage) {
+ // How to parse Header of Tasks:
+ // PID TID USER PR NI[%CPU]S VIRT RES PCY CMD NAME
+ // After parsing, header = { PID, TID, USER, PR, NI, CPU, S, VIRT, RES, PCY, CMD, NAME }
+ // And columnIndices will contain end index of each word.
+ header = parseHeader(line, "[ %]");
+ nextToUsage = false;
+
+ // NAME is not in the list since the last split index is default to the end of line.
+ const char* headerNames[11] = { "PID", "TID", "USER", "PR", "NI", "CPU", "S", "VIRT", "RES", "PCY", "CMD" };
+ size_t lastIndex = 0;
+ for (int i = 0; i < 11; i++) {
+ string s = headerNames[i];
+ lastIndex = line.find(s, lastIndex);
+ if (lastIndex == string::npos) {
+ fprintf(stderr, "Bad Task Header: %s\n", line.c_str());
+ return -1;
+ }
+ lastIndex += s.length();
+ columnIndices.push_back(lastIndex);
+ }
+ // Need to remove the end index of CMD and use the start index of NAME because CMD values contain spaces.
+ // for example: ... CMD NAME
+ // ... Jit thread pool com.google.android.gms.feedback
+ // If use end index of CMD, parsed result = { "Jit", "thread pool com.google.android.gms.feedback" }
+ // If use start index of NAME, parsed result = { "Jit thread pool", "com.google.android.gms.feedback" }
+ int endCMD = columnIndices.back();
+ columnIndices.pop_back();
+ columnIndices.push_back(line.find("NAME", endCMD) - 1);
+ continue;
+ }
+
+ record = parseRecordByColumns(line, columnIndices);
+ if (record.size() != header.size()) {
+ fprintf(stderr, "[%s]Line %d has missing fields:\n%s\n", this->name.string(), nline, line.c_str());
+ continue;
+ }
+
+ long long token = proto.start(CpuInfo::TASKS);
+ for (int i=0; i<(int)record.size(); i++) {
+ if (!table.insertField(&proto, header[i], record[i])) {
+ fprintf(stderr, "[%s]Line %d fails to insert field %s with value %s\n",
+ this->name.string(), nline, header[i].c_str(), record[i].c_str());
+ }
+ }
+ proto.end(token);
+ }
+
+ if (!reader.ok(&line)) {
+ fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
+ return -1;
+ }
+
+ if (!proto.flush(out)) {
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ return -1;
+ }
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ return NO_ERROR;
+}
diff --git a/cmds/incident_helper/src/parsers/CpuInfoParser.h b/cmds/incident_helper/src/parsers/CpuInfoParser.h
new file mode 100644
index 000000000000..f57bb4e169bd
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/CpuInfoParser.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 CPU_INFO_PARSER_H
+#define CPU_INFO_PARSER_H
+
+#include "TextParserBase.h"
+
+using namespace android;
+
+/**
+ * Cpu info parser, parses text produced by command
+ * 'top -b -n 1 -H -s 6 -o pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name'
+ */
+class CpuInfoParser : public TextParserBase {
+public:
+ CpuInfoParser() : TextParserBase(String8("CpuInfoParser")) {};
+ ~CpuInfoParser() {};
+
+ virtual status_t Parse(const int in, const int out) const;
+};
+
+#endif // CPU_INFO_PARSER_H
diff --git a/cmds/incident_helper/src/parsers/KernelWakesParser.cpp b/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
index cc4a1e1ecfa2..ada4a5d0ffe2 100644
--- a/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
+++ b/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
@@ -23,8 +23,6 @@
using namespace android::os;
-const std::string LINE_DELIMITER = "\t";
-
status_t
KernelWakesParser::Parse(const int in, const int out) const
{
@@ -42,12 +40,12 @@ KernelWakesParser::Parse(const int in, const int out) const
if (line.empty()) continue;
// parse head line
if (nline++ == 0) {
- header = parseHeader(line, LINE_DELIMITER);
+ header = parseHeader(line, TAB_DELIMITER);
continue;
}
// parse for each record, the line delimiter is \t only!
- record = parseRecord(line, LINE_DELIMITER);
+ record = parseRecord(line, TAB_DELIMITER);
if (record.size() != header.size()) {
// TODO: log this to incident report!
@@ -57,7 +55,7 @@ KernelWakesParser::Parse(const int in, const int out) const
long long token = proto.start(KernelWakeSources::WAKEUP_SOURCES);
for (int i=0; i<(int)record.size(); i++) {
- if (!table.insertField(proto, header[i], record[i])) {
+ if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
this->name.string(), nline, header[i].c_str(), record[i].c_str());
}
diff --git a/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp b/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
index 6047bd189b95..f1b93ff9ec41 100644
--- a/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
+++ b/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
@@ -23,8 +23,6 @@
using namespace android::os;
-const std::string LINE_DELIMITER = ",";
-
status_t
PageTypeInfoParser::Parse(const int in, const int out) const
{
@@ -44,37 +42,37 @@ PageTypeInfoParser::Parse(const int in, const int out) const
continue;
}
- if (hasPrefix(&line, "Page block order:")) {
+ if (stripPrefix(&line, "Page block order:")) {
pageBlockOrder = toInt(line);
proto.write(PageTypeInfo::PAGE_BLOCK_ORDER, pageBlockOrder);
continue;
}
- if (hasPrefix(&line, "Pages per block:")) {
+ if (stripPrefix(&line, "Pages per block:")) {
proto.write(PageTypeInfo::PAGES_PER_BLOCK, toInt(line));
continue;
}
- if (hasPrefix(&line, "Free pages count per migrate type at order")) {
+ if (stripPrefix(&line, "Free pages count per migrate type at order")) {
migrateTypeSession = true;
continue;
}
- if (hasPrefix(&line, "Number of blocks type")) {
+ if (stripPrefix(&line, "Number of blocks type")) {
blockHeader = parseHeader(line);
continue;
}
- record_t record = parseRecord(line, LINE_DELIMITER);
+ record_t record = parseRecord(line, COMMA_DELIMITER);
if (migrateTypeSession && record.size() == 3) {
long long token = proto.start(PageTypeInfo::MIGRATE_TYPES);
// expect part 0 starts with "Node"
- if (hasPrefix(&record[0], "Node")) {
+ if (stripPrefix(&record[0], "Node")) {
proto.write(MigrateTypeProto::NODE, toInt(record[0]));
} else return BAD_VALUE;
// expect part 1 starts with "zone"
- if (hasPrefix(&record[1], "zone")) {
+ if (stripPrefix(&record[1], "zone")) {
proto.write(MigrateTypeProto::ZONE, record[1]);
} else return BAD_VALUE;
// expect part 2 starts with "type"
- if (hasPrefix(&record[2], "type")) {
+ if (stripPrefix(&record[2], "type")) {
// expect the rest of part 2 has number of (pageBlockOrder + 2) parts
// An example looks like:
// header line: type 0 1 2 3 4 5 6 7 8 9 10
@@ -94,16 +92,16 @@ PageTypeInfoParser::Parse(const int in, const int out) const
proto.end(token);
} else if (!blockHeader.empty() && record.size() == 2) {
long long token = proto.start(PageTypeInfo::BLOCKS);
- if (hasPrefix(&record[0], "Node")) {
+ if (stripPrefix(&record[0], "Node")) {
proto.write(BlockProto::NODE, toInt(record[0]));
} else return BAD_VALUE;
- if (hasPrefix(&record[1], "zone")) {
+ if (stripPrefix(&record[1], "zone")) {
record_t blockCounts = parseRecord(record[1]);
proto.write(BlockProto::ZONE, blockCounts[0]);
for (size_t i=0; i<blockHeader.size(); i++) {
- if (!table.insertField(proto, blockHeader[i], blockCounts[i+1])) {
+ if (!table.insertField(&proto, blockHeader[i], blockCounts[i+1])) {
return BAD_VALUE;
}
}
diff --git a/cmds/incident_helper/src/parsers/ProcrankParser.cpp b/cmds/incident_helper/src/parsers/ProcrankParser.cpp
index 93f970f820d9..a4eb0fdfd988 100644
--- a/cmds/incident_helper/src/parsers/ProcrankParser.cpp
+++ b/cmds/incident_helper/src/parsers/ProcrankParser.cpp
@@ -46,11 +46,11 @@ ProcrankParser::Parse(const int in, const int out) const
continue;
}
- if (hasPrefix(&line, "ZRAM:")) {
+ if (stripPrefix(&line, "ZRAM:")) {
zram = line;
continue;
}
- if (hasPrefix(&line, "RAM:")) {
+ if (stripPrefix(&line, "RAM:")) {
ram = line;
continue;
}
@@ -68,7 +68,7 @@ ProcrankParser::Parse(const int in, const int out) const
long long token = proto.start(Procrank::PROCESSES);
for (int i=0; i<(int)record.size(); i++) {
- if (!table.insertField(proto, header[i], record[i])) {
+ if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
this->name.string(), nline, header[i].c_str(), record[i].c_str());
}
@@ -82,7 +82,7 @@ ProcrankParser::Parse(const int in, const int out) const
record = parseRecord(total);
long long token = proto.start(SummaryProto::TOTAL);
for (int i=(int)record.size(); i>0; i--) {
- table.insertField(proto, header[header.size() - i].c_str(), record[record.size() - i].c_str());
+ table.insertField(&proto, header[header.size() - i].c_str(), record[record.size() - i].c_str());
}
proto.end(token);
}
diff --git a/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp b/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp
new file mode 100644
index 000000000000..ee5feb03242e
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "incident_helper"
+
+#include <android/util/ProtoOutputStream.h>
+
+#include "frameworks/base/core/proto/android/os/system_properties.proto.h"
+#include "ih_util.h"
+#include "SystemPropertiesParser.h"
+
+using namespace android::os;
+
+const string LINE_DELIMITER = "]: [";
+
+// system properties' names sometimes are not valid proto field names, make the names valid.
+static string convertToFieldName(const string& name) {
+ int len = (int)name.length();
+ char cstr[len + 1];
+ strcpy(cstr, name.c_str());
+ for (int i = 0; i < len; i++) {
+ if (!isValidChar(cstr[i])) {
+ cstr[i] = '_';
+ }
+ }
+ return string(cstr);
+}
+
+status_t
+SystemPropertiesParser::Parse(const int in, const int out) const
+{
+ Reader reader(in);
+ 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);
+
+ // parse line by line
+ while (reader.readLine(&line)) {
+ if (line.empty()) continue;
+
+ line = line.substr(1, line.size() - 2); // trim []
+ size_t index = line.find(LINE_DELIMITER); // split by "]: ["
+ if (index == string::npos) {
+ fprintf(stderr, "Bad Line %s\n", line.c_str());
+ continue;
+ }
+ name = line.substr(0, index);
+ value = trim(line.substr(index + 4), DEFAULT_WHITESPACE);
+ if (value.empty()) continue;
+
+ // 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 (!reader.ok(&line)) {
+ fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
+ return -1;
+ }
+
+ if (!proto.flush(out)) {
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ return -1;
+ }
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ return NO_ERROR;
+}
diff --git a/cmds/incident_helper/src/parsers/SystemPropertiesParser.h b/cmds/incident_helper/src/parsers/SystemPropertiesParser.h
new file mode 100644
index 000000000000..c4016006a48a
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/SystemPropertiesParser.h
@@ -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.
+ */
+
+#ifndef SYSTEM_PROPERTIES_PARSER_H
+#define SYSTEM_PROPERTIES_PARSER_H
+
+#include "TextParserBase.h"
+
+using namespace android;
+
+/**
+ * SystemProperties parser, parses text produced by command getprop.
+ */
+class SystemPropertiesParser : public TextParserBase {
+public:
+ SystemPropertiesParser() : TextParserBase(String8("SystemPropertiesParser")) {};
+ ~SystemPropertiesParser() {};
+
+ virtual status_t Parse(const int in, const int out) const;
+};
+
+#endif // SYSTEM_PROPERTIES_PARSER_H
diff --git a/cmds/incident_helper/testdata/cpuinfo.txt b/cmds/incident_helper/testdata/cpuinfo.txt
new file mode 100644
index 000000000000..ec4a83960698
--- /dev/null
+++ b/cmds/incident_helper/testdata/cpuinfo.txt
@@ -0,0 +1,15 @@
+Tasks: 2038 total, 1 running,2033 sleeping, 0 stopped, 0 zombie
+
+Mem: 3842668k total, 3761936k used, 80732k free, 220188k buffers
+
+Swap: 524284k total, 25892k used, 498392k free, 1316952k cached
+
+400%cpu 17%user 0%nice 43%sys 338%idle 0%iow 0%irq 1%sirq 0%host
+
+ PID TID USER PR NI[%CPU]S VIRT RES PCY CMD NAME
+
+
+29438 29438 rootabcdefghij 20 0 57.9 R 14M 3.8M top test top
+ 916 916 system 18 -2 1.4 S 4.6G 404M fg system_server system_server
+ 28 28 root -2 0 1.4 S 0 0 bg rcuc/3 [rcuc/3]
+ 27 27 root RT 0 1.4 S 0 0 ta migration/3 [migration/3] \ No newline at end of file
diff --git a/cmds/incident_helper/testdata/system_properties.txt b/cmds/incident_helper/testdata/system_properties.txt
new file mode 100644
index 000000000000..57c07ee9d75e
--- /dev/null
+++ b/cmds/incident_helper/testdata/system_properties.txt
@@ -0,0 +1,14 @@
+[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]
+[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
diff --git a/cmds/incident_helper/tests/CpuInfoParser_test.cpp b/cmds/incident_helper/tests/CpuInfoParser_test.cpp
new file mode 100644
index 000000000000..57ad15cf3910
--- /dev/null
+++ b/cmds/incident_helper/tests/CpuInfoParser_test.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "CpuInfoParser.h"
+
+#include "frameworks/base/core/proto/android/os/cpuinfo.pb.h"
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/message.h>
+#include <gtest/gtest.h>
+#include <string.h>
+#include <fcntl.h>
+
+using namespace android::base;
+using namespace android::os;
+using namespace std;
+using ::testing::StrEq;
+using ::testing::Test;
+using ::testing::internal::CaptureStderr;
+using ::testing::internal::CaptureStdout;
+using ::testing::internal::GetCapturedStderr;
+using ::testing::internal::GetCapturedStdout;
+
+class CpuInfoParserTest : public Test {
+public:
+ virtual void SetUp() override {
+ 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;
+
+ const string kTestPath = GetExecutableDirectory();
+ const string kTestDataPath = kTestPath + "/testdata/";
+};
+
+TEST_F(CpuInfoParserTest, HasSwapInfo) {
+ const string testFile = kTestDataPath + "cpuinfo.txt";
+ CpuInfoParser parser;
+ CpuInfo expected;
+
+ CpuInfo::TaskStats* taskStats = expected.mutable_task_stats();
+ taskStats->set_total(2038);
+ taskStats->set_running(1);
+ taskStats->set_sleeping(2033);
+ taskStats->set_stopped(0);
+ taskStats->set_zombie(0);
+
+ CpuInfo::MemStats* mem = expected.mutable_mem();
+ mem->set_total(3842668);
+ mem->set_used(3761936);
+ mem->set_free(80732);
+ mem->set_buffers(220188);
+
+ CpuInfo::MemStats* swap = expected.mutable_swap();
+ swap->set_total(524284);
+ swap->set_used(25892);
+ swap->set_free(498392);
+ swap->set_cached(1316952);
+
+ CpuInfo::CpuUsage* usage = expected.mutable_cpu_usage();
+ usage->set_cpu(400);
+ usage->set_user(17);
+ usage->set_nice(0);
+ usage->set_sys(43);
+ usage->set_idle(338);
+ usage->set_iow(0);
+ usage->set_irq(0);
+ usage->set_sirq(1);
+ usage->set_host(0);
+
+ // This is a special line which is able to be parsed by the CpuInfoParser
+ CpuInfo::Task* task1 = expected.add_tasks();
+ task1->set_pid(29438);
+ task1->set_tid(29438);
+ task1->set_user("rootabcdefghij");
+ task1->set_pr("20");
+ task1->set_ni(0);
+ task1->set_cpu(57.9);
+ task1->set_s(CpuInfo::Task::STATUS_R);
+ task1->set_virt("14M");
+ task1->set_res("3.8M");
+ task1->set_pcy(CpuInfo::Task::POLICY_UNKNOWN);
+ task1->set_cmd("top test");
+ task1->set_name("top");
+
+ CpuInfo::Task* task2 = expected.add_tasks();
+ task2->set_pid(916);
+ task2->set_tid(916);
+ task2->set_user("system");
+ task2->set_pr("18");
+ task2->set_ni(-2);
+ task2->set_cpu(1.4);
+ task2->set_s(CpuInfo::Task::STATUS_S);
+ task2->set_virt("4.6G");
+ task2->set_res("404M");
+ task2->set_pcy(CpuInfo::Task::POLICY_fg);
+ task2->set_cmd("system_server");
+ task2->set_name("system_server");
+
+ CpuInfo::Task* task3 = expected.add_tasks();
+ task3->set_pid(28);
+ task3->set_tid(28);
+ task3->set_user("root");
+ task3->set_pr("-2");
+ task3->set_ni(0);
+ task3->set_cpu(1.4);
+ task3->set_s(CpuInfo::Task::STATUS_S);
+ task3->set_virt("0");
+ task3->set_res("0");
+ task3->set_pcy(CpuInfo::Task::POLICY_bg);
+ task3->set_cmd("rcuc/3");
+ task3->set_name("[rcuc/3]");
+
+ CpuInfo::Task* task4 = expected.add_tasks();
+ task4->set_pid(27);
+ task4->set_tid(27);
+ task4->set_user("root");
+ task4->set_pr("RT");
+ task4->set_ni(0);
+ task4->set_cpu(1.4);
+ task4->set_s(CpuInfo::Task::STATUS_S);
+ task4->set_virt("0");
+ task4->set_res("0");
+ task4->set_pcy(CpuInfo::Task::POLICY_ta);
+ task4->set_cmd("migration/3");
+ task4->set_name("[migration/3]");
+
+ 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));
+ close(fd);
+}
diff --git a/cmds/incident_helper/tests/SystemPropertiesParser_test.cpp b/cmds/incident_helper/tests/SystemPropertiesParser_test.cpp
new file mode 100644
index 000000000000..23e292a512b9
--- /dev/null
+++ b/cmds/incident_helper/tests/SystemPropertiesParser_test.cpp
@@ -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.
+ */
+
+#include "SystemPropertiesParser.h"
+
+#include "frameworks/base/core/proto/android/os/system_properties.pb.h"
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/message.h>
+#include <gtest/gtest.h>
+#include <string.h>
+#include <fcntl.h>
+
+using namespace android::base;
+using namespace android::os;
+using namespace std;
+using ::testing::StrEq;
+using ::testing::Test;
+using ::testing::internal::CaptureStderr;
+using ::testing::internal::CaptureStdout;
+using ::testing::internal::GetCapturedStderr;
+using ::testing::internal::GetCapturedStdout;
+
+class SystemPropertiesParserTest : public Test {
+public:
+ virtual void SetUp() override {
+ 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;
+
+ const string kTestPath = GetExecutableDirectory();
+ const string kTestDataPath = kTestPath + "/testdata/";
+};
+
+TEST_F(SystemPropertiesParserTest, HasSwapInfo) {
+ const string testFile = kTestDataPath + "system_properties.txt";
+ 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");
+
+ 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));
+ close(fd);
+}
diff --git a/cmds/incident_helper/tests/ih_util_test.cpp b/cmds/incident_helper/tests/ih_util_test.cpp
index da88ee3a0120..5740b330d949 100644
--- a/cmds/incident_helper/tests/ih_util_test.cpp
+++ b/cmds/incident_helper/tests/ih_util_test.cpp
@@ -62,36 +62,72 @@ TEST(IhUtilTest, ParseRecord) {
EXPECT_EQ(expected, result);
}
-TEST(IhUtilTest, Reader) {
- TemporaryFile tf;
- ASSERT_NE(tf.fd, -1);
- ASSERT_TRUE(WriteStringToFile("test string\nsecond\nooo\n", tf.path, false));
+TEST(IhUtilTest, ParseRecordByColumns) {
+ record_t result, expected;
+ std::vector<int> indices = { 3, 10 };
- Reader r(tf.fd);
- string line;
- ASSERT_TRUE(r.readLine(&line));
- EXPECT_THAT(line, StrEq("test string"));
- ASSERT_TRUE(r.readLine(&line));
- EXPECT_THAT(line, StrEq("second"));
- ASSERT_TRUE(r.readLine(&line));
- EXPECT_THAT(line, StrEq("ooo"));
- ASSERT_FALSE(r.readLine(&line));
- ASSERT_TRUE(r.ok(&line));
+ result = parseRecordByColumns("12345", indices);
+ expected = {};
+ EXPECT_EQ(expected, result);
+
+ result = parseRecordByColumns("abc \t2345 6789 ", indices);
+ expected = { "abc", "2345", "6789" };
+ EXPECT_EQ(expected, result);
+
+ result = parseRecordByColumns("abc \t23456789 bob", indices);
+ expected = { "abc", "23456789", "bob" };
+ EXPECT_EQ(expected, result);
+}
+
+TEST(IhUtilTest, stripPrefix) {
+ string data1 = "Swap: abc ";
+ EXPECT_TRUE(stripPrefix(&data1, "Swap:"));
+ EXPECT_THAT(data1, StrEq("abc"));
+
+ string data2 = "Swap: abc ";
+ EXPECT_FALSE(stripPrefix(&data2, "Total:"));
+ EXPECT_THAT(data2, StrEq("Swap: abc "));
+
+ string data3 = "Swap: abc ";
+ EXPECT_TRUE(stripPrefix(&data3, "Swa"));
+ EXPECT_THAT(data3, StrEq("p: abc"));
+
+ string data4 = "Swap: abc ";
+ EXPECT_FALSE(stripPrefix(&data4, "Swa", true));
+ EXPECT_THAT(data4, StrEq("Swap: abc "));
+}
+
+TEST(IhUtilTest, stripSuffix) {
+ string data1 = " 243%abc";
+ EXPECT_TRUE(stripSuffix(&data1, "abc"));
+ EXPECT_THAT(data1, StrEq("243%"));
+
+ string data2 = " 243%abc";
+ EXPECT_FALSE(stripSuffix(&data2, "Not right"));
+ EXPECT_THAT(data2, StrEq(" 243%abc"));
+
+ string data3 = " 243%abc";
+ EXPECT_TRUE(stripSuffix(&data3, "bc"));
+ EXPECT_THAT(data3, StrEq("243%a"));
+
+ string data4 = " 243%abc";
+ EXPECT_FALSE(stripSuffix(&data4, "bc", true));
+ EXPECT_THAT(data4, StrEq(" 243%abc"));
}
-TEST(IhUtilTest, ReaderSmallBufSize) {
+TEST(IhUtilTest, Reader) {
TemporaryFile tf;
ASSERT_NE(tf.fd, -1);
- ASSERT_TRUE(WriteStringToFile("test string\nsecond\nooiecccojreo", tf.path, false));
+ ASSERT_TRUE(WriteStringToFile("test string\nsecond\nooo\n", tf.path));
- Reader r(tf.fd, 5);
+ Reader r(tf.fd);
string line;
ASSERT_TRUE(r.readLine(&line));
EXPECT_THAT(line, StrEq("test string"));
ASSERT_TRUE(r.readLine(&line));
EXPECT_THAT(line, StrEq("second"));
ASSERT_TRUE(r.readLine(&line));
- EXPECT_THAT(line, StrEq("ooiecccojreo"));
+ EXPECT_THAT(line, StrEq("ooo"));
ASSERT_FALSE(r.readLine(&line));
ASSERT_TRUE(r.ok(&line));
}
@@ -99,20 +135,19 @@ TEST(IhUtilTest, ReaderSmallBufSize) {
TEST(IhUtilTest, ReaderEmpty) {
TemporaryFile tf;
ASSERT_NE(tf.fd, -1);
- ASSERT_TRUE(WriteStringToFile("", tf.path, false));
+ ASSERT_TRUE(WriteStringToFile("", tf.path));
Reader r(tf.fd);
string line;
- ASSERT_TRUE(r.readLine(&line));
- EXPECT_THAT(line, StrEq(""));
ASSERT_FALSE(r.readLine(&line));
+ EXPECT_THAT(line, StrEq(""));
ASSERT_TRUE(r.ok(&line));
}
TEST(IhUtilTest, ReaderMultipleEmptyLines) {
TemporaryFile tf;
ASSERT_NE(tf.fd, -1);
- ASSERT_TRUE(WriteStringToFile("\n\n", tf.path, false));
+ ASSERT_TRUE(WriteStringToFile("\n\n", tf.path));
Reader r(tf.fd);
string line;
@@ -130,15 +165,7 @@ TEST(IhUtilTest, ReaderFailedNegativeFd) {
string line;
EXPECT_FALSE(r.readLine(&line));
EXPECT_FALSE(r.ok(&line));
- EXPECT_THAT(line, StrEq("Negative fd"));
-}
-
-TEST(IhUtilTest, ReaderFailedZeroBufferSize) {
- Reader r(23, 0);
- string line;
- EXPECT_FALSE(r.readLine(&line));
- EXPECT_FALSE(r.ok(&line));
- EXPECT_THAT(line, StrEq("Zero buffer capacity"));
+ EXPECT_THAT(line, StrEq("Invalid fd -123"));
}
TEST(IhUtilTest, ReaderFailedBadFd) {
@@ -146,5 +173,5 @@ TEST(IhUtilTest, ReaderFailedBadFd) {
string line;
EXPECT_FALSE(r.readLine(&line));
EXPECT_FALSE(r.ok(&line));
- EXPECT_THAT(line, StrEq("Fail to read from fd"));
+ EXPECT_THAT(line, StrEq("Invalid fd 1231432"));
}
diff --git a/cmds/incidentd/tests/FdBuffer_test.cpp b/cmds/incidentd/tests/FdBuffer_test.cpp
index 2afa778b734c..3fd2ed82a26e 100644
--- a/cmds/incidentd/tests/FdBuffer_test.cpp
+++ b/cmds/incidentd/tests/FdBuffer_test.cpp
@@ -84,7 +84,7 @@ protected:
TEST_F(FdBufferTest, ReadAndWrite) {
std::string testdata = "FdBuffer test string";
- ASSERT_TRUE(WriteStringToFile(testdata, tf.path, false));
+ ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
AssertBufferReadSuccessful(testdata.size());
AssertBufferContent(testdata.c_str());
@@ -97,7 +97,7 @@ TEST_F(FdBufferTest, IterateEmpty) {
TEST_F(FdBufferTest, ReadAndIterate) {
std::string testdata = "FdBuffer test string";
- ASSERT_TRUE(WriteStringToFile(testdata, tf.path, false));
+ ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
int i=0;
@@ -137,7 +137,7 @@ TEST_F(FdBufferTest, ReadTimeout) {
TEST_F(FdBufferTest, ReadInStreamAndWrite) {
std::string testdata = "simply test read in stream";
std::string expected = HEAD + testdata;
- ASSERT_TRUE(WriteStringToFile(testdata, tf.path, false));
+ ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
int pid = fork();
ASSERT_TRUE(pid != -1);
@@ -166,7 +166,7 @@ TEST_F(FdBufferTest, ReadInStreamAndWrite) {
TEST_F(FdBufferTest, ReadInStreamAndWriteAllAtOnce) {
std::string testdata = "child process flushes only after all data are read.";
std::string expected = HEAD + testdata;
- ASSERT_TRUE(WriteStringToFile(testdata, tf.path, false));
+ ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
int pid = fork();
ASSERT_TRUE(pid != -1);
@@ -196,7 +196,7 @@ TEST_F(FdBufferTest, ReadInStreamAndWriteAllAtOnce) {
}
TEST_F(FdBufferTest, ReadInStreamEmpty) {
- ASSERT_TRUE(WriteStringToFile("", tf.path, false));
+ ASSERT_TRUE(WriteStringToFile("", tf.path));
int pid = fork();
ASSERT_TRUE(pid != -1);
@@ -260,7 +260,7 @@ TEST_F(FdBufferTest, ReadInStreamMoreThan4MB) {
TEST_F(FdBufferTest, ReadInStreamTimeOut) {
std::string testdata = "timeout test";
- ASSERT_TRUE(WriteStringToFile(testdata, tf.path, false));
+ ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
int pid = fork();
ASSERT_TRUE(pid != -1);
diff --git a/cmds/incidentd/tests/PrivacyBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
index 84a2a825b4c3..ca9462394493 100644
--- a/cmds/incidentd/tests/PrivacyBuffer_test.cpp
+++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
@@ -60,7 +60,7 @@ public:
}
void writeToFdBuffer(string str) {
- ASSERT_TRUE(WriteStringToFile(str, tf.path, false));
+ ASSERT_TRUE(WriteStringToFile(str, tf.path));
ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, 10000));
ASSERT_EQ(str.size(), buffer.size());
}
diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp
index 25b05b2b1518..649e908a83c4 100644
--- a/cmds/incidentd/tests/Section_test.cpp
+++ b/cmds/incidentd/tests/Section_test.cpp
@@ -99,7 +99,7 @@ TEST(SectionTest, FileSection) {
ReportRequestSet requests;
ASSERT_TRUE(tf.fd != -1);
- ASSERT_TRUE(WriteStringToFile("iamtestdata", tf.path, false));
+ ASSERT_TRUE(WriteStringToFile("iamtestdata", tf.path));
requests.setMainFd(STDOUT_FILENO);
@@ -173,7 +173,7 @@ TEST(SectionTest, TestFilterPiiTaggedFields) {
ReportRequestSet requests;
ASSERT_TRUE(tf.fd != -1);
- ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path, false));
+ ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path));
requests.setMainFd(STDOUT_FILENO);
@@ -186,7 +186,7 @@ TEST(SectionTest, TestBadFdRequest) {
TemporaryFile input;
FileSection fs(NOOP_PARSER, input.path);
ReportRequestSet requests;
- ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path, false));
+ ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path));
IncidentReportArgs args;
args.setAll(true);
@@ -205,7 +205,7 @@ TEST(SectionTest, TestBadRequests) {
TemporaryFile input;
FileSection fs(NOOP_PARSER, input.path);
ReportRequestSet requests;
- ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path, false));
+ ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path));
IncidentReportArgs args;
args.setAll(true);
@@ -223,7 +223,7 @@ TEST(SectionTest, TestMultipleRequests) {
ASSERT_TRUE(output1.fd != -1);
ASSERT_TRUE(output2.fd != -1);
ASSERT_TRUE(output3.fd != -1);
- ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path, false));
+ ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path));
IncidentReportArgs args1, args2, args3;
args1.setAll(true);
@@ -265,7 +265,7 @@ TEST(SectionTest, TestMultipleRequestsBySpec) {
ASSERT_TRUE(output2.fd != -1);
ASSERT_TRUE(output3.fd != -1);
- ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path, false));
+ ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path));
IncidentReportArgs args1, args2, args3, args4;
args1.setAll(true);
diff --git a/cmds/input/input b/cmds/input/input
index 7f1a18e369c6..54ab94762e5c 100755
--- a/cmds/input/input
+++ b/cmds/input/input
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "input" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/locksettings/locksettings b/cmds/locksettings/locksettings
index c963b238726b..0ef4fa9f6771 100755
--- a/cmds/locksettings/locksettings
+++ b/cmds/locksettings/locksettings
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "locksettings" on the device
#
base=/system
diff --git a/cmds/media/media b/cmds/media/media
index 11944426b316..5c0eb2f39c2d 100755
--- a/cmds/media/media
+++ b/cmds/media/media
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "media_cmd" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/pm/pm b/cmds/pm/pm
index 81838386c055..53f85b2f9c51 100755
--- a/cmds/pm/pm
+++ b/cmds/pm/pm
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "pm" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/requestsync/requestsync b/cmds/requestsync/requestsync
index 931567583e90..2d5d0e41705a 100755
--- a/cmds/requestsync/requestsync
+++ b/cmds/requestsync/requestsync
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "requestsync" on the device
#
base=/system
diff --git a/cmds/sm/sm b/cmds/sm/sm
index 8fba0070630f..4bc859e0c374 100755
--- a/cmds/sm/sm
+++ b/cmds/sm/sm
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "sm" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index a9a4118a8e98..77e8efafa2a0 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -20,6 +20,9 @@ import static android.os.storage.StorageManager.PROP_ADOPTABLE_FBE;
import static android.os.storage.StorageManager.PROP_HAS_ADOPTABLE;
import static android.os.storage.StorageManager.PROP_VIRTUAL_DISK;
+import android.os.IBinder;
+import android.os.IVoldTaskListener;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
@@ -29,6 +32,8 @@ import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.util.Log;
+import java.util.concurrent.CompletableFuture;
+
public final class Sm {
private static final String TAG = "Sm";
@@ -96,6 +101,8 @@ public final class Sm {
runSetEmulateFbe();
} else if ("get-fbe-mode".equals(op)) {
runGetFbeMode();
+ } else if ("idle-maint".equals(op)) {
+ runIdleMaint();
} else if ("fstrim".equals(op)) {
runFstrim();
} else if ("set-virtual-disk".equals(op)) {
@@ -221,9 +228,23 @@ public final class Sm {
mSm.format(volId);
}
- public void runBenchmark() throws RemoteException {
+ public void runBenchmark() throws Exception {
final String volId = nextArg();
- mSm.benchmark(volId);
+ final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
+ mSm.benchmark(volId, new IVoldTaskListener.Stub() {
+ @Override
+ public void onStatus(int status, PersistableBundle extras) {
+ // Ignored
+ }
+
+ @Override
+ public void onFinished(int status, PersistableBundle extras) {
+ // Touch to unparcel
+ extras.size();
+ result.complete(extras);
+ }
+ });
+ System.out.println(result.get());
}
public void runForget() throws RemoteException {
@@ -235,8 +256,22 @@ public final class Sm {
}
}
- public void runFstrim() throws RemoteException {
- mSm.fstrim(0);
+ public void runFstrim() throws Exception {
+ final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
+ mSm.fstrim(0, new IVoldTaskListener.Stub() {
+ @Override
+ public void onStatus(int status, PersistableBundle extras) {
+ // Ignored
+ }
+
+ @Override
+ public void onFinished(int status, PersistableBundle extras) {
+ // Touch to unparcel
+ extras.size();
+ result.complete(extras);
+ }
+ });
+ System.out.println(result.get());
}
public void runSetVirtualDisk() throws RemoteException {
@@ -245,6 +280,15 @@ public final class Sm {
StorageManager.DEBUG_VIRTUAL_DISK);
}
+ public void runIdleMaint() throws RemoteException {
+ final boolean im_run = "run".equals(nextArg());
+ if (im_run) {
+ mSm.runIdleMaintenance();
+ } else {
+ mSm.abortIdleMaintenance();
+ }
+ }
+
private String nextArg() {
if (mNextArg >= mArgs.length) {
return null;
@@ -267,6 +311,7 @@ public final class Sm {
System.err.println(" sm unmount VOLUME");
System.err.println(" sm format VOLUME");
System.err.println(" sm benchmark VOLUME");
+ System.err.println(" sm idle-maint [run|abort]");
System.err.println(" sm fstrim");
System.err.println("");
System.err.println(" sm forget [UUID|all]");
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 4ebca8430cf4..5fcb8a1a0892 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -20,7 +20,7 @@
cc_library_host_shared {
name: "libstats_proto_host",
srcs: [
- "src/stats_events.proto",
+ "src/atoms.proto",
],
shared_libs: [
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 54ade3563851..d8603636c7c0 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -20,7 +20,7 @@ statsd_common_src := \
../../core/java/android/os/IStatsManager.aidl \
src/stats_log.proto \
src/statsd_config.proto \
- src/stats_events_copy.proto \
+ src/atoms_copy.proto \
src/anomaly/AnomalyMonitor.cpp \
src/condition/CombinationConditionTracker.cpp \
src/condition/condition_util.cpp \
@@ -29,15 +29,18 @@ statsd_common_src := \
src/config/ConfigKey.cpp \
src/config/ConfigListener.cpp \
src/config/ConfigManager.cpp \
- src/external/KernelWakelockPuller.cpp \
- src/external/StatsPullerManager.cpp \
+ src/external/StatsCompanionServicePuller.cpp \
+ src/external/ResourcePowerManagerPuller.cpp \
+ src/external/CpuTimePerUidPuller.cpp \
+ src/external/CpuTimePerUidFreqPuller.cpp \
+ src/external/StatsPullerManagerImpl.cpp \
src/logd/LogEvent.cpp \
src/logd/LogListener.cpp \
src/logd/LogReader.cpp \
src/matchers/CombinationLogMatchingTracker.cpp \
src/matchers/matcher_util.cpp \
src/matchers/SimpleLogMatchingTracker.cpp \
- src/metrics/CountAnomalyTracker.cpp \
+ src/anomaly/DiscreteAnomalyTracker.cpp \
src/metrics/MetricProducer.cpp \
src/metrics/EventMetricProducer.cpp \
src/metrics/CountMetricProducer.cpp \
@@ -45,6 +48,7 @@ statsd_common_src := \
src/metrics/duration_helper/OringDurationTracker.cpp \
src/metrics/duration_helper/MaxDurationTracker.cpp \
src/metrics/ValueMetricProducer.cpp \
+ src/metrics/GaugeMetricProducer.cpp \
src/metrics/MetricsManager.cpp \
src/metrics/metrics_manager_util.cpp \
src/packages/UidMap.cpp \
@@ -71,7 +75,15 @@ statsd_common_shared_libraries := \
libutils \
libservices \
libandroidfw \
- libprotoutil
+ libprotoutil \
+ libstatslog \
+ libhardware \
+ libhardware_legacy \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ android.hardware.power@1.0 \
+ android.hardware.power@1.1
# =========
# statsd
@@ -140,16 +152,20 @@ LOCAL_CFLAGS += \
LOCAL_SRC_FILES := \
$(statsd_common_src) \
tests/AnomalyMonitor_test.cpp \
- tests/ConditionTracker_test.cpp \
+ tests/anomaly/AnomalyTracker_test.cpp \
tests/ConfigManager_test.cpp \
tests/indexed_priority_queue_test.cpp \
tests/LogEntryMatcher_test.cpp \
tests/LogReader_test.cpp \
tests/MetricsManager_test.cpp \
tests/UidMap_test.cpp \
- tests/OringDurationTracker_test.cpp \
- tests/MaxDurationTracker_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/EventMetricProducer_test.cpp \
+ tests/metrics/ValueMetricProducer_test.cpp
LOCAL_STATIC_LIBRARIES := \
libgmock
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index c0cedb1b467e..b764ce56767b 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -15,9 +15,9 @@
*/
#include "Log.h"
+#include "statslog.h"
#include "StatsLogProcessor.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "metrics/CountMetricProducer.h"
#include "stats_util.h"
@@ -25,6 +25,14 @@
#include <utils/Errors.h>
using namespace android;
+using android::util::FIELD_COUNT_REPEATED;
+using android::util::FIELD_TYPE_BOOL;
+using android::util::FIELD_TYPE_FLOAT;
+using android::util::FIELD_TYPE_INT32;
+using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_MESSAGE;
+using android::util::FIELD_TYPE_STRING;
+using android::util::ProtoOutputStream;
using std::make_unique;
using std::unique_ptr;
using std::vector;
@@ -33,6 +41,14 @@ namespace android {
namespace os {
namespace statsd {
+// for ConfigMetricsReport
+const int FIELD_ID_CONFIG_KEY = 1;
+const int FIELD_ID_METRICS = 2;
+const int FIELD_ID_UID_MAP = 3;
+// for ConfigKey
+const int FIELD_ID_UID = 1;
+const int FIELD_ID_NAME = 2;
+
StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap,
const std::function<void(const vector<uint8_t>&)>& pushLog)
: mUidMap(uidMap), mPushLog(pushLog) {
@@ -48,6 +64,22 @@ void StatsLogProcessor::OnLogEvent(const LogEvent& msg) {
pair.second->onLogEvent(msg);
flushIfNecessary(msg.GetTimestampNs(), pair.first, pair.second);
}
+
+ // Hard-coded logic to update the isolated uid's in the uid-map.
+ // The field numbers need to be currently updated by hand with atoms.proto
+ if (msg.GetTagId() == android::util::ISOLATED_UID_CHANGED) {
+ status_t err = NO_ERROR, err2 = NO_ERROR, err3 = NO_ERROR;
+ bool is_create = msg.GetBool(3, &err);
+ auto parent_uid = int(msg.GetLong(1, &err2));
+ auto isolated_uid = int(msg.GetLong(2, &err3));
+ if (err == NO_ERROR && err2 == NO_ERROR && err3 == NO_ERROR) {
+ if (is_create) {
+ mUidMap->assignIsolatedUid(isolated_uid, parent_uid);
+ } else {
+ mUidMap->removeIsolatedUid(isolated_uid, parent_uid);
+ }
+ }
+ }
}
void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) {
@@ -70,27 +102,46 @@ void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig
}
}
-ConfigMetricsReport StatsLogProcessor::onDumpReport(const ConfigKey& key) {
- ConfigMetricsReport report;
-
+vector<uint8_t> StatsLogProcessor::onDumpReport(const ConfigKey& key) {
auto it = mMetricsManagers.find(key);
if (it == mMetricsManagers.end()) {
ALOGW("Config source %s does not exist", key.ToString().c_str());
- return report;
+ return vector<uint8_t>();
}
- auto set_key = report.mutable_config_key();
- set_key->set_uid(key.GetUid());
- set_key->set_name(key.GetName());
- for (auto m : it->second->onDumpReport()) {
- // Transfer the vector of StatsLogReport into a field
- // TODO: perhaps we just have bytes being returned from onDumpReport and transfer bytes
- auto dest = report.add_metrics();
- *dest = m;
+ ProtoOutputStream proto;
+
+ // Fill in ConfigKey.
+ long long configKeyToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
+ proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid());
+ proto.write(FIELD_TYPE_STRING | FIELD_ID_NAME, key.GetName());
+ proto.end(configKeyToken);
+
+ // Fill 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());
}
- auto temp = mUidMap->getOutput(key);
- report.set_allocated_uid_map(&temp);
- return report;
+
+ // Fill in UidMap.
+ auto uidMap = mUidMap->getOutput(key);
+ const int uidMapSize = uidMap.ByteSize();
+ char uidMapBuffer[uidMapSize];
+ uidMap.SerializeToArray(&uidMapBuffer[0], uidMapSize);
+ proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP, uidMapBuffer, uidMapSize);
+
+ vector<uint8_t> buffer(proto.size());
+ size_t pos = 0;
+ auto iter = proto.data();
+ while (iter.readBuffer() != NULL) {
+ size_t toRead = iter.currentToRead();
+ std::memcpy(&buffer[pos], iter.readBuffer(), toRead);
+ pos += toRead;
+ iter.rp()->move(toRead);
+ }
+
+ return buffer;
}
void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 0083827a347d..f38d71550eda 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -41,8 +41,7 @@ public:
void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config);
void OnConfigRemoved(const ConfigKey& key);
- // TODO: Once we have the ProtoOutputStream in c++, we can just return byte array.
- ConfigMetricsReport onDumpReport(const ConfigKey& key);
+ vector<uint8_t> onDumpReport(const ConfigKey& key);
/* Request a flush through a binder call. */
void flush();
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index edb1a0f94e2b..a0b234087fd0 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1,5 +1,5 @@
/*
- * 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.
@@ -18,6 +18,8 @@
#include "Log.h"
#include "StatsService.h"
+#include "config/ConfigKey.h"
+#include "config/ConfigManager.h"
#include "storage/DropboxReader.h"
#include <android-base/file.h>
@@ -39,6 +41,8 @@ namespace android {
namespace os {
namespace statsd {
+constexpr const char* kPermissionDump = "android.permission.DUMP";
+
// ======================================================================
/**
* Watches for the death of the stats companion (system process).
@@ -67,8 +71,8 @@ StatsService::StatsService(const sp<Looper>& handlerLooper)
{
mUidMap = new UidMap();
mConfigManager = new ConfigManager();
- mProcessor = new StatsLogProcessor(mUidMap, [this](const vector<uint8_t>& log) {
- pushLog(log);
+ mProcessor = new StatsLogProcessor(mUidMap, [](const vector<uint8_t>& log) {
+ // TODO: Update how we send data out of StatsD.
});
mConfigManager->AddListener(mProcessor);
@@ -198,6 +202,10 @@ status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>&
if (!args[0].compare(String8("pull-source")) && args.size() > 1) {
return cmd_print_pulled_metrics(out, args);
}
+
+ if (!args[0].compare(String8("send-broadcast"))) {
+ return cmd_trigger_broadcast(args);
+ }
}
print_cmd_help(out);
@@ -238,6 +246,19 @@ void StatsService::print_cmd_help(FILE* out) {
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, "\n");
+ fprintf(out, "\n");
+ fprintf(out, "usage: adb shell cmd stats send-broadcast PACKAGE CLASS\n");
+ fprintf(out, " Send a broadcast that triggers one subscriber to fetch metrics.\n");
+ fprintf(out, " PACKAGE The name of the package to receive the broadcast.\n");
+ fprintf(out, " CLASS The name of the class to receive the broadcast.\n");
+}
+
+status_t StatsService::cmd_trigger_broadcast(Vector<String8>& args) {
+ auto sc = getStatsCompanionService();
+ sc->sendBroadcast(String16(args[1]), String16(args[2]));
+ ALOGD("StatsService::trigger broadcast succeeded");
+ return NO_ERROR;
}
status_t StatsService::cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
@@ -373,12 +394,15 @@ status_t StatsService::cmd_print_uid_map(FILE* out) {
status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args) {
int s = atoi(args[1].c_str());
- auto stats = m_stats_puller_manager.Pull(s, time(nullptr));
- for (const auto& it : stats) {
- fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
+ vector<shared_ptr<LogEvent> > stats;
+ if (mStatsPullerManager.Pull(s, &stats)) {
+ for (const auto& it : stats) {
+ fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
+ }
+ fprintf(out, "Pull from %d: Received %zu elements\n", s, stats.size());
+ return NO_ERROR;
}
- fprintf(out, "Pull from %d: Received %zu elements\n", s, stats.size());
- return NO_ERROR;
+ return UNKNOWN_ERROR;
}
Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
@@ -440,7 +464,7 @@ Status StatsService::informPollAlarmFired() {
"Only system uid can call informPollAlarmFired");
}
- m_stats_puller_manager.OnAlarmFired();
+ mStatsPullerManager.OnAlarmFired();
if (DEBUG) ALOGD("StatsService::informPollAlarmFired succeeded");
@@ -517,29 +541,51 @@ void StatsService::OnLogEvent(const LogEvent& event) {
mProcessor->OnLogEvent(event);
}
-Status StatsService::requestPush() {
- mProcessor->flush();
- return Status::ok();
+Status StatsService::getData(const String16& key, vector<uint8_t>* output) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ if (checkCallingPermission(String16(kPermissionDump),
+ reinterpret_cast<int32_t*>(ipc->getCallingPid()),
+ reinterpret_cast<int32_t*>(ipc->getCallingUid()))) {
+ // TODO: Implement this.
+ return Status::ok();
+ } else {
+ return Status::fromExceptionCode(binder::Status::EX_SECURITY);
+ }
}
-Status StatsService::pushLog(const vector<uint8_t>& log) {
- std::lock_guard<std::mutex> lock(mLock);
- for (size_t i = 0; i < mCallbacks.size(); i++) {
- mCallbacks[i]->onReceiveLogs((vector<uint8_t>*)&log);
+Status StatsService::addConfiguration(const String16& key,
+ const vector <uint8_t>& config,
+ const String16& package, const String16& cls,
+ bool* success) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ int32_t* uid = reinterpret_cast<int32_t*>(ipc->getCallingUid());
+ if (checkCallingPermission(String16(kPermissionDump),
+ reinterpret_cast<int32_t*>(ipc->getCallingPid()), uid)) {
+ string keyString = string(String8(key).string());
+ ConfigKey configKey(*uid, keyString);
+ StatsdConfig cfg;
+ cfg.ParseFromArray(&config[0], config.size());
+ mConfigManager->UpdateConfig(configKey, cfg);
+ mConfigManager->SetConfigReceiver(configKey, string(String8(package).string()),
+ string(String8(cls).string()));
+ *success = true;
+ return Status::ok();
+ } else {
+ return Status::fromExceptionCode(binder::Status::EX_SECURITY);
}
- return Status::ok();
}
-Status StatsService::subscribeStatsLog(const sp<IStatsCallbacks>& callback) {
- std::lock_guard<std::mutex> lock(mLock);
- for (size_t i = 0; i < mCallbacks.size(); i++) {
- if (mCallbacks[i] == callback) {
- return Status::fromStatusT(-errno);
- }
+Status StatsService::removeConfiguration(const String16& key, bool* success) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ if (checkCallingPermission(String16(kPermissionDump),
+ reinterpret_cast<int32_t*>(ipc->getCallingPid()),
+ reinterpret_cast<int32_t*>(ipc->getCallingUid()))) {
+ // TODO: Implement this.
+ return Status::ok();
+ } else {
+ *success = false;
+ return Status::fromExceptionCode(binder::Status::EX_SECURITY);
}
- mCallbacks.add(callback);
- IInterface::asBinder(callback)->linkToDeath(this);
- return Status::ok();
}
void StatsService::binderDied(const wp<IBinder>& who) {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 3930d319ce8d..c3729deabb4b 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -1,5 +1,5 @@
/*
- * 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.
@@ -71,20 +71,22 @@ public:
virtual void OnLogEvent(const LogEvent& event);
/**
- * Binder call to force trigger pushLog. This would be called by callback
- * clients.
+ * Binder call for clients to request data for this configuration key.
*/
- virtual Status requestPush() override;
+ virtual Status getData(const String16& key, vector<uint8_t>* output) override;
/**
- * Pushes stats log entries from statsd to callback clients.
+ * Binder call to let clients send a configuration and indicate they're interested when they
+ * should requestData for this configuration.
*/
- Status pushLog(const vector<uint8_t>& log);
+ virtual Status addConfiguration(const String16& key, const vector <uint8_t>& config,
+ const String16& package, const String16& cls, bool* success)
+ override;
/**
- * Binder call to listen to statsd to send stats log entries.
+ * Binder call to allow clients to remove the specified configuration.
*/
- virtual Status subscribeStatsLog(const sp<IStatsCallbacks>& callbacks) override;
+ virtual Status removeConfiguration(const String16& key, bool* success) override;
// TODO: public for testing since statsd doesn't run when system starts. Change to private
// later.
@@ -120,6 +122,11 @@ private:
void print_cmd_help(FILE* out);
/**
+ * Trigger a broadcast.
+ */
+ status_t cmd_trigger_broadcast(Vector<String8>& args);
+
+ /**
* Handle the config sub-command.
*/
status_t cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
@@ -157,7 +164,7 @@ private:
/**
* Fetches external metrics.
*/
- StatsPullerManager& m_stats_puller_manager = StatsPullerManager::GetInstance();
+ StatsPullerManager mStatsPullerManager;
/**
* Tracks the configurations that have been passed to statsd.
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.h b/cmds/statsd/src/anomaly/AnomalyMonitor.h
index e2ac623c4670..d9207e99dd6f 100644
--- a/cmds/statsd/src/anomaly/AnomalyMonitor.h
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.h
@@ -55,6 +55,7 @@ struct AnomalyAlarm : public RefBase {
};
};
+// TODO: Rename this file to AnomalyAlarmMonitor.
/**
* Manages alarms for Anomaly Detection.
*/
@@ -95,6 +96,15 @@ public:
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> popSoonerThan(
uint32_t timestampSec);
+ // TODO: Function that uses popSoonerThan to get all alarms that have fired, and then
+ // iterates over all DurationAnomalyTracker, looking for those alarms. When they're found,
+ // have them declareAnomaly on those alarms. This means that DurationAnomalyTracker
+ // must be thread-safe (since this is being called on a different thread). There is no
+ // worry about missing the alarms (due to them being cancelled after this function being called)
+ // because DurationAnomalyTracker guarantees that it checks for anaomlies when it cancels
+ // alarms anyway.
+ // void declareAnomalies(uint32_t timestampSec);
+
/**
* Returns the projected alarm timestamp that is registered with
* StatsCompanionService. This may not be equal to the soonest alarm,
diff --git a/cmds/statsd/src/anomaly/DiscreteAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DiscreteAnomalyTracker.cpp
new file mode 100644
index 000000000000..64921779acdc
--- /dev/null
+++ b/cmds/statsd/src/anomaly/DiscreteAnomalyTracker.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 DEBUG true // STOPSHIP if true
+#include "Log.h"
+
+#include "DiscreteAnomalyTracker.h"
+
+#include <time.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+DiscreteAnomalyTracker::DiscreteAnomalyTracker(const Alert& alert) : mAlert(alert) {
+ VLOG("DiscreteAnomalyTracker() called");
+ if (mAlert.number_of_buckets() <= 0) {
+ ALOGE("Cannot create DiscreteAnomalyTracker with %lld buckets",
+ (long long)mAlert.number_of_buckets());
+ return;
+ }
+ mPastBuckets.resize(mAlert.number_of_buckets());
+ reset(); // initialization
+}
+
+DiscreteAnomalyTracker::~DiscreteAnomalyTracker() {
+ VLOG("~DiscreteAnomalyTracker() called");
+}
+
+void DiscreteAnomalyTracker::reset() {
+ VLOG("reset() called.");
+ mPastBuckets.clear();
+ mPastBuckets.resize(mAlert.number_of_buckets());
+ mSumOverPastBuckets.clear();
+ mCurrentBucketIndex = -1;
+ mLastAlarmAtBucketIndex = -1;
+ mAnomalyDeclared = 0;
+}
+
+size_t DiscreteAnomalyTracker::index(int64_t bucketNum) {
+ return bucketNum % mAlert.number_of_buckets();
+}
+
+void DiscreteAnomalyTracker::addOrUpdateBucket(std::shared_ptr<const DimToValMap> BucketValues,
+ int64_t bucketIndex) {
+ VLOG("addPastBucket() called.");
+ if (bucketIndex <= mCurrentBucketIndex - mAlert.number_of_buckets()) {
+ ALOGE("Cannot add a past bucket %lld units in past", (long long)bucketIndex);
+ return;
+ }
+
+ // Empty out old mPastBuckets[i] values and update mSumOverPastBuckets.
+ if (bucketIndex - mCurrentBucketIndex >= mAlert.number_of_buckets()) {
+ mPastBuckets.clear();
+ mPastBuckets.resize(mAlert.number_of_buckets());
+ mSumOverPastBuckets.clear();
+ } else {
+ for (int64_t i = std::max(
+ 0LL, (long long)(mCurrentBucketIndex - mAlert.number_of_buckets() + 1));
+ i < bucketIndex - mAlert.number_of_buckets(); i++) {
+ const int idx = index(i);
+ subtractBucketFromSum(mPastBuckets[idx]);
+ mPastBuckets[idx] = nullptr; // release (but not clear) the old bucket.
+ }
+ }
+ subtractBucketFromSum(mPastBuckets[index(bucketIndex)]);
+ mPastBuckets[index(bucketIndex)] = nullptr; // release (but not clear) the old bucket.
+
+ // Replace the oldest bucket with the new bucket we are adding.
+ mPastBuckets[index(bucketIndex)] = BucketValues;
+ addBucketToSum(BucketValues);
+
+ mCurrentBucketIndex = std::max(mCurrentBucketIndex, bucketIndex);
+}
+
+void DiscreteAnomalyTracker::subtractBucketFromSum(const shared_ptr<const DimToValMap>& bucket) {
+ if (bucket == nullptr) {
+ return;
+ }
+ // For each dimension present in the bucket, subtract its value from its corresponding sum.
+ for (const auto& keyValuePair : *bucket) {
+ auto itr = mSumOverPastBuckets.find(keyValuePair.first);
+ if (itr == mSumOverPastBuckets.end()) {
+ continue;
+ }
+ itr->second -= keyValuePair.second;
+ // TODO: No need to look up the object twice like this. Use a var.
+ if (itr->second == 0) {
+ mSumOverPastBuckets.erase(itr);
+ }
+ }
+}
+
+void DiscreteAnomalyTracker::addBucketToSum(const shared_ptr<const DimToValMap>& bucket) {
+ if (bucket == nullptr) {
+ return;
+ }
+ // For each dimension present in the bucket, add its value to its corresponding sum.
+ for (const auto& keyValuePair : *bucket) {
+ mSumOverPastBuckets[keyValuePair.first] += keyValuePair.second;
+ }
+}
+
+bool DiscreteAnomalyTracker::detectAnomaly() {
+ for (auto itr = mSumOverPastBuckets.begin(); itr != mSumOverPastBuckets.end(); itr++) {
+ if (mAlert.has_trigger_if_sum_gt() && itr->second > mAlert.trigger_if_sum_gt()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void DiscreteAnomalyTracker::declareAndDeclareAnomaly() {
+ if (detectAnomaly()) {
+ declareAnomaly();
+ }
+}
+
+void DiscreteAnomalyTracker::declareAnomaly() {
+ if (mLastAlarmAtBucketIndex >= 0 && mCurrentBucketIndex - mLastAlarmAtBucketIndex <=
+ (long long)mAlert.refractory_period_in_buckets()) {
+ VLOG("Skipping anomaly check since within refractory period");
+ return;
+ }
+ mAnomalyDeclared++;
+ // TODO(guardrail): Consider guarding against too short refractory periods.
+ mLastAlarmAtBucketIndex = mCurrentBucketIndex;
+
+ if (mAlert.has_incidentd_details()) {
+ // TODO: Can construct a name based on the criteria (and/or relay the criteria).
+ ALOGW("An anomaly (nameless) has occurred! Informing incidentd.");
+ // TODO: Send incidentd_details.name and incidentd_details.incidentd_sections to incidentd
+ } else {
+ ALOGW("An anomaly has occurred! (But informing incidentd not requested.)");
+ }
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/anomaly/DiscreteAnomalyTracker.h b/cmds/statsd/src/anomaly/DiscreteAnomalyTracker.h
new file mode 100644
index 000000000000..ed7d5d715a6d
--- /dev/null
+++ b/cmds/statsd/src/anomaly/DiscreteAnomalyTracker.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gtest/gtest_prod.h>
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
+#include "stats_util.h" // HashableDimensionKey and DimToValMap
+
+#include <memory> // unique_ptr
+#include <stdlib.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::unordered_map;
+using std::shared_ptr;
+
+// This anomaly track assmues that all values are non-negative.
+class DiscreteAnomalyTracker {
+ public:
+ DiscreteAnomalyTracker(const Alert& alert);
+
+ virtual ~DiscreteAnomalyTracker();
+
+ // Adds a new bucket or updates an existing bucket.
+ // Bucket index starts from 0.
+ void addOrUpdateBucket(std::shared_ptr<const DimToValMap> BucketValues, int64_t bucketIndex);
+
+ // Returns true if detected anomaly for the existing buckets on one or more dimension keys.
+ bool detectAnomaly();
+
+ // Informs incidentd about the detected alert.
+ void declareAnomaly();
+
+ // Detects the alert and informs the incidentd when applicable.
+ void declareAndDeclareAnomaly();
+
+private:
+ // statsd_config.proto Alert message that defines this tracker.
+ const Alert mAlert;
+
+ // The exisiting bucket list.
+ std::vector<shared_ptr<const DimToValMap>> mPastBuckets;
+
+ // Sum over all existing buckets cached in mPastBuckets.
+ DimToValMap mSumOverPastBuckets;
+
+ // Current bucket index of the current anomaly detection window. Bucket index starts from 0.
+ int64_t mCurrentBucketIndex = -1;
+
+ // The bucket index when the last anomaly was declared.
+ int64_t mLastAlarmAtBucketIndex = -1;
+
+ // The total number of declared anomalies.
+ int64_t mAnomalyDeclared = 0;
+
+ // Add the information in the given bucket to mSumOverPastBuckets.
+ void addBucketToSum(const shared_ptr<const DimToValMap>& bucket);
+
+ // Subtract the information in the given bucket from mSumOverPastBuckets
+ // and remove any items with value 0.
+ void subtractBucketFromSum(const shared_ptr<const DimToValMap>& bucket);
+
+ // Calculates the corresponding bucket index within the circular array.
+ size_t index(int64_t bucketNum);
+
+ // Resets all data. For use when all the data gets stale.
+ void reset();
+
+ FRIEND_TEST(AnomalyTrackerTest, TestConsecutiveBuckets);
+ FRIEND_TEST(AnomalyTrackerTest, TestSparseBuckets);
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/stats_events.proto b/cmds/statsd/src/atoms.proto
index 51244c6bdf4b..ba93febe8ad4 100644
--- a/cmds/statsd/src/stats_events.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -19,10 +19,10 @@ syntax = "proto2";
// TODO: Not the right package and class name
package android.os.statsd;
option java_package = "com.android.os";
-option java_outer_classname = "StatsEventProto";
+option java_outer_classname = "AtomsProto";
/**
- * The master event class. This message defines all of the available
+ * 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.
@@ -30,12 +30,12 @@ option java_outer_classname = "StatsEventProto";
* generates the android.util.StatsLog class, which contains the constants
* and methods that Android uses to log.
*
- * This StatsEvent class is not actually built into the Android system.
+ * 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 StatsEvent {
- // Pushed events start at 2.
+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;
@@ -72,6 +72,7 @@ message StatsEvent {
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.
}
@@ -81,7 +82,13 @@ message StatsEvent {
WifiBytesTransferredByFgBg wifi_bytes_transferred_by_fg_bg = 1001;
MobileBytesTransferred mobile_bytes_transferred = 1002;
MobileBytesTransferredByFgBg mobile_bytes_transferred_by_fg_bg = 1003;
- KernelWakelocksReported kernel_wakelocks_reported = 1004;
+ 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;
}
}
@@ -95,8 +102,7 @@ message WorkSource {
/*
* *****************************************************************************
- * Below are all of the individual atoms that are logged by Android via statsd
- * and Westworld.
+ * 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.
@@ -107,7 +113,7 @@ message WorkSource {
* - 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 StatsEvent.
+ * 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]
@@ -390,7 +396,7 @@ message WakelockStateChanged {
FULL = 1;
WINDOW = 2;
}
- optional int32 type = 2;
+ optional Type type = 2;
// The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
optional string tag = 3;
@@ -418,7 +424,7 @@ message UidWakelockStateChanged {
FULL = 1;
WINDOW = 2;
}
- optional int32 type = 2;
+ optional Type type = 2;
enum State {
OFF = 0;
@@ -691,7 +697,6 @@ message SettingChanged {
optional int32 user = 7;
}
-
/*
* Logs activity going to foreground or background
*
@@ -794,7 +799,7 @@ message MobileBytesTransferredByFgBg {
* Pulled from:
* StatsCompanionService using KernelWakelockReader.
*/
-message KernelWakelocksReported {
+message KernelWakelockPulled {
optional string name = 1;
optional int32 count = 2;
@@ -803,3 +808,101 @@ message KernelWakelocksReported {
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/atoms_copy.proto b/cmds/statsd/src/atoms_copy.proto
new file mode 100644
index 000000000000..58e225a317f0
--- /dev/null
+++ b/cmds/statsd/src/atoms_copy.proto
@@ -0,0 +1,910 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 953bcb3d67a4..41f5fcaf8dbc 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -115,49 +115,47 @@ void CombinationConditionTracker::isConditionMet(
evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache);
}
-bool CombinationConditionTracker::evaluateCondition(
+void CombinationConditionTracker::evaluateCondition(
const LogEvent& event, const std::vector<MatchingState>& eventMatcherValues,
const std::vector<sp<ConditionTracker>>& mAllConditions,
std::vector<ConditionState>& nonSlicedConditionCache,
- std::vector<bool>& nonSlicedChangedCache, vector<bool>& slicedConditionChanged) {
+ std::vector<bool>& conditionChangedCache) {
// value is up to date.
if (nonSlicedConditionCache[mIndex] != ConditionState::kNotEvaluated) {
- return false;
+ return;
}
for (const int childIndex : mChildren) {
if (nonSlicedConditionCache[childIndex] == ConditionState::kNotEvaluated) {
const sp<ConditionTracker>& child = mAllConditions[childIndex];
child->evaluateCondition(event, eventMatcherValues, mAllConditions,
- nonSlicedConditionCache, nonSlicedChangedCache,
- slicedConditionChanged);
+ nonSlicedConditionCache, conditionChangedCache);
}
}
- ConditionState newCondition =
- evaluateCombinationCondition(mChildren, mLogicalOperation, nonSlicedConditionCache);
-
- bool nonSlicedChanged = (mNonSlicedConditionState != newCondition);
- mNonSlicedConditionState = newCondition;
+ if (!mSliced) {
+ ConditionState newCondition =
+ evaluateCombinationCondition(mChildren, mLogicalOperation, nonSlicedConditionCache);
- nonSlicedConditionCache[mIndex] = mNonSlicedConditionState;
+ bool nonSlicedChanged = (mNonSlicedConditionState != newCondition);
+ mNonSlicedConditionState = newCondition;
- nonSlicedChangedCache[mIndex] = nonSlicedChanged;
+ nonSlicedConditionCache[mIndex] = mNonSlicedConditionState;
- if (mSliced) {
+ conditionChangedCache[mIndex] = nonSlicedChanged;
+ } else {
for (const int childIndex : mChildren) {
// If any of the sliced condition in children condition changes, the combination
// condition may be changed too.
- if (slicedConditionChanged[childIndex]) {
- slicedConditionChanged[mIndex] = true;
+ if (conditionChangedCache[childIndex]) {
+ conditionChangedCache[mIndex] = true;
break;
}
}
+ nonSlicedConditionCache[mIndex] = ConditionState::kUnknown;
ALOGD("CombinationCondition %s sliced may changed? %d", mName.c_str(),
- slicedConditionChanged[mIndex] == true);
+ conditionChangedCache[mIndex] == true);
}
-
- return nonSlicedChanged;
}
} // namespace statsd
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index dbdb3b7d31d7..3d2c6bb82e72 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -35,12 +35,11 @@ public:
const std::unordered_map<std::string, int>& conditionNameIndexMap,
std::vector<bool>& stack) override;
- bool evaluateCondition(const LogEvent& event,
+ void evaluateCondition(const LogEvent& event,
const std::vector<MatchingState>& eventMatcherValues,
const std::vector<sp<ConditionTracker>>& mAllConditions,
std::vector<ConditionState>& conditionCache,
- std::vector<bool>& changedCache,
- std::vector<bool>& slicedConditionMayChanged) override;
+ std::vector<bool>& changedCache) override;
void isConditionMet(const std::map<std::string, HashableDimensionKey>& conditionParameters,
const std::vector<sp<ConditionTracker>>& allConditions,
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index bb5ddeb4ec2b..0ac7ef38e0aa 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -56,25 +56,20 @@ public:
std::vector<bool>& stack) = 0;
// evaluate current condition given the new event.
- // return true if the condition state changed, false if the condition state is not changed.
// event: the new log event
// eventMatcherValues: the results of the LogMatcherTrackers. LogMatcherTrackers always process
// event before ConditionTrackers, because ConditionTracker depends on
// LogMatchingTrackers.
// mAllConditions: the list of all ConditionTracker
// conditionCache: the cached non-sliced condition of the ConditionTrackers for this new event.
- // nonSlicedConditionChanged: the bit map to record whether non-sliced condition has changed.
- // slicedConditionMayChanged: the bit map to record whether sliced condition may have changed.
- // Because sliced condition needs parameters to determine the value. So the sliced
- // condition is not pushed to metrics. We only inform the relevant metrics that the sliced
- // condition may have changed, and metrics should pull the conditions that they are
- // interested in.
- virtual bool evaluateCondition(const LogEvent& event,
+ // conditionChanged: the bit map to record whether the condition has changed.
+ // If the condition has dimension, then any sub condition changes will report
+ // conditionChanged.
+ virtual void evaluateCondition(const LogEvent& event,
const std::vector<MatchingState>& eventMatcherValues,
const std::vector<sp<ConditionTracker>>& mAllConditions,
std::vector<ConditionState>& conditionCache,
- std::vector<bool>& nonSlicedConditionChanged,
- std::vector<bool>& slicedConditionMayChanged) = 0;
+ std::vector<bool>& conditionChanged) = 0;
// Return the current condition state.
virtual ConditionState isConditionMet() {
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index b691faea205d..60060fe60fbd 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -74,13 +74,21 @@ SimpleConditionTracker::SimpleConditionTracker(
mStopAllLogMatcherIndex = -1;
}
- mDimension.insert(mDimension.begin(), simpleCondition.dimension().begin(),
- simpleCondition.dimension().end());
+ mOutputDimension.insert(mOutputDimension.begin(), simpleCondition.dimension().begin(),
+ simpleCondition.dimension().end());
- if (mDimension.size() > 0) {
+ if (mOutputDimension.size() > 0) {
mSliced = true;
}
+ if (simpleCondition.initial_value() == SimpleCondition_InitialValue_FALSE) {
+ mInitialValue = ConditionState::kFalse;
+ } else {
+ mInitialValue = ConditionState::kUnknown;
+ }
+
+ mNonSlicedConditionState = mInitialValue;
+
mInitialized = true;
}
@@ -97,127 +105,181 @@ bool SimpleConditionTracker::init(const vector<Condition>& allConditionConfig,
return mInitialized;
}
-void print(unordered_map<HashableDimensionKey, ConditionState>& conditions, const string& name) {
+void print(map<HashableDimensionKey, int>& conditions, const string& name) {
VLOG("%s DUMP:", name.c_str());
-
for (const auto& pair : conditions) {
- VLOG("\t%s %d", pair.first.c_str(), pair.second);
+ VLOG("\t%s : %d", pair.first.c_str(), pair.second);
}
}
-bool SimpleConditionTracker::evaluateCondition(const LogEvent& event,
+void SimpleConditionTracker::handleStopAll(std::vector<ConditionState>& conditionCache,
+ std::vector<bool>& conditionChangedCache) {
+ // Unless the default condition is false, and there was nothing started, otherwise we have
+ // triggered a condition change.
+ conditionChangedCache[mIndex] =
+ (mInitialValue == ConditionState::kFalse && mSlicedConditionState.empty()) ? false
+ : true;
+
+ // After StopAll, we know everything has stopped. From now on, default condition is false.
+ mInitialValue = ConditionState::kFalse;
+ mSlicedConditionState.clear();
+ conditionCache[mIndex] = ConditionState::kFalse;
+}
+
+void SimpleConditionTracker::handleConditionEvent(const HashableDimensionKey& outputKey,
+ bool matchStart,
+ std::vector<ConditionState>& conditionCache,
+ std::vector<bool>& conditionChangedCache) {
+ bool changed = false;
+ auto outputIt = mSlicedConditionState.find(outputKey);
+ ConditionState newCondition;
+ if (outputIt == mSlicedConditionState.end()) {
+ // We get a new output key.
+ newCondition = matchStart ? ConditionState::kTrue : ConditionState::kFalse;
+ if (matchStart && mInitialValue != ConditionState::kTrue) {
+ mSlicedConditionState[outputKey] = 1;
+ changed = true;
+ } else if (mInitialValue != ConditionState::kFalse) {
+ // it's a stop and we don't have history about it.
+ // If the default condition is not false, it means this stop is valuable to us.
+ mSlicedConditionState[outputKey] = 0;
+ changed = true;
+ }
+ } else {
+ // we have history about this output key.
+ auto& startedCount = outputIt->second;
+ // assign the old value first.
+ newCondition = startedCount > 0 ? ConditionState::kTrue : ConditionState::kFalse;
+ if (matchStart) {
+ if (startedCount == 0) {
+ // This condition for this output key will change from false -> true
+ changed = true;
+ }
+
+ // it's ok to do ++ here, even if we don't count nesting. The >1 counts will be treated
+ // as 1 if not counting nesting.
+ startedCount++;
+ newCondition = ConditionState::kTrue;
+ } else {
+ // This is a stop event.
+ if (startedCount > 0) {
+ if (mCountNesting) {
+ startedCount--;
+ if (startedCount == 0) {
+ newCondition = ConditionState::kFalse;
+ }
+ } else {
+ // not counting nesting, so ignore the number of starts, stop now.
+ startedCount = 0;
+ newCondition = ConditionState::kFalse;
+ }
+ // if everything has stopped for this output key, condition true -> false;
+ if (startedCount == 0) {
+ changed = true;
+ }
+ }
+
+ // if default condition is false, it means we don't need to keep the false values.
+ if (mInitialValue == ConditionState::kFalse && startedCount == 0) {
+ mSlicedConditionState.erase(outputIt);
+ VLOG("erase key %s", outputKey.c_str());
+ }
+ }
+ }
+
+ // dump all dimensions for debugging
+ if (DEBUG) {
+ print(mSlicedConditionState, mName);
+ }
+
+ conditionChangedCache[mIndex] = changed;
+ conditionCache[mIndex] = newCondition;
+
+ VLOG("SimpleCondition %s nonSlicedChange? %d", mName.c_str(),
+ conditionChangedCache[mIndex] == true);
+}
+
+void SimpleConditionTracker::evaluateCondition(const LogEvent& event,
const vector<MatchingState>& eventMatcherValues,
const vector<sp<ConditionTracker>>& mAllConditions,
vector<ConditionState>& conditionCache,
- vector<bool>& nonSlicedConditionChanged,
- std::vector<bool>& slicedConditionChanged) {
+ vector<bool>& conditionChangedCache) {
if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
// it has been evaluated.
- VLOG("Yes, already evaluated, %s %d", mName.c_str(), mNonSlicedConditionState);
- return false;
+ VLOG("Yes, already evaluated, %s %d", mName.c_str(), conditionCache[mIndex]);
+ return;
}
- // Ignore nesting, because we know we cannot trust ourselves on tracking nesting conditions.
+ if (mStopAllLogMatcherIndex >= 0 &&
+ eventMatcherValues[mStopAllLogMatcherIndex] == MatchingState::kMatched) {
+ handleStopAll(conditionCache, conditionChangedCache);
+ return;
+ }
- ConditionState newCondition = mNonSlicedConditionState;
- bool matched = false;
+ int matchedState = -1;
// Note: The order to evaluate the following start, stop, stop_all matters.
// The priority of overwrite is stop_all > stop > start.
if (mStartLogMatcherIndex >= 0 &&
eventMatcherValues[mStartLogMatcherIndex] == MatchingState::kMatched) {
- matched = true;
- newCondition = ConditionState::kTrue;
+ matchedState = 1;
}
if (mStopLogMatcherIndex >= 0 &&
eventMatcherValues[mStopLogMatcherIndex] == MatchingState::kMatched) {
- matched = true;
- newCondition = ConditionState::kFalse;
+ matchedState = 0;
}
- bool stopAll = false;
- if (mStopAllLogMatcherIndex >= 0 &&
- eventMatcherValues[mStopAllLogMatcherIndex] == MatchingState::kMatched) {
- matched = true;
- newCondition = ConditionState::kFalse;
- stopAll = true;
- }
-
- if (matched == false) {
- slicedConditionChanged[mIndex] = false;
- nonSlicedConditionChanged[mIndex] = false;
- conditionCache[mIndex] = mNonSlicedConditionState;
- return false;
- }
-
- bool nonSlicedChanged = mNonSlicedConditionState != newCondition;
-
- bool slicedChanged = false;
-
- if (stopAll) {
- // TODO: handle stop all; all dimension should be cleared.
- }
-
-
- if (mDimension.size() > 0) {
- HashableDimensionKey hashableKey = getHashableKey(getDimensionKey(event, mDimension));
- if (mSlicedConditionState.find(hashableKey) == mSlicedConditionState.end() ||
- mSlicedConditionState[hashableKey] != newCondition) {
- slicedChanged = true;
- mSlicedConditionState[hashableKey] = newCondition;
- }
- VLOG("key: %s %d", hashableKey.c_str(), newCondition);
- // dump all dimensions for debugging
- if (DEBUG) {
- print(mSlicedConditionState, mName);
+ if (matchedState < 0) {
+ // The event doesn't match this condition. So we just report existing condition values.
+ conditionChangedCache[mIndex] = false;
+ if (mSliced) {
+ // if the condition result is sliced. metrics won't directly get value from the
+ // cache, so just set any value other than kNotEvaluated.
+ conditionCache[mIndex] = ConditionState::kUnknown;
+ } else if (mSlicedConditionState.find(DEFAULT_DIMENSION_KEY) ==
+ mSlicedConditionState.end()) {
+ // condition not sliced, but we haven't seen the matched start or stop yet. so return
+ // initial value.
+ conditionCache[mIndex] = mInitialValue;
+ } else {
+ // return the cached condition.
+ conditionCache[mIndex] = mSlicedConditionState[DEFAULT_DIMENSION_KEY] > 0
+ ? ConditionState::kTrue
+ : ConditionState::kFalse;
}
+ return;
}
- // even if this SimpleCondition is not sliced, it may be part of a sliced CombinationCondition
- // if the nonSliced condition changed, it may affect the sliced condition in the parent node.
- // so mark the slicedConditionChanged to be true.
- // For example: APP_IN_BACKGROUND_OR_SCREEN_OFF
- // APP_IN_BACKGROUND is sliced [App_A->True, App_B->False].
- // SCREEN_OFF is not sliced, and it changes from False -> True;
- // We need to populate this change to parent condition. Because for App_B,
- // the APP_IN_BACKGROUND_OR_SCREEN_OFF condition would change from False->True.
- slicedConditionChanged[mIndex] = mSliced ? slicedChanged : nonSlicedChanged;
- nonSlicedConditionChanged[mIndex] = nonSlicedChanged;
-
- VLOG("SimpleCondition %s nonSlicedChange? %d SlicedChanged? %d", mName.c_str(),
- nonSlicedConditionChanged[mIndex] == true, slicedConditionChanged[mIndex] == true);
- mNonSlicedConditionState = newCondition;
- conditionCache[mIndex] = mNonSlicedConditionState;
-
- return nonSlicedConditionChanged[mIndex];
+ // outputKey is the output key values. e.g, uid:1234
+ const HashableDimensionKey outputKey = getHashableKey(getDimensionKey(event, mOutputDimension));
+ handleConditionEvent(outputKey, matchedState == 1, conditionCache, conditionChangedCache);
}
void SimpleConditionTracker::isConditionMet(
const map<string, HashableDimensionKey>& conditionParameters,
const vector<sp<ConditionTracker>>& allConditions, vector<ConditionState>& conditionCache) {
const auto pair = conditionParameters.find(mName);
- if (pair == conditionParameters.end()) {
- // the query does not need my sliced condition. just return the non sliced condition.
- conditionCache[mIndex] = mNonSlicedConditionState;
- VLOG("Condition %s return %d", mName.c_str(), mNonSlicedConditionState);
+ HashableDimensionKey key =
+ (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!",
+ mName.c_str());
+ conditionCache[mIndex] = mInitialValue;
return;
}
- const HashableDimensionKey& key = pair->second;
VLOG("simpleCondition %s query key: %s", mName.c_str(), key.c_str());
- if (mSlicedConditionState.find(key) == mSlicedConditionState.end()) {
- // never seen this key before. the condition is unknown to us.
- conditionCache[mIndex] = ConditionState::kUnknown;
+ auto startedCountIt = mSlicedConditionState.find(key);
+ if (startedCountIt == mSlicedConditionState.end()) {
+ conditionCache[mIndex] = mInitialValue;
} else {
- conditionCache[mIndex] = mSlicedConditionState[key];
+ conditionCache[mIndex] =
+ startedCountIt->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
}
VLOG("Condition %s return %d", mName.c_str(), conditionCache[mIndex]);
-
- if (DEBUG) {
- print(mSlicedConditionState, mName);
- }
}
} // namespace statsd
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index b72157baf1e2..2eda0b1af8b0 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -17,6 +17,7 @@
#ifndef SIMPLE_CONDITION_TRACKER_H
#define SIMPLE_CONDITION_TRACKER_H
+#include <gtest/gtest_prod.h>
#include "ConditionTracker.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "stats_util.h"
@@ -38,12 +39,11 @@ public:
const std::unordered_map<std::string, int>& conditionNameIndexMap,
std::vector<bool>& stack) override;
- bool evaluateCondition(const LogEvent& event,
+ void evaluateCondition(const LogEvent& event,
const std::vector<MatchingState>& eventMatcherValues,
const std::vector<sp<ConditionTracker>>& mAllConditions,
std::vector<ConditionState>& conditionCache,
- std::vector<bool>& changedCache,
- std::vector<bool>& slicedChangedCache) override;
+ std::vector<bool>& changedCache) override;
void isConditionMet(const std::map<std::string, HashableDimensionKey>& conditionParameters,
const std::vector<sp<ConditionTracker>>& allConditions,
@@ -62,15 +62,22 @@ private:
// The index of the LogEventMatcher which defines the stop all.
int mStopAllLogMatcherIndex;
- // The dimension defines at the atom level, how start and stop should match.
- // e.g., APP_IN_FOREGROUND, the dimension should be the uid field. Each "start" and
- // "stop" tells you the state change of a particular app. Without this dimension, this
- // condition does not make sense.
- std::vector<KeyMatcher> mDimension;
+ ConditionState mInitialValue;
- // Keep the map from the internal HashableDimensionKey to std::vector<KeyValuePair>
- // that StatsLogReport wants.
- std::unordered_map<HashableDimensionKey, ConditionState> mSlicedConditionState;
+ std::vector<KeyMatcher> mOutputDimension;
+
+ std::map<HashableDimensionKey, int> mSlicedConditionState;
+
+ void handleStopAll(std::vector<ConditionState>& conditionCache,
+ std::vector<bool>& changedCache);
+
+ void handleConditionEvent(const HashableDimensionKey& outputKey, bool matchStart,
+ std::vector<ConditionState>& conditionCache,
+ std::vector<bool>& changedCache);
+
+ FRIEND_TEST(SimpleConditionTrackerTest, TestSlicedCondition);
+ FRIEND_TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim);
+ FRIEND_TEST(SimpleConditionTrackerTest, TestStopAll);
};
} // namespace statsd
diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp
index 40d41be381fd..2618a217c378 100644
--- a/cmds/statsd/src/condition/condition_util.cpp
+++ b/cmds/statsd/src/condition/condition_util.cpp
@@ -25,7 +25,6 @@
#include <unordered_map>
#include "../matchers/matcher_util.h"
#include "ConditionTracker.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "stats_util.h"
diff --git a/cmds/statsd/src/condition/condition_util.h b/cmds/statsd/src/condition/condition_util.h
index 47e245e4704b..4167bf922b19 100644
--- a/cmds/statsd/src/condition/condition_util.h
+++ b/cmds/statsd/src/condition/condition_util.h
@@ -19,7 +19,6 @@
#include <vector>
#include "../matchers/matcher_util.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
namespace android {
diff --git a/cmds/statsd/src/config/ConfigListener.h b/cmds/statsd/src/config/ConfigListener.h
index a58766d2a382..19ccfcfe7491 100644
--- a/cmds/statsd/src/config/ConfigListener.h
+++ b/cmds/statsd/src/config/ConfigListener.h
@@ -16,7 +16,6 @@
#pragma once
-#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
#include "config/ConfigKey.h"
#include <utils/RefBase.h>
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 88127194753f..a9ce4a337590 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -60,6 +60,14 @@ void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& confi
}
}
+void ConfigManager::SetConfigReceiver(const ConfigKey& key, const string& pkg, const string& cls) {
+ mConfigReceivers[key] = pair<string, string>(pkg, cls);
+}
+
+void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) {
+ mConfigReceivers.erase(key);
+}
+
void ConfigManager::RemoveConfig(const ConfigKey& key) {
unordered_map<ConfigKey, StatsdConfig>::iterator it = mConfigs.find(key);
if (it != mConfigs.end()) {
@@ -85,6 +93,7 @@ void ConfigManager::RemoveConfigs(int uid) {
if (it->first.GetUid() == uid) {
removed.push_back(it->first);
it = mConfigs.erase(it);
+ mConfigReceivers.erase(it->first);
} else {
it++;
}
@@ -116,7 +125,7 @@ void ConfigManager::update_saved_configs() {
static StatsdConfig build_fake_config() {
// HACK: Hard code a test metric for counting screen on events...
StatsdConfig config;
- config.set_config_id(12345L);
+ config.set_name("12345");
int WAKE_LOCK_TAG_ID = 1111; // put a fake id here to make testing easier.
int WAKE_LOCK_UID_KEY_ID = 1;
@@ -139,32 +148,43 @@ static StatsdConfig build_fake_config() {
int UID_PROCESS_STATE_TAG_ID = 27;
int UID_PROCESS_STATE_UID_KEY = 1;
- int KERNEL_WAKELOCK_TAG_ID = 41;
+ int KERNEL_WAKELOCK_TAG_ID = 1004;
int KERNEL_WAKELOCK_NAME_KEY = 4;
+ int DEVICE_TEMPERATURE_TAG_ID = 33;
+ int DEVICE_TEMPERATURE_KEY = 1;
+
// Count Screen ON events.
CountMetric* metric = config.add_count_metric();
- metric->set_metric_id(1);
+ metric->set_name("1");
metric->set_what("SCREEN_TURNED_ON");
metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
// Anomaly threshold for screen-on count.
- Alert* alert = metric->add_alerts();
+ Alert* alert = config.add_alerts();
+ alert->set_name("1");
alert->set_number_of_buckets(6);
alert->set_trigger_if_sum_gt(10);
alert->set_refractory_period_secs(30);
// Count process state changes, slice by uid.
metric = config.add_count_metric();
- metric->set_metric_id(2);
+ metric->set_name("2");
metric->set_what("PROCESS_STATE_CHANGE");
metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
KeyMatcher* keyMatcher = metric->add_dimension();
keyMatcher->set_key(UID_PROCESS_STATE_UID_KEY);
+ // Anomaly threshold for background count.
+ alert = config.add_alerts();
+ alert->set_name("2");
+ alert->set_number_of_buckets(4);
+ alert->set_trigger_if_sum_gt(30);
+ alert->set_refractory_period_secs(20);
+
// Count process state changes, slice by uid, while SCREEN_IS_OFF
metric = config.add_count_metric();
- metric->set_metric_id(3);
+ metric->set_name("3");
metric->set_what("PROCESS_STATE_CHANGE");
metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
keyMatcher = metric->add_dimension();
@@ -173,7 +193,7 @@ static StatsdConfig build_fake_config() {
// Count wake lock, slice by uid, while SCREEN_IS_ON and app in background
metric = config.add_count_metric();
- metric->set_metric_id(4);
+ metric->set_name("4");
metric->set_what("APP_GET_WL");
metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
keyMatcher = metric->add_dimension();
@@ -186,13 +206,13 @@ static StatsdConfig build_fake_config() {
// Duration of an app holding any wl, while screen on and app in background, slice by uid
DurationMetric* durationMetric = config.add_duration_metric();
- durationMetric->set_metric_id(5);
+ durationMetric->set_name("5");
durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
durationMetric->set_type(DurationMetric_AggregationType_DURATION_SUM);
keyMatcher = durationMetric->add_dimension();
keyMatcher->set_key(WAKE_LOCK_UID_KEY_ID);
- durationMetric->set_what("WL_STATE_PER_APP_PER_NAME");
- durationMetric->set_predicate("APP_IS_BACKGROUND_AND_SCREEN_ON");
+ durationMetric->set_what("WL_HELD_PER_APP_PER_NAME");
+ 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);
@@ -200,13 +220,13 @@ static StatsdConfig build_fake_config() {
// max Duration of an app holding any wl, while screen on and app in background, slice by uid
durationMetric = config.add_duration_metric();
- durationMetric->set_metric_id(6);
+ durationMetric->set_name("6");
durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
durationMetric->set_type(DurationMetric_AggregationType_DURATION_MAX_SPARSE);
keyMatcher = durationMetric->add_dimension();
keyMatcher->set_key(WAKE_LOCK_UID_KEY_ID);
- durationMetric->set_what("WL_STATE_PER_APP_PER_NAME");
- durationMetric->set_predicate("APP_IS_BACKGROUND_AND_SCREEN_ON");
+ durationMetric->set_what("WL_HELD_PER_APP_PER_NAME");
+ 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);
@@ -214,11 +234,11 @@ static StatsdConfig build_fake_config() {
// Duration of an app holding any wl, while screen on and app in background
durationMetric = config.add_duration_metric();
- durationMetric->set_metric_id(7);
+ durationMetric->set_name("7");
durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
durationMetric->set_type(DurationMetric_AggregationType_DURATION_MAX_SPARSE);
- durationMetric->set_what("WL_STATE_PER_APP_PER_NAME");
- durationMetric->set_predicate("APP_IS_BACKGROUND_AND_SCREEN_ON");
+ durationMetric->set_what("WL_HELD_PER_APP_PER_NAME");
+ 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);
@@ -226,14 +246,14 @@ static StatsdConfig build_fake_config() {
// Duration of screen on time.
durationMetric = config.add_duration_metric();
- durationMetric->set_metric_id(8);
- durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
+ durationMetric->set_name("8");
+ durationMetric->mutable_bucket()->set_bucket_size_millis(10 * 1000L);
durationMetric->set_type(DurationMetric_AggregationType_DURATION_SUM);
durationMetric->set_what("SCREEN_IS_ON");
// Value metric to count KERNEL_WAKELOCK when screen turned on
ValueMetric* valueMetric = config.add_value_metric();
- valueMetric->set_metric_id(6);
+ valueMetric->set_name("6");
valueMetric->set_what("KERNEL_WAKELOCK");
valueMetric->set_value_field(1);
valueMetric->set_condition("SCREEN_IS_ON");
@@ -244,10 +264,22 @@ static StatsdConfig build_fake_config() {
// Add an EventMetric to log process state change events.
EventMetric* eventMetric = config.add_event_metric();
- eventMetric->set_metric_id(9);
+ eventMetric->set_name("9");
eventMetric->set_what("SCREEN_TURNED_ON");
+ // Add an GaugeMetric.
+ GaugeMetric* gaugeMetric = config.add_gauge_metric();
+ gaugeMetric->set_name("10");
+ gaugeMetric->set_what("DEVICE_TEMPERATURE");
+ gaugeMetric->set_gauge_field(DEVICE_TEMPERATURE_KEY);
+ 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(
+ DEVICE_TEMPERATURE_TAG_ID);
+
LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
eventMatcher->set_name("SCREEN_TURNED_ON");
SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
@@ -301,18 +333,26 @@ static StatsdConfig build_fake_config() {
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->set_name("KERNEL_WAKELOCK");
+ simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->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);
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);
condition = config.add_condition();
condition->set_name("APP_IS_BACKGROUND");
@@ -321,6 +361,7 @@ static StatsdConfig build_fake_config() {
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);
condition = config.add_condition();
condition->set_name("APP_IS_BACKGROUND_AND_SCREEN_ON");
@@ -330,7 +371,7 @@ static StatsdConfig build_fake_config() {
combination_condition->add_condition("SCREEN_IS_ON");
condition = config.add_condition();
- condition->set_name("WL_STATE_PER_APP_PER_NAME");
+ 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");
@@ -338,6 +379,17 @@ static StatsdConfig build_fake_config() {
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);
+
+ 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);
return config;
}
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index 5d73eaf3c7b6..c21247f97967 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -32,6 +32,7 @@ using android::RefBase;
using std::string;
using std::unordered_map;
using std::vector;
+using std::pair;
/**
* Keeps track of which configurations have been set from various sources.
@@ -64,6 +65,16 @@ public:
void UpdateConfig(const ConfigKey& key, const StatsdConfig& data);
/**
+ * Sets the broadcast receiver for a configuration key.
+ */
+ void SetConfigReceiver(const ConfigKey& key, const string& pkg, const string& cls);
+
+ /**
+ * Erase any broadcast receiver associated with this config key.
+ */
+ void RemoveConfigReceiver(const ConfigKey& key);
+
+ /**
* A configuration was removed.
*
* Reports this to listeners.
@@ -87,11 +98,17 @@ private:
void update_saved_configs();
/**
- * The Configs that have been set
+ * The Configs that have been set. Each config should
*/
unordered_map<ConfigKey, StatsdConfig> mConfigs;
/**
+ * Each config key can be subscribed by up to one receiver, specified as the package name and
+ * class name.
+ */
+ unordered_map<ConfigKey, pair<string, string>> mConfigReceivers;
+
+ /**
* The ConfigListeners that will be told about changes.
*/
vector<sp<ConfigListener>> mListeners;
diff --git a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
new file mode 100644
index 000000000000..e004d217a966
--- /dev/null
+++ b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
@@ -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.
+ */
+
+#define DEBUG true // STOPSHIP if true
+#include "Log.h"
+
+#include <fstream>
+#include "external/CpuTimePerUidFreqPuller.h"
+
+#include "logd/LogEvent.h"
+#include "statslog.h"
+
+using std::make_shared;
+using std::shared_ptr;
+using std::ifstream;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+static const string sProcFile = "/proc/uid_cputime/show_uid_stat";
+static const int kLineBufferSize = 1024;
+
+/**
+ * Reads /proc/uid_time_in_state which has the format:
+ *
+ * uid: [freq1] [freq2] [freq3] ...
+ * [uid1]: [time in freq1] [time in freq2] [time in freq3] ...
+ * [uid2]: [time in freq1] [time in freq2] [time in freq3] ...
+ * ...
+ *
+ * This provides the times a UID's processes spent executing at each different cpu frequency.
+ * The file contains a monotonically increasing count of time for a single boot.
+ */
+bool CpuTimePerUidFreqPuller::Pull(const int tagId, vector<shared_ptr<LogEvent>>* data) {
+ data->clear();
+
+ ifstream fin;
+ fin.open(sProcFile);
+ if (!fin.good()) {
+ VLOG("Failed to read pseudo file %s", sProcFile.c_str());
+ return false;
+ }
+
+ uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+ char buf[kLineBufferSize];
+ // first line prints the format and frequencies
+ fin.getline(buf, kLineBufferSize);
+ char * pch;
+ while(!fin.eof()){
+ fin.getline(buf, kLineBufferSize);
+ pch = strtok (buf, " :");
+ if (pch == NULL) break;
+ uint64_t uid = std::stoull(pch);
+ pch = strtok(NULL, " ");
+ uint64_t timeMs;
+ int idx = 0;
+ do {
+ timeMs = std::stoull(pch);
+ auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID_FREQ_PULLED, timestamp);
+ auto elemList = ptr->GetAndroidLogEventList();
+ *elemList << uid;
+ *elemList << idx;
+ *elemList << timeMs;
+ ptr->init();
+ data->push_back(ptr);
+ VLOG("uid %lld, freq idx %d, sys time %lld", (long long)uid, idx, (long long)timeMs);
+ idx ++;
+ pch = strtok(NULL, " ");
+ } while (pch != NULL);
+ }
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.h b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.h
new file mode 100644
index 000000000000..839e5aab3dc2
--- /dev/null
+++ b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.h
@@ -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.
+ */
+
+#pragma once
+
+#include <utils/String16.h>
+#include "StatsPuller.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Reads /proc/uid_cputime/show_uid_stat which has the line format:
+ *
+ * uid: user_time_micro_seconds system_time_micro_seconds
+ *
+ * This provides the time a UID's processes spent executing in user-space and kernel-space.
+ * The file contains a monotonically increasing count of time for a single boot.
+ */
+class CpuTimePerUidFreqPuller : public StatsPuller {
+ public:
+ bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) override;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/CpuTimePerUidPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
new file mode 100644
index 000000000000..b84b877a0ee9
--- /dev/null
+++ b/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 DEBUG true // STOPSHIP if true
+#include "Log.h"
+
+#include <fstream>
+#include "external/CpuTimePerUidPuller.h"
+
+#include "logd/LogEvent.h"
+#include "statslog.h"
+
+using std::make_shared;
+using std::shared_ptr;
+using std::ifstream;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+static const string sProcFile = "/proc/uid_cputime/show_uid_stat";
+static const int kLineBufferSize = 1024;
+
+/**
+ * Reads /proc/uid_cputime/show_uid_stat which has the line format:
+ *
+ * uid: user_time_micro_seconds system_time_micro_seconds power_in_milli-amp-micro_seconds
+ *
+ * This provides the time a UID's processes spent executing in user-space and kernel-space.
+ * The file contains a monotonically increasing count of time for a single boot.
+ */
+bool CpuTimePerUidPuller::Pull(const int tagId, vector<shared_ptr<LogEvent>>* data) {
+ data->clear();
+
+ ifstream fin;
+ fin.open(sProcFile);
+ if (!fin.good()) {
+ VLOG("Failed to read pseudo file %s", sProcFile.c_str());
+ return false;
+ }
+
+ uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+ char buf[kLineBufferSize];
+ char * pch;
+ while(!fin.eof()){
+ fin.getline(buf, kLineBufferSize);
+ pch = strtok(buf, " :");
+ if (pch == NULL) break;
+ uint64_t uid = std::stoull(pch);
+ pch = strtok(buf, " ");
+ uint64_t userTimeMs = std::stoull(pch);
+ pch = strtok(buf, " ");
+ uint64_t sysTimeMs = std::stoull(pch);
+
+ auto ptr = make_shared<LogEvent>(android::util::CPU_TIME_PER_UID_PULLED, timestamp);
+ auto elemList = ptr->GetAndroidLogEventList();
+ *elemList << uid;
+ *elemList << userTimeMs;
+ *elemList << sysTimeMs;
+ ptr->init();
+ data->push_back(ptr);
+ VLOG("uid %lld, user time %lld, sys time %lld", (long long)uid, (long long)userTimeMs, (long long)sysTimeMs);
+ }
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/CpuTimePerUidPuller.h b/cmds/statsd/src/external/CpuTimePerUidPuller.h
new file mode 100644
index 000000000000..9bb89463725e
--- /dev/null
+++ b/cmds/statsd/src/external/CpuTimePerUidPuller.h
@@ -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.
+ */
+
+#pragma once
+
+#include <utils/String16.h>
+#include "StatsPuller.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Reads /proc/uid_cputime/show_uid_stat which has the line format:
+ *
+ * uid: user_time_micro_seconds system_time_micro_seconds
+ *
+ * This provides the time a UID's processes spent executing in user-space and kernel-space.
+ * The file contains a monotonically increasing count of time for a single boot.
+ */
+class CpuTimePerUidPuller : public StatsPuller {
+ public:
+ bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) override;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp b/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp
new file mode 100644
index 000000000000..319feef49b35
--- /dev/null
+++ b/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp
@@ -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.
+ */
+
+#define DEBUG true // STOPSHIP if true
+#include "Log.h"
+
+#include <android/hardware/power/1.0/IPower.h>
+#include <android/hardware/power/1.1/IPower.h>
+#include <fcntl.h>
+#include <hardware/power.h>
+#include <hardware_legacy/power.h>
+#include <inttypes.h>
+#include <semaphore.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "external/ResourcePowerManagerPuller.h"
+#include "external/StatsPuller.h"
+
+#include "logd/LogEvent.h"
+#include "statslog.h"
+
+using android::hardware::hidl_vec;
+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::Return;
+using android::hardware::Void;
+
+using std::make_shared;
+using std::shared_ptr;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0 = nullptr;
+sp<android::hardware::power::V1_1::IPower> gPowerHalV1_1 = nullptr;
+std::mutex gPowerHalMutex;
+bool gPowerHalExists = true;
+
+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");
+ } else {
+ ALOGW("Couldn't load power HAL service");
+ gPowerHalExists = false;
+ }
+ }
+ return gPowerHalV1_0 != nullptr;
+}
+
+bool ResourcePowerManagerPuller::Pull(const int tagId, vector<shared_ptr<LogEvent>>* data) {
+ std::lock_guard<std::mutex> lock(gPowerHalMutex);
+
+ if (!getPowerHal()) {
+ ALOGE("Power Hal not loaded");
+ return false;
+ }
+
+ uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+
+ data->clear();
+ Return<void> ret = gPowerHalV1_0->getPlatformLowPowerStats(
+ [&data, timestamp](hidl_vec<PowerStatePlatformSleepState> states, Status status) {
+
+ if (status != Status::SUCCESS) return;
+
+ for (size_t i = 0; i < states.size(); i++) {
+ const PowerStatePlatformSleepState& state = states[i];
+
+ auto statePtr = make_shared<LogEvent>(
+ android::util::POWER_STATE_PLATFORM_SLEEP_STATE_PULLED, timestamp);
+ auto elemList = statePtr->GetAndroidLogEventList();
+ *elemList << state.name;
+ *elemList << state.residencyInMsecSinceBoot;
+ *elemList << state.totalTransitions;
+ *elemList << state.supportedOnlyInSuspend;
+ statePtr->init();
+ data->push_back(statePtr);
+ VLOG("powerstate: %s, %lld, %lld, %d", state.name.c_str(),
+ (long long)state.residencyInMsecSinceBoot,
+ (long long)state.totalTransitions, state.supportedOnlyInSuspend ? 1 : 0);
+ for (auto voter : state.voters) {
+ auto voterPtr =
+ make_shared<LogEvent>(android::util::POWER_STATE_VOTER_PULLED, timestamp);
+ auto elemList = voterPtr->GetAndroidLogEventList();
+ *elemList << state.name;
+ *elemList << voter.name;
+ *elemList << voter.totalTimeInMsecVotedForSinceBoot;
+ *elemList << voter.totalNumberOfTimesVotedSinceBoot;
+ voterPtr->init();
+ data->push_back(voterPtr);
+ VLOG("powerstatevoter: %s, %s, %lld, %lld", state.name.c_str(),
+ voter.name.c_str(), (long long)voter.totalTimeInMsecVotedForSinceBoot,
+ (long long)voter.totalNumberOfTimesVotedSinceBoot);
+ }
+ }
+ });
+ if (!ret.isOk()) {
+ ALOGE("getLowPowerStats() failed: power HAL service not available");
+ gPowerHalV1_0 = nullptr;
+ return false;
+ }
+
+ // 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) {
+ ret = gPowerHal_1_1->getSubsystemLowPowerStats(
+ [&data, timestamp](hidl_vec<PowerStateSubsystem> subsystems, Status status) {
+
+ if (status != Status::SUCCESS) return;
+
+ if (subsystems.size() > 0) {
+ for (size_t i = 0; i < subsystems.size(); i++) {
+ const PowerStateSubsystem& subsystem = subsystems[i];
+ for (size_t j = 0; j < subsystem.states.size(); j++) {
+ const PowerStateSubsystemSleepState& state = subsystem.states[j];
+ auto subsystemStatePtr = make_shared<LogEvent>(
+ android::util::POWER_STATE_SUBSYSTEM_SLEEP_STATE_PULLED, timestamp);
+ auto elemList = subsystemStatePtr->GetAndroidLogEventList();
+ *elemList << subsystem.name;
+ *elemList << state.name;
+ *elemList << state.residencyInMsecSinceBoot;
+ *elemList << state.totalTransitions;
+ *elemList << state.lastEntryTimestampMs;
+ *elemList << state.supportedOnlyInSuspend;
+ subsystemStatePtr->init();
+ data->push_back(subsystemStatePtr);
+ VLOG("subsystemstate: %s, %s, %lld, %lld, %lld",
+ subsystem.name.c_str(), state.name.c_str(),
+ (long long)state.residencyInMsecSinceBoot,
+ (long long)state.totalTransitions,
+ (long long)state.lastEntryTimestampMs);
+ }
+ }
+ }
+ });
+ }
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.h b/cmds/statsd/src/external/ResourcePowerManagerPuller.h
index cc8059d80601..c396c12de0d7 100644
--- a/cmds/statsd/src/external/KernelWakelockPuller.h
+++ b/cmds/statsd/src/external/ResourcePowerManagerPuller.h
@@ -23,12 +23,12 @@ namespace android {
namespace os {
namespace statsd {
-class KernelWakelockPuller : public StatsPuller {
+/**
+ * Reads hal for sleep states
+ */
+class ResourcePowerManagerPuller : public StatsPuller {
public:
- // a number of stats need to be pulled from StatsCompanionService
- //
- const static int PULL_CODE_KERNEL_WAKELOCKS;
- vector<StatsLogEventWrapper> Pull() override;
+ bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) override;
};
} // namespace statsd
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.cpp b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
index 00259a83d3db..8e9639971679 100644
--- a/cmds/statsd/src/external/KernelWakelockPuller.cpp
+++ b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
@@ -20,37 +20,49 @@
#include <android/os/IStatsCompanionService.h>
#include <binder/IPCThreadState.h>
#include <private/android_filesystem_config.h>
-#include "KernelWakelockPuller.h"
+#include "StatsCompanionServicePuller.h"
#include "StatsService.h"
using namespace android;
using namespace android::base;
using namespace android::binder;
using namespace android::os;
-using namespace std;
+using std::make_shared;
+using std::shared_ptr;
+using std::vector;
namespace android {
namespace os {
namespace statsd {
-const int KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS = 1004;
+const int kLogMsgHeaderSize = 28;
// The reading and parsing are implemented in Java. It is not difficult to port over. But for now
// let StatsCompanionService handle that and send the data back.
-vector<StatsLogEventWrapper> KernelWakelockPuller::Pull() {
+bool StatsCompanionServicePuller::Pull(const int tagId, vector<shared_ptr<LogEvent> >* data) {
sp<IStatsCompanionService> statsCompanion = StatsService::getStatsCompanionService();
vector<StatsLogEventWrapper> returned_value;
if (statsCompanion != NULL) {
- Status status = statsCompanion->pullData(KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS,
- &returned_value);
+ Status status = statsCompanion->pullData(tagId, &returned_value);
if (!status.isOk()) {
ALOGW("error pulling kernel wakelock");
+ return false;
+ }
+ data->clear();
+ 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;
+ // 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!");
- return returned_value;
+ return true;
} else {
ALOGW("statsCompanion not found!");
- return returned_value;
+ return false;
}
}
diff --git a/cmds/statsd/src/external/StatsCompanionServicePuller.h b/cmds/statsd/src/external/StatsCompanionServicePuller.h
new file mode 100644
index 000000000000..3ff2274f1d65
--- /dev/null
+++ b/cmds/statsd/src/external/StatsCompanionServicePuller.h
@@ -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.
+ */
+
+#pragma once
+
+#include <utils/String16.h>
+#include "StatsPuller.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class StatsCompanionServicePuller : public StatsPuller {
+public:
+ bool Pull(const int tagId, vector<std::shared_ptr<LogEvent> >* data) override;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
index 774e7f093087..940ad9c788ef 100644
--- a/cmds/statsd/src/external/StatsPuller.h
+++ b/cmds/statsd/src/external/StatsPuller.h
@@ -19,6 +19,7 @@
#include <android/os/StatsLogEventWrapper.h>
#include <utils/String16.h>
#include <vector>
+#include "logd/LogEvent.h"
using android::os::StatsLogEventWrapper;
using std::vector;
@@ -31,7 +32,7 @@ class StatsPuller {
public:
virtual ~StatsPuller(){};
- virtual vector<StatsLogEventWrapper> Pull() = 0;
+ virtual bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) = 0;
};
} // namespace statsd
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
deleted file mode 100644
index f45cb1ccaa74..000000000000
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ /dev/null
@@ -1,189 +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.
- */
-
-#define DEBUG true
-#include "Log.h"
-
-#include <android/os/IStatsCompanionService.h>
-#include <cutils/log.h>
-#include <algorithm>
-#include <climits>
-#include "KernelWakelockPuller.h"
-#include "StatsPullerManager.h"
-#include "StatsService.h"
-#include "logd/LogEvent.h"
-
-#include <iostream>
-
-using std::string;
-using std::vector;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-const int kernel_wakelock = 1;
-const unordered_map<string, int> StatsPullerManager::kPullCodes({{"KERNEL_WAKELOCK",
- kernel_wakelock}});
-
-StatsPullerManager::StatsPullerManager()
- : mCurrentPullingInterval(LONG_MAX), mPullStartTimeMs(get_pull_start_time_ms()) {
- mPullers.insert({kernel_wakelock, make_unique<KernelWakelockPuller>()});
- mStatsCompanionService = get_stats_companion_service();
- if (mStatsCompanionService != nullptr) {
- mStatsCompanionService->cancelPullingAlarms();
- } else {
- VLOG("Failed to update pulling interval");
- }
-}
-
-static const int log_msg_header_size = 28;
-
-vector<shared_ptr<LogEvent>> StatsPullerManager::Pull(int pullCode, uint64_t timestampSec) {
- if (DEBUG) ALOGD("Initiating pulling %d", pullCode);
-
- vector<shared_ptr<LogEvent>> ret;
- auto itr = mPullers.find(pullCode);
- if (itr != mPullers.end()) {
- vector<StatsLogEventWrapper> outputs = itr->second->Pull();
- for (const StatsLogEventWrapper& it : outputs) {
- log_msg tmp;
- tmp.entry_v1.sec = timestampSec;
- tmp.entry_v1.nsec = 0;
- 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 = log_msg_header_size;
- // And set the received bytes starting after the 28 bytes reserved for header.
- copy(it.bytes.begin(), it.bytes.end(), tmp.buf + log_msg_header_size);
- shared_ptr<LogEvent> evt = make_shared<LogEvent>(tmp);
- ret.push_back(evt);
- }
- return ret;
- } else {
- ALOGD("Unknown pull code %d", pullCode);
- return ret; // Return early since we don't know what to pull.
- }
-}
-
-sp<IStatsCompanionService> StatsPullerManager::get_stats_companion_service() {
- 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 nullptr;
- }
- }
- return statsCompanion;
-}
-
-StatsPullerManager& StatsPullerManager::GetInstance() {
- static StatsPullerManager instance;
- return instance;
-}
-
-int StatsPullerManager::GetPullCode(string atomName) {
- if (kPullCodes.find(atomName) != kPullCodes.end()) {
- return kPullCodes.find(atomName)->second;
- } else {
- return -1;
- }
-}
-
-long StatsPullerManager::get_pull_start_time_ms() {
- // TODO: limit and align pull intervals to 10min boundaries if this turns out to be a problem
- return time(nullptr) * 1000;
-}
-
-void StatsPullerManager::RegisterReceiver(int pullCode, sp<PullDataReceiver> receiver, long intervalMs) {
- AutoMutex _l(mReceiversLock);
- vector<ReceiverInfo>& receivers = mReceivers[pullCode];
- for (auto it = receivers.begin(); it != receivers.end(); it++) {
- if (it->receiver.get() == receiver.get()) {
- VLOG("Receiver already registered of %d", (int)receivers.size());
- return;
- }
- }
- ReceiverInfo receiverInfo;
- receiverInfo.receiver = receiver;
- receiverInfo.timeInfo.first = intervalMs;
- receivers.push_back(receiverInfo);
-
- // There is only one alarm for all pulled events. So only set it to the smallest denom.
- if (intervalMs < mCurrentPullingInterval) {
- VLOG("Updating pulling interval %ld", intervalMs);
- mCurrentPullingInterval = intervalMs;
- if (mStatsCompanionService != nullptr) {
- mStatsCompanionService->setPullingAlarms(mPullStartTimeMs, mCurrentPullingInterval);
- } else {
- VLOG("Failed to update pulling interval");
- }
- }
- VLOG("Puller for pullcode %d registered of %d", pullCode, (int)receivers.size());
-}
-
-void StatsPullerManager::UnRegisterReceiver(int pullCode, sp<PullDataReceiver> receiver) {
- AutoMutex _l(mReceiversLock);
- if (mReceivers.find(pullCode) == mReceivers.end()) {
- VLOG("Unknown pull code or no receivers: %d", pullCode);
- return;
- }
- auto& receivers = mReceivers.find(pullCode)->second;
- for (auto it = receivers.begin(); it != receivers.end(); it++) {
- if (receiver.get() == it->receiver.get()) {
- receivers.erase(it);
- VLOG("Puller for pullcode %d unregistered of %d", pullCode, (int)receivers.size());
- return;
- }
- }
-}
-
-void StatsPullerManager::OnAlarmFired() {
- AutoMutex _l(mReceiversLock);
-
- uint64_t currentTimeMs = time(nullptr) * 1000;
-
- vector<pair<int, vector<ReceiverInfo*>>> needToPull =
- vector<pair<int, vector<ReceiverInfo*>>>();
- for (auto& pair : mReceivers) {
- vector<ReceiverInfo*> receivers = vector<ReceiverInfo*>();
- if (pair.second.size() != 0){
- for(auto& receiverInfo : pair.second) {
- if (receiverInfo.timeInfo.first + receiverInfo.timeInfo.second > currentTimeMs) {
- receivers.push_back(&receiverInfo);
- }
- }
- if (receivers.size() > 0) {
- needToPull.push_back(make_pair(pair.first, receivers));
- }
- }
- }
-
- for (const auto& pullInfo : needToPull) {
- const vector<shared_ptr<LogEvent>>& data = Pull(pullInfo.first, currentTimeMs/1000);
- for(const auto& receiverInfo : pullInfo.second) {
- receiverInfo->receiver->onDataPulled(data);
- receiverInfo->timeInfo.second = currentTimeMs;
- }
- }
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
index e599b6904ed4..2e803c9bd2d6 100644
--- a/cmds/statsd/src/external/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -16,77 +16,41 @@
#pragma once
-#include <android/os/IStatsCompanionService.h>
-#include <binder/IServiceManager.h>
-#include <utils/RefBase.h>
-#include <utils/String16.h>
-#include <utils/String8.h>
-#include <utils/threads.h>
-#include <string>
-#include <unordered_map>
-#include <vector>
-#include "PullDataReceiver.h"
-#include "StatsPuller.h"
-#include "logd/LogEvent.h"
+#include "StatsPullerManagerImpl.h"
namespace android {
namespace os {
namespace statsd {
-class StatsPullerManager : public virtual RefBase {
-public:
- static StatsPullerManager& GetInstance();
+class StatsPullerManager{
+ public:
+ virtual ~StatsPullerManager() {}
- void RegisterReceiver(int pullCode, sp<PullDataReceiver> receiver, long intervalMs);
+ virtual void RegisterReceiver(int tagId, wp<PullDataReceiver> receiver, long intervalMs) {
+ mPullerManager.RegisterReceiver(tagId, receiver, intervalMs);
+ };
- void UnRegisterReceiver(int pullCode, sp<PullDataReceiver> receiver);
+ virtual void UnRegisterReceiver(int tagId, wp<PullDataReceiver> receiver) {
+ mPullerManager.UnRegisterReceiver(tagId, receiver);
+ };
- // We return a vector of shared_ptr since LogEvent's copy constructor is not available.
- vector<std::shared_ptr<LogEvent>> Pull(const int pullCode, const uint64_t timestampSec);
+ // Verify if we know how to pull for this matcher
+ bool PullerForMatcherExists(int tagId) {
+ return mPullerManager.PullerForMatcherExists(tagId);
+ }
- // Translate metric name to pullCodes.
- // return -1 if no valid pullCode is found
- int GetPullCode(std::string metricName);
+ void OnAlarmFired() {
+ mPullerManager.OnAlarmFired();
+ }
- void OnAlarmFired();
+ virtual bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ return mPullerManager.Pull(tagId, data);
+ }
-private:
- StatsPullerManager();
-
- sp<IStatsCompanionService> mStatsCompanionService = nullptr;
-
- sp<IStatsCompanionService> get_stats_companion_service();
-
- std::unordered_map<int, std::unique_ptr<StatsPuller>> mPullers;
-
-
-
- // internal state of a bucket.
- typedef struct {
- // pull_interval_sec : last_pull_time_sec
- std::pair<uint64_t, uint64_t> timeInfo;
- sp<PullDataReceiver> receiver;
- } ReceiverInfo;
-
- std::map<int, std::vector<ReceiverInfo>> mReceivers;
-
- Mutex mReceiversLock;
-
- long mCurrentPullingInterval;
-
- // for value metrics, it is important for the buckets to be aligned to multiple of smallest
- // bucket size. All pulled metrics start pulling based on this time, so that they can be
- // correctly attributed to the correct buckets. Pulled data attach a timestamp which is the
- // request time.
- const long mPullStartTimeMs;
-
- long get_pull_start_time_ms();
-
- LogEvent parse_pulled_data(String16 data);
-
- static const std::unordered_map<std::string, int> kPullCodes;
+ private:
+ StatsPullerManagerImpl& mPullerManager = StatsPullerManagerImpl::GetInstance();
};
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
new file mode 100644
index 000000000000..07d0b3e2aac5
--- /dev/null
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 DEBUG true
+#include "Log.h"
+
+#include <android/os/IStatsCompanionService.h>
+#include <cutils/log.h>
+#include <algorithm>
+#include <climits>
+#include "CpuTimePerUidFreqPuller.h"
+#include "CpuTimePerUidPuller.h"
+#include "ResourcePowerManagerPuller.h"
+#include "StatsCompanionServicePuller.h"
+#include "StatsPullerManagerImpl.h"
+#include "StatsService.h"
+#include "logd/LogEvent.h"
+#include "statslog.h"
+
+#include <iostream>
+
+using std::make_shared;
+using std::map;
+using std::shared_ptr;
+using std::string;
+using std::vector;
+using std::list;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+StatsPullerManagerImpl::StatsPullerManagerImpl()
+ : mCurrentPullingInterval(LONG_MAX), mPullStartTimeMs(get_pull_start_time_ms()) {
+ shared_ptr<StatsPuller> statsCompanionServicePuller = make_shared<StatsCompanionServicePuller>();
+ shared_ptr<StatsPuller> resourcePowerManagerPuller = make_shared<ResourcePowerManagerPuller>();
+ shared_ptr<StatsPuller> cpuTimePerUidPuller = make_shared<CpuTimePerUidPuller>();
+ shared_ptr<StatsPuller> cpuTimePerUidFreqPuller = make_shared<CpuTimePerUidFreqPuller>();
+
+ mPullers.insert({android::util::KERNEL_WAKELOCK_PULLED,
+ statsCompanionServicePuller});
+ mPullers.insert({android::util::WIFI_BYTES_TRANSFERRED,
+ statsCompanionServicePuller});
+ mPullers.insert({android::util::MOBILE_BYTES_TRANSFERRED,
+ statsCompanionServicePuller});
+ mPullers.insert({android::util::WIFI_BYTES_TRANSFERRED_BY_FG_BG,
+ statsCompanionServicePuller});
+ mPullers.insert({android::util::MOBILE_BYTES_TRANSFERRED_BY_FG_BG,
+ statsCompanionServicePuller});
+ mPullers.insert({android::util::POWER_STATE_PLATFORM_SLEEP_STATE_PULLED,
+ resourcePowerManagerPuller});
+ mPullers.insert({android::util::POWER_STATE_VOTER_PULLED,
+ resourcePowerManagerPuller});
+ mPullers.insert({android::util::POWER_STATE_SUBSYSTEM_SLEEP_STATE_PULLED,
+ resourcePowerManagerPuller});
+ mPullers.insert({android::util::CPU_TIME_PER_UID_PULLED, cpuTimePerUidPuller});
+ mPullers.insert({android::util::CPU_TIME_PER_UID_FREQ_PULLED, cpuTimePerUidFreqPuller});
+
+ mStatsCompanionService = StatsService::getStatsCompanionService();
+}
+
+bool StatsPullerManagerImpl::Pull(int tagId, vector<shared_ptr<LogEvent>>* data) {
+ if (DEBUG) ALOGD("Initiating pulling %d", tagId);
+
+ if (mPullers.find(tagId) != mPullers.end()) {
+ return mPullers.find(tagId)->second->Pull(tagId, data);
+ } else {
+ ALOGD("Unknown tagId %d", tagId);
+ return false; // Return early since we don't know what to pull.
+ }
+}
+
+StatsPullerManagerImpl& StatsPullerManagerImpl::GetInstance() {
+ static StatsPullerManagerImpl instance;
+ return instance;
+}
+
+bool StatsPullerManagerImpl::PullerForMatcherExists(int tagId) {
+ return mPullers.find(tagId) != mPullers.end();
+}
+
+long StatsPullerManagerImpl::get_pull_start_time_ms() {
+ // TODO: limit and align pull intervals to 10min boundaries if this turns out to be a problem
+ return time(nullptr) * 1000;
+}
+
+void StatsPullerManagerImpl::RegisterReceiver(int tagId, wp<PullDataReceiver> receiver,
+ long intervalMs) {
+ AutoMutex _l(mReceiversLock);
+ auto& receivers = mReceivers[tagId];
+ for (auto it = receivers.begin(); it != receivers.end(); it++) {
+ if (it->receiver == receiver) {
+ VLOG("Receiver already registered of %d", (int)receivers.size());
+ return;
+ }
+ }
+ ReceiverInfo receiverInfo;
+ receiverInfo.receiver = receiver;
+ receiverInfo.timeInfo.first = intervalMs;
+ receivers.push_back(receiverInfo);
+
+ // There is only one alarm for all pulled events. So only set it to the smallest denom.
+ if (intervalMs < mCurrentPullingInterval) {
+ VLOG("Updating pulling interval %ld", intervalMs);
+ mCurrentPullingInterval = intervalMs;
+ if (mStatsCompanionService != nullptr) {
+ mStatsCompanionService->setPullingAlarms(mPullStartTimeMs, mCurrentPullingInterval);
+ } else {
+ VLOG("Failed to update pulling interval");
+ }
+ }
+ VLOG("Puller for tagId %d registered of %d", tagId, (int)receivers.size());
+}
+
+void StatsPullerManagerImpl::UnRegisterReceiver(int tagId, wp<PullDataReceiver> receiver) {
+ AutoMutex _l(mReceiversLock);
+ if (mReceivers.find(tagId) == mReceivers.end()) {
+ VLOG("Unknown pull code or no receivers: %d", tagId);
+ return;
+ }
+ auto& receivers = mReceivers.find(tagId)->second;
+ for (auto it = receivers.begin(); it != receivers.end(); it++) {
+ if (receiver == it->receiver) {
+ receivers.erase(it);
+ VLOG("Puller for tagId %d unregistered of %d", tagId, (int)receivers.size());
+ return;
+ }
+ }
+}
+
+void StatsPullerManagerImpl::OnAlarmFired() {
+ AutoMutex _l(mReceiversLock);
+
+ uint64_t currentTimeMs = time(nullptr) * 1000;
+
+ vector<pair<int, vector<ReceiverInfo*>>> needToPull =
+ vector<pair<int, vector<ReceiverInfo*>>>();
+ for (auto& pair : mReceivers) {
+ vector<ReceiverInfo*> receivers = vector<ReceiverInfo*>();
+ if (pair.second.size() != 0) {
+ for (auto& receiverInfo : pair.second) {
+ if (receiverInfo.timeInfo.first + receiverInfo.timeInfo.second > currentTimeMs) {
+ receivers.push_back(&receiverInfo);
+ }
+ }
+ if (receivers.size() > 0) {
+ needToPull.push_back(make_pair(pair.first, receivers));
+ }
+ }
+ }
+
+ for (const auto& pullInfo : needToPull) {
+ vector<shared_ptr<LogEvent>> data;
+ if (Pull(pullInfo.first, &data)) {
+ for (const auto& receiverInfo : pullInfo.second) {
+ sp<PullDataReceiver> receiverPtr = receiverInfo->receiver.promote();
+ if (receiverPtr != nullptr) {
+ receiverPtr->onDataPulled(data);
+ receiverInfo->timeInfo.second = currentTimeMs;
+ } else {
+ VLOG("receiver already gone.");
+ }
+ }
+ }
+ }
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.h b/cmds/statsd/src/external/StatsPullerManagerImpl.h
new file mode 100644
index 000000000000..0b9f21e3217c
--- /dev/null
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/os/IStatsCompanionService.h>
+#include <binder/IServiceManager.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+#include <string>
+#include <unordered_map>
+#include <vector>
+#include <list>
+#include "PullDataReceiver.h"
+#include "StatsPuller.h"
+#include "logd/LogEvent.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class StatsPullerManagerImpl : public virtual RefBase {
+public:
+ static StatsPullerManagerImpl& GetInstance();
+
+ void RegisterReceiver(int tagId, wp<PullDataReceiver> receiver, long intervalMs);
+
+ void UnRegisterReceiver(int tagId, wp<PullDataReceiver> receiver);
+
+ // Verify if we know how to pull for this matcher
+ bool PullerForMatcherExists(int tagId);
+
+ void OnAlarmFired();
+
+ bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data);
+
+private:
+ StatsPullerManagerImpl();
+
+ // use this to update alarm
+ sp<IStatsCompanionService> mStatsCompanionService = nullptr;
+
+ sp<IStatsCompanionService> get_stats_companion_service();
+
+ // mapping from simple matcher tagId to puller
+ std::map<int, std::shared_ptr<StatsPuller>> mPullers;
+
+ typedef struct {
+ // pull_interval_sec : last_pull_time_sec
+ std::pair<uint64_t, uint64_t> timeInfo;
+ wp<PullDataReceiver> receiver;
+ } ReceiverInfo;
+
+ // mapping from simple matcher tagId to receivers
+ std::map<int, std::list<ReceiverInfo>> mReceivers;
+
+ Mutex mReceiversLock;
+
+ long mCurrentPullingInterval;
+
+ // for pulled metrics, it is important for the buckets to be aligned to multiple of smallest
+ // bucket size. All pulled metrics start pulling based on this time, so that they can be
+ // correctly attributed to the correct buckets. Pulled data attach a timestamp which is the
+ // request time.
+ const long mPullStartTimeMs;
+
+ long get_pull_start_time_ms();
+
+ LogEvent parse_pulled_data(String16 data);
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 8220fcb95a8c..913b906986c3 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -35,7 +35,7 @@ LogEvent::LogEvent(log_msg& msg) : mList(msg) {
init(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec, &mList);
}
-LogEvent::LogEvent(int tag) : mList(tag) {
+LogEvent::LogEvent(int tag, uint64_t timestampNs) : mList(tag), mTimestampNs(timestampNs) {
}
LogEvent::~LogEvent() {
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index df75d9f2e0b1..298494049628 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -50,7 +50,7 @@ public:
* any of the values. This constructor is useful for unit-testing since we can't pass in an
* android_log_event_list since there is no copy constructor or assignment operator available.
*/
- explicit LogEvent(int tag);
+ explicit LogEvent(int tag, uint64_t timestampNs);
~LogEvent();
@@ -123,7 +123,9 @@ private:
vector<android_log_list_element> mElements;
// Need a copy of the android_log_event_list so the strings are not cleared.
android_log_event_list mList;
- long mTimestampNs;
+
+ uint64_t mTimestampNs;
+
int mTagId;
};
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index a7402800630e..41b24bc5ebd6 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -1,5 +1,5 @@
/*
- * 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.
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
index 006d74c05b9c..adb691e9568e 100644
--- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
@@ -22,7 +22,6 @@
#include <unordered_map>
#include <vector>
#include "LogMatchingTracker.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
namespace android {
diff --git a/cmds/statsd/src/matchers/LogMatchingTracker.h b/cmds/statsd/src/matchers/LogMatchingTracker.h
index d82da3ba759c..ffbf2488ad2c 100644
--- a/cmds/statsd/src/matchers/LogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/LogMatchingTracker.h
@@ -17,7 +17,6 @@
#ifndef LOG_MATCHING_TRACKER_H
#define LOG_MATCHING_TRACKER_H
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "logd/LogEvent.h"
#include "matchers/matcher_util.h"
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
index e110ec87affc..5dca55ed8d45 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
@@ -23,7 +23,6 @@
#include <unordered_map>
#include <vector>
#include "LogMatchingTracker.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
namespace android {
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 6aa22118b320..1c699e822420 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -16,7 +16,6 @@
#include "Log.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "matchers/LogMatchingTracker.h"
#include "matchers/matcher_util.h"
@@ -113,6 +112,7 @@ bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher, const LogEvent& e
if (err == NO_ERROR && val != NULL) {
if (!(cur.eq_string() == val)) {
allMatched = false;
+ break;
}
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqInt ||
@@ -127,26 +127,30 @@ bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher, const LogEvent& e
if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqInt) {
if (!(val == cur.eq_int())) {
allMatched = false;
+ break;
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLtInt) {
if (!(val < cur.lt_int())) {
allMatched = false;
+ break;
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kGtInt) {
if (!(val > cur.gt_int())) {
allMatched = false;
+ break;
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLteInt) {
if (!(val <= cur.lte_int())) {
allMatched = false;
+ break;
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kGteInt) {
if (!(val >= cur.gte_int())) {
allMatched = false;
+ break;
}
}
}
- break;
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kEqBool) {
// Boolean fields
status_t err = NO_ERROR;
@@ -154,6 +158,7 @@ bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher, const LogEvent& e
if (err == NO_ERROR) {
if (!(cur.eq_bool() == val)) {
allMatched = false;
+ break;
}
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLtFloat ||
@@ -165,10 +170,12 @@ bool matchesSimple(const SimpleLogEntryMatcher& simpleMatcher, const LogEvent& e
if (matcherCase == KeyValueMatcher::ValueMatcherCase::kLtFloat) {
if (!(cur.lt_float() <= val)) {
allMatched = false;
+ break;
}
} else if (matcherCase == KeyValueMatcher::ValueMatcherCase::kGtFloat) {
if (!(cur.gt_float() >= val)) {
allMatched = false;
+ break;
}
}
}
diff --git a/cmds/statsd/src/metrics/CountAnomalyTracker.cpp b/cmds/statsd/src/metrics/CountAnomalyTracker.cpp
deleted file mode 100644
index 7aa748fdeb77..000000000000
--- a/cmds/statsd/src/metrics/CountAnomalyTracker.cpp
+++ /dev/null
@@ -1,129 +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.
- */
-
-#define DEBUG true // STOPSHIP if true
-#include "Log.h"
-
-#include "CountAnomalyTracker.h"
-
-#include <time.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-CountAnomalyTracker::CountAnomalyTracker(const Alert& alert)
- : mAlert(alert),
- mNumPastBuckets(alert.number_of_buckets() > 0 ? alert.number_of_buckets() - 1 : 0),
- mPastBuckets(mNumPastBuckets > 0 ? (new int[mNumPastBuckets]) : nullptr) {
-
- VLOG("CountAnomalyTracker() called");
- if (alert.number_of_buckets() < 1) {
- ALOGE("Cannot create CountAnomalyTracker with %d buckets", alert.number_of_buckets());
- }
- reset(); // initialization
-}
-
-CountAnomalyTracker::~CountAnomalyTracker() {
- VLOG("~CountAnomalyTracker() called");
-}
-
-void CountAnomalyTracker::addPastBucket(int pastBucketCount,
- time_t numberOfBucketsAgo) {
- VLOG("addPastBucket() called.");
- if (numberOfBucketsAgo < 1) {
- ALOGE("Cannot add a past bucket %ld units in past", numberOfBucketsAgo);
- return;
- }
- // If past bucket was ancient, just empty out all past info.
- // This always applies if mNumPastBuckets == 0 (i.e. store no past buckets).
- if (numberOfBucketsAgo > (time_t) mNumPastBuckets) {
- reset();
- return;
- }
-
- // Empty out old mPastBuckets[i] values and update mSumPastCounters.
- for (size_t i = mOldestBucketIndex;
- i < mOldestBucketIndex + numberOfBucketsAgo; i++) {
- mSumPastCounters -= mPastBuckets[index(i)];
- mPastBuckets[index(i)] = 0;
- }
-
- // Replace the oldest bucket with the new bucket we are adding.
- mPastBuckets[mOldestBucketIndex] = pastBucketCount;
- mSumPastCounters += pastBucketCount;
-
- // Advance the oldest bucket index by numberOfBucketsAgo units.
- mOldestBucketIndex = index(mOldestBucketIndex + numberOfBucketsAgo);
-
- // TODO: Once dimensions are added to mSumPastCounters:
- // iterate through mSumPastCounters and remove any entries that are 0.
-}
-
-void CountAnomalyTracker::reset() {
- VLOG("reset() called.");
- for (size_t i = 0; i < mNumPastBuckets; i++) {
- mPastBuckets[i] = 0;
- }
- mSumPastCounters = 0;
- mOldestBucketIndex = 0;
-}
-
-void CountAnomalyTracker::checkAnomaly(int currentCount) {
- // Skip the check if in refractory period.
- if (time(nullptr) < mRefractoryPeriodEndsSec) {
- VLOG("Skipping anomaly check since within refractory period");
- return;
- }
-
- // TODO: Remove these extremely verbose debugging log.
- VLOG("Checking whether %d + %d > %lld",
- mSumPastCounters, currentCount, mAlert.trigger_if_sum_gt());
-
- // Note that this works even if mNumPastBuckets < 1 (since then
- // mSumPastCounters = 0 so the comparison is based only on currentCount).
- if (mAlert.has_trigger_if_sum_gt() &&
- mSumPastCounters + currentCount > mAlert.trigger_if_sum_gt()) {
- declareAnomaly();
- }
-}
-
-void CountAnomalyTracker::declareAnomaly() {
- // TODO(guardrail): Consider guarding against too short refractory periods.
- time_t currTime = time(nullptr);
- mRefractoryPeriodEndsSec = currTime + mAlert.refractory_period_secs();
-
- // TODO: If we had access to the bucket_size_millis, consider calling reset()
- // if (mAlert.refractory_period_secs() > mNumPastBuckets * bucket_size_millis * 1000).
-
- if (mAlert.has_incidentd_details()) {
- const Alert_IncidentdDetails& incident = mAlert.incidentd_details();
- if (incident.has_alert_name()) {
- ALOGW("An anomaly (%s) has occurred! Informing incidentd.",
- incident.alert_name().c_str());
- } else {
- // TODO: Can construct a name based on the criteria (and/or relay the criteria).
- ALOGW("An anomaly (nameless) has occurred! Informing incidentd.");
- }
- // TODO: Send incidentd_details.name and incidentd_details.incidentd_sections to incidentd
- } else {
- ALOGW("An anomaly has occurred! (But informing incidentd not requested.)");
- }
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/metrics/CountAnomalyTracker.h b/cmds/statsd/src/metrics/CountAnomalyTracker.h
deleted file mode 100644
index 79c47d2a6bab..000000000000
--- a/cmds/statsd/src/metrics/CountAnomalyTracker.h
+++ /dev/null
@@ -1,87 +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 COUNT_ANOMALY_TRACKER_H
-#define COUNT_ANOMALY_TRACKER_H
-
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
-
-#include <memory> // unique_ptr
-#include <stdlib.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// TODO: Can probably be used for Count, Value, and Gauge. If so, rename to ValueAnomalyTracker.
-// (caveat: currently, the value cannot be negative. Probably fine for P.)
-class CountAnomalyTracker {
-public:
- CountAnomalyTracker(const Alert& alert);
-
- virtual ~CountAnomalyTracker();
-
-
- // Adds a new past bucket, holding pastBucketCount, and then advances the
- // present by numberOfBucketsAgo buckets (filling any intervening buckets
- // with 0s).
- // Thus, the newly added bucket (which holds pastBucketCount) is stored
- // numberOfBucketsAgo buckets ago.
- void addPastBucket(int pastBucketCount, time_t numberOfBucketsAgo);
-
- // Informs the anomaly tracker of the current bucket's count, so that it can
- // determine whether an anomaly has occurred. This value is not stored.
- void checkAnomaly(int currentCount);
-
-private:
- // statsd_config.proto Alert message that defines this tracker.
- const Alert mAlert;
-
- // 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).
- const size_t mNumPastBuckets;
-
- // Count values for each of the past mNumPastBuckets buckets.
- // TODO: Add dimensions. This parallels the type of CountMetricProducer.mCounter.
- std::unique_ptr<int[]> mPastBuckets;
-
- // Sum over all of mPastBuckets (cached).
- // TODO: Add dimensions. This parallels the type of CountMetricProducer.mCounter.
- // At that point, mSumPastCounters must never contain entries of 0.
- int mSumPastCounters;
-
- // Index of the oldest bucket (i.e. the next bucket to be overwritten).
- size_t mOldestBucketIndex = 0;
-
- // Timestamp that the refractory period (if this anomaly was declared) ends, in seconds.
- // If an anomaly was never declared, set to 0.
- time_t mRefractoryPeriodEndsSec = 0;
-
- void declareAnomaly();
-
- // Calculates the corresponding index within the circular array.
- size_t index(size_t unsafeIndex) {
- return unsafeIndex % mNumPastBuckets;
- }
-
- // Resets all data. For use when all the data gets stale.
- void reset();
-};
-
-} // namespace statsd
-} // namespace os
-} // namespace android
-#endif // COUNT_ANOMALY_TRACKER_H
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 71cb7717d2d7..f9da68e8e5c5 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -17,14 +17,20 @@
#define DEBUG true // STOPSHIP if true
#include "Log.h"
-#include "CountAnomalyTracker.h"
+#include "../anomaly/DiscreteAnomalyTracker.h"
#include "CountMetricProducer.h"
#include "stats_util.h"
#include <limits.h>
#include <stdlib.h>
-using namespace android::util;
+using android::util::FIELD_COUNT_REPEATED;
+using android::util::FIELD_TYPE_BOOL;
+using android::util::FIELD_TYPE_FLOAT;
+using android::util::FIELD_TYPE_INT32;
+using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_MESSAGE;
+using android::util::FIELD_TYPE_STRING;
using android::util::ProtoOutputStream;
using std::map;
using std::string;
@@ -36,7 +42,7 @@ namespace os {
namespace statsd {
// for StatsLogReport
-const int FIELD_ID_METRIC_ID = 1;
+const int FIELD_ID_NAME = 1;
const int FIELD_ID_START_REPORT_NANOS = 2;
const int FIELD_ID_END_REPORT_NANOS = 3;
const int FIELD_ID_COUNT_METRICS = 5;
@@ -57,11 +63,11 @@ const int FIELD_ID_END_BUCKET_NANOS = 2;
const int FIELD_ID_COUNT = 3;
// TODO: add back AnomalyTracker.
+
CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int conditionIndex,
- const sp<ConditionWizard>& wizard)
- // TODO: Pass in the start time from MetricsManager, instead of calling time() here.
- : MetricProducer((time(nullptr) * NANO_SECONDS_IN_A_SECOND), conditionIndex, wizard),
- mMetric(metric) {
+ const sp<ConditionWizard>& wizard,
+ const uint64_t startTimeNs)
+ : MetricProducer(startTimeNs, conditionIndex, wizard), mMetric(metric) {
// TODO: evaluate initial conditions. and set mConditionMet.
if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000 * 1000;
@@ -69,17 +75,6 @@ CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int co
mBucketSizeNs = LLONG_MAX;
}
- mAnomalyTrackers.reserve(metric.alerts_size());
- for (int i = 0; i < metric.alerts_size(); i++) {
- const Alert& alert = metric.alerts(i);
- if (alert.trigger_if_sum_gt() > 0 && alert.number_of_buckets() > 0) {
- mAnomalyTrackers.push_back(std::make_unique<CountAnomalyTracker>(alert));
- } else {
- ALOGW("Ignoring invalid count metric alert: threshold=%lld num_buckets= %d",
- alert.trigger_if_sum_gt(), alert.number_of_buckets());
- }
- }
-
// TODO: use UidMap if uid->pkg_name is required
mDimension.insert(mDimension.begin(), metric.dimension().begin(), metric.dimension().end());
@@ -91,7 +86,7 @@ CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int co
startNewProtoOutputStream(mStartTimeNs);
- VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
+ VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -101,7 +96,7 @@ CountMetricProducer::~CountMetricProducer() {
void CountMetricProducer::startNewProtoOutputStream(long long startTime) {
mProto = std::make_unique<ProtoOutputStream>();
- mProto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_ID, mMetric.metric_id());
+ 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);
}
@@ -110,29 +105,33 @@ void CountMetricProducer::finish() {
}
void CountMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
- VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
+ VLOG("Metric %s onSlicedConditionMayChange", mMetric.name().c_str());
}
-StatsLogReport CountMetricProducer::onDumpReport() {
- long long endTime = time(nullptr) * NANO_SECONDS_IN_A_SECOND;
+std::unique_ptr<std::vector<uint8_t>> CountMetricProducer::onDumpReport() {
+ 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.
flushCounterIfNeeded(endTime);
+ VLOG("metric %s dump report now...", mMetric.name().c_str());
- for (const auto& counter : mPastBucketProtos) {
+ for (const auto& counter : mPastBuckets) {
const HashableDimensionKey& hashableKey = counter.first;
+ VLOG(" dimension key %s", hashableKey.c_str());
auto it = mDimensionKeyMap.find(hashableKey);
if (it == mDimensionKeyMap.end()) {
ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
continue;
}
- long long wrapperToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DATA);
+ long long wrapperToken =
+ mProto->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_ID_DIMENSION);
+ long long dimensionToken =
+ mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DIMENSION);
mProto->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
if (kv.has_value_str()) {
mProto->write(FIELD_TYPE_INT32 | FIELD_ID_VALUE_STR, kv.value_str());
@@ -147,20 +146,18 @@ StatsLogReport CountMetricProducer::onDumpReport() {
}
// Then fill bucket_info (CountBucketInfo).
- for (const auto& proto : counter.second) {
- size_t bufferSize = proto->size();
- char* buffer(new char[bufferSize]);
- size_t pos = 0;
- auto it = proto->data();
- while (it.readBuffer() != NULL) {
- size_t toRead = it.currentToRead();
- std::memcpy(&buffer[pos], it.readBuffer(), toRead);
- pos += toRead;
- it.rp()->move(toRead);
- }
- mProto->write(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION, buffer, bufferSize);
+ 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);
+ VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs,
+ (long long)bucket.mBucketEndNs, (long long)bucket.mCount);
}
-
mProto->end(wrapperToken);
}
@@ -168,31 +165,20 @@ StatsLogReport CountMetricProducer::onDumpReport() {
mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
(long long)mCurrentBucketStartTimeNs);
- size_t bufferSize = mProto->size();
- VLOG("metric %lld dump report now...", mMetric.metric_id());
- std::unique_ptr<uint8_t[]> buffer(new 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);
- }
+ VLOG("metric %s dump report now...", mMetric.name().c_str());
+ std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
startNewProtoOutputStream(endTime);
- mPastBucketProtos.clear();
+ mPastBuckets.clear();
mByteSize = 0;
- // TODO: Once we migrate all MetricProducers to use ProtoOutputStream, we should return this:
- // return std::move(buffer);
- return StatsLogReport();
+ return buffer;
// TODO: Clear mDimensionKeyMap once the report is dumped.
}
void CountMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
- VLOG("Metric %lld onConditionChanged", mMetric.metric_id());
+ VLOG("Metric %s onConditionChanged", mMetric.name().c_str());
mCondition = conditionMet;
}
@@ -208,25 +194,19 @@ void CountMetricProducer::onMatchedLogEventInternal(
return;
}
- auto it = mCurrentSlicedCounter.find(eventKey);
+ auto it = mCurrentSlicedCounter->find(eventKey);
- if (it == mCurrentSlicedCounter.end()) {
+ if (it == mCurrentSlicedCounter->end()) {
// create a counter for the new key
- mCurrentSlicedCounter[eventKey] = 1;
-
+ (*mCurrentSlicedCounter)[eventKey] = 1;
} else {
// increment the existing value
auto& count = it->second;
count++;
}
- // TODO: Re-add anomaly detection (similar to):
- // for (auto& tracker : mAnomalyTrackers) {
- // tracker->checkAnomaly(mCounter);
- // }
-
- VLOG("metric %lld %s->%d", mMetric.metric_id(), eventKey.c_str(),
- mCurrentSlicedCounter[eventKey]);
+ VLOG("metric %s %s->%d", mMetric.name().c_str(), eventKey.c_str(),
+ (*mCurrentSlicedCounter)[eventKey]);
}
// When a new matched event comes in, we check if event falls into the current
@@ -237,34 +217,32 @@ void CountMetricProducer::flushCounterIfNeeded(const uint64_t eventTimeNs) {
}
// adjust the bucket start time
- int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
-
- for (const auto& counter : mCurrentSlicedCounter) {
- unique_ptr<ProtoOutputStream> proto = make_unique<ProtoOutputStream>();
- proto->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
- (long long)mCurrentBucketStartTimeNs);
- proto->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
- (long long)mCurrentBucketStartTimeNs + mBucketSizeNs);
- proto->write(FIELD_TYPE_INT64 | FIELD_ID_COUNT, (long long)counter.second);
-
- auto& bucketList = mPastBucketProtos[counter.first];
- bucketList.push_back(std::move(proto));
- mByteSize += proto->size();
-
- VLOG("metric %lld, dump key value: %s -> %d", mMetric.metric_id(), counter.first.c_str(),
+ // TODO: This (and addPastBucket to which it goes) doesn't really need to be an int64.
+ uint64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
+
+ CountBucket info;
+ info.mBucketStartNs = mCurrentBucketStartTimeNs;
+ info.mBucketEndNs = mCurrentBucketStartTimeNs + mBucketSizeNs;
+ for (const auto& counter : *mCurrentSlicedCounter) {
+ info.mCount = counter.second;
+ auto& bucketList = mPastBuckets[counter.first];
+ bucketList.push_back(info);
+ VLOG("metric %s, dump key value: %s -> %d", mMetric.name().c_str(), counter.first.c_str(),
counter.second);
+ mByteSize += sizeof(info);
}
- // TODO: Re-add anomaly detection (similar to):
- // for (auto& tracker : mAnomalyTrackers) {
- // tracker->addPastBucket(mCounter, numBucketsForward);
- //}
+ for (auto& tracker : mAnomalyTrackers) {
+ tracker->addOrUpdateBucket(mCurrentSlicedCounter, mCurrentBucketNum);
+ tracker->declareAndDeclareAnomaly();
+ }
- // Reset counters
- mCurrentSlicedCounter.clear();
+ // Reset counters (do not clear, since the old one is still referenced in mAnomalyTrackers).
+ mCurrentSlicedCounter = std::make_shared<DimToValMap>();
mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
- VLOG("metric %lld: new bucket start time: %lld", mMetric.metric_id(),
+ mCurrentBucketNum += numBucketsForward;
+ VLOG("metric %s: new bucket start time: %lld", mMetric.name().c_str(),
(long long)mCurrentBucketStartTimeNs);
}
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 473a4ba4f428..b7e480c4e78d 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -20,25 +20,29 @@
#include <unordered_map>
#include <android/util/ProtoOutputStream.h>
+#include <gtest/gtest_prod.h>
#include "../condition/ConditionTracker.h"
#include "../matchers/matcher_util.h"
-#include "CountAnomalyTracker.h"
+#include "../anomaly/DiscreteAnomalyTracker.h"
#include "MetricProducer.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "stats_util.h"
-using namespace std;
-
namespace android {
namespace os {
namespace statsd {
+struct CountBucket {
+ int64_t mBucketStartNs;
+ int64_t mBucketEndNs;
+ int64_t mCount;
+};
+
class CountMetricProducer : public MetricProducer {
public:
// TODO: Pass in the start time from MetricsManager, it should be consistent for all metrics.
CountMetricProducer(const CountMetric& countMetric, const int conditionIndex,
- const sp<ConditionWizard>& wizard);
+ const sp<ConditionWizard>& wizard, const uint64_t startTimeNs);
virtual ~CountMetricProducer();
@@ -46,7 +50,8 @@ public:
void finish() override;
- StatsLogReport onDumpReport() 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;
@@ -63,26 +68,26 @@ protected:
bool condition, const LogEvent& event,
bool scheduledPull) override;
+ void startNewProtoOutputStream(long long timestamp) override;
+
private:
const CountMetric mMetric;
- std::unordered_map<HashableDimensionKey,
- std::vector<unique_ptr<android::util::ProtoOutputStream>>> mPastBucketProtos;
+ // TODO: Add a lock to mPastBuckets.
+ std::unordered_map<HashableDimensionKey, std::vector<CountBucket>> mPastBuckets;
size_t mByteSize;
// The current bucket.
- std::unordered_map<HashableDimensionKey, int> mCurrentSlicedCounter;
+ std::shared_ptr<DimToValMap> mCurrentSlicedCounter = std::make_shared<DimToValMap>();
- vector<unique_ptr<CountAnomalyTracker>> mAnomalyTrackers;
+ vector<std::unique_ptr<DiscreteAnomalyTracker>> mAnomalyTrackers;
void flushCounterIfNeeded(const uint64_t newEventTime);
- std::unique_ptr<android::util::ProtoOutputStream> mProto;
-
- long long mProtoToken;
-
- void startNewProtoOutputStream(long long timestamp);
+ FRIEND_TEST(CountMetricProducerTest, TestNonDimensionalEvents);
+ FRIEND_TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition);
+ FRIEND_TEST(CountMetricProducerTest, TestEventsWithSlicedCondition);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 340f503fd651..de6f3653f7ad 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -23,6 +23,14 @@
#include <limits.h>
#include <stdlib.h>
+using android::util::FIELD_COUNT_REPEATED;
+using android::util::FIELD_TYPE_BOOL;
+using android::util::FIELD_TYPE_FLOAT;
+using android::util::FIELD_TYPE_INT32;
+using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_MESSAGE;
+using android::util::FIELD_TYPE_STRING;
+using android::util::ProtoOutputStream;
using std::string;
using std::unordered_map;
using std::vector;
@@ -31,13 +39,34 @@ namespace android {
namespace os {
namespace statsd {
+// for StatsLogReport
+const int FIELD_ID_NAME = 1;
+const int FIELD_ID_START_REPORT_NANOS = 2;
+const int FIELD_ID_END_REPORT_NANOS = 3;
+const int FIELD_ID_DURATION_METRICS = 6;
+// for DurationMetricDataWrapper
+const int FIELD_ID_DATA = 1;
+// for DurationMetricData
+const int FIELD_ID_DIMENSION = 1;
+const int FIELD_ID_BUCKET_INFO = 2;
+// for KeyValuePair
+const int FIELD_ID_KEY = 1;
+const int FIELD_ID_VALUE_STR = 2;
+const int FIELD_ID_VALUE_INT = 3;
+const int FIELD_ID_VALUE_BOOL = 4;
+const int FIELD_ID_VALUE_FLOAT = 5;
+// for DurationBucketInfo
+const int FIELD_ID_START_BUCKET_NANOS = 1;
+const int FIELD_ID_END_BUCKET_NANOS = 2;
+const int FIELD_ID_DURATION = 3;
+
DurationMetricProducer::DurationMetricProducer(const DurationMetric& metric,
const int conditionIndex, const size_t startIndex,
const size_t stopIndex, const size_t stopAllIndex,
const sp<ConditionWizard>& wizard,
- const vector<KeyMatcher>& internalDimension)
- // TODO: Pass in the start time from MetricsManager, instead of calling time() here.
- : MetricProducer(time(nullptr) * NANO_SECONDS_IN_A_SECOND, conditionIndex, wizard),
+ const vector<KeyMatcher>& internalDimension,
+ const uint64_t startTimeNs)
+ : MetricProducer(startTimeNs, conditionIndex, wizard),
mMetric(metric),
mStartIndex(startIndex),
mStopIndex(stopIndex),
@@ -61,7 +90,9 @@ DurationMetricProducer::DurationMetricProducer(const DurationMetric& metric,
mConditionSliced = true;
}
- VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
+ startNewProtoOutputStream(mStartTimeNs);
+
+ VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -69,8 +100,15 @@ DurationMetricProducer::~DurationMetricProducer() {
VLOG("~DurationMetric() called");
}
+void DurationMetricProducer::startNewProtoOutputStream(long long startTime) {
+ mProto = std::make_unique<ProtoOutputStream>();
+ mProto->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
+ mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DURATION_METRICS);
+}
+
unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker(
- vector<DurationBucketInfo>& bucket) {
+ vector<DurationBucket>& bucket) {
switch (mMetric.type()) {
case DurationMetric_AggregationType_DURATION_SUM:
return make_unique<OringDurationTracker>(mWizard, mConditionTrackerIndex,
@@ -89,7 +127,7 @@ void DurationMetricProducer::finish() {
}
void DurationMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
- VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
+ VLOG("Metric %s onSlicedConditionMayChange", mMetric.name().c_str());
// Now for each of the on-going event, check if the condition has changed for them.
flushIfNeeded(eventTime);
for (auto& pair : mCurrentSlicedDuration) {
@@ -98,7 +136,7 @@ void DurationMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime
}
void DurationMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
- VLOG("Metric %lld onConditionChanged", mMetric.metric_id());
+ VLOG("Metric %s onConditionChanged", mMetric.name().c_str());
mCondition = conditionMet;
// TODO: need to populate the condition change time from the event which triggers the condition
// change, instead of using current time.
@@ -123,30 +161,71 @@ static void addDurationBucketsToReport(StatsLogReport_DurationMetricDataWrapper&
}
}
-StatsLogReport DurationMetricProducer::onDumpReport() {
- VLOG("metric %lld dump report now...", mMetric.metric_id());
- StatsLogReport report;
- report.set_metric_id(mMetric.metric_id());
- report.set_start_report_nanos(mStartTimeNs);
+std::unique_ptr<std::vector<uint8_t>> DurationMetricProducer::onDumpReport() {
+ 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(time(nullptr) * NANO_SECONDS_IN_A_SECOND);
- report.set_end_report_nanos(mCurrentBucketStartTimeNs);
+ flushIfNeeded(endTime);
+ VLOG("metric %s dump report now...", mMetric.name().c_str());
- StatsLogReport_DurationMetricDataWrapper* wrapper = report.mutable_duration_metrics();
for (const auto& pair : mPastBuckets) {
const HashableDimensionKey& hashableKey = pair.first;
+ VLOG(" dimension key %s", hashableKey.c_str());
auto it = mDimensionKeyMap.find(hashableKey);
if (it == mDimensionKeyMap.end()) {
ALOGW("Dimension key %s not found?!?! skip...", hashableKey.c_str());
continue;
}
- VLOG(" dimension key %s", hashableKey.c_str());
- addDurationBucketsToReport(*wrapper, it->second, pair.second);
+ long long wrapperToken =
+ mProto->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());
+ if (kv.has_value_str()) {
+ mProto->write(FIELD_TYPE_INT32 | 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());
+ } else if (kv.has_value_bool()) {
+ mProto->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());
+ }
+ mProto->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);
+ VLOG("\t bucket [%lld - %lld] duration: %lld", (long long)bucket.mBucketStartNs,
+ (long long)bucket.mBucketEndNs, (long long)bucket.mDuration);
+ }
+
+ mProto->end(wrapperToken);
}
- return report;
-};
+
+ mProto->end(mProtoToken);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
+ (long long)mCurrentBucketStartTimeNs);
+
+ std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
+
+ startNewProtoOutputStream(endTime);
+ mPastBuckets.clear();
+
+ return buffer;
+}
void DurationMetricProducer::flushIfNeeded(uint64_t eventTime) {
if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTime) {
@@ -154,10 +233,12 @@ void DurationMetricProducer::flushIfNeeded(uint64_t eventTime) {
}
VLOG("flushing...........");
- for (auto it = mCurrentSlicedDuration.begin(); it != mCurrentSlicedDuration.end(); ++it) {
+ for (auto it = mCurrentSlicedDuration.begin(); it != mCurrentSlicedDuration.end();) {
if (it->second->flushIfNeeded(eventTime)) {
VLOG("erase bucket for key %s", it->first.c_str());
- mCurrentSlicedDuration.erase(it);
+ it = mCurrentSlicedDuration.erase(it);
+ } else {
+ ++it;
}
}
@@ -188,17 +269,17 @@ void DurationMetricProducer::onMatchedLogEventInternal(
if (matcherIndex == mStartIndex) {
it->second->noteStart(atomKey, condition, event.GetTimestampNs(), conditionKeys);
-
} else if (matcherIndex == mStopIndex) {
it->second->noteStop(atomKey, event.GetTimestampNs());
}
}
size_t DurationMetricProducer::byteSize() {
-// TODO: return actual proto size when ProtoOutputStream is ready for use for
-// DurationMetricsProducer.
-// return mProto->size();
- return 0;
+ size_t totalSize = 0;
+ for (const auto& pair : mPastBuckets) {
+ totalSize += pair.second.size() * kBucketSize;
+ }
+ return totalSize;
}
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index febf25d45cc2..eea00454d5e6 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -19,13 +19,13 @@
#include <unordered_map>
+#include <android/util/ProtoOutputStream.h>
#include "../condition/ConditionTracker.h"
#include "../matchers/matcher_util.h"
#include "MetricProducer.h"
#include "duration_helper/DurationTracker.h"
#include "duration_helper/MaxDurationTracker.h"
#include "duration_helper/OringDurationTracker.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "stats_util.h"
@@ -40,7 +40,7 @@ public:
DurationMetricProducer(const DurationMetric& durationMetric, const int conditionIndex,
const size_t startIndex, const size_t stopIndex,
const size_t stopAllIndex, const sp<ConditionWizard>& wizard,
- const vector<KeyMatcher>& internalDimension);
+ const vector<KeyMatcher>& internalDimension, const uint64_t startTimeNs);
virtual ~DurationMetricProducer();
@@ -48,7 +48,8 @@ public:
void finish() override;
- StatsLogReport onDumpReport() 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;
@@ -65,6 +66,8 @@ protected:
bool condition, const LogEvent& event,
bool scheduledPull) override;
+ void startNewProtoOutputStream(long long timestamp) override;
+
private:
const DurationMetric mMetric;
@@ -81,7 +84,8 @@ private:
const vector<KeyMatcher> mInternalDimension;
// Save the past buckets and we can clear when the StatsLogReport is dumped.
- std::unordered_map<HashableDimensionKey, std::vector<DurationBucketInfo>> mPastBuckets;
+ // TODO: Add a lock to mPastBuckets.
+ std::unordered_map<HashableDimensionKey, std::vector<DurationBucket>> mPastBuckets;
// The current bucket.
std::unordered_map<HashableDimensionKey, std::unique_ptr<DurationTracker>>
@@ -89,9 +93,11 @@ private:
void flushDurationIfNeeded(const uint64_t newEventTime);
- std::unique_ptr<DurationTracker> createDurationTracker(std::vector<DurationBucketInfo>& bucket);
+ std::unique_ptr<DurationTracker> createDurationTracker(std::vector<DurationBucket>& bucket);
void flushIfNeeded(uint64_t timestamp);
+
+ static const size_t kBucketSize = sizeof(DurationBucket{});
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index cbae1d343f03..74ba40ba20ae 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -23,7 +23,13 @@
#include <limits.h>
#include <stdlib.h>
-using namespace android::util;
+using android::util::FIELD_COUNT_REPEATED;
+using android::util::FIELD_TYPE_BOOL;
+using android::util::FIELD_TYPE_FLOAT;
+using android::util::FIELD_TYPE_INT32;
+using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_STRING;
+using android::util::FIELD_TYPE_MESSAGE;
using android::util::ProtoOutputStream;
using std::map;
using std::string;
@@ -35,7 +41,7 @@ namespace os {
namespace statsd {
// for StatsLogReport
-const int FIELD_ID_METRIC_ID = 1;
+const int FIELD_ID_NAME = 1;
const int FIELD_ID_START_REPORT_NANOS = 2;
const int FIELD_ID_END_REPORT_NANOS = 3;
const int FIELD_ID_EVENT_METRICS = 4;
@@ -43,13 +49,12 @@ const int FIELD_ID_EVENT_METRICS = 4;
const int FIELD_ID_DATA = 1;
// for EventMetricData
const int FIELD_ID_TIMESTAMP_NANOS = 1;
-const int FIELD_ID_STATS_EVENTS = 2;
+const int FIELD_ID_ATOMS = 2;
EventMetricProducer::EventMetricProducer(const EventMetric& metric, const int conditionIndex,
- const sp<ConditionWizard>& wizard)
- // TODO: Pass in the start time from MetricsManager, instead of calling time() here.
- : MetricProducer((time(nullptr) * NANO_SECONDS_IN_A_SECOND), conditionIndex, wizard),
- mMetric(metric) {
+ const sp<ConditionWizard>& wizard,
+ const uint64_t startTimeNs)
+ : MetricProducer(startTimeNs, conditionIndex, wizard), mMetric(metric) {
if (metric.links().size() > 0) {
mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
metric.links().end());
@@ -58,7 +63,7 @@ EventMetricProducer::EventMetricProducer(const EventMetric& metric, const int co
startNewProtoOutputStream(mStartTimeNs);
- VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
+ VLOG("metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -70,7 +75,7 @@ void EventMetricProducer::startNewProtoOutputStream(long long startTime) {
mProto = std::make_unique<ProtoOutputStream>();
// TODO: We need to auto-generate the field IDs for StatsLogReport, EventMetricData,
// and StatsEvent.
- mProto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_ID, mMetric.metric_id());
+ 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);
}
@@ -81,32 +86,23 @@ void EventMetricProducer::finish() {
void EventMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
}
-StatsLogReport EventMetricProducer::onDumpReport() {
- long long endTime = time(nullptr) * NANO_SECONDS_IN_A_SECOND;
+std::unique_ptr<std::vector<uint8_t>> EventMetricProducer::onDumpReport() {
+ long long endTime = time(nullptr) * NS_PER_SEC;
mProto->end(mProtoToken);
mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, endTime);
size_t bufferSize = mProto->size();
- VLOG("metric %lld dump report now... proto size: %zu ", mMetric.metric_id(), bufferSize);
- std::unique_ptr<uint8_t[]> buffer(new 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);
- }
+ VLOG("metric %s dump report now... proto size: %zu ", mMetric.name().c_str(), bufferSize);
+ std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
startNewProtoOutputStream(endTime);
+ mByteSize = 0;
- // TODO: Once we migrate all MetricProducers to use ProtoOutputStream, we should return this:
- // return std::move(buffer);
- return StatsLogReport();
+ return buffer;
}
void EventMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
- VLOG("Metric %lld onConditionChanged", mMetric.metric_id());
+ VLOG("Metric %s onConditionChanged", mMetric.name().c_str());
mCondition = conditionMet;
}
@@ -114,21 +110,22 @@ void EventMetricProducer::onMatchedLogEventInternal(
const size_t matcherIndex, const HashableDimensionKey& eventKey,
const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition,
const LogEvent& event, bool scheduledPull) {
-
if (!condition) {
return;
}
- long long wrapperToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DATA);
+ long long wrapperToken =
+ mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
mProto->write(FIELD_TYPE_INT64 | FIELD_ID_TIMESTAMP_NANOS, (long long)event.GetTimestampNs());
- long long eventToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_STATS_EVENTS);
+ long long eventToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOMS);
event.ToProto(*mProto);
mProto->end(eventToken);
mProto->end(wrapperToken);
+ // TODO: Find a proper way to derive the size of incoming LogEvent.
}
size_t EventMetricProducer::byteSize() {
- return mProto->size();
+ return mByteSize;
}
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 7dd0e38a0533..77406216f421 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -20,10 +20,10 @@
#include <unordered_map>
#include <android/util/ProtoOutputStream.h>
+
#include "../condition/ConditionTracker.h"
#include "../matchers/matcher_util.h"
#include "MetricProducer.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "stats_util.h"
@@ -35,19 +35,21 @@ class EventMetricProducer : public MetricProducer {
public:
// TODO: Pass in the start time from MetricsManager, it should be consistent for all metrics.
EventMetricProducer(const EventMetric& eventMetric, const int conditionIndex,
- const sp<ConditionWizard>& wizard);
+ const sp<ConditionWizard>& wizard, const uint64_t startTimeNs);
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;
+ bool condition, const LogEvent& event,
+ bool scheduledPull) override;
void onConditionChanged(const bool conditionMet, const uint64_t eventTime) override;
void finish() override;
- StatsLogReport onDumpReport() 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;
@@ -58,14 +60,13 @@ public:
// TODO: Implement this later.
virtual void notifyAppRemoved(const string& apk, const int uid) override{};
+protected:
+ void startNewProtoOutputStream(long long timestamp) override;
+
private:
const EventMetric mMetric;
- std::unique_ptr<android::util::ProtoOutputStream> mProto;
-
- long long mProtoToken;
-
- void startNewProtoOutputStream(long long timestamp);
+ size_t mByteSize;
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
new file mode 100644
index 000000000000..ed18f897943e
--- /dev/null
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -0,0 +1,298 @@
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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 DEBUG true // STOPSHIP if true
+#include "Log.h"
+
+#include "GaugeMetricProducer.h"
+#include "stats_util.h"
+
+#include <cutils/log.h>
+#include <limits.h>
+#include <stdlib.h>
+
+using android::util::FIELD_COUNT_REPEATED;
+using android::util::FIELD_TYPE_BOOL;
+using android::util::FIELD_TYPE_FLOAT;
+using android::util::FIELD_TYPE_INT32;
+using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_MESSAGE;
+using android::util::FIELD_TYPE_STRING;
+using android::util::ProtoOutputStream;
+using std::map;
+using std::string;
+using std::unordered_map;
+using std::vector;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// for StatsLogReport
+const int FIELD_ID_NAME = 1;
+const int FIELD_ID_START_REPORT_NANOS = 2;
+const int FIELD_ID_END_REPORT_NANOS = 3;
+const int FIELD_ID_GAUGE_METRICS = 8;
+// for GaugeMetricDataWrapper
+const int FIELD_ID_DATA = 1;
+// for GaugeMetricData
+const int FIELD_ID_DIMENSION = 1;
+const int FIELD_ID_BUCKET_INFO = 2;
+// for KeyValuePair
+const int FIELD_ID_KEY = 1;
+const int FIELD_ID_VALUE_STR = 2;
+const int FIELD_ID_VALUE_INT = 3;
+const int FIELD_ID_VALUE_BOOL = 4;
+const int FIELD_ID_VALUE_FLOAT = 5;
+// for GaugeBucketInfo
+const int FIELD_ID_START_BUCKET_NANOS = 1;
+const int FIELD_ID_END_BUCKET_NANOS = 2;
+const int FIELD_ID_GAUGE = 3;
+
+GaugeMetricProducer::GaugeMetricProducer(const GaugeMetric& metric, const int conditionIndex,
+ const sp<ConditionWizard>& wizard, const int pullTagId)
+ : MetricProducer((time(nullptr) * NS_PER_SEC), conditionIndex, wizard),
+ mMetric(metric),
+ mPullTagId(pullTagId) {
+ if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
+ mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000 * 1000;
+ } else {
+ mBucketSizeNs = kDefaultGaugemBucketSizeNs;
+ }
+
+ // TODO: use UidMap if uid->pkg_name is required
+ mDimension.insert(mDimension.begin(), metric.dimension().begin(), metric.dimension().end());
+
+ if (metric.links().size() > 0) {
+ mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
+ metric.links().end());
+ mConditionSliced = true;
+ }
+
+ // Kicks off the puller immediately.
+ if (mPullTagId != -1) {
+ mStatsPullerManager.RegisterReceiver(mPullTagId, this,
+ 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");
+}
+
+void GaugeMetricProducer::startNewProtoOutputStream(long long startTime) {
+ mProto = std::make_unique<ProtoOutputStream>();
+ mProto->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
+ mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_GAUGE_METRICS);
+}
+
+void GaugeMetricProducer::finish() {
+}
+
+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.
+ flushGaugeIfNeededLocked(time(nullptr) * NS_PER_SEC);
+
+ for (const auto& pair : mPastBuckets) {
+ const HashableDimensionKey& hashableKey = pair.first;
+ auto it = mDimensionKeyMap.find(hashableKey);
+ if (it == mDimensionKeyMap.end()) {
+ ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
+ continue;
+ }
+
+ VLOG(" dimension key %s", hashableKey.c_str());
+ long long wrapperToken =
+ mProto->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());
+ if (kv.has_value_str()) {
+ mProto->write(FIELD_TYPE_INT32 | 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());
+ } else if (kv.has_value_bool()) {
+ mProto->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());
+ }
+ mProto->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);
+ VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs,
+ (long long)bucket.mBucketEndNs, (long long)bucket.mGauge);
+ }
+ mProto->end(wrapperToken);
+ }
+ mProto->end(mProtoToken);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
+ (long long)mCurrentBucketStartTimeNs);
+
+ std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
+
+ startNewProtoOutputStream(time(nullptr) * NS_PER_SEC);
+ mPastBuckets.clear();
+ mByteSize = 0;
+
+ return buffer;
+
+ // TODO: Clear mDimensionKeyMap once the report is dumped.
+}
+
+void GaugeMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
+ AutoMutex _l(mLock);
+ VLOG("Metric %s onConditionChanged", mMetric.name().c_str());
+ mCondition = conditionMet;
+
+ // Push mode. Nothing to do.
+ if (mPullTagId == -1) {
+ return;
+ }
+ // If (1) the condition is not met or (2) we already pulled the gauge metric in the current
+ // bucket, do not pull gauge again.
+ if (!mCondition || mCurrentSlicedBucket.size() > 0) {
+ return;
+ }
+ vector<std::shared_ptr<LogEvent>> allData;
+ if (!mStatsPullerManager.Pull(mPullTagId, &allData)) {
+ ALOGE("Stats puller failed for tag: %d", mPullTagId);
+ return;
+ }
+ for (const auto& data : allData) {
+ onMatchedLogEvent(0, *data, false /*scheduledPull*/);
+ }
+ flushGaugeIfNeededLocked(eventTime);
+}
+
+void GaugeMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
+ VLOG("Metric %s onSlicedConditionMayChange", mMetric.name().c_str());
+}
+
+long GaugeMetricProducer::getGauge(const LogEvent& event) {
+ status_t err = NO_ERROR;
+ long val = event.GetLong(mMetric.gauge_field(), &err);
+ if (err == NO_ERROR) {
+ return val;
+ } else {
+ VLOG("Can't find value in message.");
+ return -1;
+ }
+}
+
+void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
+ AutoMutex mutex(mLock);
+ if (allData.size() == 0) {
+ return;
+ }
+ for (const auto& data : allData) {
+ onMatchedLogEvent(0, *data, true /*scheduledPull*/);
+ }
+ uint64_t eventTime = allData.at(0)->GetTimestampNs();
+ flushGaugeIfNeededLocked(eventTime);
+}
+
+void GaugeMetricProducer::onMatchedLogEventInternal(
+ const size_t matcherIndex, const HashableDimensionKey& eventKey,
+ const map<string, HashableDimensionKey>& conditionKey, bool condition,
+ const LogEvent& event, bool scheduledPull) {
+ if (condition == false) {
+ return;
+ }
+ 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;
+ }
+
+ // For gauge metric, we just simply use the latest guage in the given bucket.
+ const long gauge = getGauge(event);
+ if (gauge < 0) {
+ VLOG("Invalid gauge at event Time: %lld", (long long)eventTimeNs);
+ return;
+ }
+ mCurrentSlicedBucket[eventKey] = gauge;
+ if (mPullTagId < 0) {
+ flushGaugeIfNeededLocked(eventTimeNs);
+ }
+}
+
+// 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.
+// if data is pushed, onMatchedLogEvent will only be called through onConditionChanged() inside
+// the GaugeMetricProducer while holding the lock.
+void GaugeMetricProducer::flushGaugeIfNeededLocked(const uint64_t eventTimeNs) {
+ if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTimeNs) {
+ VLOG("event time is %lld, less than next bucket start time %lld", (long long)eventTimeNs,
+ (long long)(mCurrentBucketStartTimeNs + mBucketSizeNs));
+ return;
+ }
+
+ // Adjusts the bucket start time
+ int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
+
+ GaugeBucket info;
+ info.mBucketStartNs = mCurrentBucketStartTimeNs;
+ info.mBucketEndNs = mCurrentBucketStartTimeNs + mBucketSizeNs;
+
+ for (const auto& slice : mCurrentSlicedBucket) {
+ info.mGauge = slice.second;
+ auto& bucketList = mPastBuckets[slice.first];
+ bucketList.push_back(info);
+ mByteSize += sizeof(info);
+
+ VLOG("gauge metric %s, dump key value: %s -> %ld", mMetric.name().c_str(),
+ slice.first.c_str(), slice.second);
+ }
+ // Reset counters
+ mCurrentSlicedBucket.clear();
+
+ mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
+ VLOG("metric %s: new bucket start time: %lld", mMetric.name().c_str(),
+ (long long)mCurrentBucketStartTimeNs);
+}
+
+size_t GaugeMetricProducer::byteSize() {
+ return mByteSize;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
new file mode 100644
index 000000000000..f9e4deb9f04e
--- /dev/null
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <unordered_map>
+
+#include <android/util/ProtoOutputStream.h>
+#include "../condition/ConditionTracker.h"
+#include "../external/PullDataReceiver.h"
+#include "../external/StatsPullerManager.h"
+#include "../matchers/matcher_util.h"
+#include "MetricProducer.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "stats_util.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+struct GaugeBucket {
+ int64_t mBucketStartNs;
+ int64_t mBucketEndNs;
+ int64_t mGauge;
+};
+
+// This gauge metric producer first register the puller to automatically pull the gauge at the
+// beginning of each bucket. If the condition is met, insert it to the bucket info. Otherwise
+// proactively pull the gauge when the condition is changed to be true. Therefore, the gauge metric
+// producer always reports the guage at the earliest time of the bucket when the condition is met.
+class GaugeMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver {
+public:
+ // TODO: Pass in the start time from MetricsManager, it should be consistent
+ // for all metrics.
+ GaugeMetricProducer(const GaugeMetric& countMetric, const int conditionIndex,
+ const sp<ConditionWizard>& wizard, const int pullTagId);
+
+ virtual ~GaugeMetricProducer();
+
+ // 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;
+
+ // TODO: Pass a timestamp as a parameter in onDumpReport.
+ std::unique_ptr<std::vector<uint8_t>> onDumpReport() override;
+
+ size_t byteSize() override;
+
+ // TODO: Implement this later.
+ virtual void notifyAppUpgrade(const string& apk, const int uid, const int 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;
+
+private:
+ // The default bucket size for gauge metric is 1 second.
+ static const uint64_t kDefaultGaugemBucketSizeNs = 1000 * 1000 * 1000;
+ const GaugeMetric mMetric;
+
+ StatsPullerManager mStatsPullerManager;
+ // tagId for pulled data. -1 if this is not pulled
+ const int mPullTagId;
+
+ Mutex mLock;
+
+ // Save the past buckets and we can clear when the StatsLogReport is dumped.
+ // TODO: Add a lock to mPastBuckets.
+ std::unordered_map<HashableDimensionKey, std::vector<GaugeBucket>> mPastBuckets;
+
+ // The current bucket.
+ std::unordered_map<HashableDimensionKey, long> mCurrentSlicedBucket;
+
+ void flushGaugeIfNeededLocked(const uint64_t newEventTime);
+
+ long getGauge(const LogEvent& event);
+
+ size_t mByteSize;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 535f4a276fe1..62fb632faaaf 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -64,6 +64,23 @@ void MetricProducer::onMatchedLogEvent(const size_t matcherIndex, const LogEvent
scheduledPull);
}
+std::unique_ptr<std::vector<uint8_t>> MetricProducer::serializeProto() {
+ 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;
+}
+
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 3b117ec4e307..c0930e381ce3 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -23,7 +23,6 @@
#include <log/logprint.h>
#include <utils/RefBase.h>
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
namespace android {
namespace os {
@@ -39,7 +38,9 @@ public:
const sp<ConditionWizard>& wizard)
: mStartTimeNs(startTimeNs),
mCurrentBucketStartTimeNs(startTimeNs),
+ mCurrentBucketNum(0),
mCondition(conditionIndex >= 0 ? false : true),
+ mConditionSliced(false),
mWizard(wizard),
mConditionTrackerIndex(conditionIndex) {
// reuse the same map for non-sliced metrics too. this way, we avoid too many if-else.
@@ -58,7 +59,9 @@ public:
// coming. MetricProducer should do the clean up, and dump existing data to dropbox.
virtual void finish() = 0;
- virtual StatsLogReport onDumpReport() = 0;
+ // TODO: Pass a timestamp as a parameter in onDumpReport and update all its
+ // implementations.
+ virtual std::unique_ptr<std::vector<uint8_t>> onDumpReport() = 0;
virtual bool isConditionSliced() const {
return mConditionSliced;
@@ -71,6 +74,8 @@ protected:
uint64_t mCurrentBucketStartTimeNs;
+ uint64_t mCurrentBucketNum;
+
int64_t mBucketSizeNs;
bool mCondition;
@@ -108,6 +113,14 @@ protected:
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;
+
+ long long mProtoToken;
+
+ virtual void startNewProtoOutputStream(long long timestamp) = 0;
+
+ std::unique_ptr<std::vector<uint8_t>> serializeProto();
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 521fcc33ac47..e8a862fef79b 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -15,17 +15,17 @@
*/
#define DEBUG true // STOPSHIP if true
#include "Log.h"
-
#include "MetricsManager.h"
-#include <log/logprint.h>
-#include "../condition/CombinationConditionTracker.h"
-#include "../condition/SimpleConditionTracker.h"
-#include "../matchers/CombinationLogMatchingTracker.h"
-#include "../matchers/SimpleLogMatchingTracker.h"
+
#include "CountMetricProducer.h"
+#include "condition/CombinationConditionTracker.h"
+#include "condition/SimpleConditionTracker.h"
+#include "matchers/CombinationLogMatchingTracker.h"
+#include "matchers/SimpleLogMatchingTracker.h"
#include "metrics_manager_util.h"
#include "stats_util.h"
+#include <log/logprint.h>
using std::make_unique;
using std::set;
using std::string;
@@ -56,10 +56,10 @@ void MetricsManager::finish() {
}
}
-vector<StatsLogReport> MetricsManager::onDumpReport() {
+vector<std::unique_ptr<vector<uint8_t>>> MetricsManager::onDumpReport() {
VLOG("=========================Metric Reports Start==========================");
// one StatsLogReport per MetricProduer
- vector<StatsLogReport> reportList;
+ vector<std::unique_ptr<vector<uint8_t>>> reportList;
for (auto& metric : mAllMetricProducers) {
reportList.push_back(metric->onDumpReport());
}
@@ -80,8 +80,6 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
return;
}
- // Since at least one of the metrics is interested in this event, we parse it now.
- ALOGD("%s", event.ToString().c_str());
vector<MatchingState> matcherCache(mAllLogEntryMatchers.size(), MatchingState::kNotComputed);
for (auto& matcher : mAllLogEntryMatchers) {
@@ -104,18 +102,17 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
ConditionState::kNotEvaluated);
// A bitmap to track if a condition has changed value.
vector<bool> changedCache(mAllConditionTrackers.size(), false);
- vector<bool> slicedChangedCache(mAllConditionTrackers.size(), false);
for (size_t i = 0; i < mAllConditionTrackers.size(); i++) {
if (conditionToBeEvaluated[i] == false) {
continue;
}
sp<ConditionTracker>& condition = mAllConditionTrackers[i];
condition->evaluateCondition(event, matcherCache, mAllConditionTrackers, conditionCache,
- changedCache, slicedChangedCache);
+ changedCache);
}
for (size_t i = 0; i < mAllConditionTrackers.size(); i++) {
- if (changedCache[i] == false && slicedChangedCache[i] == false) {
+ if (changedCache[i] == false) {
continue;
}
auto pair = mConditionToMetricMap.find(i);
@@ -124,14 +121,13 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
for (auto metricIndex : metricList) {
// metric cares about non sliced condition, and it's changed.
// Push the new condition to it directly.
- if (!mAllMetricProducers[metricIndex]->isConditionSliced() && changedCache[i]) {
+ if (!mAllMetricProducers[metricIndex]->isConditionSliced()) {
mAllMetricProducers[metricIndex]->onConditionChanged(conditionCache[i],
eventTime);
// 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() &&
- slicedChangedCache[i]) {
+ } else if (mAllMetricProducers[metricIndex]->isConditionSliced()) {
mAllMetricProducers[metricIndex]->onSlicedConditionMayChange(eventTime);
}
}
@@ -146,7 +142,8 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
auto& metricList = pair->second;
for (const int metricIndex : metricList) {
// pushed metrics are never scheduled pulls
- mAllMetricProducers[metricIndex]->onMatchedLogEvent(i, event, false);
+ mAllMetricProducers[metricIndex]->onMatchedLogEvent(
+ i, event, false /* schedulePull */);
}
}
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 44cd6371199e..39c79f99daca 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -44,7 +44,7 @@ public:
void finish();
// Config source owner can call onDumpReport() to get all the metrics collected.
- std::vector<StatsLogReport> onDumpReport();
+ std::vector<std::unique_ptr<std::vector<uint8_t>>> onDumpReport();
size_t byteSize();
@@ -96,4 +96,3 @@ private:
} // namespace statsd
} // namespace os
} // namespace android
-
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index cb6166dafa3a..a35070bab54b 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -23,133 +23,215 @@
#include <limits.h>
#include <stdlib.h>
-using std::map;
-using std::unordered_map;
+using android::util::FIELD_COUNT_REPEATED;
+using android::util::FIELD_TYPE_BOOL;
+using android::util::FIELD_TYPE_FLOAT;
+using android::util::FIELD_TYPE_INT32;
+using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_MESSAGE;
+using android::util::FIELD_TYPE_STRING;
+using android::util::ProtoOutputStream;
using std::list;
+using std::make_pair;
using std::make_shared;
+using std::map;
using std::shared_ptr;
using std::unique_ptr;
+using std::unordered_map;
namespace android {
namespace os {
namespace statsd {
+// for StatsLogReport
+const int FIELD_ID_NAME = 1;
+const int FIELD_ID_START_REPORT_NANOS = 2;
+const int FIELD_ID_END_REPORT_NANOS = 3;
+const int FIELD_ID_VALUE_METRICS = 7;
+// for ValueMetricDataWrapper
+const int FIELD_ID_DATA = 1;
+// for ValueMetricData
+const int FIELD_ID_DIMENSION = 1;
+const int FIELD_ID_BUCKET_INFO = 2;
+// for KeyValuePair
+const int FIELD_ID_KEY = 1;
+const int FIELD_ID_VALUE_STR = 2;
+const int FIELD_ID_VALUE_INT = 3;
+const int FIELD_ID_VALUE_BOOL = 4;
+const int FIELD_ID_VALUE_FLOAT = 5;
+// for ValueBucketInfo
+const int FIELD_ID_START_BUCKET_NANOS = 1;
+const int FIELD_ID_END_BUCKET_NANOS = 2;
+const int FIELD_ID_VALUE = 3;
+
+static const uint64_t kDefaultBucketSizeMillis = 60 * 60 * 1000L;
+
// ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
ValueMetricProducer::ValueMetricProducer(const ValueMetric& metric, const int conditionIndex,
- const sp<ConditionWizard>& wizard)
- : MetricProducer((time(nullptr) / 600 * 600 * NANO_SECONDS_IN_A_SECOND), conditionIndex,
- wizard),
+ const sp<ConditionWizard>& wizard, const int pullTagId,
+ const uint64_t startTimeNs,
+ shared_ptr<StatsPullerManager> statsPullerManager)
+ : MetricProducer(startTimeNs, conditionIndex, wizard),
mMetric(metric),
- mPullCode(mStatsPullerManager.GetPullCode(mMetric.what())) {
- // TODO: valuemetric for pushed events may need unlimited bucket length
- mBucketSizeNs = mMetric.bucket().bucket_size_millis() * 1000 * 1000;
+ mStatsPullerManager(statsPullerManager),
+ mPullTagId(pullTagId) {
+ // TODO: valuemetric for pushed events may need unlimited bucket length
+ if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
+ mBucketSizeNs = mMetric.bucket().bucket_size_millis() * 1000 * 1000;
+ } else {
+ mBucketSizeNs = kDefaultBucketSizeMillis * 1000 * 1000;
+ }
- mDimension.insert(mDimension.begin(), metric.dimension().begin(), metric.dimension().end());
+ mDimension.insert(mDimension.begin(), metric.dimension().begin(), metric.dimension().end());
- if (metric.links().size() > 0) {
- mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
- metric.links().end());
- mConditionSliced = true;
- }
+ if (metric.links().size() > 0) {
+ mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
+ metric.links().end());
+ mConditionSliced = true;
+ }
- if (!metric.has_condition() && mPullCode != -1) {
- mStatsPullerManager.RegisterReceiver(mPullCode, this, metric.bucket().bucket_size_millis());
- }
+ if (!metric.has_condition() && mPullTagId != -1) {
+ VLOG("Setting up periodic pulling for %d", mPullTagId);
+ mStatsPullerManager->RegisterReceiver(mPullTagId, this,
+ metric.bucket().bucket_size_millis());
+ }
- VLOG("value metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
- (long long)mBucketSizeNs, (long long)mStartTimeNs);
+ startNewProtoOutputStream(mStartTimeNs);
+
+ VLOG("value metric %s created. bucket size %lld start_time: %lld", metric.name().c_str(),
+ (long long)mBucketSizeNs, (long long)mStartTimeNs);
+}
+
+// for testing
+ValueMetricProducer::ValueMetricProducer(const ValueMetric& metric, const int conditionIndex,
+ const sp<ConditionWizard>& wizard, const int pullTagId,
+ const uint64_t startTimeNs)
+ : ValueMetricProducer(metric, conditionIndex, wizard, pullTagId, startTimeNs,
+ make_shared<StatsPullerManager>()) {
}
ValueMetricProducer::~ValueMetricProducer() {
- VLOG("~ValueMetricProducer() called");
+ VLOG("~ValueMetricProducer() called");
+ if (mPullTagId != -1) {
+ mStatsPullerManager->UnRegisterReceiver(mPullTagId, this);
+ }
}
-void ValueMetricProducer::finish() {
- // TODO: write the StatsLogReport to dropbox using
- // DropboxWriter.
+void ValueMetricProducer::startNewProtoOutputStream(long long startTime) {
+ mProto = std::make_unique<ProtoOutputStream>();
+ mProto->write(FIELD_TYPE_STRING | FIELD_ID_NAME, mMetric.name());
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
+ mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_VALUE_METRICS);
}
-static void addSlicedCounterToReport(StatsLogReport_ValueMetricDataWrapper& wrapper,
- const vector<KeyValuePair>& key,
- const vector<ValueBucketInfo>& buckets) {
- ValueMetricData* data = wrapper.add_data();
- for (const auto& kv : key) {
- data->add_dimension()->CopyFrom(kv);
- }
- for (const auto& bucket : buckets) {
- data->add_bucket_info()->CopyFrom(bucket);
- VLOG("\t bucket [%lld - %lld] value: %lld", bucket.start_bucket_nanos(),
- bucket.end_bucket_nanos(), bucket.value());
- }
+void ValueMetricProducer::finish() {
+ // TODO: write the StatsLogReport to dropbox using
+ // DropboxWriter.
}
void ValueMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
- VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
+ VLOG("Metric %s onSlicedConditionMayChange", mMetric.name().c_str());
}
-StatsLogReport ValueMetricProducer::onDumpReport() {
- VLOG("metric %lld dump report now...", mMetric.metric_id());
+std::unique_ptr<std::vector<uint8_t>> ValueMetricProducer::onDumpReport() {
+ VLOG("metric %s dump report now...", mMetric.name().c_str());
- StatsLogReport report;
- report.set_metric_id(mMetric.metric_id());
- report.set_start_report_nanos(mStartTimeNs);
+ for (const auto& pair : mPastBuckets) {
+ const HashableDimensionKey& hashableKey = pair.first;
+ VLOG(" dimension key %s", hashableKey.c_str());
+ auto it = mDimensionKeyMap.find(hashableKey);
+ if (it == mDimensionKeyMap.end()) {
+ ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
+ continue;
+ }
+ long long wrapperToken =
+ mProto->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());
+ if (kv.has_value_str()) {
+ mProto->write(FIELD_TYPE_INT32 | 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());
+ } else if (kv.has_value_bool()) {
+ mProto->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());
+ }
+ mProto->end(dimensionToken);
+ }
- // 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.
- // flush_if_needed(time(nullptr) * NANO_SECONDS_IN_A_SECOND);
- report.set_end_report_nanos(mCurrentBucketStartTimeNs);
+ // 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);
+ VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs,
+ (long long)bucket.mBucketEndNs, (long long)bucket.mValue);
+ }
+ mProto->end(wrapperToken);
+ }
+ mProto->end(mProtoToken);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
+ (long long)mCurrentBucketStartTimeNs);
- StatsLogReport_ValueMetricDataWrapper* wrapper = report.mutable_value_metrics();
+ VLOG("metric %s dump report now...", mMetric.name().c_str());
+ std::unique_ptr<std::vector<uint8_t>> buffer = serializeProto();
- for (const auto& pair : mPastBuckets) {
- const HashableDimensionKey& hashableKey = pair.first;
- auto it = mDimensionKeyMap.find(hashableKey);
- if (it == mDimensionKeyMap.end()) {
- ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
- continue;
- }
+ startNewProtoOutputStream(time(nullptr) * NS_PER_SEC);
+ mPastBuckets.clear();
+ mByteSize = 0;
- VLOG(" dimension key %s", hashableKey.c_str());
- addSlicedCounterToReport(*wrapper, it->second, pair.second);
- }
- return report;
- // TODO: Clear mPastBuckets, mDimensionKeyMap once the report is dumped.
+ return buffer;
+
+ // TODO: Clear mDimensionKeyMap once the report is dumped.
}
void ValueMetricProducer::onConditionChanged(const bool condition, const uint64_t eventTime) {
+ AutoMutex _l(mLock);
mCondition = condition;
- if (mPullCode != -1) {
- vector<shared_ptr<LogEvent>> allData = mStatsPullerManager.Pull(mPullCode, eventTime);
+ if (mPullTagId != -1) {
if (mCondition == true) {
- mStatsPullerManager.RegisterReceiver(mPullCode, this,
- mMetric.bucket().bucket_size_millis());
- } else if (mCondition == ConditionState::kFalse) {
- mStatsPullerManager.UnRegisterReceiver(mPullCode, this);
- }
- if (allData.size() == 0) {
- return;
+ mStatsPullerManager->RegisterReceiver(mPullTagId, this,
+ mMetric.bucket().bucket_size_millis());
+ } else if (mCondition == false) {
+ mStatsPullerManager->UnRegisterReceiver(mPullTagId, this);
}
- AutoMutex _l(mLock);
- if (allData.size() == 0) {
- return;
- }
- for (const auto& data : allData) {
- onMatchedLogEvent(0, *data, false);
+
+ vector<shared_ptr<LogEvent>> allData;
+ if (mStatsPullerManager->Pull(mPullTagId, &allData)) {
+ if (allData.size() == 0) {
+ return;
+ }
+ for (const auto& data : allData) {
+ onMatchedLogEvent(0, *data, false);
+ }
+ flush_if_needed(eventTime);
}
- flush_if_needed(eventTime);
+ return;
}
- return;
}
void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
- if (mCondition == ConditionState::kTrue || !mMetric.has_condition()) {
- AutoMutex _l(mLock);
+ AutoMutex _l(mLock);
+ 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) {
+ flush_if_needed(eventTime);
+ }
for (const auto& data : allData) {
onMatchedLogEvent(0, *data, true);
}
@@ -158,50 +240,62 @@ void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven
}
void ValueMetricProducer::onMatchedLogEventInternal(
- const size_t matcherIndex, const HashableDimensionKey& eventKey,
- const map<string, HashableDimensionKey>& conditionKey, bool condition,
- const LogEvent& event, bool scheduledPull) {
- 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;
- }
-
- Interval& interval = mCurrentSlicedBucket[eventKey];
-
- long value = get_value(event);
-
- if (scheduledPull) {
- if (interval.raw.size() > 0) {
- interval.raw.back().second = value;
- } else {
- interval.raw.push_back(std::make_pair(value, value));
+ const size_t matcherIndex, const HashableDimensionKey& eventKey,
+ const map<string, HashableDimensionKey>& conditionKey, bool condition,
+ const LogEvent& event, bool scheduledPull) {
+ 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;
}
- mNextSlicedBucket[eventKey].raw[0].first = value;
- } else {
- if (mCondition == ConditionState::kTrue) {
- interval.raw.push_back(std::make_pair(value, 0));
+
+ Interval& interval = mCurrentSlicedBucket[eventKey];
+
+ long value = get_value(event);
+
+ if (mPullTagId != -1) {
+ 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 {
- if (interval.raw.size() != 0) {
- interval.raw.back().second = value;
- }
+ flush_if_needed(eventTimeNs);
+ interval.raw.push_back(make_pair(value, 0));
}
- }
- if (mPullCode == -1) {
- flush_if_needed(eventTimeNs);
- }
}
long ValueMetricProducer::get_value(const LogEvent& event) {
- status_t err = NO_ERROR;
- long val = event.GetLong(mMetric.value_field(), &err);
- if (err == NO_ERROR) {
- return val;
- } else {
- VLOG("Can't find value in message.");
- return 0;
- }
+ status_t err = NO_ERROR;
+ long val = event.GetLong(mMetric.value_field(), &err);
+ if (err == NO_ERROR) {
+ return val;
+ } else {
+ VLOG("Can't find value in message. %s", event.ToString().c_str());
+ return 0;
+ }
}
void ValueMetricProducer::flush_if_needed(const uint64_t eventTimeNs) {
@@ -213,34 +307,47 @@ void ValueMetricProducer::flush_if_needed(const uint64_t eventTimeNs) {
VLOG("finalizing bucket for %ld, dumping %d slices", (long)mCurrentBucketStartTimeNs,
(int)mCurrentSlicedBucket.size());
- ValueBucketInfo info;
- info.set_start_bucket_nanos(mCurrentBucketStartTimeNs);
- info.set_end_bucket_nanos(mCurrentBucketStartTimeNs + mBucketSizeNs);
+ ValueBucket info;
+ info.mBucketStartNs = mCurrentBucketStartTimeNs;
+ info.mBucketEndNs = mCurrentBucketStartTimeNs + mBucketSizeNs;
+ int tainted = 0;
for (const auto& slice : mCurrentSlicedBucket) {
- long value = 0;
- for (const auto& pair : slice.second.raw) {
- value += pair.second - pair.first;
- }
- info.set_value(value);
- VLOG(" %s, %ld", slice.first.c_str(), value);
- // it will auto create new vector of ValuebucketInfo if the key is not found.
- auto& bucketList = mPastBuckets[slice.first];
- bucketList.push_back(info);
+ long value = 0;
+ if (mPullTagId != -1) {
+ for (const auto& pair : slice.second.raw) {
+ value += (pair.second - pair.first);
+ }
+ } else {
+ for (const auto& pair : slice.second.raw) {
+ value += pair.first;
+ }
+ }
+ tainted += slice.second.tainted;
+ info.mValue = value;
+ VLOG(" %s, %ld, %d", slice.first.c_str(), value, tainted);
+ // it will auto create new vector of ValuebucketInfo if the key is not found.
+ auto& bucketList = mPastBuckets[slice.first];
+ bucketList.push_back(info);
+ mByteSize += sizeof(info);
}
// Reset counters
mCurrentSlicedBucket.swap(mNextSlicedBucket);
mNextSlicedBucket.clear();
int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
- if (numBucketsForward >1) {
+ if (numBucketsForward > 1) {
VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
}
mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
- VLOG("metric %lld: new bucket start time: %lld", mMetric.metric_id(),
+ VLOG("metric %s: new bucket start time: %lld", mMetric.name().c_str(),
(long long)mCurrentBucketStartTimeNs);
}
+size_t ValueMetricProducer::byteSize() {
+ return mByteSize;
+}
+
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 4f1791351f87..c6c87f5b15f6 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -16,24 +16,30 @@
#pragma once
+#include <gtest/gtest_prod.h>
#include <utils/threads.h>
#include <list>
#include "../condition/ConditionTracker.h"
#include "../external/PullDataReceiver.h"
#include "../external/StatsPullerManager.h"
-#include "CountAnomalyTracker.h"
#include "MetricProducer.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
namespace android {
namespace os {
namespace statsd {
+struct ValueBucket {
+ int64_t mBucketStartNs;
+ int64_t mBucketEndNs;
+ int64_t mValue;
+};
+
class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver {
public:
ValueMetricProducer(const ValueMetric& valueMetric, const int conditionIndex,
- const sp<ConditionWizard>& wizard);
+ const sp<ConditionWizard>& wizard, const int pullTagId,
+ const uint64_t startTimeNs);
virtual ~ValueMetricProducer();
@@ -41,13 +47,14 @@ public:
void finish() override;
- StatsLogReport onDumpReport() 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;
- // TODO: Implement this later.
- size_t byteSize() override{return 0;};
+
+ size_t byteSize() override;
// TODO: Implement this later.
virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
@@ -60,18 +67,28 @@ protected:
bool condition, const LogEvent& event,
bool scheduledPull) override;
+ void startNewProtoOutputStream(long long timestamp) override;
+
private:
const ValueMetric mMetric;
- StatsPullerManager& mStatsPullerManager = StatsPullerManager::GetInstance();
+ std::shared_ptr<StatsPullerManager> mStatsPullerManager;
+
+ // for testing
+ ValueMetricProducer(const ValueMetric& valueMetric, const int conditionIndex,
+ const sp<ConditionWizard>& wizard, const int pullTagId,
+ const uint64_t startTimeNs,
+ std::shared_ptr<StatsPullerManager> statsPullerManager);
Mutex mLock;
- const int mPullCode;
+ // tagId for pulled data. -1 if this is not pulled
+ const int mPullTagId;
// internal state of a bucket.
typedef struct {
std::vector<std::pair<long, long>> raw;
+ bool tainted;
} Interval;
std::unordered_map<HashableDimensionKey, Interval> mCurrentSlicedBucket;
@@ -80,11 +97,18 @@ private:
std::unordered_map<HashableDimensionKey, Interval> mNextSlicedBucket;
// Save the past buckets and we can clear when the StatsLogReport is dumped.
- std::unordered_map<HashableDimensionKey, std::vector<ValueBucketInfo>> mPastBuckets;
+ // TODO: Add a lock to mPastBuckets.
+ std::unordered_map<HashableDimensionKey, std::vector<ValueBucket>> mPastBuckets;
long get_value(const LogEvent& event);
void flush_if_needed(const uint64_t eventTimeNs);
+
+ size_t mByteSize;
+
+ FRIEND_TEST(ValueMetricProducerTest, TestNonDimensionalEvents);
+ FRIEND_TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition);
+ FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 0d0d9a4e2647..5c76d0e6513b 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -20,8 +20,6 @@
#include "condition/ConditionWizard.h"
#include "stats_util.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-
namespace android {
namespace os {
namespace statsd {
@@ -47,10 +45,16 @@ struct DurationInfo {
DurationInfo() : state(kStopped), lastStartTime(0), lastDuration(0){};
};
+struct DurationBucket {
+ int64_t mBucketStartNs;
+ int64_t mBucketEndNs;
+ int64_t mDuration;
+};
+
class DurationTracker {
public:
DurationTracker(sp<ConditionWizard> wizard, int conditionIndex, uint64_t currentBucketStartNs,
- uint64_t bucketSizeNs, std::vector<DurationBucketInfo>& bucket)
+ uint64_t bucketSizeNs, std::vector<DurationBucket>& bucket)
: mWizard(wizard),
mConditionTrackerIndex(conditionIndex),
mCurrentBucketStartTimeNs(currentBucketStartNs),
@@ -77,7 +81,7 @@ protected:
int64_t mBucketSizeNs;
- std::vector<DurationBucketInfo>& mBucket; // where to write output
+ std::vector<DurationBucket>& mBucket; // where to write output
int64_t mDuration; // current recorded duration result
};
@@ -86,4 +90,4 @@ protected:
} // namespace os
} // namespace android
-#endif // DURATION_TRACKER_H \ No newline at end of file
+#endif // DURATION_TRACKER_H
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index 856ca9d979f5..43c21a830ecf 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -25,7 +25,7 @@ namespace statsd {
MaxDurationTracker::MaxDurationTracker(sp<ConditionWizard> wizard, int conditionIndex,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
- std::vector<DurationBucketInfo>& bucket)
+ std::vector<DurationBucket>& bucket)
: DurationTracker(wizard, conditionIndex, currentBucketStartNs, bucketSizeNs, bucket) {
}
@@ -106,10 +106,12 @@ bool MaxDurationTracker::flushIfNeeded(uint64_t eventTime) {
// adjust the bucket start time
int numBucketsForward = (eventTime - mCurrentBucketStartTimeNs) / mBucketSizeNs;
- DurationBucketInfo info;
uint64_t endTime = mCurrentBucketStartTimeNs + mBucketSizeNs;
- info.set_start_bucket_nanos(mCurrentBucketStartTimeNs);
- info.set_end_bucket_nanos(endTime);
+
+ DurationBucket info;
+ info.mBucketStartNs = mCurrentBucketStartTimeNs;
+ info.mBucketEndNs = endTime;
+
uint64_t oldBucketStartTimeNs = mCurrentBucketStartTimeNs;
mCurrentBucketStartTimeNs += (numBucketsForward)*mBucketSizeNs;
@@ -150,7 +152,7 @@ bool MaxDurationTracker::flushIfNeeded(uint64_t eventTime) {
}
if (mDuration != 0) {
- info.set_duration_nanos(mDuration);
+ info.mDuration = mDuration;
mBucket.push_back(info);
VLOG(" final duration for last bucket: %lld", (long long)mDuration);
}
@@ -158,10 +160,10 @@ bool MaxDurationTracker::flushIfNeeded(uint64_t eventTime) {
mDuration = 0;
if (hasOnGoingStartedEvent) {
for (int i = 1; i < numBucketsForward; i++) {
- DurationBucketInfo info;
- info.set_start_bucket_nanos(oldBucketStartTimeNs + mBucketSizeNs * i);
- info.set_end_bucket_nanos(endTime + mBucketSizeNs * i);
- info.set_duration_nanos(mBucketSizeNs);
+ DurationBucket info;
+ info.mBucketStartNs = oldBucketStartTimeNs + mBucketSizeNs * i;
+ info.mBucketEndNs = endTime + mBucketSizeNs * i;
+ info.mDuration = mBucketSizeNs;
mBucket.push_back(info);
VLOG(" filling gap bucket with duration %lld", (long long)mBucketSizeNs);
}
@@ -171,7 +173,6 @@ bool MaxDurationTracker::flushIfNeeded(uint64_t eventTime) {
}
void MaxDurationTracker::onSlicedConditionMayChange(const uint64_t timestamp) {
- // VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
// Now for each of the on-going event, check if the condition has changed for them.
for (auto& pair : mInfos) {
if (pair.second.state == kStopped) {
@@ -224,4 +225,4 @@ void MaxDurationTracker::noteConditionChanged(const HashableDimensionKey& key, b
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index c74d070a3297..b095884876a8 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -19,8 +19,6 @@
#include "DurationTracker.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-
namespace android {
namespace os {
namespace statsd {
@@ -32,7 +30,7 @@ class MaxDurationTracker : public DurationTracker {
public:
MaxDurationTracker(sp<ConditionWizard> wizard, int conditionIndex,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
- std::vector<DurationBucketInfo>& bucket);
+ std::vector<DurationBucket>& bucket);
void noteStart(const HashableDimensionKey& key, bool condition, const uint64_t eventTime,
const ConditionKey& conditionKey) override;
void noteStop(const HashableDimensionKey& key, const uint64_t eventTime) override;
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index e045fb4fb012..e4f1d2149f7c 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -22,7 +22,7 @@ namespace os {
namespace statsd {
OringDurationTracker::OringDurationTracker(sp<ConditionWizard> wizard, int conditionIndex,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
- std::vector<DurationBucketInfo>& bucket)
+ std::vector<DurationBucket>& bucket)
: DurationTracker(wizard, conditionIndex, currentBucketStartNs, bucketSizeNs, bucket),
mStarted(),
mPaused() {
@@ -82,10 +82,10 @@ bool OringDurationTracker::flushIfNeeded(uint64_t eventTime) {
VLOG("OringDurationTracker Flushing.............");
// adjust the bucket start time
int numBucketsForward = (eventTime - mCurrentBucketStartTimeNs) / mBucketSizeNs;
- DurationBucketInfo info;
+ DurationBucket info;
uint64_t endTime = mCurrentBucketStartTimeNs + mBucketSizeNs;
- info.set_start_bucket_nanos(mCurrentBucketStartTimeNs);
- info.set_end_bucket_nanos(endTime);
+ info.mBucketStartNs = mCurrentBucketStartTimeNs;
+ info.mBucketEndNs = endTime;
uint64_t oldBucketStartTimeNs = mCurrentBucketStartTimeNs;
mCurrentBucketStartTimeNs += (numBucketsForward)*mBucketSizeNs;
@@ -94,7 +94,7 @@ bool OringDurationTracker::flushIfNeeded(uint64_t eventTime) {
mDuration += (endTime - mLastStartTime);
}
if (mDuration != 0) {
- info.set_duration_nanos(mDuration);
+ info.mDuration = mDuration;
// it will auto create new vector of CountbucketInfo if the key is not found.
mBucket.push_back(info);
VLOG(" duration: %lld", (long long)mDuration);
@@ -102,10 +102,10 @@ bool OringDurationTracker::flushIfNeeded(uint64_t eventTime) {
if (mStarted.size() > 0) {
for (int i = 1; i < numBucketsForward; i++) {
- DurationBucketInfo info;
- info.set_start_bucket_nanos(oldBucketStartTimeNs + mBucketSizeNs * i);
- info.set_end_bucket_nanos(endTime + mBucketSizeNs * i);
- info.set_duration_nanos(mBucketSizeNs);
+ DurationBucket info;
+ info.mBucketStartNs = oldBucketStartTimeNs + mBucketSizeNs * i;
+ info.mBucketEndNs = endTime + mBucketSizeNs * i;
+ info.mDuration = mBucketSizeNs;
mBucket.push_back(info);
VLOG(" add filling bucket with duration %lld", (long long)mBucketSizeNs);
}
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index 542525153fb0..b54dafaa1758 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -29,7 +29,7 @@ class OringDurationTracker : public DurationTracker {
public:
OringDurationTracker(sp<ConditionWizard> wizard, int conditionIndex,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
- std::vector<DurationBucketInfo>& bucket);
+ std::vector<DurationBucket>& bucket);
void noteStart(const HashableDimensionKey& key, bool condition, const uint64_t eventTime,
const ConditionKey& conditionKey) override;
void noteStop(const HashableDimensionKey& key, const uint64_t eventTime) override;
@@ -54,4 +54,4 @@ private:
} // namespace os
} // namespace android
-#endif // ORING_DURATION_TRACKER_H \ No newline at end of file
+#endif // ORING_DURATION_TRACKER_H
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 3d4036e8d176..4c63b20f5fb6 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -22,6 +22,7 @@
#include "CountMetricProducer.h"
#include "DurationMetricProducer.h"
#include "EventMetricProducer.h"
+#include "GaugeMetricProducer.h"
#include "ValueMetricProducer.h"
#include "stats_util.h"
@@ -191,17 +192,18 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l
unordered_map<int, std::vector<int>>& conditionToMetricMap,
unordered_map<int, std::vector<int>>& trackerToMetricMap) {
sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
- const int allMetricsCount =
- config.count_metric_size() + config.duration_metric_size() + config.event_metric_size();
+ const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
+ config.event_metric_size() + config.value_metric_size();
allMetricProducers.reserve(allMetricsCount);
- StatsPullerManager& statsPullerManager = StatsPullerManager::GetInstance();
+ StatsPullerManager statsPullerManager;
+ uint64_t startTimeNs = time(nullptr) * NS_PER_SEC;
// Build MetricProducers for each metric defined in config.
- // (1) build CountMetricProducer
+ // build CountMetricProducer
for (int i = 0; i < config.count_metric_size(); i++) {
const CountMetric& metric = config.count_metric(i);
if (!metric.has_what()) {
- ALOGW("cannot find what in CountMetric %lld", metric.metric_id());
+ ALOGW("cannot find what in CountMetric %s", metric.name().c_str());
return false;
}
@@ -218,12 +220,19 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l
handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
metric.links(), allConditionTrackers, conditionIndex,
conditionToMetricMap);
+ } else {
+ if (metric.links_size() > 0) {
+ ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+ return false;
+ }
}
- sp<MetricProducer> countProducer = new CountMetricProducer(metric, conditionIndex, wizard);
+ sp<MetricProducer> countProducer =
+ new CountMetricProducer(metric, conditionIndex, wizard, startTimeNs);
allMetricProducers.push_back(countProducer);
}
+ // build DurationMetricProducer
for (int i = 0; i < config.duration_metric_size(); i++) {
int metricIndex = allMetricProducers.size();
const DurationMetric& metric = config.duration_metric(i);
@@ -272,24 +281,30 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l
int conditionIndex = -1;
- if (metric.has_predicate()) {
- handleMetricWithConditions(metric.predicate(), metricIndex, conditionTrackerMap,
+ if (metric.has_condition()) {
+ handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
metric.links(), allConditionTrackers, conditionIndex,
conditionToMetricMap);
+ } else {
+ if (metric.links_size() > 0) {
+ ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+ return false;
+ }
}
sp<MetricProducer> durationMetric = new DurationMetricProducer(
metric, conditionIndex, trackerIndices[0], trackerIndices[1], trackerIndices[2],
- wizard, internalDimension);
+ wizard, internalDimension, startTimeNs);
allMetricProducers.push_back(durationMetric);
}
+ // build EventMetricProducer
for (int i = 0; i < config.event_metric_size(); i++) {
int metricIndex = allMetricProducers.size();
const EventMetric& metric = config.event_metric(i);
- if (!metric.has_metric_id() || !metric.has_what()) {
- ALOGW("cannot find the metric id or what in config");
+ if (!metric.has_name() || !metric.has_what()) {
+ ALOGW("cannot find the metric name or what in config");
return false;
}
int trackerIndex;
@@ -303,40 +318,107 @@ bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& l
handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
metric.links(), allConditionTrackers, conditionIndex,
conditionToMetricMap);
+ } else {
+ if (metric.links_size() > 0) {
+ ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+ return false;
+ }
}
- sp<MetricProducer> eventMetric = new EventMetricProducer(metric, conditionIndex, wizard);
+ sp<MetricProducer> eventMetric =
+ new EventMetricProducer(metric, conditionIndex, wizard, startTimeNs);
allMetricProducers.push_back(eventMetric);
}
- // value metrics
+ // build ValueMetricProducer
for (int i = 0; i < config.value_metric_size(); i++) {
const ValueMetric& metric = config.value_metric(i);
if (!metric.has_what()) {
- ALOGW("cannot find what in ValueMetric %lld", metric.metric_id());
+ ALOGW("cannot find what in ValueMetric %s", metric.name().c_str());
return false;
}
- int pullCode = statsPullerManager.GetPullCode(metric.what());
- if (pullCode == -1) {
- ALOGW("cannot find %s in pulled metrics", metric.what().c_str());
+ int metricIndex = allMetricProducers.size();
+ int trackerIndex;
+ if (!handleMetricWithLogTrackers(metric.what(), metricIndex, metric.dimension_size() > 0,
+ allLogEntryMatchers, logTrackerMap, trackerToMetricMap,
+ trackerIndex)) {
return false;
}
- sp<MetricProducer> valueProducer;
- auto condition_it = conditionTrackerMap.find(metric.condition());
- if (condition_it == conditionTrackerMap.end()) {
- ALOGW("cannot find the Condition %s in the config", metric.condition().c_str());
+ sp<LogMatchingTracker> atomMatcher = allLogEntryMatchers.at(trackerIndex);
+ // If it is pulled atom, it should be simple matcher with one tagId.
+ int pullTagId = -1;
+ for (int tagId : atomMatcher->getTagIds()) {
+ if (statsPullerManager.PullerForMatcherExists(tagId)) {
+ if (atomMatcher->getTagIds().size() != 1) {
+ return false;
+ }
+ pullTagId = tagId;
+ }
+ }
+
+ int conditionIndex = -1;
+ if (metric.has_condition()) {
+ handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
+ metric.links(), allConditionTrackers, conditionIndex,
+ conditionToMetricMap);
+ } else {
+ if (metric.links_size() > 0) {
+ ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+ return false;
+ }
+ }
+
+ sp<MetricProducer> valueProducer =
+ new ValueMetricProducer(metric, conditionIndex, wizard, pullTagId, startTimeNs);
+ allMetricProducers.push_back(valueProducer);
+ }
+
+ // Gauge metrics.
+ for (int i = 0; i < config.gauge_metric_size(); i++) {
+ const GaugeMetric& metric = config.gauge_metric(i);
+ if (!metric.has_what()) {
+ ALOGW("cannot find what in ValueMetric %s", metric.name().c_str());
return false;
}
+
int metricIndex = allMetricProducers.size();
- valueProducer = new ValueMetricProducer(metric, condition_it->second, wizard);
- // will create new vector if not exist before.
- auto& metricList = conditionToMetricMap[condition_it->second];
- metricList.push_back(metricIndex);
+ int trackerIndex;
+ if (!handleMetricWithLogTrackers(metric.what(), metricIndex, metric.dimension_size() > 0,
+ allLogEntryMatchers, logTrackerMap, trackerToMetricMap,
+ trackerIndex)) {
+ return false;
+ }
- allMetricProducers.push_back(valueProducer);
+ sp<LogMatchingTracker> atomMatcher = allLogEntryMatchers.at(trackerIndex);
+ // If it is pulled atom, it should be simple matcher with one tagId.
+ int pullTagId = -1;
+ for (int tagId : atomMatcher->getTagIds()) {
+ if (statsPullerManager.PullerForMatcherExists(tagId)) {
+ if (atomMatcher->getTagIds().size() != 1) {
+ return false;
+ }
+ pullTagId = tagId;
+ }
+ }
+
+ int conditionIndex = -1;
+ if (metric.has_condition()) {
+ handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
+ metric.links(), allConditionTrackers, conditionIndex,
+ conditionToMetricMap);
+ } else {
+ if (metric.links_size() > 0) {
+ ALOGW("metrics has a EventConditionLink but doesn't have a condition");
+ return false;
+ }
+ }
+
+ sp<MetricProducer> gaugeProducer =
+ new GaugeMetricProducer(metric, conditionIndex, wizard, pullTagId);
+ allMetricProducers.push_back(gaugeProducer);
}
return true;
}
@@ -355,6 +437,7 @@ bool initStatsdConfig(const StatsdConfig& config, set<int>& allTagIds,
ALOGE("initLogMatchingTrackers failed");
return false;
}
+ ALOGD("initLogMatchingTrackers succeed...");
if (!initConditions(config, logTrackerMap, conditionTrackerMap, allConditionTrackers,
trackerToConditionMap)) {
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index e089d0653238..edf3af0aff8e 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -21,7 +21,7 @@
#include <vector>
#include "../condition/ConditionTracker.h"
-#include "../external/StatsPullerManager.h"
+#include "../external/StatsPullerManagerImpl.h"
#include "../matchers/LogMatchingTracker.h"
namespace android {
diff --git a/cmds/statsd/src/packages/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h
index 13e776fb1f80..5aa3db573c70 100644
--- a/cmds/statsd/src/packages/PackageInfoListener.h
+++ b/cmds/statsd/src/packages/PackageInfoListener.h
@@ -1,5 +1,5 @@
/*
- * 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.
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index d83c3a426685..6c32d3e1b11e 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, versionCode 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,7 +52,7 @@ int UidMap::getAppVersion(int uid, const string& packageName) const {
void UidMap::updateMap(const vector<int32_t>& uid, const vector<int32_t>& versionCode,
const vector<String16>& packageName) {
- updateMap(time(nullptr) * 1000000000, uid, versionCode, packageName);
+ updateMap(time(nullptr) * NS_PER_SEC, uid, versionCode, packageName);
}
void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
@@ -76,7 +76,7 @@ void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
}
void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int32_t& versionCode) {
- updateApp(time(nullptr) * 1000000000, app_16, uid, 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,
@@ -112,7 +112,7 @@ void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const i
}
void UidMap::removeApp(const String16& app_16, const int32_t& uid) {
- removeApp(time(nullptr) * 1000000000, app_16, uid);
+ removeApp(time(nullptr) * NS_PER_SEC, app_16, uid);
}
void UidMap::removeApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid) {
lock_guard<mutex> lock(mMutex);
@@ -150,6 +150,31 @@ void UidMap::removeListener(sp<PackageInfoListener> producer) {
mSubscribers.erase(producer);
}
+void UidMap::assignIsolatedUid(int isolatedUid, int parentUid) {
+ lock_guard<mutex> lock(mIsolatedMutex);
+
+ mIsolatedUidMap[isolatedUid] = parentUid;
+}
+
+void UidMap::removeIsolatedUid(int isolatedUid, int parentUid) {
+ lock_guard<mutex> lock(mIsolatedMutex);
+
+ auto it = mIsolatedUidMap.find(isolatedUid);
+ if (it != mIsolatedUidMap.end()) {
+ mIsolatedUidMap.erase(it);
+ }
+}
+
+int UidMap::getParentUidOrSelf(int uid) {
+ lock_guard<mutex> lock(mIsolatedMutex);
+
+ auto it = mIsolatedUidMap.find(uid);
+ if (it != mIsolatedUidMap.end()) {
+ return it->second;
+ }
+ return uid;
+}
+
void UidMap::clearOutput() {
mOutput.Clear();
@@ -177,7 +202,7 @@ int64_t UidMap::getMinimumTimestampNs() {
}
UidMapping UidMap::getOutput(const ConfigKey& key) {
- return getOutput(time(nullptr) * 1000000000, key);
+ return getOutput(time(nullptr) * NS_PER_SEC, key);
}
UidMapping UidMap::getOutput(const int64_t& timestamp, const ConfigKey& key) {
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index bf120e04d7c8..24eb96619527 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -1,5 +1,5 @@
/*
- * 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.
@@ -84,6 +84,12 @@ public:
// Informs uid map that a config is removed. Used for keeping mConfigKeys up to date.
void OnConfigRemoved(const ConfigKey& key);
+ void assignIsolatedUid(int isolatedUid, int parentUid);
+ void removeIsolatedUid(int isolatedUid, int parentUid);
+
+ // Returns the parent uid if it exists. Otherwise, returns the same uid that was passed-in.
+ int getParentUidOrSelf(int uid);
+
// Gets the output. If every config key has received the output, then the output is cleared.
UidMapping getOutput(const ConfigKey& key);
@@ -105,11 +111,16 @@ private:
// TODO: Use shared_mutex for improved read-locking if a library can be found in Android.
mutable mutex mMutex;
+ mutable mutex mIsolatedMutex;
// Maps uid to application data. This must be multimap since there is a feature in Android for
// multiple apps to share the same uid.
std::unordered_multimap<int, AppData> mMap;
+ // Maps isolated uid to the parent uid. Any metrics for an isolated uid will instead contribute
+ // to the parent uid.
+ std::unordered_map<int, int> mIsolatedUidMap;
+
// We prepare the output proto as apps are updated, so that we can grab the current output.
UidMapping mOutput;
diff --git a/cmds/statsd/src/stats_events_copy.proto b/cmds/statsd/src/stats_events_copy.proto
deleted file mode 100644
index 9470372005f8..000000000000
--- a/cmds/statsd/src/stats_events_copy.proto
+++ /dev/null
@@ -1,467 +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.
- */
-
-// STOPSHIP: this is a duplicate of stats_event.proto with LITE_RUNTIME added
-// to produce device side lite proto. We should move statsd to soong so that
-// we can generate full and lite library from the same proto file.
-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 = "StatsEventProto";
-
-/**
- * The master event 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 StatsEvent 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 StatsEvent {
- oneof event {
- // 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.
- 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;
- // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
- }
-}
-
-/**
- * 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
- * and Westworld.
- *
- * 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 StatsEvent.
- * - 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 WakelockChanged {
- // TODO: Add attribution instead of uid.
- optional int32 uid = 1;
-
- // Type of wakelock.
- enum Type {
- PARTIAL = 0;
- FULL = 1;
- WINDOW = 2;
- }
- optional int32 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 int32 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;
-} \ No newline at end of file
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 1e37ff8c0aef..4f5df5512847 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -22,7 +22,7 @@ package android.os.statsd;
option java_package = "com.android.os";
option java_outer_classname = "StatsLog";
-import "frameworks/base/cmds/statsd/src/stats_events_copy.proto";
+import "frameworks/base/cmds/statsd/src/atoms_copy.proto";
message KeyValuePair {
optional int32 key = 1;
@@ -38,7 +38,7 @@ message KeyValuePair {
message EventMetricData {
optional int64 timestamp_nanos = 1;
- optional StatsEvent stats_events = 2;
+ optional Atom atom = 2;
}
message CountBucketInfo {
diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h
index d3d7e3709644..e1d0aceb3bd5 100644
--- a/cmds/statsd/src/stats_util.h
+++ b/cmds/statsd/src/stats_util.h
@@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef STATS_UTIL_H
-#define STATS_UTIL_H
+
+#pragma once
#include "logd/LogReader.h"
#include "storage/DropboxWriter.h"
@@ -22,18 +22,23 @@
#include <log/logprint.h>
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include <unordered_map>
+
namespace android {
namespace os {
namespace statsd {
#define DEFAULT_DIMENSION_KEY ""
#define MATCHER_NOT_FOUND -2
-#define NANO_SECONDS_IN_A_SECOND (1000 * 1000 * 1000)
typedef std::string HashableDimensionKey;
typedef std::map<std::string, HashableDimensionKey> ConditionKey;
+// TODO: For P, change int to int64_t.
+// TODO: Should HashableDimensionKey be marked here as const?
+typedef std::unordered_map<HashableDimensionKey, int> DimToValMap;
+
EventMetricData parse(log_msg msg);
int getTagId(log_msg msg);
@@ -42,5 +47,3 @@ std::string getHashableKey(std::vector<KeyValuePair> key);
} // namespace statsd
} // namespace os
} // namespace android
-
-#endif // STATS_UTIL_H
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 87884b33cef0..9a760b1b8ca5 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -83,7 +83,13 @@ message SimpleCondition {
optional string stop_all = 4;
- repeated KeyMatcher dimension = 5;
+ enum InitialValue {
+ UNKNOWN = 0;
+ FALSE = 1;
+ }
+ optional InitialValue initial_value = 5 [default = UNKNOWN];
+
+ repeated KeyMatcher dimension = 6;
}
message Condition {
@@ -106,110 +112,104 @@ message Bucket {
}
message Alert {
- message IncidentdDetails {
- optional string alert_name = 1;
- repeated int32 incidentd_sections = 2;
+ optional string name = 1;
+
+ optional string metric_name = 2;
+
+ message IncidentdDetails {
+ repeated int32 section = 1;
}
- optional IncidentdDetails incidentd_details = 1;
+ optional IncidentdDetails incidentd_details = 3;
- optional int32 number_of_buckets = 3;
+ optional int32 number_of_buckets = 4;
- optional int32 refractory_period_secs = 4;
+ optional int32 refractory_period_secs = 5;
- optional int64 trigger_if_sum_gt = 5;
+ optional int64 trigger_if_sum_gt = 6;
+
+ optional int32 refractory_period_in_buckets = 7;
}
message EventMetric {
- optional int64 metric_id = 1;
+ optional string name = 1;
- optional string what = 2;
+ optional string what = 2;
- optional string condition = 3;
+ optional string condition = 3;
- repeated EventConditionLink links = 4;
+ repeated EventConditionLink links = 4;
}
message CountMetric {
- optional int64 metric_id = 1;
-
- optional string what = 2;
+ optional string name = 1;
- optional string condition = 3;
+ optional string what = 2;
- repeated KeyMatcher dimension = 4;
+ optional string condition = 3;
- optional Bucket bucket = 5;
+ repeated KeyMatcher dimension = 4;
- repeated Alert alerts = 6;
+ optional Bucket bucket = 5;
- optional bool include_in_output = 7;
+ optional bool include_in_output = 6;
- repeated EventConditionLink links = 8;
+ repeated EventConditionLink links = 7;
}
message DurationMetric {
- optional int64 metric_id = 1;
-
- optional string what = 2;
+ optional string name = 1;
- enum AggregationType {
- DURATION_SUM = 1;
+ optional string what = 2;
- DURATION_MAX_SPARSE = 2;
- }
- optional AggregationType type = 3;
-
- optional string predicate = 4;
+ optional string condition = 3;
- repeated KeyMatcher dimension = 5;
+ repeated EventConditionLink links = 4;
- optional Bucket bucket = 6;
+ enum AggregationType {
+ DURATION_SUM = 1;
- repeated Alert alerts = 7;
+ DURATION_MAX_SPARSE = 2;
+ }
+ optional AggregationType type = 5;
- repeated EventConditionLink links = 8;
+ repeated KeyMatcher dimension = 6;
+ optional Bucket bucket = 7;
}
message GaugeMetric {
- optional int64 metric_id = 1;
+ optional string name = 1;
- optional string what = 2;
+ optional string what = 2;
- optional int32 gauge_field = 3;
+ optional int32 gauge_field = 3;
- optional string condition = 4;
+ optional string condition = 4;
- repeated KeyMatcher dimension = 5;
+ repeated KeyMatcher dimension = 5;
- optional Bucket bucket = 6;
+ optional Bucket bucket = 6;
- repeated Alert alerts = 7;
-
- repeated EventConditionLink links = 8;
+ repeated EventConditionLink links = 7;
}
message ValueMetric {
- optional int64 metric_id = 1;
-
- optional string what = 2;
+ optional string name = 1;
- optional int32 value_field = 3;
+ optional string what = 2;
- optional string condition = 4;
+ optional int32 value_field = 3;
- repeated KeyMatcher dimension = 5;
+ optional string condition = 4;
- optional Bucket bucket = 6;
+ repeated KeyMatcher dimension = 5;
- repeated Alert alerts = 7;
+ optional Bucket bucket = 6;
- repeated EventConditionLink links = 8;
+ repeated EventConditionLink links = 7;
- enum Operation {
- SUM = 1;
- }
- optional Operation operation = 9 [default = SUM];
+ enum Operation { SUM = 1; }
+ optional Operation operation = 9 [default = SUM];
}
message EventConditionLink {
@@ -220,17 +220,21 @@ message EventConditionLink {
};
message StatsdConfig {
- optional int64 config_id = 1;
+ optional string name = 1;
+
+ repeated EventMetric event_metric = 2;
+
+ repeated CountMetric count_metric = 3;
- repeated EventMetric event_metric = 2;
+ repeated ValueMetric value_metric = 4;
- repeated CountMetric count_metric = 3;
+ repeated GaugeMetric gauge_metric = 5;
- repeated ValueMetric value_metric = 4;
+ repeated DurationMetric duration_metric = 6;
- repeated DurationMetric duration_metric = 5;
+ repeated LogEntryMatcher log_entry_matcher = 7;
- repeated LogEntryMatcher log_entry_matcher = 6;
+ repeated Condition condition = 8;
- repeated Condition condition = 7;
+ repeated Alert alerts = 9;
}
diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp
index aa896cafffaf..fad5de67ca1a 100644
--- a/cmds/statsd/tests/ConfigManager_test.cpp
+++ b/cmds/statsd/tests/ConfigManager_test.cpp
@@ -30,7 +30,7 @@ namespace os {
namespace statsd {
static ostream& operator<<(ostream& os, const StatsdConfig& config) {
- return os << "StatsdConfig{id=" << config.config_id() << "}";
+ return os << "StatsdConfig{name=" << config.name().c_str() << "}";
}
} // namespace statsd
@@ -56,8 +56,8 @@ MATCHER_P2(ConfigKeyEq, uid, name, "") {
/**
* Validate that the StatsdConfig is the one we wanted.
*/
-MATCHER_P(StatsdConfigEq, configId, "") {
- return arg.config_id() == configId;
+MATCHER_P(StatsdConfigEq, name, "") {
+ return arg.name() == name;
}
/**
@@ -70,13 +70,13 @@ TEST(ConfigManagerTest, TestAddUpdateRemove) {
manager->AddListener(listener);
StatsdConfig config91;
- config91.set_config_id(91);
+ config91.set_name("91");
StatsdConfig config92;
- config92.set_config_id(92);
+ config92.set_name("92");
StatsdConfig config93;
- config93.set_config_id(93);
+ config93.set_name("93");
StatsdConfig config94;
- config94.set_config_id(94);
+ config94.set_name("94");
{
InSequence s;
@@ -85,27 +85,27 @@ TEST(ConfigManagerTest, TestAddUpdateRemove) {
// TODO: Remove this when we get rid of the fake one, and make this
// test loading one from disk somewhere.
EXPECT_CALL(*(listener.get()),
- OnConfigUpdated(ConfigKeyEq(0, "fake"), StatsdConfigEq(12345)))
+ OnConfigUpdated(ConfigKeyEq(0, "fake"), StatsdConfigEq("12345")))
.RetiresOnSaturation();
manager->Startup();
// Add another one
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "zzz"), StatsdConfigEq(91)))
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "zzz"), StatsdConfigEq("91")))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(1, "zzz"), config91);
// Update It
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "zzz"), StatsdConfigEq(92)))
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "zzz"), StatsdConfigEq("92")))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(1, "zzz"), config92);
// Add one with the same uid but a different name
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "yyy"), StatsdConfigEq(93)))
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "yyy"), StatsdConfigEq("93")))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(1, "yyy"), config93);
// Add one with the same name but a different uid
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(2, "zzz"), StatsdConfigEq(94)))
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(2, "zzz"), StatsdConfigEq("94")))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(2, "zzz"), config94);
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index fdfe8ef46853..bb4930a9a342 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -42,7 +42,7 @@ TEST(LogEntryMatcherTest, TestSimpleMatcher) {
auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
simpleMatcher->set_tag(TAG_ID);
- LogEvent event(TAG_ID);
+ LogEvent event(TAG_ID, 0);
// Convert to a LogEvent
event.init();
@@ -62,7 +62,7 @@ TEST(LogEntryMatcherTest, TestBoolMatcher) {
keyValue2->mutable_key_matcher()->set_key(FIELD_ID_2);
// Set up the event
- LogEvent event(TAG_ID);
+ LogEvent event(TAG_ID, 0);
auto list = event.GetAndroidLogEventList();
*list << true;
*list << false;
@@ -98,7 +98,7 @@ TEST(LogEntryMatcherTest, TestStringMatcher) {
keyValue->set_eq_string("some value");
// Set up the event
- LogEvent event(TAG_ID);
+ LogEvent event(TAG_ID, 0);
auto list = event.GetAndroidLogEventList();
*list << "some value";
@@ -109,6 +109,39 @@ TEST(LogEntryMatcherTest, TestStringMatcher) {
EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
}
+TEST(LogEntryMatcherTest, TestMultiFieldsMatcher) {
+ // Set up the matcher
+ LogEntryMatcher matcher;
+ auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
+ simpleMatcher->set_tag(TAG_ID);
+ auto keyValue1 = simpleMatcher->add_key_value_matcher();
+ keyValue1->mutable_key_matcher()->set_key(FIELD_ID_1);
+ auto keyValue2 = simpleMatcher->add_key_value_matcher();
+ keyValue2->mutable_key_matcher()->set_key(FIELD_ID_2);
+
+ // Set up the event
+ LogEvent event(TAG_ID, 0);
+ auto list = event.GetAndroidLogEventList();
+ *list << 2;
+ *list << 3;
+
+ // Convert to a LogEvent
+ event.init();
+
+ // Test
+ keyValue1->set_eq_int(2);
+ keyValue2->set_eq_int(3);
+ EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
+
+ keyValue1->set_eq_int(2);
+ keyValue2->set_eq_int(4);
+ EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
+
+ keyValue1->set_eq_int(4);
+ keyValue2->set_eq_int(3);
+ EXPECT_FALSE(matchesSimple(*simpleMatcher, event));
+}
+
TEST(LogEntryMatcherTest, TestIntComparisonMatcher) {
// Set up the matcher
LogEntryMatcher matcher;
@@ -119,7 +152,7 @@ TEST(LogEntryMatcherTest, TestIntComparisonMatcher) {
keyValue->mutable_key_matcher()->set_key(FIELD_ID_1);
// Set up the event
- LogEvent event(TAG_ID);
+ LogEvent event(TAG_ID, 0);
auto list = event.GetAndroidLogEventList();
*list << 11;
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index e8e4d8be1cd6..caa1cf4dba1b 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -17,6 +17,7 @@
#include "src/condition/ConditionTracker.h"
#include "src/matchers/LogMatchingTracker.h"
#include "src/metrics/CountMetricProducer.h"
+#include "src/metrics/GaugeMetricProducer.h"
#include "src/metrics/MetricProducer.h"
#include "src/metrics/ValueMetricProducer.h"
#include "src/metrics/metrics_manager_util.h"
@@ -40,7 +41,7 @@ using std::vector;
StatsdConfig buildGoodConfig() {
StatsdConfig config;
- config.set_config_id(12345L);
+ config.set_name("12345");
LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
eventMatcher->set_name("SCREEN_IS_ON");
@@ -75,7 +76,7 @@ StatsdConfig buildGoodConfig() {
StatsdConfig buildCircleMatchers() {
StatsdConfig config;
- config.set_config_id(12345L);
+ config.set_name("12345");
LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
eventMatcher->set_name("SCREEN_IS_ON");
@@ -101,7 +102,7 @@ StatsdConfig buildCircleMatchers() {
StatsdConfig buildMissingMatchers() {
StatsdConfig config;
- config.set_config_id(12345L);
+ config.set_name("12345");
LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
eventMatcher->set_name("SCREEN_IS_ON");
@@ -127,7 +128,7 @@ StatsdConfig buildMissingMatchers() {
StatsdConfig buildDimensionMetricsWithMultiTags() {
StatsdConfig config;
- config.set_config_id(12345L);
+ config.set_name("12345");
LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
eventMatcher->set_name("BATTERY_VERY_LOW");
@@ -149,7 +150,7 @@ StatsdConfig buildDimensionMetricsWithMultiTags() {
// Count process state changes, slice by uid, while SCREEN_IS_OFF
CountMetric* metric = config.add_count_metric();
- metric->set_metric_id(3);
+ metric->set_name("3");
metric->set_what("BATTERY_LOW");
metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
KeyMatcher* keyMatcher = metric->add_dimension();
@@ -160,7 +161,7 @@ StatsdConfig buildDimensionMetricsWithMultiTags() {
StatsdConfig buildCircleConditions() {
StatsdConfig config;
- config.set_config_id(12345L);
+ config.set_name("12345");
LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
eventMatcher->set_name("SCREEN_IS_ON");
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index 671f6d4ac472..c64719ee0c85 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -13,7 +13,10 @@
// limitations under the License.
#include "packages/UidMap.h"
+#include "StatsLogProcessor.h"
#include "config/ConfigKey.h"
+#include "logd/LogEvent.h"
+#include "statslog.h"
#include <gtest/gtest.h>
@@ -29,6 +32,31 @@ namespace statsd {
const string kApp1 = "app1.sharing.1";
const string kApp2 = "app2.sharing.1";
+TEST(UidMapTest, TestIsolatedUID) {
+ sp<UidMap> m = new UidMap();
+ StatsLogProcessor p(m, nullptr);
+ LogEvent addEvent(android::util::ISOLATED_UID_CHANGED, 1);
+ android_log_event_list* list = addEvent.GetAndroidLogEventList();
+ *list << 100; // parent UID
+ *list << 101; // isolated UID
+ *list << 1; // Indicates creation.
+ addEvent.init();
+
+ EXPECT_EQ(101, m->getParentUidOrSelf(101));
+
+ p.OnLogEvent(addEvent);
+ EXPECT_EQ(100, m->getParentUidOrSelf(101));
+
+ LogEvent removeEvent(android::util::ISOLATED_UID_CHANGED, 1);
+ list = removeEvent.GetAndroidLogEventList();
+ *list << 100; // parent UID
+ *list << 101; // isolated UID
+ *list << 0; // Indicates removal.
+ removeEvent.init();
+ p.OnLogEvent(removeEvent);
+ EXPECT_EQ(101, m->getParentUidOrSelf(101));
+}
+
TEST(UidMapTest, TestMatching) {
UidMap m;
vector<int32_t> uids;
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
new file mode 100644
index 000000000000..b8150d04ed07
--- /dev/null
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -0,0 +1,239 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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/anomaly/DiscreteAnomalyTracker.h"
+
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <vector>
+
+using namespace testing;
+using android::sp;
+using std::set;
+using std::unordered_map;
+using std::vector;
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+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++) {
+ (*bucket)[itr->first] += itr->second;
+ }
+}
+
+std::shared_ptr<DimToValMap> MockeBucket(
+ const std::vector<std::pair<string, long>>& key_value_pair_list) {
+ std::shared_ptr<DimToValMap> bucket = std::make_shared<DimToValMap>();
+ AddValueToBucket(key_value_pair_list, bucket);
+ return bucket;
+}
+
+TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
+ Alert alert;
+ alert.set_number_of_buckets(3);
+ alert.set_refractory_period_in_buckets(3);
+ alert.set_trigger_if_sum_gt(2);
+
+ DiscreteAnomalyTracker anomaly_tracker(alert);
+
+ std::shared_ptr<DimToValMap> bucket0 = MockeBucket({{"a", 1}, {"b", 2}, {"c", 1}});
+ // Adds bucket #0
+ anomaly_tracker.addOrUpdateBucket(bucket0, 0);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 3UL);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 1);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 2);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+ EXPECT_FALSE(anomaly_tracker.detectAnomaly());
+ anomaly_tracker.declareAndDeclareAnomaly();
+ EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 0L);
+
+ // Adds bucket #0 again. The sum does not change.
+ anomaly_tracker.addOrUpdateBucket(bucket0, 0);
+ EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 0L);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 3UL);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 1);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 2);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+ EXPECT_FALSE(anomaly_tracker.detectAnomaly());
+ anomaly_tracker.declareAndDeclareAnomaly();
+ EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 0L);
+ EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, -1L);
+
+ // Adds bucket #1.
+ std::shared_ptr<DimToValMap> bucket1 = MockeBucket({{"b", 2}});
+ anomaly_tracker.addOrUpdateBucket(bucket1, 1);
+ EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 1L);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 3UL);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 1);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 4);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+ // Alarm.
+ EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+ anomaly_tracker.declareAndDeclareAnomaly();
+ EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 1L);
+ EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 1L);
+
+ // Adds bucket #1 again. The sum does not change.
+ anomaly_tracker.addOrUpdateBucket(bucket1, 1);
+ EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 1L);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 3UL);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 1);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 4);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+ // Alarm.
+ EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+ anomaly_tracker.declareAndDeclareAnomaly();
+ EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 1L);
+ EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 1L);
+
+ // Adds bucket #2.
+ anomaly_tracker.addOrUpdateBucket(MockeBucket({{"a", 1}}), 2);
+ EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 2L);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 3UL);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 2);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 4);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+ EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+ // Within refractory period.
+ anomaly_tracker.declareAndDeclareAnomaly();
+ EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 1L);
+ EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 1L);
+
+ // Adds bucket #3.
+ anomaly_tracker.addOrUpdateBucket(MockeBucket({{"a", 1}}), 3);
+ EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 3L);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 2UL);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 2);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 2);
+ EXPECT_FALSE(anomaly_tracker.detectAnomaly());
+
+ // Adds bucket #3.
+ anomaly_tracker.addOrUpdateBucket(MockeBucket({{"a", 2}}), 4);
+ EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 4L);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 1UL);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 4);
+ EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+ // Within refractory period.
+ anomaly_tracker.declareAndDeclareAnomaly();
+ EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 1L);
+ EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 1L);
+
+ anomaly_tracker.addOrUpdateBucket(MockeBucket({{"a", 1}}), 5);
+ EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 5L);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 1UL);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 4);
+ EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+ // Within refractory period.
+ anomaly_tracker.declareAndDeclareAnomaly();
+ EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 2L);
+ EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 5L);
+}
+
+TEST(AnomalyTrackerTest, TestSparseBuckets) {
+ Alert alert;
+ alert.set_number_of_buckets(3);
+ alert.set_refractory_period_in_buckets(3);
+ alert.set_trigger_if_sum_gt(2);
+
+ DiscreteAnomalyTracker anomaly_tracker(alert);
+
+ // Add bucket #9
+ anomaly_tracker.addOrUpdateBucket(MockeBucket({{"a", 1}, {"b", 2}, {"c", 1}}), 9);
+ EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 9L);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 3UL);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("a")->second, 1);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 2);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+ EXPECT_FALSE(anomaly_tracker.detectAnomaly());
+ anomaly_tracker.declareAndDeclareAnomaly();
+ EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 0L);
+ EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, -1L);
+
+ // Add bucket #16
+ anomaly_tracker.addOrUpdateBucket(MockeBucket({{"b", 4}}), 16);
+ EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 16L);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 1UL);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 4);
+ EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+ anomaly_tracker.declareAndDeclareAnomaly();
+ EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 1L);
+ EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 16L);
+
+ // Add bucket #18
+ anomaly_tracker.addOrUpdateBucket(MockeBucket({{"b", 1}, {"c", 1}}), 18);
+ EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 18L);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 2UL);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 5);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+ EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+ anomaly_tracker.declareAndDeclareAnomaly();
+ // Within refractory period.
+ EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 1L);
+ EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 16L);
+
+ // Add bucket #18 again.
+ anomaly_tracker.addOrUpdateBucket(MockeBucket({{"b", 1}, {"c", 1}}), 18);
+ EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 18L);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 2UL);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 5);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+ EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+ anomaly_tracker.declareAndDeclareAnomaly();
+ EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 1L);
+ EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 16L);
+
+ // Add bucket #20
+ anomaly_tracker.addOrUpdateBucket(MockeBucket({{"b", 3}, {"d", 1}}), 20);
+ EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 20L);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 3UL);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("b")->second, 4);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("c")->second, 1);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("d")->second, 1);
+ EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+ anomaly_tracker.declareAndDeclareAnomaly();
+ EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 2L);
+ EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 20L);
+
+ // Add bucket #25
+ anomaly_tracker.addOrUpdateBucket(MockeBucket({{"d", 1}}), 25);
+ EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 25L);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 1UL);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("d")->second, 1L);
+ EXPECT_FALSE(anomaly_tracker.detectAnomaly());
+ anomaly_tracker.declareAndDeclareAnomaly();
+ EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 2L);
+ EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 20L);
+
+ // Add bucket #28
+ anomaly_tracker.addOrUpdateBucket(MockeBucket({{"e", 5}}), 28);
+ EXPECT_EQ(anomaly_tracker.mCurrentBucketIndex, 28L);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.size(), 1UL);
+ EXPECT_EQ(anomaly_tracker.mSumOverPastBuckets.find("e")->second, 5L);
+ EXPECT_TRUE(anomaly_tracker.detectAnomaly());
+ anomaly_tracker.declareAndDeclareAnomaly();
+ EXPECT_EQ(anomaly_tracker.mAnomalyDeclared, 3L);
+ EXPECT_EQ(anomaly_tracker.mLastAlarmAtBucketIndex, 28L);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/ConditionTracker_test.cpp b/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp
index 2935ac7136ba..23d69267d1c0 100644
--- a/cmds/statsd/tests/ConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp
@@ -23,7 +23,6 @@
using namespace android::os::statsd;
using std::vector;
-
#ifdef __ANDROID__
TEST(ConditionTrackerTest, TestUnknownCondition) {
LogicalOperation operation = LogicalOperation::AND;
@@ -39,7 +38,7 @@ TEST(ConditionTrackerTest, TestUnknownCondition) {
conditionResults.push_back(ConditionState::kTrue);
EXPECT_EQ(evaluateCombinationCondition(children, operation, conditionResults),
- ConditionState::kUnknown);
+ ConditionState::kUnknown);
}
TEST(ConditionTrackerTest, TestAndCondition) {
// Set up the matcher
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
new file mode 100644
index 000000000000..855e66615f8e
--- /dev/null
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -0,0 +1,481 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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/condition/SimpleConditionTracker.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <vector>
+
+using std::map;
+using std::unordered_map;
+using std::vector;
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+SimpleCondition 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");
+ if (outputSlicedUid) {
+ KeyMatcher* keyMatcher = simpleCondition.add_dimension();
+ keyMatcher->set_key(1);
+ }
+
+ simpleCondition.set_count_nesting(countNesting);
+ simpleCondition.set_initial_value(defaultFalse ? SimpleCondition_InitialValue_FALSE
+ : SimpleCondition_InitialValue_UNKNOWN);
+ return simpleCondition;
+}
+
+void makeWakeLockEvent(LogEvent* event, int uid, const string& wl, int acquire) {
+ auto list = event->GetAndroidLogEventList();
+ *list << uid; // uid
+ *list << wl;
+ *list << acquire;
+ event->init();
+}
+
+map<string, HashableDimensionKey> getWakeLockQueryKey(int key, int uid,
+ const string& conditionName) {
+ // test query
+ KeyValuePair kv1;
+ kv1.set_key(key);
+ kv1.set_value_int(uid);
+ vector<KeyValuePair> kv_list;
+ kv_list.push_back(kv1);
+ map<string, HashableDimensionKey> queryKey;
+ queryKey[conditionName] = getHashableKey(kv_list);
+ return queryKey;
+}
+
+TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) {
+ SimpleCondition simpleCondition;
+ simpleCondition.set_start("SCREEN_TURNED_ON");
+ simpleCondition.set_stop("SCREEN_TURNED_OFF");
+ simpleCondition.set_count_nesting(false);
+
+ unordered_map<string, int> trackerNameIndexMap;
+ trackerNameIndexMap["SCREEN_TURNED_ON"] = 0;
+ trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1;
+
+ SimpleConditionTracker conditionTracker("SCREEN_IS_ON", 0 /*tracker index*/, simpleCondition,
+ trackerNameIndexMap);
+
+ LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
+
+ vector<MatchingState> matcherState;
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+
+ vector<sp<ConditionTracker>> allConditions;
+ vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
+ vector<bool> changedCache(1, false);
+
+ conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ changedCache);
+ // not matched start or stop. condition doesn't change
+ EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]);
+ EXPECT_FALSE(changedCache[0]);
+
+ // prepare a case for match start.
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+
+ conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ changedCache);
+ // now condition should change to true.
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+ EXPECT_TRUE(changedCache[0]);
+
+ // match nothing.
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+
+ conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ changedCache);
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+ EXPECT_FALSE(changedCache[0]);
+
+ // the case for match stop.
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+
+ conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ changedCache);
+
+ // condition changes to false.
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+ EXPECT_TRUE(changedCache[0]);
+
+ // match stop again.
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+
+ conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ changedCache);
+ // condition should still be false. not changed.
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+ EXPECT_FALSE(changedCache[0]);
+}
+
+TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) {
+ SimpleCondition simpleCondition;
+ simpleCondition.set_start("SCREEN_TURNED_ON");
+ simpleCondition.set_stop("SCREEN_TURNED_OFF");
+ simpleCondition.set_count_nesting(true);
+
+ unordered_map<string, int> trackerNameIndexMap;
+ trackerNameIndexMap["SCREEN_TURNED_ON"] = 0;
+ trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1;
+
+ SimpleConditionTracker conditionTracker("SCREEN_IS_ON", 0 /*condition tracker index*/,
+ simpleCondition, trackerNameIndexMap);
+
+ LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
+
+ // one matched start
+ vector<MatchingState> matcherState;
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ vector<sp<ConditionTracker>> allConditions;
+ vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
+ vector<bool> changedCache(1, false);
+
+ conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ changedCache);
+
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+ EXPECT_TRUE(changedCache[0]);
+
+ // prepare for another matched start.
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+
+ conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ changedCache);
+
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+ EXPECT_FALSE(changedCache[0]);
+
+ // ONE MATCHED STOP
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+
+ conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ changedCache);
+ // result should still be true
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+ EXPECT_FALSE(changedCache[0]);
+
+ // ANOTHER MATCHED STOP
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+
+ conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ changedCache);
+ // result should still be true
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+ EXPECT_TRUE(changedCache[0]);
+}
+
+TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
+ SimpleCondition simpleCondition = getWakeLockHeldCondition(
+ true /*nesting*/, true /*default to false*/, true /*output slice by uid*/);
+ string conditionName = "WL_HELD_BY_UID2";
+
+ unordered_map<string, int> trackerNameIndexMap;
+ trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
+ trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
+ trackerNameIndexMap["RELEASE_ALL"] = 2;
+
+ SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/,
+ simpleCondition, trackerNameIndexMap);
+ int uid = 111;
+
+ LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
+ makeWakeLockEvent(&event, uid, "wl1", 1);
+
+ // one matched start
+ vector<MatchingState> matcherState;
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ vector<sp<ConditionTracker>> allConditions;
+ vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
+ vector<bool> changedCache(1, false);
+
+ conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ changedCache);
+
+ EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
+ EXPECT_TRUE(changedCache[0]);
+
+ // Now test query
+ const auto queryKey = getWakeLockQueryKey(1, uid, conditionName);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+
+ conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+
+ // another wake lock acquired by this uid
+ LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
+ makeWakeLockEvent(&event2, uid, "wl2", 1);
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
+ changedCache);
+ EXPECT_FALSE(changedCache[0]);
+
+ // wake lock 1 release
+ LogEvent event3(1 /*tagId*/, 0 /*timestamp*/);
+ makeWakeLockEvent(&event3, uid, "wl1", 0); // now release it.
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
+ changedCache);
+ // nothing changes, because wake lock 2 is still held for this uid
+ EXPECT_FALSE(changedCache[0]);
+
+ LogEvent event4(1 /*tagId*/, 0 /*timestamp*/);
+ makeWakeLockEvent(&event4, uid, "wl2", 0); // now release it.
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event4, matcherState, allConditions, conditionCache,
+ changedCache);
+ EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
+ EXPECT_TRUE(changedCache[0]);
+
+ // query again
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+}
+
+TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
+ SimpleCondition simpleCondition = getWakeLockHeldCondition(
+ true /*nesting*/, true /*default to false*/, false /*slice output by uid*/);
+ string conditionName = "WL_HELD";
+
+ unordered_map<string, int> trackerNameIndexMap;
+ trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
+ trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
+ trackerNameIndexMap["RELEASE_ALL"] = 2;
+
+ SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/,
+ simpleCondition, trackerNameIndexMap);
+ int uid1 = 111;
+ string uid1_wl1 = "wl1_1";
+ int uid2 = 222;
+ string uid2_wl1 = "wl2_1";
+
+ LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
+ makeWakeLockEvent(&event, uid1, uid1_wl1, 1);
+
+ // one matched start for uid1
+ vector<MatchingState> matcherState;
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ vector<sp<ConditionTracker>> allConditions;
+ vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
+ vector<bool> changedCache(1, false);
+
+ conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ changedCache);
+
+ EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
+ EXPECT_TRUE(changedCache[0]);
+
+ // Now test query
+ map<string, HashableDimensionKey> queryKey;
+ conditionCache[0] = ConditionState::kNotEvaluated;
+
+ conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+
+ // another wake lock acquired by this uid
+ LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
+ makeWakeLockEvent(&event2, uid2, uid2_wl1, 1);
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
+ changedCache);
+ EXPECT_FALSE(changedCache[0]);
+
+ // uid1 wake lock 1 release
+ LogEvent event3(1 /*tagId*/, 0 /*timestamp*/);
+ makeWakeLockEvent(&event3, uid1, uid1_wl1, 0); // now release it.
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
+ changedCache);
+ // nothing changes, because uid2 is still holding wl.
+ EXPECT_FALSE(changedCache[0]);
+
+ LogEvent event4(1 /*tagId*/, 0 /*timestamp*/);
+ makeWakeLockEvent(&event4, uid2, uid2_wl1, 0); // now release it.
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event4, matcherState, allConditions, conditionCache,
+ changedCache);
+ EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
+ EXPECT_TRUE(changedCache[0]);
+
+ // query again
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+}
+
+TEST(SimpleConditionTrackerTest, TestStopAll) {
+ SimpleCondition simpleCondition = getWakeLockHeldCondition(
+ true /*nesting*/, true /*default to false*/, true /*output slice by uid*/);
+ string conditionName = "WL_HELD_BY_UID3";
+
+ unordered_map<string, int> trackerNameIndexMap;
+ trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
+ trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
+ trackerNameIndexMap["RELEASE_ALL"] = 2;
+
+ SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/,
+ simpleCondition, trackerNameIndexMap);
+ int uid1 = 111;
+ int uid2 = 222;
+
+ LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
+ makeWakeLockEvent(&event, uid1, "wl1", 1);
+
+ // one matched start
+ vector<MatchingState> matcherState;
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ vector<sp<ConditionTracker>> allConditions;
+ vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
+ vector<bool> changedCache(1, false);
+
+ conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ changedCache);
+
+ EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
+ EXPECT_TRUE(changedCache[0]);
+
+ // Now test query
+ const auto queryKey = getWakeLockQueryKey(1, uid1, conditionName);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+
+ conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+
+ // another wake lock acquired by uid2
+ LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
+ makeWakeLockEvent(&event2, uid2, "wl2", 1);
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
+ changedCache);
+ EXPECT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
+ EXPECT_TRUE(changedCache[0]);
+
+ // TEST QUERY
+ const auto queryKey2 = getWakeLockQueryKey(1, uid2, conditionName);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+
+ conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+
+
+ // stop all event
+ LogEvent event3(2 /*tagId*/, 0 /*timestamp*/);
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kMatched);
+
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
+ changedCache);
+ EXPECT_TRUE(changedCache[0]);
+ EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
+
+ // TEST QUERY
+ const auto queryKey3 = getWakeLockQueryKey(1, uid1, conditionName);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+
+ conditionTracker.isConditionMet(queryKey, allConditions, 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);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
new file mode 100644
index 000000000000..d07a84d4c3d8
--- /dev/null
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -0,0 +1,183 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 "metrics_test_helper.h"
+#include "src/metrics/CountMetricProducer.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <vector>
+
+using namespace testing;
+using android::sp;
+using std::set;
+using std::unordered_map;
+using std::vector;
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+ int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
+ int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
+ int tagId = 1;
+
+ CountMetric metric;
+ metric.set_name("1");
+ metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
+
+ LogEvent event1(tagId, bucketStartTimeNs + 1);
+ LogEvent event2(tagId, bucketStartTimeNs + 2);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ CountMetricProducer countProducer(metric, -1 /*-1 meaning no condition*/, wizard,
+ bucketStartTimeNs);
+
+ // 2 events in bucket 1.
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1, false);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2, false);
+ countProducer.flushCounterIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ const auto& bucketInfo = buckets[0];
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
+ EXPECT_EQ(2LL, bucketInfo.mCount);
+
+ // 1 matched event happens in bucket 2.
+ LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 2);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3, false);
+ countProducer.flushCounterIfNeeded(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY].size());
+ const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY][1];
+ EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs);
+ EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs);
+ EXPECT_EQ(1LL, bucketInfo2.mCount);
+
+ // nothing happens in bucket 3. we should not record anything for bucket 3.
+ countProducer.flushCounterIfNeeded(bucketStartTimeNs + 3 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
+ EXPECT_EQ(2UL, buckets3.size());
+}
+
+TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ CountMetric metric;
+ metric.set_name("1");
+ metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
+ metric.set_condition("SCREEN_ON");
+
+ LogEvent event1(1, bucketStartTimeNs + 1);
+ LogEvent event2(1, bucketStartTimeNs + 10);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ CountMetricProducer countProducer(metric, 1, wizard, bucketStartTimeNs);
+
+ countProducer.onConditionChanged(true, bucketStartTimeNs);
+ countProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/);
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+ countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2);
+ countProducer.onMatchedLogEvent(1 /*matcher index*/, event2, false /*pulled*/);
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+ countProducer.flushCounterIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ const auto& bucketInfo = buckets[0];
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
+ EXPECT_EQ(1LL, bucketInfo.mCount);
+}
+
+TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ CountMetric metric;
+ 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();
+ link->set_condition("APP_IN_BACKGROUND_PER_UID");
+ link->add_key_in_main()->set_key(1);
+ link->add_key_in_condition()->set_key(2);
+
+ LogEvent event1(1, bucketStartTimeNs + 1);
+ auto list = event1.GetAndroidLogEventList();
+ *list << "111"; // uid
+ event1.init();
+ ConditionKey key1;
+ key1["APP_IN_BACKGROUND_PER_UID"] = "2:111|";
+
+ LogEvent event2(1, bucketStartTimeNs + 10);
+ auto list2 = event2.GetAndroidLogEventList();
+ *list2 << "222"; // uid
+ event2.init();
+ ConditionKey key2;
+ key2["APP_IN_BACKGROUND_PER_UID"] = "2:222|";
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ EXPECT_CALL(*wizard, query(_, key1)).WillOnce(Return(ConditionState::kFalse));
+
+ EXPECT_CALL(*wizard, query(_, key2)).WillOnce(Return(ConditionState::kTrue));
+
+ CountMetricProducer countProducer(metric, 1 /*condition tracker index*/, wizard,
+ bucketStartTimeNs);
+
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1, false);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2, false);
+
+ countProducer.flushCounterIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ const auto& bucketInfo = buckets[0];
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
+ EXPECT_EQ(1LL, bucketInfo.mCount);
+}
+
+} // 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
new file mode 100644
index 000000000000..0971d2682d40
--- /dev/null
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -0,0 +1,130 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 "metrics_test_helper.h"
+#include "src/metrics/EventMetricProducer.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <vector>
+
+using namespace testing;
+using android::sp;
+using std::set;
+using std::unordered_map;
+using std::vector;
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+TEST(EventMetricProducerTest, TestNoCondition) {
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ EventMetric metric;
+ metric.set_name("1");
+
+ LogEvent event1(1 /*tag id*/, bucketStartTimeNs + 1);
+ LogEvent event2(1 /*tag id*/, bucketStartTimeNs + 2);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ EventMetricProducer eventProducer(metric, -1 /*-1 meaning no condition*/, wizard,
+ bucketStartTimeNs);
+
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/);
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2, false /*pulled*/);
+
+ // TODO: get the report and check the content after the ProtoOutputStream change is done.
+ // eventProducer.onDumpReport();
+}
+
+TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) {
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ EventMetric metric;
+ metric.set_name("1");
+ metric.set_condition("SCREEN_ON");
+
+ LogEvent event1(1, bucketStartTimeNs + 1);
+ LogEvent event2(1, bucketStartTimeNs + 10);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ EventMetricProducer eventProducer(metric, 1, wizard, bucketStartTimeNs);
+
+ eventProducer.onConditionChanged(true /*condition*/, bucketStartTimeNs);
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/);
+
+ eventProducer.onConditionChanged(false /*condition*/, bucketStartTimeNs + 2);
+
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2, false /*pulled*/);
+
+ // TODO: get the report and check the content after the ProtoOutputStream change is done.
+ // eventProducer.onDumpReport();
+}
+
+TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ EventMetric metric;
+ metric.set_name("1");
+ metric.set_condition("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON");
+ EventConditionLink* link = metric.add_links();
+ link->set_condition("APP_IN_BACKGROUND_PER_UID");
+ link->add_key_in_main()->set_key(1);
+ link->add_key_in_condition()->set_key(2);
+
+ LogEvent event1(1, bucketStartTimeNs + 1);
+ auto list = event1.GetAndroidLogEventList();
+ *list << "111"; // uid
+ event1.init();
+ ConditionKey key1;
+ key1["APP_IN_BACKGROUND_PER_UID"] = "2:111|";
+
+ LogEvent event2(1, bucketStartTimeNs + 10);
+ auto list2 = event2.GetAndroidLogEventList();
+ *list2 << "222"; // uid
+ event2.init();
+ ConditionKey key2;
+ key2["APP_IN_BACKGROUND_PER_UID"] = "2:222|";
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ EXPECT_CALL(*wizard, query(_, key1)).WillOnce(Return(ConditionState::kFalse));
+
+ EXPECT_CALL(*wizard, query(_, key2)).WillOnce(Return(ConditionState::kTrue));
+
+ EventMetricProducer eventProducer(metric, 1, wizard, bucketStartTimeNs);
+
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/);
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2, false /*pulled*/);
+
+ // TODO: get the report and check the content after the ProtoOutputStream change is done.
+ // eventProducer.onDumpReport();
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index ae8bf4265235..58bf1b30a9d0 100644
--- a/cmds/statsd/tests/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -12,12 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
+#include "metrics_test_helper.h"
#include "src/condition/ConditionWizard.h"
#include "src/metrics/duration_helper/MaxDurationTracker.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
#include <stdio.h>
#include <set>
#include <unordered_map>
@@ -32,18 +32,14 @@ using std::vector;
#ifdef __ANDROID__
-class MockConditionWizard : public ConditionWizard {
-public:
- MOCK_METHOD2(
- query,
- ConditionState(const int conditionIndex,
- const std::map<std::string, HashableDimensionKey>& conditionParameters));
-};
+namespace android {
+namespace os {
+namespace statsd {
TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- vector<DurationBucketInfo> buckets;
+ vector<DurationBucket> buckets;
ConditionKey key1;
uint64_t bucketStartTimeNs = 10000000000;
@@ -59,13 +55,13 @@ TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(20, buckets[0].duration_nanos());
+ EXPECT_EQ(20, buckets[0].mDuration);
}
TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- vector<DurationBucketInfo> buckets;
+ vector<DurationBucket> buckets;
ConditionKey key1;
uint64_t bucketStartTimeNs = 10000000000;
@@ -77,8 +73,8 @@ TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) {
tracker.flushIfNeeded(bucketStartTimeNs + (2 * bucketSizeNs) + 1);
EXPECT_EQ(2u, buckets.size());
- EXPECT_EQ((long long)(bucketSizeNs - 1), buckets[0].duration_nanos());
- EXPECT_EQ((long long)bucketSizeNs, buckets[1].duration_nanos());
+ EXPECT_EQ((long long)(bucketSizeNs - 1), buckets[0].mDuration);
+ EXPECT_EQ((long long)bucketSizeNs, buckets[1].mDuration);
}
TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
@@ -90,7 +86,7 @@ TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
EXPECT_CALL(*wizard, query(_, key1)) // #4
.WillOnce(Return(ConditionState::kFalse));
- vector<DurationBucketInfo> buckets;
+ vector<DurationBucket> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
@@ -107,9 +103,12 @@ TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(5, buckets[0].duration_nanos());
+ EXPECT_EQ(5, buckets[0].mDuration);
}
+} // namespace statsd
+} // namespace os
+} // namespace android
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/cmds/statsd/tests/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 0b7981935ab1..74a6f11754f3 100644
--- a/cmds/statsd/tests/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -12,18 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
+#include "metrics_test_helper.h"
#include "src/condition/ConditionWizard.h"
#include "src/metrics/duration_helper/OringDurationTracker.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;
@@ -31,14 +30,9 @@ using std::unordered_map;
using std::vector;
#ifdef __ANDROID__
-
-class MockConditionWizard : public ConditionWizard {
-public:
- MOCK_METHOD2(
- query,
- ConditionState(const int conditionIndex,
- const std::map<std::string, HashableDimensionKey>& conditionParameters));
-};
+namespace android {
+namespace os {
+namespace statsd {
TEST(OringDurationTrackerTest, TestDurationOverlap) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -46,7 +40,7 @@ TEST(OringDurationTrackerTest, TestDurationOverlap) {
ConditionKey key1;
key1["APP_BACKGROUND"] = "1:maps|";
- vector<DurationBucketInfo> buckets;
+ vector<DurationBucket> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
@@ -62,7 +56,7 @@ TEST(OringDurationTrackerTest, TestDurationOverlap) {
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(durationTimeNs, buckets[0].duration_nanos());
+ EXPECT_EQ(durationTimeNs, buckets[0].mDuration);
}
TEST(OringDurationTrackerTest, TestDurationConditionChange) {
@@ -74,7 +68,7 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange) {
EXPECT_CALL(*wizard, query(_, key1)) // #4
.WillOnce(Return(ConditionState::kFalse));
- vector<DurationBucketInfo> buckets;
+ vector<DurationBucket> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
@@ -91,9 +85,11 @@ TEST(OringDurationTrackerTest, TestDurationConditionChange) {
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(5, buckets[0].duration_nanos());
+ EXPECT_EQ(5, buckets[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/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
new file mode 100644
index 000000000000..72b4194d533e
--- /dev/null
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -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.
+
+#include "metrics_test_helper.h"
+#include "src/metrics/ValueMetricProducer.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <vector>
+
+using namespace testing;
+using android::sp;
+using std::set;
+using std::unordered_map;
+using std::vector;
+using std::shared_ptr;
+using std::make_shared;
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/*
+ * Tests pulled atoms with no conditions
+ */
+TEST(ValueMetricProducerTest, TestNonDimensionalEvents) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
+
+ int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
+ int64_t bucket3StartTimeNs = bucketStartTimeNs + 2*bucketSizeNs;
+
+ ValueMetric metric;
+ metric.set_name("1");
+ metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
+ metric.set_value_field(2);
+
+ int tagId = 1;
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ // TODO: pending refactor of StatsPullerManager
+ // For now we still need this so that it doesn't do real pulling.
+ shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+
+ ValueMetricProducer valueProducer(metric, -1 /*-1 meaning no condition*/, wizard,tagId,
+ bucketStartTimeNs, pullerManager);
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
+ auto list = event->GetAndroidLogEventList();
+ *list << 1;
+ *list << 11;
+ event->init();
+ allData.push_back(event);
+
+ valueProducer.onDataPulled(allData);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ // has one raw pair
+ EXPECT_EQ(1UL, curInterval.raw.size());
+ // value is 11, 11
+ EXPECT_EQ(11, curInterval.raw.front().first);
+ EXPECT_EQ(11, curInterval.raw.front().second);
+ ValueMetricProducer::Interval nextInterval = valueProducer.mNextSlicedBucket.begin()->second;
+ // has one raw pair
+ EXPECT_EQ(1UL, nextInterval.raw.size());
+ // value is 11, 0
+ EXPECT_EQ(11, nextInterval.raw.front().first);
+ EXPECT_EQ(0, nextInterval.raw.front().second);
+ EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+
+ allData.clear();
+ event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+ list = event->GetAndroidLogEventList();
+ *list << 1;
+ *list << 22;
+ event->init();
+ allData.push_back(event);
+ valueProducer.onDataPulled(allData);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ // has one raw pair
+ EXPECT_EQ(1UL, curInterval.raw.size());
+ // value is 22, 0
+ EXPECT_EQ(22, curInterval.raw.front().first);
+ EXPECT_EQ(0, curInterval.raw.front().second);
+ EXPECT_EQ(0UL, valueProducer.mNextSlicedBucket.size());
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+ EXPECT_EQ(11, valueProducer.mPastBuckets.begin()->second.back().mValue);
+
+ allData.clear();
+ event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
+ list = event->GetAndroidLogEventList();
+ *list << 1;
+ *list << 33;
+ event->init();
+ allData.push_back(event);
+ valueProducer.onDataPulled(allData);
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ EXPECT_EQ(1UL, curInterval.raw.size());
+ // value is 33, 0
+ EXPECT_EQ(33, curInterval.raw.front().first);
+ EXPECT_EQ(0, curInterval.raw.front().second);
+ EXPECT_EQ(0UL, valueProducer.mNextSlicedBucket.size());
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
+ EXPECT_EQ(11, valueProducer.mPastBuckets.begin()->second.back().mValue);
+}
+
+/*
+ * Test pulled event with non sliced condition.
+ */
+TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
+
+ int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
+ int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
+
+ ValueMetric metric;
+ metric.set_name("1");
+ metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
+ metric.set_value_field(2);
+ metric.set_condition("SCREEN_ON");
+
+ int tagId = 1;
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+ EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Invoke([] (int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
+
+ int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
+ int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ auto list = event->GetAndroidLogEventList();
+ *list << 1;
+ *list << 100;
+ event->init();
+ data->push_back(event);
+ return true;
+ }))
+ .WillOnce(Invoke([] (int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
+
+ int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
+ int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
+ auto list = event->GetAndroidLogEventList();
+ *list << 1;
+ *list << 120;
+ event->init();
+ data->push_back(event);
+ return true;
+ }));
+
+ ValueMetricProducer valueProducer(metric, 1, wizard,tagId,
+ bucketStartTimeNs, pullerManager);
+
+ valueProducer.onConditionChanged(true, bucketStartTimeNs + 10);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ // has one raw pair
+ EXPECT_EQ(1UL, curInterval.raw.size());
+ // value is 100, 0
+ EXPECT_EQ(100, curInterval.raw.front().first);
+ EXPECT_EQ(0, curInterval.raw.front().second);
+ EXPECT_EQ(0UL, valueProducer.mNextSlicedBucket.size());
+ EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+ auto list = event->GetAndroidLogEventList();
+ *list << 1;
+ *list << 110;
+ event->init();
+ allData.push_back(event);
+ valueProducer.onDataPulled(allData);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ // has one raw pair
+ EXPECT_EQ(1UL, curInterval.raw.size());
+ // value is 110, 0
+ EXPECT_EQ(110, curInterval.raw.front().first);
+ EXPECT_EQ(0, curInterval.raw.front().second);
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+ EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().mValue);
+
+ valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ // has one raw pair
+ EXPECT_EQ(1UL, curInterval.raw.size());
+ // value is 110, 120
+ EXPECT_EQ(110, curInterval.raw.front().first);
+ EXPECT_EQ(120, curInterval.raw.front().second);
+}
+
+TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
+
+ int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
+ int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
+
+ ValueMetric metric;
+ metric.set_name("1");
+ metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
+ metric.set_value_field(2);
+
+ int tagId = 1;
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ shared_ptr<MockStatsPullerManager> pullerManager = make_shared<StrictMock<MockStatsPullerManager>>();
+
+ ValueMetricProducer valueProducer(metric, -1, wizard,-1,
+ bucketStartTimeNs, pullerManager);
+
+ shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ auto list = event1->GetAndroidLogEventList();
+ *list << 1;
+ *list << 10;
+ event1->init();
+ shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ auto list2 = event2->GetAndroidLogEventList();
+ *list2 << 1;
+ *list2 << 20;
+ event2->init();
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1, false);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ // has one raw pair
+ EXPECT_EQ(1UL, curInterval.raw.size());
+ // value is 10, 0
+ EXPECT_EQ(10, curInterval.raw.front().first);
+ EXPECT_EQ(0, curInterval.raw.front().second);
+ EXPECT_EQ(0UL, valueProducer.mNextSlicedBucket.size());
+
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2, false);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ // has one raw pair
+ EXPECT_EQ(2UL, curInterval.raw.size());
+ // value is 10, 20
+ EXPECT_EQ(10, curInterval.raw.front().first);
+ EXPECT_EQ(20, curInterval.raw.back().first);
+ EXPECT_EQ(0UL, valueProducer.mNextSlicedBucket.size());
+
+ valueProducer.flush_if_needed(bucket3StartTimeNs);
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+ EXPECT_EQ(30, valueProducer.mPastBuckets.begin()->second.back().mValue);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h
new file mode 100644
index 000000000000..fa221aae1731
--- /dev/null
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#pragma once
+
+#include "src/condition/ConditionWizard.h"
+#include "src/external/StatsPullerManager.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class MockConditionWizard : public ConditionWizard {
+public:
+ MOCK_METHOD2(
+ query,
+ ConditionState(const int conditionIndex,
+ const std::map<std::string, HashableDimensionKey>& conditionParameters));
+};
+
+class MockStatsPullerManager : public StatsPullerManager {
+public:
+ MOCK_METHOD3(RegisterReceiver, void(int tagId, wp<PullDataReceiver> receiver, long intervalMs));
+ MOCK_METHOD2(UnRegisterReceiver, void(int tagId, wp<PullDataReceiver> receiver));
+ MOCK_METHOD2(Pull, bool(const int pullCode, vector<std::shared_ptr<LogEvent>>* data));
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/svc/svc b/cmds/svc/svc
index 27111cdcc6c9..07b50fe6c7b5 100755
--- a/cmds/svc/svc
+++ b/cmds/svc/svc
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "am" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/telecom/telecom b/cmds/telecom/telecom
index 9efdcfdec88e..a19036bf5bd8 100755
--- a/cmds/telecom/telecom
+++ b/cmds/telecom/telecom
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "telecom" on the device
#
base=/system
diff --git a/cmds/uiautomator/cmds/uiautomator/uiautomator b/cmds/uiautomator/cmds/uiautomator/uiautomator
index 86a1dbaad119..889c2b524dfd 100755
--- a/cmds/uiautomator/cmds/uiautomator/uiautomator
+++ b/cmds/uiautomator/cmds/uiautomator/uiautomator
@@ -1,3 +1,4 @@
+#!/system/bin/sh
#
# Copyright (C) 2012 The Android Open Source Project
#
diff --git a/cmds/vr/vr b/cmds/vr/vr
index a279007caed4..dbde02a4ac7f 100755
--- a/cmds/vr/vr
+++ b/cmds/vr/vr
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "vr" on the device
#
base=/system
diff --git a/cmds/wm/wm b/cmds/wm/wm
index f7a5bc736831..16d6bd649ef2 100755
--- a/cmds/wm/wm
+++ b/cmds/wm/wm
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "wm" on the device, which has a very rudimentary
# shell.
#
diff --git a/config/compiled-classes-phone b/config/compiled-classes-phone
index 47e148df1023..fb201ef5b4d3 100644
--- a/config/compiled-classes-phone
+++ b/config/compiled-classes-phone
@@ -3340,14 +3340,8 @@ android.os.StrictMode$9
android.os.StrictMode$AndroidBlockGuardPolicy
android.os.StrictMode$AndroidBlockGuardPolicy$1
android.os.StrictMode$AndroidCloseGuardReporter
-android.os.StrictMode$InstanceCountViolation
android.os.StrictMode$InstanceTracker
-android.os.StrictMode$LogStackTrace
android.os.StrictMode$Span
-android.os.StrictMode$StrictModeCustomViolation
-android.os.StrictMode$StrictModeDiskReadViolation
-android.os.StrictMode$StrictModeDiskWriteViolation
-android.os.StrictMode$StrictModeViolation
android.os.StrictMode$ThreadPolicy
android.os.StrictMode$ThreadPolicy$Builder
android.os.StrictMode$ThreadSpanState
@@ -3949,9 +3943,6 @@ android.telephony.VisualVoicemailSmsFilterSettings
android.telephony.VoLteServiceState
android.telephony.VoLteServiceState$1
android.telephony.gsm.GsmCellLocation
-android.telephony.ims.ImsServiceProxy$INotifyStatusChanged
-android.telephony.ims.ImsServiceProxyCompat
-android.telephony.ims.feature.IMMTelFeature
android.telephony.ims.stub.ImsConfigImplBase
android.telephony.ims.stub.ImsEcbmImplBase
android.telephony.ims.stub.ImsUtImplBase
@@ -5214,6 +5205,8 @@ com.android.internal.app.AlertController$AlertParams$4
com.android.internal.app.AlertController$ButtonHandler
com.android.internal.app.AlertController$RecycleListView
com.android.internal.app.AssistUtils
+com.android.internal.app.ColorDisplayController
+com.android.internal.app.ColorDisplayController$Callback
com.android.internal.app.IAppOpsCallback
com.android.internal.app.IAppOpsCallback$Stub
com.android.internal.app.IAppOpsCallback$Stub$Proxy
@@ -5239,8 +5232,6 @@ com.android.internal.app.IVoiceInteractionSessionShowCallback
com.android.internal.app.IVoiceInteractionSessionShowCallback$Stub
com.android.internal.app.IVoiceInteractor
com.android.internal.app.IVoiceInteractor$Stub
-com.android.internal.app.NightDisplayController
-com.android.internal.app.NightDisplayController$Callback
com.android.internal.app.ProcessMap
com.android.internal.app.ResolverActivity
com.android.internal.app.ToolbarActionBar
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 1b86724124fe..784c3f8782ee 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -1865,9 +1865,6 @@ android.os.StrictMode$InstanceCountViolation
android.os.StrictMode$InstanceTracker
android.os.StrictMode$LogStackTrace
android.os.StrictMode$Span
-android.os.StrictMode$StrictModeDiskReadViolation
-android.os.StrictMode$StrictModeDiskWriteViolation
-android.os.StrictMode$StrictModeViolation
android.os.StrictMode$ThreadPolicy
android.os.StrictMode$ThreadPolicy$Builder
android.os.StrictMode$ThreadSpanState
@@ -2771,6 +2768,7 @@ com.android.i18n.phonenumbers.ShortNumbersRegionCodeSet
com.android.ims.ImsException
com.android.internal.R$styleable
com.android.internal.app.AlertController$AlertParams
+com.android.internal.app.ColorDisplayController
com.android.internal.app.IAppOpsCallback
com.android.internal.app.IAppOpsCallback$Stub
com.android.internal.app.IAppOpsService
@@ -2783,7 +2781,6 @@ com.android.internal.app.IVoiceInteractionManagerService
com.android.internal.app.IVoiceInteractionManagerService$Stub
com.android.internal.app.IVoiceInteractor
com.android.internal.app.IVoiceInteractor$Stub
-com.android.internal.app.NightDisplayController
com.android.internal.appwidget.IAppWidgetService
com.android.internal.appwidget.IAppWidgetService$Stub
com.android.internal.appwidget.IAppWidgetService$Stub$Proxy
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 42b0f6bad0ae..1503445a1b02 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -2,3 +2,8 @@ filegroup {
name: "IKeyAttestationApplicationIdProvider.aidl",
srcs: ["android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl"],
}
+
+filegroup {
+ name: "IKeystoreService.aidl",
+ srcs: ["android/security/IKeystoreService.aidl"],
+}
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index ee89ca8d55e2..cc95eb6f4ea2 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -254,6 +254,11 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
HashMap<String, PropertyValuesHolder> mValuesMap;
/**
+ * If set to non-negative value, this will override {@link #sDurationScale}.
+ */
+ private float mDurationScale = -1f;
+
+ /**
* Public constants
*/
@@ -579,8 +584,23 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
return this;
}
+ /**
+ * Overrides the global duration scale by a custom value.
+ *
+ * @param durationScale The duration scale to set; or {@code -1f} to use the global duration
+ * scale.
+ * @hide
+ */
+ public void overrideDurationScale(float durationScale) {
+ mDurationScale = durationScale;
+ }
+
+ private float resolveDurationScale() {
+ return mDurationScale >= 0f ? mDurationScale : sDurationScale;
+ }
+
private long getScaledDuration() {
- return (long)(mDuration * sDurationScale);
+ return (long)(mDuration * resolveDurationScale());
}
/**
@@ -735,7 +755,10 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
if (mSeekFraction >= 0) {
return (long) (mDuration * mSeekFraction);
}
- float durationScale = sDurationScale == 0 ? 1 : sDurationScale;
+ float durationScale = resolveDurationScale();
+ if (durationScale == 0f) {
+ durationScale = 1f;
+ }
return (long) ((AnimationUtils.currentAnimationTimeMillis() - mStartTime) / durationScale);
}
@@ -1397,7 +1420,9 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
if (mStartTime < 0) {
// First frame. If there is start delay, start delay count down will happen *after* this
// frame.
- mStartTime = mReversing ? frameTime : frameTime + (long) (mStartDelay * sDurationScale);
+ mStartTime = mReversing
+ ? frameTime
+ : frameTime + (long) (mStartDelay * resolveDurationScale());
}
// Handle pause/resume
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a8863bf99445..99f3dee7285d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -193,10 +193,13 @@ import java.util.List;
* <a name="Fragments"></a>
* <h3>Fragments</h3>
*
- * <p>Starting with {@link android.os.Build.VERSION_CODES#HONEYCOMB}, Activity
- * implementations can make use of the {@link Fragment} class to better
+ * <p>The {@link android.support.v4.app.FragmentActivity} subclass
+ * can make use of the {@link android.support.v4.app.Fragment} class to better
* modularize their code, build more sophisticated user interfaces for larger
- * screens, and help scale their application between small and large screens.
+ * screens, and help scale their application between small and large screens.</p>
+ *
+ * <p>For more information about using fragments, read the
+ * <a href="{@docRoot}guide/components/fragments.html">Fragments</a> developer guide.</p>
*
* <a name="ActivityLifecycle"></a>
* <h3>Activity Lifecycle</h3>
@@ -915,7 +918,10 @@ public class Activity extends ContextThemeWrapper
/**
* Return the LoaderManager for this activity, creating it if needed.
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentActivity#getSupportLoaderManager()}
*/
+ @Deprecated
public LoaderManager getLoaderManager() {
return mFragments.getLoaderManager();
}
@@ -2395,7 +2401,10 @@ public class Activity extends ContextThemeWrapper
/**
* Return the FragmentManager for interacting with fragments associated
* with this activity.
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentActivity#getSupportFragmentManager()}
*/
+ @Deprecated
public FragmentManager getFragmentManager() {
return mFragments.getFragmentManager();
}
@@ -2404,7 +2413,11 @@ public class Activity extends ContextThemeWrapper
* Called when a Fragment is being attached to this activity, immediately
* after the call to its {@link Fragment#onAttach Fragment.onAttach()}
* method and before {@link Fragment#onCreate Fragment.onCreate()}.
+ *
+ * @deprecated Use {@link
+ * android.support.v4.app.FragmentActivity#onAttachFragment(android.support.v4.app.Fragment)}
*/
+ @Deprecated
public void onAttachFragment(Fragment fragment) {
}
@@ -5106,7 +5119,11 @@ public class Activity extends ContextThemeWrapper
*
* @see Fragment#startActivity
* @see Fragment#startActivityForResult
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentActivity#startActivityFromFragment(
+ * android.support.v4.app.Fragment,Intent,int)}
*/
+ @Deprecated
public void startActivityFromFragment(@NonNull Fragment fragment,
@RequiresPermission Intent intent, int requestCode) {
startActivityFromFragment(fragment, intent, requestCode, null);
@@ -5131,7 +5148,11 @@ public class Activity extends ContextThemeWrapper
*
* @see Fragment#startActivity
* @see Fragment#startActivityForResult
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentActivity#startActivityFromFragment(
+ * android.support.v4.app.Fragment,Intent,int,Bundle)}
*/
+ @Deprecated
public void startActivityFromFragment(@NonNull Fragment fragment,
@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) {
startActivityForResult(fragment.mWho, intent, requestCode, options);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2516a3e970df..21e454f11ebc 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5533,32 +5533,8 @@ public final class ActivityThread {
View.mDebugViewAttributes =
mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0;
- /**
- * For system applications on userdebug/eng builds, log stack
- * traces of disk and network access to dropbox for analysis.
- */
- if ((data.appInfo.flags &
- (ApplicationInfo.FLAG_SYSTEM |
- ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
- StrictMode.conditionallyEnableDebugLogging();
- }
-
- /**
- * For apps targetting Honeycomb or later, we don't allow network usage
- * on the main event loop / UI thread. This is what ultimately throws
- * {@link NetworkOnMainThreadException}.
- */
- if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
- StrictMode.enableDeathOnNetwork();
- }
-
- /**
- * For apps targetting N or later, we don't allow file:// Uri exposure.
- * This is what ultimately throws {@link FileUriExposedException}.
- */
- if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
- StrictMode.enableDeathOnFileUriExposure();
- }
+ StrictMode.initThreadDefaults(data.appInfo);
+ StrictMode.initVmDefaults(data.appInfo);
// We deprecated Build.SERIAL and only apps that target pre NMR1
// SDK can see it. Since access to the serial is now behind a
@@ -5655,7 +5631,12 @@ public final class ActivityThread {
mResourcesManager.getConfiguration().getLocales());
if (!Process.isIsolated()) {
- setupGraphicsSupport(appContext);
+ final int oldMask = StrictMode.allowThreadDiskWritesMask();
+ try {
+ setupGraphicsSupport(appContext);
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
+ }
}
// If we use profiles, setup the dex reporter to notify package manager
diff --git a/core/java/android/app/DexLoadReporter.java b/core/java/android/app/DexLoadReporter.java
index f99d1a8e06a4..0643414727cf 100644
--- a/core/java/android/app/DexLoadReporter.java
+++ b/core/java/android/app/DexLoadReporter.java
@@ -19,7 +19,6 @@ package android.app;
import android.os.FileUtils;
import android.os.RemoteException;
import android.os.SystemProperties;
-import android.system.ErrnoException;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -27,8 +26,6 @@ import com.android.internal.annotations.GuardedBy;
import dalvik.system.BaseDexClassLoader;
import dalvik.system.VMRuntime;
-import libcore.io.Libcore;
-
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -155,23 +152,12 @@ import java.util.Set;
return;
}
- File realDexPath;
- try {
- // Secondary dex profiles are stored in the oat directory, next to the real dex file
- // and have the same name with 'cur.prof' appended. We use the realpath because that
- // is what installd is using when processing the dex file.
- // NOTE: Keep in sync with installd.
- realDexPath = new File(Libcore.os.realpath(dexPath));
- } catch (ErrnoException ex) {
- Slog.e(TAG, "Failed to get the real path of secondary dex " + dexPath
- + ":" + ex.getMessage());
- // Do not continue with registration if we could not retrieve the real path.
- return;
- }
-
+ // Secondary dex profiles are stored in the oat directory, next to dex file
+ // and have the same name with 'cur.prof' appended.
// NOTE: Keep this in sync with installd expectations.
- File secondaryProfileDir = new File(realDexPath.getParent(), "oat");
- File secondaryProfile = new File(secondaryProfileDir, realDexPath.getName() + ".cur.prof");
+ File dexPathFile = new File(dexPath);
+ File secondaryProfileDir = new File(dexPathFile.getParent(), "oat");
+ File secondaryProfile = new File(secondaryProfileDir, dexPathFile.getName() + ".cur.prof");
// Create the profile if not already there.
// Returns true if the file was created, false if the file already exists.
diff --git a/core/java/android/app/DialogFragment.java b/core/java/android/app/DialogFragment.java
index 7e0e4d827477..a0fb6eeb9e15 100644
--- a/core/java/android/app/DialogFragment.java
+++ b/core/java/android/app/DialogFragment.java
@@ -136,7 +136,10 @@ import java.io.PrintWriter;
*
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentDialogOrActivity.java
* embed}
+ *
+ * @deprecated Use {@link android.support.v4.app.DialogFragment}
*/
+@Deprecated
public class DialogFragment extends Fragment
implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 93773454424e..a92684b5d304 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -256,7 +256,10 @@ import java.lang.reflect.InvocationTargetException;
* <p>After each call to this function, a new entry is on the stack, and
* pressing back will pop it to return the user to whatever previous state
* the activity UI was in.
+ *
+ * @deprecated Use {@link android.support.v4.app.Fragment}
*/
+@Deprecated
public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListener {
private static final ArrayMap<String, Class<?>> sClassMap =
new ArrayMap<String, Class<?>>();
@@ -414,7 +417,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* State information that has been retrieved from a fragment instance
* through {@link FragmentManager#saveFragmentInstanceState(Fragment)
* FragmentManager.saveFragmentInstanceState}.
+ *
+ * @deprecated Use {@link android.support.v4.app.Fragment.SavedState}
*/
+ @Deprecated
public static class SavedState implements Parcelable {
final Bundle mState;
@@ -458,7 +464,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
/**
* Thrown by {@link Fragment#instantiate(Context, String, Bundle)} when
* there is an instantiation failure.
+ *
+ * @deprecated Use {@link android.support.v4.app.Fragment.InstantiationException}
*/
+ @Deprecated
static public class InstantiationException extends AndroidRuntimeException {
public InstantiationException(String msg, Exception cause) {
super(msg, cause);
@@ -1031,7 +1040,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
/**
* Return the LoaderManager for this fragment, creating it if needed.
+ *
+ * @deprecated Use {@link android.support.v4.app.Fragment#getLoaderManager()}
*/
+ @Deprecated
public LoaderManager getLoaderManager() {
if (mLoaderManager != null) {
return mLoaderManager;
diff --git a/core/java/android/app/FragmentBreadCrumbs.java b/core/java/android/app/FragmentBreadCrumbs.java
index d0aa0fd605bb..e3e47ae652ca 100644
--- a/core/java/android/app/FragmentBreadCrumbs.java
+++ b/core/java/android/app/FragmentBreadCrumbs.java
@@ -65,7 +65,10 @@ public class FragmentBreadCrumbs extends ViewGroup
/**
* Interface to intercept clicks on the bread crumbs.
+ *
+ * @deprecated This widget is no longer supported.
*/
+ @Deprecated
public interface OnBreadCrumbClickListener {
/**
* Called when a bread crumb is clicked.
diff --git a/core/java/android/app/FragmentContainer.java b/core/java/android/app/FragmentContainer.java
index f8836bc829a0..a1dd32ffe95d 100644
--- a/core/java/android/app/FragmentContainer.java
+++ b/core/java/android/app/FragmentContainer.java
@@ -24,7 +24,10 @@ import android.view.View;
/**
* Callbacks to a {@link Fragment}'s container.
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentContainer}
*/
+@Deprecated
public abstract class FragmentContainer {
/**
* Return the view with the given resource ID. May return {@code null} if the
diff --git a/core/java/android/app/FragmentController.java b/core/java/android/app/FragmentController.java
index cff94d8cbf2d..cbb58d402bca 100644
--- a/core/java/android/app/FragmentController.java
+++ b/core/java/android/app/FragmentController.java
@@ -37,7 +37,10 @@ import java.util.List;
* <p>
* It is the responsibility of the host to take care of the Fragment's lifecycle.
* The methods provided by {@link FragmentController} are for that purpose.
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentController}
*/
+@Deprecated
public class FragmentController {
private final FragmentHostCallback<?> mHost;
diff --git a/core/java/android/app/FragmentHostCallback.java b/core/java/android/app/FragmentHostCallback.java
index 5ef23e630573..1edc68eda808 100644
--- a/core/java/android/app/FragmentHostCallback.java
+++ b/core/java/android/app/FragmentHostCallback.java
@@ -37,7 +37,10 @@ import java.io.PrintWriter;
* Fragments may be hosted by any object; such as an {@link Activity}. In order to
* host fragments, implement {@link FragmentHostCallback}, overriding the methods
* applicable to the host.
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentHostCallback}
*/
+@Deprecated
public abstract class FragmentHostCallback<E> extends FragmentContainer {
private final Activity mActivity;
final Context mContext;
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 0d5cd0214f37..12e60b874702 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -74,7 +74,10 @@ import java.util.concurrent.CopyOnWriteArrayList;
* {@link android.support.v4.app.FragmentActivity}. See the blog post
* <a href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">
* Fragments For All</a> for more details.
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentManager}
*/
+@Deprecated
public abstract class FragmentManager {
/**
* Representation of an entry on the fragment back stack, as created
@@ -86,7 +89,10 @@ public abstract class FragmentManager {
* <p>Note that you should never hold on to a BackStackEntry object;
* the identifier as returned by {@link #getId} is the only thing that
* will be persisted across activity instances.
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentManager.BackStackEntry}
*/
+ @Deprecated
public interface BackStackEntry {
/**
* Return the unique identifier for the entry. This is the only
@@ -129,7 +135,10 @@ public abstract class FragmentManager {
/**
* Interface to watch for changes to the back stack.
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentManager.OnBackStackChangedListener}
*/
+ @Deprecated
public interface OnBackStackChangedListener {
/**
* Called whenever the contents of the back stack change.
@@ -428,7 +437,10 @@ public abstract class FragmentManager {
/**
* Callback interface for listening to fragment state changes that happen
* within a given FragmentManager.
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentManager.FragmentLifecycleCallbacks}
*/
+ @Deprecated
public abstract static class FragmentLifecycleCallbacks {
/**
* Called right before the fragment's {@link Fragment#onAttach(Context)} method is called.
diff --git a/core/java/android/app/FragmentManagerNonConfig.java b/core/java/android/app/FragmentManagerNonConfig.java
index 50d3797dd59d..beb1a15adae3 100644
--- a/core/java/android/app/FragmentManagerNonConfig.java
+++ b/core/java/android/app/FragmentManagerNonConfig.java
@@ -27,7 +27,10 @@ import java.util.List;
* and passed to the state save and restore process for fragments in
* {@link FragmentController#retainNonConfig()} and
* {@link FragmentController#restoreAllState(Parcelable, FragmentManagerNonConfig)}.</p>
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentManagerNonConfig}
*/
+@Deprecated
public class FragmentManagerNonConfig {
private final List<Fragment> mFragments;
private final List<FragmentManagerNonConfig> mChildNonConfigs;
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index c910e9035a3f..0f4a7fb500a3 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -21,7 +21,10 @@ import java.lang.annotation.RetentionPolicy;
* <a href="{@docRoot}guide/components/fragments.html">Fragments</a> developer
* guide.</p>
* </div>
+ *
+ * @deprecated Use {@link android.support.v4.app.FragmentTransaction}
*/
+@Deprecated
public abstract class FragmentTransaction {
/**
* Calls {@link #add(int, Fragment, String)} with a 0 containerViewId.
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 388459fbbc6e..4fc649e0443e 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -22,6 +22,7 @@ import android.app.ContentProviderHolder;
import android.app.IApplicationThread;
import android.app.IActivityController;
import android.app.IAppTask;
+import android.app.IAssistDataReceiver;
import android.app.IInstrumentationWatcher;
import android.app.IProcessObserver;
import android.app.IServiceConnection;
@@ -63,7 +64,6 @@ import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.StrictMode;
import android.service.voice.IVoiceInteractionSession;
-import com.android.internal.app.IAssistDataReceiver;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -232,7 +232,7 @@ interface IActivityManager {
boolean requireFull, in String name, in String callerPackage);
void addPackageDependency(in String packageName);
void killApplication(in String pkg, int appId, int userId, in String reason);
- oneway void closeSystemDialogs(in String reason);
+ void closeSystemDialogs(in String reason);
Debug.MemoryInfo[] getProcessMemoryInfo(in int[] pids);
void killApplicationProcess(in String processName, int uid);
int startActivityIntentSender(in IApplicationThread caller,
@@ -423,7 +423,7 @@ interface IActivityManager {
int startAssistantActivity(in String callingPackage, int callingPid, int callingUid,
in Intent intent, in String resolvedType, in Bundle options, int userId);
int startRecentsActivity(in IAssistDataReceiver assistDataReceiver, in Bundle options,
- int userId);
+ in Bundle activityOptions, int userId);
int startActivityFromRecents(int taskId, in Bundle options);
Bundle getActivityOptions(in IBinder token);
List<IBinder> getAppTasks(in String callingPackage);
diff --git a/core/java/com/android/internal/app/IAssistDataReceiver.aidl b/core/java/android/app/IAssistDataReceiver.aidl
index 9c9ffef0066f..2d5daf97a1c4 100644
--- a/core/java/com/android/internal/app/IAssistDataReceiver.aidl
+++ b/core/java/android/app/IAssistDataReceiver.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.app;
+package android.app;
import android.graphics.Bitmap;
import android.os.Bundle;
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e260967f92d0..d49e11f47fea 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -17,6 +17,7 @@
package android.app;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
@@ -418,22 +419,51 @@ public class Instrumentation {
* different process. In addition, if the given Intent resolves to
* multiple activities, instead of displaying a dialog for the user to
* select an activity, an exception will be thrown.
- *
+ *
* <p>The function returns as soon as the activity goes idle following the
* call to its {@link Activity#onCreate}. Generally this means it has gone
* through the full initialization including {@link Activity#onResume} and
* drawn and displayed its initial window.
- *
+ *
* @param intent Description of the activity to start.
- *
+ *
* @see Context#startActivity
+ * @see #startActivitySync(Intent, Bundle)
*/
public Activity startActivitySync(Intent intent) {
+ return startActivitySync(intent, null /* options */);
+ }
+
+ /**
+ * Start a new activity and wait for it to begin running before returning.
+ * In addition to being synchronous, this method as some semantic
+ * differences from the standard {@link Context#startActivity} call: the
+ * activity component is resolved before talking with the activity manager
+ * (its class name is specified in the Intent that this method ultimately
+ * starts), and it does not allow you to start activities that run in a
+ * different process. In addition, if the given Intent resolves to
+ * multiple activities, instead of displaying a dialog for the user to
+ * select an activity, an exception will be thrown.
+ *
+ * <p>The function returns as soon as the activity goes idle following the
+ * call to its {@link Activity#onCreate}. Generally this means it has gone
+ * through the full initialization including {@link Activity#onResume} and
+ * drawn and displayed its initial window.
+ *
+ * @param intent Description of the activity to start.
+ * @param options Additional options for how the Activity should be started.
+ * May be null if there are no options. See {@link android.app.ActivityOptions}
+ * for how to build the Bundle supplied here; there are no supported definitions
+ * for building it manually.
+ *
+ * @see Context#startActivity(Intent, Bundle)
+ */
+ public Activity startActivitySync(Intent intent, @Nullable Bundle options) {
validateNotAppThread();
synchronized (mSync) {
intent = new Intent(intent);
-
+
ActivityInfo ai = intent.resolveActivityInfo(
getTargetContext().getPackageManager(), 0);
if (ai == null) {
@@ -447,7 +477,7 @@ public class Instrumentation {
+ myProc + " resolved to different process "
+ ai.processName + ": " + intent);
}
-
+
intent.setComponent(new ComponentName(
ai.applicationInfo.packageName, ai.name));
final ActivityWaiter aw = new ActivityWaiter(intent);
@@ -457,7 +487,7 @@ public class Instrumentation {
}
mWaitingActivities.add(aw);
- getTargetContext().startActivity(intent);
+ getTargetContext().startActivity(intent, options);
do {
try {
@@ -465,7 +495,7 @@ public class Instrumentation {
} catch (InterruptedException e) {
}
} while (mWaitingActivities.contains(aw));
-
+
return aw.activity;
}
}
diff --git a/core/java/android/app/ListFragment.java b/core/java/android/app/ListFragment.java
index 0b96d84d216a..90b77b398f44 100644
--- a/core/java/android/app/ListFragment.java
+++ b/core/java/android/app/ListFragment.java
@@ -144,7 +144,10 @@ import android.widget.TextView;
*
* @see #setListAdapter
* @see android.widget.ListView
+ *
+ * @deprecated Use {@link android.support.v4.app.ListFragment}
*/
+@Deprecated
public class ListFragment extends Fragment {
final private Handler mHandler = new Handler();
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index 56dfc589b0a7..7969684ab5a9 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -54,11 +54,17 @@ import java.lang.reflect.Modifier;
* <p>For more information about using loaders, read the
* <a href="{@docRoot}guide/topics/fundamentals/loaders.html">Loaders</a> developer guide.</p>
* </div>
+ *
+ * @deprecated Use {@link android.support.v4.app.LoaderManager}
*/
+@Deprecated
public abstract class LoaderManager {
/**
* Callback interface for a client to interact with the manager.
+ *
+ * @deprecated Use {@link android.support.v4.app.LoaderManager.LoaderCallbacks}
*/
+ @Deprecated
public interface LoaderCallbacks<D> {
/**
* Instantiate and return a new Loader for the given ID.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8226e0fb4e71..d5d95fb85a6a 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -22,6 +22,7 @@ import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -3900,7 +3901,7 @@ public class Notification implements Parcelable
final Bundle ex = mN.extras;
updateBackgroundColor(contentView);
bindNotificationHeader(contentView, p.ambient);
- bindLargeIcon(contentView);
+ bindLargeIcon(contentView, p.hideLargeIcon, p.alwaysShowReply);
boolean showProgress = handleProgressBar(p.hasProgress, contentView, ex);
if (p.title != null) {
contentView.setViewVisibility(R.id.title, View.VISIBLE);
@@ -4110,11 +4111,13 @@ public class Notification implements Parcelable
}
}
- private void bindLargeIcon(RemoteViews contentView) {
+ private void bindLargeIcon(RemoteViews contentView, boolean hideLargeIcon,
+ boolean alwaysShowReply) {
if (mN.mLargeIcon == null && mN.largeIcon != null) {
mN.mLargeIcon = Icon.createWithBitmap(mN.largeIcon);
}
- if (mN.mLargeIcon != null) {
+ boolean showLargeIcon = mN.mLargeIcon != null && !hideLargeIcon;
+ if (showLargeIcon) {
contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
contentView.setImageViewIcon(R.id.right_icon, mN.mLargeIcon);
processLargeLegacyIcon(mN.mLargeIcon, contentView);
@@ -4122,32 +4125,45 @@ public class Notification implements Parcelable
contentView.setViewLayoutMarginEndDimen(R.id.line1, endMargin);
contentView.setViewLayoutMarginEndDimen(R.id.text, endMargin);
contentView.setViewLayoutMarginEndDimen(R.id.progress, endMargin);
- // Bind the reply action
- Action action = findReplyAction();
- contentView.setViewVisibility(R.id.reply_icon_action, action != null
- ? View.VISIBLE
- : View.GONE);
-
- if (action != null) {
- int contrastColor = resolveContrastColor();
+ }
+ // Bind the reply action
+ Action action = findReplyAction();
+
+ boolean actionVisible = action != null && (showLargeIcon || alwaysShowReply);
+ int replyId = showLargeIcon ? R.id.reply_icon_action : R.id.right_icon;
+ if (actionVisible) {
+ // We're only showing the icon as big if we're hiding the large icon
+ int contrastColor = resolveContrastColor();
+ int iconColor;
+ if (showLargeIcon) {
contentView.setDrawableTint(R.id.reply_icon_action,
true /* targetBackground */,
contrastColor, PorterDuff.Mode.SRC_ATOP);
- int iconColor = NotificationColorUtil.isColorLight(contrastColor)
- ? Color.BLACK : Color.WHITE;
- contentView.setDrawableTint(R.id.reply_icon_action,
- false /* targetBackground */,
- iconColor, PorterDuff.Mode.SRC_ATOP);
contentView.setOnClickPendingIntent(R.id.right_icon,
action.actionIntent);
- contentView.setOnClickPendingIntent(R.id.reply_icon_action,
- action.actionIntent);
contentView.setRemoteInputs(R.id.right_icon, action.mRemoteInputs);
- contentView.setRemoteInputs(R.id.reply_icon_action, action.mRemoteInputs);
-
+ iconColor = NotificationColorUtil.isColorLight(contrastColor)
+ ? Color.BLACK : Color.WHITE;
+ } else {
+ contentView.setImageViewResource(R.id.right_icon,
+ R.drawable.ic_reply_notification_large);
+ contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
+ iconColor = contrastColor;
}
+ contentView.setDrawableTint(replyId,
+ false /* targetBackground */,
+ iconColor,
+ PorterDuff.Mode.SRC_ATOP);
+ contentView.setOnClickPendingIntent(replyId,
+ action.actionIntent);
+ contentView.setRemoteInputs(replyId, action.mRemoteInputs);
+ } else {
+ contentView.setRemoteInputs(R.id.right_icon, null);
}
- contentView.setViewVisibility(R.id.right_icon_container, mN.mLargeIcon != null
+ contentView.setViewVisibility(R.id.reply_icon_action, actionVisible && showLargeIcon
+ ? View.VISIBLE
+ : View.GONE);
+ contentView.setViewVisibility(R.id.right_icon_container, actionVisible || showLargeIcon
? View.VISIBLE
: View.GONE);
}
@@ -6055,18 +6071,12 @@ public class Notification implements Parcelable
protected void restoreFromExtras(Bundle extras) {
super.restoreFromExtras(extras);
- mMessages.clear();
- mHistoricMessages.clear();
mUserDisplayName = extras.getCharSequence(EXTRA_SELF_DISPLAY_NAME);
mConversationTitle = extras.getCharSequence(EXTRA_CONVERSATION_TITLE);
Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES);
- if (messages != null && messages instanceof Parcelable[]) {
- mMessages = Message.getMessagesFromBundleArray(messages);
- }
+ mMessages = Message.getMessagesFromBundleArray(messages);
Parcelable[] histMessages = extras.getParcelableArray(EXTRA_HISTORIC_MESSAGES);
- if (histMessages != null && histMessages instanceof Parcelable[]) {
- mHistoricMessages = Message.getMessagesFromBundleArray(histMessages);
- }
+ mHistoricMessages = Message.getMessagesFromBundleArray(histMessages);
}
/**
@@ -6074,38 +6084,34 @@ public class Notification implements Parcelable
*/
@Override
public RemoteViews makeContentView(boolean increasedHeight) {
- if (!increasedHeight) {
- Message m = findLatestIncomingMessage();
- CharSequence title = mConversationTitle != null
- ? mConversationTitle
- : (m == null) ? null : m.mSender;
- CharSequence text = (m == null)
- ? null
- : mConversationTitle != null ? makeMessageLine(m, mBuilder) : m.mText;
-
- return mBuilder.applyStandardTemplate(mBuilder.getBaseLayoutResource(),
- mBuilder.mParams.reset().hasProgress(false).title(title).text(text));
- } else {
- mBuilder.mOriginalActions = mBuilder.mActions;
- mBuilder.mActions = new ArrayList<>();
- RemoteViews remoteViews = makeBigContentView();
- mBuilder.mActions = mBuilder.mOriginalActions;
- mBuilder.mOriginalActions = null;
- return remoteViews;
- }
+ mBuilder.mOriginalActions = mBuilder.mActions;
+ mBuilder.mActions = new ArrayList<>();
+ RemoteViews remoteViews = makeBigContentView();
+ mBuilder.mActions = mBuilder.mOriginalActions;
+ mBuilder.mOriginalActions = null;
+ return remoteViews;
}
private Message findLatestIncomingMessage() {
- for (int i = mMessages.size() - 1; i >= 0; i--) {
- Message m = mMessages.get(i);
+ return findLatestIncomingMessage(mMessages);
+ }
+
+ /**
+ * @hide
+ */
+ @Nullable
+ public static Message findLatestIncomingMessage(
+ List<Message> messages) {
+ for (int i = messages.size() - 1; i >= 0; i--) {
+ Message m = messages.get(i);
// Incoming messages have a non-empty sender.
if (!TextUtils.isEmpty(m.mSender)) {
return m;
}
}
- if (!mMessages.isEmpty()) {
+ if (!messages.isEmpty()) {
// No incoming messages, fall back to outgoing message
- return mMessages.get(mMessages.size() - 1);
+ return messages.get(messages.size() - 1);
}
return null;
}
@@ -6115,118 +6121,82 @@ public class Notification implements Parcelable
*/
@Override
public RemoteViews makeBigContentView() {
- CharSequence title = !TextUtils.isEmpty(super.mBigContentTitle)
+ CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle)
? super.mBigContentTitle
: mConversationTitle;
- boolean hasTitle = !TextUtils.isEmpty(title);
-
- if (mMessages.size() == 1) {
- // Special case for a single message: Use the big text style
- // so the collapsed and expanded versions match nicely.
- CharSequence bigTitle;
- CharSequence text;
- if (hasTitle) {
- bigTitle = title;
- text = makeMessageLine(mMessages.get(0), mBuilder);
- } else {
- bigTitle = mMessages.get(0).mSender;
- text = mMessages.get(0).mText;
- }
- RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
- mBuilder.getBigTextLayoutResource(),
- mBuilder.mParams.reset().hasProgress(false).title(bigTitle).text(null));
- BigTextStyle.applyBigTextContentView(mBuilder, contentView, text);
- return contentView;
- }
-
+ boolean isOneToOne = TextUtils.isEmpty(conversationTitle);
+ if (isOneToOne) {
+ // Let's add the conversationTitle in case we didn't have one before and all
+ // messages are from the same sender
+ conversationTitle = createConversationTitleFromMessages();
+ } else if (hasOnlyWhiteSpaceSenders()) {
+ isOneToOne = true;
+ }
+ boolean hasTitle = !TextUtils.isEmpty(conversationTitle);
RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
mBuilder.getMessagingLayoutResource(),
- mBuilder.mParams.reset().hasProgress(false).title(title).text(null));
-
- int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3,
- R.id.inbox_text4, R.id.inbox_text5, R.id.inbox_text6};
-
- // Make sure all rows are gone in case we reuse a view.
- for (int rowId : rowIds) {
- contentView.setViewVisibility(rowId, View.GONE);
- }
+ mBuilder.mParams.reset().hasProgress(false).title(conversationTitle).text(null)
+ .hideLargeIcon(isOneToOne).alwaysShowReply(true));
+ addExtras(mBuilder.mN.extras);
+ contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
+ mBuilder.resolveContrastColor());
+ contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
+ mBuilder.mN.mLargeIcon);
+ contentView.setBoolean(R.id.status_bar_latest_event_content, "setIsOneToOne",
+ isOneToOne);
+ contentView.setBundle(R.id.status_bar_latest_event_content, "setData",
+ mBuilder.mN.extras);
+ return contentView;
+ }
- int i=0;
- contentView.setViewLayoutMarginBottomDimen(R.id.line1,
- hasTitle ? R.dimen.notification_messaging_spacing : 0);
- contentView.setInt(R.id.notification_messaging, "setNumIndentLines",
- !mBuilder.mN.hasLargeIcon() ? 0 : (hasTitle ? 1 : 2));
-
- int contractedChildId = View.NO_ID;
- Message contractedMessage = findLatestIncomingMessage();
- int firstHistoricMessage = Math.max(0, mHistoricMessages.size()
- - (rowIds.length - mMessages.size()));
- while (firstHistoricMessage + i < mHistoricMessages.size() && i < rowIds.length) {
- Message m = mHistoricMessages.get(firstHistoricMessage + i);
- int rowId = rowIds[i];
-
- contentView.setTextViewText(rowId, makeMessageLine(m, mBuilder));
-
- if (contractedMessage == m) {
- contractedChildId = rowId;
+ private boolean hasOnlyWhiteSpaceSenders() {
+ for (int i = 0; i < mMessages.size(); i++) {
+ Message m = mMessages.get(i);
+ CharSequence sender = m.getSender();
+ if (!isWhiteSpace(sender)) {
+ return false;
}
-
- i++;
}
+ return true;
+ }
- int firstMessage = Math.max(0, mMessages.size() - rowIds.length);
- while (firstMessage + i < mMessages.size() && i < rowIds.length) {
- Message m = mMessages.get(firstMessage + i);
- int rowId = rowIds[i];
-
- contentView.setViewVisibility(rowId, View.VISIBLE);
- contentView.setTextViewText(rowId, mBuilder.processTextSpans(
- makeMessageLine(m, mBuilder)));
- mBuilder.setTextViewColorSecondary(contentView, rowId);
-
- if (contractedMessage == m) {
- contractedChildId = rowId;
- }
-
- i++;
+ private boolean isWhiteSpace(CharSequence sender) {
+ if (TextUtils.isEmpty(sender)) {
+ return true;
}
- // Clear the remaining views for reapply. Ensures that historic message views can
- // reliably be identified as being GONE and having non-null text.
- while (i < rowIds.length) {
- int rowId = rowIds[i];
- contentView.setTextViewText(rowId, null);
- i++;
+ if (sender.toString().matches("^\\s*$")) {
+ return true;
}
-
- // Record this here to allow transformation between the contracted and expanded views.
- contentView.setInt(R.id.notification_messaging, "setContractedChildId",
- contractedChildId);
- return contentView;
+ // Let's check if we only have 0 whitespace chars. Some apps did this as a workaround
+ // For the presentation that we had.
+ for (int i = 0; i < sender.length(); i++) {
+ char c = sender.charAt(i);
+ if (c != '\u200B') {
+ return false;
+ }
+ }
+ return true;
}
- private CharSequence makeMessageLine(Message m, Builder builder) {
- BidiFormatter bidi = BidiFormatter.getInstance();
- SpannableStringBuilder sb = new SpannableStringBuilder();
- boolean colorize = builder.isColorized();
- TextAppearanceSpan colorSpan;
- CharSequence messageName;
- if (TextUtils.isEmpty(m.mSender)) {
- CharSequence replyName = mUserDisplayName == null ? "" : mUserDisplayName;
- sb.append(bidi.unicodeWrap(replyName),
- makeFontColorSpan(colorize
- ? builder.getPrimaryTextColor()
- : mBuilder.resolveContrastColor()),
- 0 /* flags */);
- } else {
- sb.append(bidi.unicodeWrap(m.mSender),
- makeFontColorSpan(colorize
- ? builder.getPrimaryTextColor()
- : Color.BLACK),
- 0 /* flags */);
+ private CharSequence createConversationTitleFromMessages() {
+ ArraySet<CharSequence> names = new ArraySet<>();
+ for (int i = 0; i < mMessages.size(); i++) {
+ Message m = mMessages.get(i);
+ CharSequence sender = m.getSender();
+ if (sender != null) {
+ names.add(sender);
+ }
+ }
+ SpannableStringBuilder title = new SpannableStringBuilder();
+ int size = names.size();
+ for (int i = 0; i < size; i++) {
+ CharSequence name = names.valueAt(i);
+ if (!TextUtils.isEmpty(title)) {
+ title.append(", ");
+ }
+ title.append(BidiFormatter.getInstance().unicodeWrap(name));
}
- CharSequence text = m.mText == null ? "" : m.mText;
- sb.append(" ").append(bidi.unicodeWrap(text));
- return sb;
+ return title;
}
/**
@@ -6234,19 +6204,9 @@ public class Notification implements Parcelable
*/
@Override
public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
- if (increasedHeight) {
- return makeBigContentView();
- }
- Message m = findLatestIncomingMessage();
- CharSequence title = mConversationTitle != null
- ? mConversationTitle
- : (m == null) ? null : m.mSender;
- CharSequence text = (m == null)
- ? null
- : mConversationTitle != null ? makeMessageLine(m, mBuilder) : m.mText;
-
- return mBuilder.applyStandardTemplateWithActions(mBuilder.getBigBaseLayoutResource(),
- mBuilder.mParams.reset().hasProgress(false).title(title).text(text));
+ RemoteViews remoteViews = makeBigContentView();
+ remoteViews.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1);
+ return remoteViews;
}
private static TextAppearanceSpan makeFontColorSpan(int color) {
@@ -6394,7 +6354,15 @@ public class Notification implements Parcelable
return bundles;
}
- static List<Message> getMessagesFromBundleArray(Parcelable[] bundles) {
+ /**
+ * @return A list of messages read from the bundles.
+ *
+ * @hide
+ */
+ public static List<Message> getMessagesFromBundleArray(Parcelable[] bundles) {
+ if (bundles == null) {
+ return new ArrayList<>();
+ }
List<Message> messages = new ArrayList<>(bundles.length);
for (int i = 0; i < bundles.length; i++) {
if (bundles[i] instanceof Bundle) {
@@ -8487,6 +8455,8 @@ public class Notification implements Parcelable
boolean ambient = false;
CharSequence title;
CharSequence text;
+ boolean hideLargeIcon;
+ public boolean alwaysShowReply;
final StandardTemplateParams reset() {
hasProgress = true;
@@ -8511,6 +8481,16 @@ public class Notification implements Parcelable
return this;
}
+ final StandardTemplateParams alwaysShowReply(boolean alwaysShowReply) {
+ this.alwaysShowReply = alwaysShowReply;
+ return this;
+ }
+
+ final StandardTemplateParams hideLargeIcon(boolean hideLargeIcon) {
+ this.hideLargeIcon = hideLargeIcon;
+ return this;
+ }
+
final StandardTemplateParams ambient(boolean ambient) {
Preconditions.checkState(title == null && text == null, "must set ambient before text");
this.ambient = ambient;
@@ -8527,7 +8507,6 @@ public class Notification implements Parcelable
text = extras.getCharSequence(EXTRA_TEXT);
}
this.text = b.processLegacyText(text, ambient);
-
return this;
}
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index a52dc1e4e768..f931589b50a2 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -758,10 +758,10 @@ public class NotificationManager {
}
/**
- * Checks the ability to read/modify notification do not disturb policy for the calling package.
+ * Checks the ability to modify notification do not disturb policy for the calling package.
*
* <p>
- * Returns true if the calling package can read/modify notification policy.
+ * Returns true if the calling package can modify notification policy.
*
* <p>
* Apps can request policy access by sending the user to the activity that matches the system
@@ -839,8 +839,6 @@ public class NotificationManager {
* Gets the current notification policy.
*
* <p>
- * Only available if policy access is granted to this package.
- * See {@link #isNotificationPolicyAccessGranted}.
*/
public Policy getNotificationPolicy() {
INotificationManager service = getService();
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 50f1f364b9e5..e48946f2c3e4 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -41,6 +41,8 @@ import android.content.pm.IShortcutService;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutManager;
+import android.content.pm.crossprofile.CrossProfileApps;
+import android.content.pm.crossprofile.ICrossProfileApps;
import android.content.res.Resources;
import android.hardware.ConsumerIrManager;
import android.hardware.ISerialManager;
@@ -81,6 +83,7 @@ import android.net.INetworkPolicyManager;
import android.net.IpSecManager;
import android.net.NetworkPolicyManager;
import android.net.NetworkScoreManager;
+import android.net.NetworkWatchlistManager;
import android.net.lowpan.ILowpanManager;
import android.net.lowpan.LowpanManager;
import android.net.nsd.INsdManager;
@@ -134,6 +137,7 @@ import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.euicc.EuiccManager;
import android.util.Log;
+import android.util.StatsManager;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.WindowManager;
@@ -150,6 +154,7 @@ import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.app.ISoundTriggerService;
import com.android.internal.appwidget.IAppWidgetService;
+import com.android.internal.net.INetworkWatchlistManager;
import com.android.internal.os.IDropBoxManagerService;
import com.android.internal.policy.PhoneLayoutInflater;
@@ -304,14 +309,14 @@ final class SystemServiceRegistry {
}});
registerService(Context.BATTERY_SERVICE, BatteryManager.class,
- new StaticServiceFetcher<BatteryManager>() {
+ new CachedServiceFetcher<BatteryManager>() {
@Override
- public BatteryManager createService() throws ServiceNotFoundException {
+ public BatteryManager createService(ContextImpl ctx) throws ServiceNotFoundException {
IBatteryStats stats = IBatteryStats.Stub.asInterface(
ServiceManager.getServiceOrThrow(BatteryStats.SERVICE_NAME));
IBatteryPropertiesRegistrar registrar = IBatteryPropertiesRegistrar.Stub
.asInterface(ServiceManager.getServiceOrThrow("batteryproperties"));
- return new BatteryManager(stats, registrar);
+ return new BatteryManager(ctx, stats, registrar);
}});
registerService(Context.NFC_SERVICE, NfcManager.class,
@@ -448,6 +453,13 @@ final class SystemServiceRegistry {
ctx.mMainThread.getHandler().getLooper());
}});
+ registerService(Context.STATS_MANAGER, StatsManager.class,
+ new StaticServiceFetcher<StatsManager>() {
+ @Override
+ public StatsManager createService() throws ServiceNotFoundException {
+ return new StatsManager();
+ }});
+
registerService(Context.STATUS_BAR_SERVICE, StatusBarManager.class,
new CachedServiceFetcher<StatusBarManager>() {
@Override
@@ -862,6 +874,17 @@ final class SystemServiceRegistry {
return new ShortcutManager(ctx, IShortcutService.Stub.asInterface(b));
}});
+ registerService(Context.NETWORK_WATCHLIST_SERVICE, NetworkWatchlistManager.class,
+ new CachedServiceFetcher<NetworkWatchlistManager>() {
+ @Override
+ public NetworkWatchlistManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IBinder b =
+ ServiceManager.getServiceOrThrow(Context.NETWORK_WATCHLIST_SERVICE);
+ return new NetworkWatchlistManager(ctx,
+ INetworkWatchlistManager.Stub.asInterface(b));
+ }});
+
registerService(Context.SYSTEM_HEALTH_SERVICE, SystemHealthManager.class,
new CachedServiceFetcher<SystemHealthManager>() {
@Override
@@ -909,6 +932,18 @@ final class SystemServiceRegistry {
public RulesManager createService(ContextImpl ctx) {
return new RulesManager(ctx.getOuterContext());
}});
+
+ registerService(Context.CROSS_PROFILE_APPS_SERVICE, CrossProfileApps.class,
+ new CachedServiceFetcher<CrossProfileApps>() {
+ @Override
+ public CrossProfileApps createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(
+ Context.CROSS_PROFILE_APPS_SERVICE);
+ return new CrossProfileApps(ctx.getOuterContext(),
+ ICrossProfileApps.Stub.asInterface(b));
+ }
+ });
}
/**
diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index 0f006b6618b3..8686944baeaa 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -152,6 +152,9 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
public void onClick(View view) {
if (mTimePicker.validateInput()) {
TimePickerDialog.this.onClick(TimePickerDialog.this, BUTTON_POSITIVE);
+ // Clearing focus forces the dialog to commit any pending
+ // changes, e.g. typed text in a NumberPicker.
+ mTimePicker.clearFocus();
dismiss();
}
}
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index de27b4fd97f0..2c1fad1cf140 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -500,15 +500,12 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
* @hide
*/
public boolean supportSplitScreenWindowingMode() {
- return supportSplitScreenWindowingMode(mWindowingMode, mActivityType);
+ return supportSplitScreenWindowingMode(mActivityType);
}
/** @hide */
- public static boolean supportSplitScreenWindowingMode(int windowingMode, int activityType) {
- if (activityType == ACTIVITY_TYPE_ASSISTANT) {
- return false;
- }
- return windowingMode != WINDOWING_MODE_FREEFORM && windowingMode != WINDOWING_MODE_PINNED;
+ public static boolean supportSplitScreenWindowingMode(int activityType) {
+ return activityType != ACTIVITY_TYPE_ASSISTANT;
}
/** @hide */
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 772c6d60856f..f0226b7e848f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3246,6 +3246,7 @@ public class DevicePolicyManager {
* that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}
*/
public void wipeData(int flags) {
+ throwIfParentInstance("wipeData");
final String wipeReasonForUser = mContext.getString(
R.string.work_profile_deleted_description_dpm_wipe);
wipeDataInternal(flags, wipeReasonForUser);
@@ -3270,6 +3271,7 @@ public class DevicePolicyManager {
* @throws IllegalArgumentException if the input reason string is null or empty.
*/
public void wipeDataWithReason(int flags, @NonNull CharSequence reason) {
+ throwIfParentInstance("wipeDataWithReason");
Preconditions.checkNotNull(reason, "CharSequence is null");
wipeDataInternal(flags, reason.toString());
}
@@ -3283,7 +3285,6 @@ public class DevicePolicyManager {
* @hide
*/
private void wipeDataInternal(int flags, @NonNull String wipeReasonForUser) {
- throwIfParentInstance("wipeDataWithReason");
if (mService != null) {
try {
mService.wipeDataWithReason(flags, wipeReasonForUser);
@@ -6096,8 +6097,8 @@ public class DevicePolicyManager {
/**
* Flag used by {@link #createAndManageUser} to specify that the user should be created
- * ephemeral.
- * @hide
+ * ephemeral. Ephemeral users will be removed after switching to another user or rebooting the
+ * device.
*/
public static final int MAKE_USER_EPHEMERAL = 0x0002;
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index b640bd5bee2a..530d84b420a3 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -16,6 +16,12 @@
package android.app.job;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.util.TimeUtils.formatDuration;
import android.annotation.BytesLong;
@@ -25,6 +31,8 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.content.ClipData;
import android.content.ComponentName;
+import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
import android.net.Uri;
import android.os.BaseBundle;
import android.os.Bundle;
@@ -56,6 +64,7 @@ public class JobInfo implements Parcelable {
NETWORK_TYPE_ANY,
NETWORK_TYPE_UNMETERED,
NETWORK_TYPE_NOT_ROAMING,
+ NETWORK_TYPE_CELLULAR,
NETWORK_TYPE_METERED,
})
@Retention(RetentionPolicy.SOURCE)
@@ -69,8 +78,21 @@ public class JobInfo implements Parcelable {
public static final int NETWORK_TYPE_UNMETERED = 2;
/** This job requires network connectivity that is not roaming. */
public static final int NETWORK_TYPE_NOT_ROAMING = 3;
- /** This job requires metered connectivity such as most cellular data networks. */
- public static final int NETWORK_TYPE_METERED = 4;
+ /** This job requires network connectivity that is a cellular network. */
+ public static final int NETWORK_TYPE_CELLULAR = 4;
+
+ /**
+ * This job requires metered connectivity such as most cellular data
+ * networks.
+ *
+ * @deprecated Cellular networks may be unmetered, or Wi-Fi networks may be
+ * metered, so this isn't a good way of selecting a specific
+ * transport. Instead, use {@link #NETWORK_TYPE_CELLULAR} or
+ * {@link android.net.NetworkRequest.Builder#addTransportType(int)}
+ * if your job requires a specific network transport.
+ */
+ @Deprecated
+ public static final int NETWORK_TYPE_METERED = NETWORK_TYPE_CELLULAR;
/** Sentinel value indicating that bytes are unknown. */
public static final int NETWORK_BYTES_UNKNOWN = -1;
@@ -253,7 +275,7 @@ public class JobInfo implements Parcelable {
private final long triggerContentMaxDelay;
private final boolean hasEarlyConstraint;
private final boolean hasLateConstraint;
- private final int networkType;
+ private final NetworkRequest networkRequest;
private final long networkBytes;
private final long minLatencyMillis;
private final long maxExecutionDelayMillis;
@@ -385,10 +407,37 @@ public class JobInfo implements Parcelable {
}
/**
- * The kind of connectivity requirements that the job has.
+ * Return the basic description of the kind of network this job requires.
+ *
+ * @deprecated This method attempts to map {@link #getRequiredNetwork()}
+ * into the set of simple constants, which results in a loss of
+ * fidelity. Callers should move to using
+ * {@link #getRequiredNetwork()} directly.
+ * @see Builder#setRequiredNetworkType(int)
*/
+ @Deprecated
public @NetworkType int getNetworkType() {
- return networkType;
+ if (networkRequest == null) {
+ return NETWORK_TYPE_NONE;
+ } else if (networkRequest.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
+ return NETWORK_TYPE_UNMETERED;
+ } else if (networkRequest.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING)) {
+ return NETWORK_TYPE_NOT_ROAMING;
+ } else if (networkRequest.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
+ return NETWORK_TYPE_CELLULAR;
+ } else {
+ return NETWORK_TYPE_ANY;
+ }
+ }
+
+ /**
+ * Return the detailed description of the kind of network this job requires,
+ * or {@code null} if no specific kind of network is required.
+ *
+ * @see Builder#setRequiredNetwork(NetworkRequest)
+ */
+ public @Nullable NetworkRequest getRequiredNetwork() {
+ return networkRequest;
}
/**
@@ -438,8 +487,7 @@ public class JobInfo implements Parcelable {
* job does not recur periodically.
*/
public long getIntervalMillis() {
- final long minInterval = getMinPeriodMillis();
- return intervalMillis >= minInterval ? intervalMillis : minInterval;
+ return intervalMillis;
}
/**
@@ -447,10 +495,7 @@ public class JobInfo implements Parcelable {
* execute at any time in a window of flex length at the end of the period.
*/
public long getFlexMillis() {
- long interval = getIntervalMillis();
- long percentClamp = 5 * interval / 100;
- long clampedFlex = Math.max(flexMillis, Math.max(percentClamp, getMinFlexMillis()));
- return clampedFlex <= interval ? clampedFlex : interval;
+ return flexMillis;
}
/**
@@ -459,8 +504,7 @@ public class JobInfo implements Parcelable {
* to 30 seconds, minimum is currently 10 seconds.
*/
public long getInitialBackoffMillis() {
- final long minBackoff = getMinBackoffMillis();
- return initialBackoffMillis >= minBackoff ? initialBackoffMillis : minBackoff;
+ return initialBackoffMillis;
}
/**
@@ -538,7 +582,7 @@ public class JobInfo implements Parcelable {
if (hasLateConstraint != j.hasLateConstraint) {
return false;
}
- if (networkType != j.networkType) {
+ if (!Objects.equals(networkRequest, j.networkRequest)) {
return false;
}
if (networkBytes != j.networkBytes) {
@@ -601,7 +645,9 @@ public class JobInfo implements Parcelable {
hashCode = 31 * hashCode + Long.hashCode(triggerContentMaxDelay);
hashCode = 31 * hashCode + Boolean.hashCode(hasEarlyConstraint);
hashCode = 31 * hashCode + Boolean.hashCode(hasLateConstraint);
- hashCode = 31 * hashCode + networkType;
+ if (networkRequest != null) {
+ hashCode = 31 * hashCode + networkRequest.hashCode();
+ }
hashCode = 31 * hashCode + Long.hashCode(networkBytes);
hashCode = 31 * hashCode + Long.hashCode(minLatencyMillis);
hashCode = 31 * hashCode + Long.hashCode(maxExecutionDelayMillis);
@@ -632,7 +678,11 @@ public class JobInfo implements Parcelable {
triggerContentUris = in.createTypedArray(TriggerContentUri.CREATOR);
triggerContentUpdateDelay = in.readLong();
triggerContentMaxDelay = in.readLong();
- networkType = in.readInt();
+ if (in.readInt() != 0) {
+ networkRequest = NetworkRequest.CREATOR.createFromParcel(in);
+ } else {
+ networkRequest = null;
+ }
networkBytes = in.readLong();
minLatencyMillis = in.readLong();
maxExecutionDelayMillis = in.readLong();
@@ -661,7 +711,7 @@ public class JobInfo implements Parcelable {
: null;
triggerContentUpdateDelay = b.mTriggerContentUpdateDelay;
triggerContentMaxDelay = b.mTriggerContentMaxDelay;
- networkType = b.mNetworkType;
+ networkRequest = b.mNetworkRequest;
networkBytes = b.mNetworkBytes;
minLatencyMillis = b.mMinLatencyMillis;
maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
@@ -699,7 +749,12 @@ public class JobInfo implements Parcelable {
out.writeTypedArray(triggerContentUris, flags);
out.writeLong(triggerContentUpdateDelay);
out.writeLong(triggerContentMaxDelay);
- out.writeInt(networkType);
+ if (networkRequest != null) {
+ out.writeInt(1);
+ networkRequest.writeToParcel(out, flags);
+ } else {
+ out.writeInt(0);
+ }
out.writeLong(networkBytes);
out.writeLong(minLatencyMillis);
out.writeLong(maxExecutionDelayMillis);
@@ -833,7 +888,7 @@ public class JobInfo implements Parcelable {
private int mFlags;
// Requirements.
private int mConstraintFlags;
- private int mNetworkType;
+ private NetworkRequest mNetworkRequest;
private long mNetworkBytes = NETWORK_BYTES_UNKNOWN;
private ArrayList<TriggerContentUri> mTriggerContentUris;
private long mTriggerContentUpdateDelay = -1;
@@ -934,24 +989,84 @@ public class JobInfo implements Parcelable {
}
/**
- * Set some description of the kind of network type your job needs to
- * have. Not calling this function means the network is not necessary,
- * as the default is {@link #NETWORK_TYPE_NONE}. Bear in mind that
- * calling this function defines network as a strict requirement for
- * your job. If the network requested is not available your job will
- * never run. See {@link #setOverrideDeadline(long)} to change this
- * behaviour.
+ * Set basic description of the kind of network your job requires. If
+ * you need more precise control over network capabilities, see
+ * {@link #setRequiredNetwork(NetworkRequest)}.
+ * <p>
+ * If your job doesn't need a network connection, you don't need to call
+ * this method, as the default value is {@link #NETWORK_TYPE_NONE}.
+ * <p>
+ * Calling this method defines network as a strict requirement for your
+ * job. If the network requested is not available your job will never
+ * run. See {@link #setOverrideDeadline(long)} to change this behavior.
+ * Calling this method will override any requirements previously defined
+ * by {@link #setRequiredNetwork(NetworkRequest)}; you typically only
+ * want to call one of these methods.
* <p class="note">
- * Note: When your job executes in
+ * When your job executes in
* {@link JobService#onStartJob(JobParameters)}, be sure to use the
* specific network returned by {@link JobParameters#getNetwork()},
* otherwise you'll use the default network which may not meet this
* constraint.
*
+ * @see #setRequiredNetwork(NetworkRequest)
+ * @see JobInfo#getNetworkType()
* @see JobParameters#getNetwork()
*/
public Builder setRequiredNetworkType(@NetworkType int networkType) {
- mNetworkType = networkType;
+ if (networkType == NETWORK_TYPE_NONE) {
+ return setRequiredNetwork(null);
+ } else {
+ final NetworkRequest.Builder builder = new NetworkRequest.Builder();
+
+ // All types require validated Internet
+ builder.addCapability(NET_CAPABILITY_INTERNET);
+ builder.addCapability(NET_CAPABILITY_VALIDATED);
+ builder.removeCapability(NET_CAPABILITY_NOT_VPN);
+
+ if (networkType == NETWORK_TYPE_ANY) {
+ // No other capabilities
+ } else if (networkType == NETWORK_TYPE_UNMETERED) {
+ builder.addCapability(NET_CAPABILITY_NOT_METERED);
+ } else if (networkType == NETWORK_TYPE_NOT_ROAMING) {
+ builder.addCapability(NET_CAPABILITY_NOT_ROAMING);
+ } else if (networkType == NETWORK_TYPE_CELLULAR) {
+ builder.addTransportType(TRANSPORT_CELLULAR);
+ }
+
+ return setRequiredNetwork(builder.build());
+ }
+ }
+
+ /**
+ * Set detailed description of the kind of network your job requires.
+ * <p>
+ * If your job doesn't need a network connection, you don't need to call
+ * this method, as the default is {@code null}.
+ * <p>
+ * Calling this method defines network as a strict requirement for your
+ * job. If the network requested is not available your job will never
+ * run. See {@link #setOverrideDeadline(long)} to change this behavior.
+ * Calling this method will override any requirements previously defined
+ * by {@link #setRequiredNetworkType(int)}; you typically only want to
+ * call one of these methods.
+ * <p class="note">
+ * When your job executes in
+ * {@link JobService#onStartJob(JobParameters)}, be sure to use the
+ * specific network returned by {@link JobParameters#getNetwork()},
+ * otherwise you'll use the default network which may not meet this
+ * constraint.
+ *
+ * @param networkRequest The detailed description of the kind of network
+ * this job requires, or {@code null} if no specific kind of
+ * network is required. Defining a {@link NetworkSpecifier}
+ * is only supported for jobs that aren't persisted.
+ * @see #setRequiredNetworkType(int)
+ * @see JobInfo#getRequiredNetwork()
+ * @see JobParameters#getNetwork()
+ */
+ public Builder setRequiredNetwork(@Nullable NetworkRequest networkRequest) {
+ mNetworkRequest = networkRequest;
return this;
}
@@ -1140,6 +1255,21 @@ public class JobInfo implements Parcelable {
* higher.
*/
public Builder setPeriodic(long intervalMillis, long flexMillis) {
+ final long minPeriod = getMinPeriodMillis();
+ if (intervalMillis < minPeriod) {
+ Log.w(TAG, "Requested interval " + formatDuration(intervalMillis) + " for job "
+ + mJobId + " is too small; raising to " + formatDuration(minPeriod));
+ intervalMillis = minPeriod;
+ }
+
+ final long percentClamp = 5 * intervalMillis / 100;
+ final long minFlex = Math.max(percentClamp, getMinFlexMillis());
+ if (flexMillis < minFlex) {
+ Log.w(TAG, "Requested flex " + formatDuration(flexMillis) + " for job " + mJobId
+ + " is too small; raising to " + formatDuration(minFlex));
+ flexMillis = minFlex;
+ }
+
mIsPeriodic = true;
mIntervalMillis = intervalMillis;
mFlexMillis = flexMillis;
@@ -1189,6 +1319,13 @@ public class JobInfo implements Parcelable {
*/
public Builder setBackoffCriteria(long initialBackoffMillis,
@BackoffPolicy int backoffPolicy) {
+ final long minBackoff = getMinBackoffMillis();
+ if (initialBackoffMillis < minBackoff) {
+ Log.w(TAG, "Requested backoff " + formatDuration(initialBackoffMillis) + " for job "
+ + mJobId + " is too small; raising to " + formatDuration(minBackoff));
+ initialBackoffMillis = minBackoff;
+ }
+
mBackoffPolicySet = true;
mInitialBackoffMillis = initialBackoffMillis;
mBackoffPolicy = backoffPolicy;
@@ -1213,16 +1350,22 @@ public class JobInfo implements Parcelable {
public JobInfo build() {
// Allow jobs with no constraints - What am I, a database?
if (!mHasEarlyConstraint && !mHasLateConstraint && mConstraintFlags == 0 &&
- mNetworkType == NETWORK_TYPE_NONE &&
+ mNetworkRequest == null &&
mTriggerContentUris == null) {
throw new IllegalArgumentException("You're trying to build a job with no " +
"constraints, this is not allowed.");
}
// Check that network estimates require network type
- if (mNetworkBytes > 0 && mNetworkType == NETWORK_TYPE_NONE) {
+ if (mNetworkBytes > 0 && mNetworkRequest == null) {
throw new IllegalArgumentException(
"Can't provide estimated network usage without requiring a network");
}
+ // We can't serialize network specifiers
+ if (mIsPersisted && mNetworkRequest != null
+ && mNetworkRequest.networkCapabilities.getNetworkSpecifier() != null) {
+ throw new IllegalArgumentException(
+ "Network specifiers aren't supported for persistent jobs");
+ }
// Check that a deadline was not set on a periodic job.
if (mIsPeriodic) {
if (mMaxExecutionDelayMillis != 0L) {
@@ -1257,31 +1400,7 @@ public class JobInfo implements Parcelable {
" back-off policy, so calling setBackoffCriteria with" +
" setRequiresDeviceIdle is an error.");
}
- JobInfo job = new JobInfo(this);
- if (job.isPeriodic()) {
- if (job.intervalMillis != job.getIntervalMillis()) {
- StringBuilder builder = new StringBuilder();
- builder.append("Specified interval for ")
- .append(String.valueOf(mJobId))
- .append(" is ");
- formatDuration(mIntervalMillis, builder);
- builder.append(". Clamped to ");
- formatDuration(job.getIntervalMillis(), builder);
- Log.w(TAG, builder.toString());
- }
- if (job.flexMillis != job.getFlexMillis()) {
- StringBuilder builder = new StringBuilder();
- builder.append("Specified flex for ")
- .append(String.valueOf(mJobId))
- .append(" is ");
- formatDuration(mFlexMillis, builder);
- builder.append(". Clamped to ");
- formatDuration(job.getFlexMillis(), builder);
- Log.w(TAG, builder.toString());
- }
- }
- return job;
+ return new JobInfo(this);
}
}
-
}
diff --git a/core/java/android/app/slice/Slice.java b/core/java/android/app/slice/Slice.java
index f6b6b869ae0f..616a5be3e552 100644
--- a/core/java/android/app/slice/Slice.java
+++ b/core/java/android/app/slice/Slice.java
@@ -21,8 +21,12 @@ import android.annotation.Nullable;
import android.annotation.StringDef;
import android.app.PendingIntent;
import android.app.RemoteInput;
+import android.content.ContentProvider;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.IContentProvider;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
@@ -54,7 +58,12 @@ public final class Slice implements Parcelable {
public @interface SliceHint{ }
/**
- * Hint that this content is a title of other content in the slice.
+ * Hint that this content is a title of other content in the slice. This can also indicate that
+ * the content should be used in the shortcut representation of the slice (icon, label, action),
+ * normally this should be indicated by adding the hint on the action containing that content.
+ *
+ * @see SliceView#MODE_SHORTCUT
+ * @see SliceItem#TYPE_ACTION
*/
public static final String HINT_TITLE = "title";
/**
@@ -100,6 +109,21 @@ public final class Slice implements Parcelable {
*/
public static final String HINT_NO_TINT = "no_tint";
/**
+ * Hint to indicate that this content should not be shown in the {@link SliceView#MODE_SMALL}
+ * and {@link SliceView#MODE_LARGE} modes of SliceView. This content may be used to populate
+ * the {@link SliceView#MODE_SHORTCUT} format of the slice.
+ * @hide
+ */
+ public static final String HINT_HIDDEN = "hidden";
+ /**
+ * Hint to indicate that this content has a toggle action associated with it. To indicate that
+ * the toggle is on, use {@link #HINT_SELECTED}. When the toggle state changes, the intent
+ * associated with it will be sent along with an extra {@link #EXTRA_TOGGLE_STATE} which can be
+ * retrieved to see the new state of the toggle.
+ * @hide
+ */
+ public static final String HINT_TOGGLE = "toggle";
+ /**
* Hint to indicate that this slice is incomplete and an update will be sent once
* loading is complete. Slices which contain HINT_PARTIAL will not be cached by the
* OS and should not be cached by apps.
@@ -112,6 +136,11 @@ public final class Slice implements Parcelable {
* @hide
*/
public static final String HINT_ALT = "alt";
+ /**
+ * Key to retrieve an extra added to an intent when a control is changed.
+ * @hide
+ */
+ public static final String EXTRA_TOGGLE_STATE = "android.app.slice.extra.TOGGLE_STATE";
private final SliceItem[] mItems;
private final @SliceHint String[] mHints;
@@ -398,4 +427,58 @@ public final class Slice implements Parcelable {
resolver.releaseProvider(provider);
}
}
+
+ /**
+ * Turns a slice intent into slice content. Expects an explicit intent. If there is no
+ * {@link ContentProvider} associated with the given intent this will throw
+ * {@link IllegalArgumentException}.
+ *
+ * @param context The context to use.
+ * @param intent The intent associated with a slice.
+ * @return The Slice provided by the app or null if none is given.
+ * @see Slice
+ * @see SliceProvider#onMapIntentToUri(Intent)
+ * @see Intent
+ */
+ public static @Nullable Slice bindSlice(Context context, @NonNull Intent intent) {
+ Preconditions.checkNotNull(intent, "intent");
+ Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null,
+ "Slice intent must be explicit " + intent);
+ ContentResolver resolver = context.getContentResolver();
+
+ // Check if the intent has data for the slice uri on it and use that
+ final Uri intentData = intent.getData();
+ if (intentData != null && SliceProvider.SLICE_TYPE.equals(resolver.getType(intentData))) {
+ return bindSlice(resolver, intentData);
+ }
+ // Otherwise ask the app
+ List<ResolveInfo> providers =
+ context.getPackageManager().queryIntentContentProviders(intent, 0);
+ if (providers == null) {
+ throw new IllegalArgumentException("Unable to resolve intent " + intent);
+ }
+ String authority = providers.get(0).providerInfo.authority;
+ Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(authority).build();
+ IContentProvider provider = resolver.acquireProvider(uri);
+ if (provider == null) {
+ throw new IllegalArgumentException("Unknown URI " + uri);
+ }
+ try {
+ Bundle extras = new Bundle();
+ extras.putParcelable(SliceProvider.EXTRA_INTENT, intent);
+ final Bundle res = provider.call(resolver.getPackageName(),
+ SliceProvider.METHOD_MAP_INTENT, null, extras);
+ if (res == null) {
+ return null;
+ }
+ return res.getParcelable(SliceProvider.EXTRA_SLICE);
+ } catch (RemoteException e) {
+ // Arbitrary and not worth documenting, as Activity
+ // Manager will kill this process shortly anyway.
+ return null;
+ } finally {
+ resolver.releaseProvider(provider);
+ }
+ }
}
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index da718dc9a2a2..05f4ce6eb10f 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -16,10 +16,13 @@
package android.app.slice;
import android.Manifest.permission;
+import android.annotation.NonNull;
+import android.app.slice.widget.SliceView;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
+import android.content.IntentFilter;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
@@ -37,29 +40,45 @@ import android.util.Log;
import java.util.concurrent.CountDownLatch;
/**
- * A SliceProvider allows app to provide content to be displayed in system
- * spaces. This content is templated and can contain actions, and the behavior
- * of how it is surfaced is specific to the system surface.
+ * A SliceProvider allows an app to provide content to be displayed in system spaces. This content
+ * is templated and can contain actions, and the behavior of how it is surfaced is specific to the
+ * system surface.
+ * <p>
+ * Slices are not currently live content. They are bound once and shown to the user. If the content
+ * changes due to a callback from user interaction, then
+ * {@link ContentResolver#notifyChange(Uri, ContentObserver)} should be used to notify the system.
+ * </p>
+ * <p>
+ * The provider needs to be declared in the manifest to provide the authority for the app. The
+ * authority for most slices is expected to match the package of the application.
+ * </p>
*
- * <p>Slices are not currently live content. They are bound once and shown to the
- * user. If the content changes due to a callback from user interaction, then
- * {@link ContentResolver#notifyChange(Uri, ContentObserver)}
- * should be used to notify the system.</p>
- *
- * <p>The provider needs to be declared in the manifest to provide the authority
- * for the app. The authority for most slices is expected to match the package
- * of the application.</p>
* <pre class="prettyprint">
* {@literal
* <provider
* android:name="com.android.mypkg.MySliceProvider"
* android:authorities="com.android.mypkg" />}
* </pre>
+ * <p>
+ * Slices can be identified by a Uri or by an Intent. To link an Intent with a slice, the provider
+ * must have an {@link IntentFilter} matching the slice intent. When a slice is being requested via
+ * an intent, {@link #onMapIntentToUri(Intent)} can be called and is expected to return an
+ * appropriate Uri representing the slice.
+ *
+ * <pre class="prettyprint">
+ * {@literal
+ * <provider
+ * android:name="com.android.mypkg.MySliceProvider"
+ * android:authorities="com.android.mypkg">
+ * <intent-filter>
+ * <action android:name="android.intent.action.MY_SLICE_INTENT" />
+ * </intent-filter>
+ * </provider>}
+ * </pre>
*
* @see Slice
*/
public abstract class SliceProvider extends ContentProvider {
-
/**
* This is the Android platform's MIME type for a slice: URI
* containing a slice implemented through {@link SliceProvider}.
@@ -78,6 +97,14 @@ public abstract class SliceProvider extends ContentProvider {
/**
* @hide
*/
+ public static final String METHOD_MAP_INTENT = "map_slice";
+ /**
+ * @hide
+ */
+ public static final String EXTRA_INTENT = "slice_intent";
+ /**
+ * @hide
+ */
public static final String EXTRA_SLICE = "slice";
private static final boolean DEBUG = false;
@@ -98,6 +125,20 @@ public abstract class SliceProvider extends ContentProvider {
// TODO: Provide alternate notifyChange that takes in the slice (i.e. notifyChange(Uri, Slice)).
public abstract Slice onBindSlice(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}.
+ *
+ * @return Uri representing the slice associated with the provided intent.
+ * @see {@link Slice}
+ * @see {@link SliceView#setSlice(Intent)}
+ */
+ public @NonNull Uri onMapIntentToUri(Intent intent) {
+ throw new UnsupportedOperationException(
+ "This provider has not implemented intent to uri mapping");
+ }
+
@Override
public final int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
@@ -159,6 +200,19 @@ public abstract class SliceProvider extends ContentProvider {
Bundle b = new Bundle();
b.putParcelable(EXTRA_SLICE, s);
return b;
+ } else if (method.equals(METHOD_MAP_INTENT)) {
+ getContext().enforceCallingPermission(permission.BIND_SLICE,
+ "Slice binding requires the permission BIND_SLICE");
+ Intent intent = extras.getParcelable(EXTRA_INTENT);
+ Uri uri = onMapIntentToUri(intent);
+ Bundle b = new Bundle();
+ if (uri != null) {
+ Slice s = handleBindSlice(uri);
+ b.putParcelable(EXTRA_SLICE, s);
+ } else {
+ b.putParcelable(EXTRA_SLICE, null);
+ }
+ return b;
}
return super.call(method, arg, extras);
}
diff --git a/core/java/android/app/slice/widget/GridView.java b/core/java/android/app/slice/widget/GridView.java
index 67a3c671ba0c..793abc05a489 100644
--- a/core/java/android/app/slice/widget/GridView.java
+++ b/core/java/android/app/slice/widget/GridView.java
@@ -126,6 +126,9 @@ public class GridView extends LinearLayout implements SliceListView {
* Returns true if this item is just an image.
*/
private boolean addItem(SliceItem item) {
+ if (item.hasHint(Slice.HINT_HIDDEN)) {
+ return false;
+ }
if (item.getType() == SliceItem.TYPE_IMAGE) {
ImageView v = new ImageView(getContext());
v.setImageIcon(item.getIcon());
@@ -145,6 +148,9 @@ public class GridView extends LinearLayout implements SliceListView {
items.addAll(item.getSlice().getItems());
}
items.forEach(i -> {
+ if (i.hasHint(Slice.HINT_HIDDEN)) {
+ return;
+ }
Context context = getContext();
switch (i.getType()) {
case SliceItem.TYPE_TEXT:
diff --git a/core/java/android/app/slice/widget/LargeTemplateView.java b/core/java/android/app/slice/widget/LargeTemplateView.java
index f45b2a8f6671..788f6fb6d10a 100644
--- a/core/java/android/app/slice/widget/LargeTemplateView.java
+++ b/core/java/android/app/slice/widget/LargeTemplateView.java
@@ -85,9 +85,14 @@ public class LargeTemplateView extends SliceModeView {
addList(slice, items);
} else {
slice.getItems().forEach(item -> {
- if (item.hasHint(Slice.HINT_ACTIONS)) {
+ if (item.hasHint(Slice.HINT_HIDDEN)) {
+ // If it's hidden we don't show it
+ return;
+ } else if (item.hasHint(Slice.HINT_ACTIONS)) {
+ // Action groups don't show in lists
return;
} else if (item.getType() == SliceItem.TYPE_COLOR) {
+ // A color is not a list item
return;
} else if (item.getType() == SliceItem.TYPE_SLICE
&& item.hasHint(Slice.HINT_LIST)) {
@@ -108,8 +113,12 @@ public class LargeTemplateView extends SliceModeView {
private void addList(Slice slice, List<SliceItem> items) {
List<SliceItem> sliceItems = slice.getItems();
- sliceItems.forEach(i -> i.addHint(Slice.HINT_LIST_ITEM));
- items.addAll(sliceItems);
+ sliceItems.forEach(i -> {
+ if (!i.hasHint(Slice.HINT_HIDDEN) && i.getType() != SliceItem.TYPE_COLOR) {
+ i.addHint(Slice.HINT_LIST_ITEM);
+ items.add(i);
+ }
+ });
}
/**
diff --git a/core/java/android/app/slice/widget/ShortcutView.java b/core/java/android/app/slice/widget/ShortcutView.java
index 0bca8ce283cc..0b7ad0d667dd 100644
--- a/core/java/android/app/slice/widget/ShortcutView.java
+++ b/core/java/android/app/slice/widget/ShortcutView.java
@@ -24,13 +24,20 @@ import android.app.slice.SliceQuery;
import android.app.slice.widget.SliceView.SliceModeView;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.net.Uri;
import com.android.internal.R;
+import java.util.List;
+
/**
* @hide
*/
@@ -38,27 +45,26 @@ public class ShortcutView extends SliceModeView {
private static final String TAG = "ShortcutView";
- private PendingIntent mAction;
private Uri mUri;
+ private PendingIntent mAction;
+ private SliceItem mLabel;
+ private SliceItem mIcon;
+
private int mLargeIconSize;
private int mSmallIconSize;
public ShortcutView(Context context) {
super(context);
- mSmallIconSize = getContext().getResources().getDimensionPixelSize(R.dimen.slice_icon_size);
+ final Resources res = getResources();
+ mSmallIconSize = res.getDimensionPixelSize(R.dimen.slice_icon_size);
+ mLargeIconSize = res.getDimensionPixelSize(R.dimen.slice_shortcut_size);
}
@Override
public void setSlice(Slice slice) {
removeAllViews();
- SliceItem sliceItem = SliceQuery.find(slice, SliceItem.TYPE_ACTION);
- SliceItem iconItem = SliceQuery.getPrimaryIcon(slice);
- SliceItem textItem = sliceItem != null
- ? SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT)
- : SliceQuery.find(slice, SliceItem.TYPE_TEXT);
- SliceItem colorItem = sliceItem != null
- ? SliceQuery.find(sliceItem, SliceItem.TYPE_COLOR)
- : SliceQuery.find(slice, SliceItem.TYPE_COLOR);
+ determineShortcutItems(getContext(), slice);
+ SliceItem colorItem = SliceQuery.find(slice, SliceItem.TYPE_COLOR);
if (colorItem == null) {
colorItem = SliceQuery.find(slice, SliceItem.TYPE_COLOR);
}
@@ -67,13 +73,11 @@ public class ShortcutView extends SliceModeView {
ShapeDrawable circle = new ShapeDrawable(new OvalShape());
circle.setTint(color);
setBackground(circle);
- if (iconItem != null) {
- final boolean isLarge = iconItem.hasHint(Slice.HINT_LARGE);
+ if (mIcon != null) {
+ final boolean isLarge = mIcon.hasHint(Slice.HINT_LARGE);
final int iconSize = isLarge ? mLargeIconSize : mSmallIconSize;
- SliceViewUtil.createCircledIcon(getContext(), color, iconSize, iconItem.getIcon(),
+ SliceViewUtil.createCircledIcon(getContext(), color, iconSize, mIcon.getIcon(),
isLarge, this /* parent */);
- mAction = sliceItem != null ? sliceItem.getAction()
- : null;
mUri = slice.getUri();
setClickable(true);
} else {
@@ -103,4 +107,69 @@ public class ShortcutView extends SliceModeView {
}
return true;
}
+
+ /**
+ * Looks at the slice and determines which items are best to use to compose the shortcut.
+ */
+ private void determineShortcutItems(Context context, Slice slice) {
+ List<String> h = slice.getHints();
+ SliceItem sliceItem = new SliceItem(slice, SliceItem.TYPE_SLICE,
+ h.toArray(new String[h.size()]));
+ SliceItem titleItem = SliceQuery.find(slice, SliceItem.TYPE_ACTION,
+ Slice.HINT_TITLE, null);
+
+ if (titleItem != null) {
+ // Preferred case: hinted action containing hinted image and text
+ mAction = titleItem.getAction();
+ mIcon = SliceQuery.find(titleItem.getSlice(), SliceItem.TYPE_IMAGE, Slice.HINT_TITLE,
+ null);
+ mLabel = SliceQuery.find(titleItem.getSlice(), SliceItem.TYPE_TEXT, Slice.HINT_TITLE,
+ null);
+ } else {
+ // No hinted action; just use the first one
+ SliceItem actionItem = SliceQuery.find(sliceItem, SliceItem.TYPE_ACTION, (String) null,
+ null);
+ mAction = (actionItem != null) ? actionItem.getAction() : null;
+ }
+ // First fallback: any hinted image and text
+ if (mIcon == null) {
+ mIcon = SliceQuery.find(sliceItem, SliceItem.TYPE_IMAGE, Slice.HINT_TITLE,
+ null);
+ }
+ if (mLabel == null) {
+ mLabel = SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT, Slice.HINT_TITLE,
+ null);
+ }
+ // Second fallback: first image and text
+ if (mIcon == null) {
+ mIcon = SliceQuery.find(sliceItem, SliceItem.TYPE_IMAGE, (String) null,
+ null);
+ }
+ if (mLabel == null) {
+ mLabel = SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT, (String) null,
+ null);
+ }
+ // Final fallback: use app info
+ if (mIcon == null || mLabel == null || mAction == null) {
+ PackageManager pm = context.getPackageManager();
+ ProviderInfo providerInfo = pm.resolveContentProvider(
+ slice.getUri().getAuthority(), 0);
+ ApplicationInfo appInfo = providerInfo.applicationInfo;
+ if (appInfo != null) {
+ if (mIcon == null) {
+ Drawable icon = appInfo.loadDefaultIcon(pm);
+ mIcon = new SliceItem(SliceViewUtil.createIconFromDrawable(icon),
+ SliceItem.TYPE_IMAGE, new String[] {Slice.HINT_LARGE});
+ }
+ if (mLabel == null) {
+ mLabel = new SliceItem(pm.getApplicationLabel(appInfo),
+ SliceItem.TYPE_TEXT, null);
+ }
+ if (mAction == null) {
+ mAction = PendingIntent.getActivity(context, 0,
+ pm.getLaunchIntentForPackage(appInfo.packageName), 0);
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/app/slice/widget/SliceView.java b/core/java/android/app/slice/widget/SliceView.java
index 5bafbc03cac6..fa1b64ceed97 100644
--- a/core/java/android/app/slice/widget/SliceView.java
+++ b/core/java/android/app/slice/widget/SliceView.java
@@ -115,7 +115,9 @@ public class SliceView extends ViewGroup {
*/
public static final String MODE_LARGE = "SLICE_LARGE";
/**
- * Mode indicating this slice should be presented as an icon.
+ * Mode indicating this slice should be presented as an icon. A shortcut requires an intent,
+ * icon, and label. This can be indicated by using {@link Slice#HINT_TITLE} on an action in a
+ * slice.
*/
public static final String MODE_SHORTCUT = "SLICE_ICON";
@@ -181,10 +183,25 @@ public class SliceView extends ViewGroup {
}
/**
+ * Populates this view with the {@link Slice} associated with the provided {@link Intent}. To
+ * use this method your app must have the permission
+ * {@link android.Manifest.permission#BIND_SLICE}).
+ * <p>
+ * Setting a slice differs from {@link #showSlice(Slice)} because it will ensure the view is
+ * updated with the slice identified by the provided intent changes. The lifecycle of this
+ * observer is handled by SliceView in {@link #onAttachedToWindow()} and
+ * {@link #onDetachedFromWindow()}. To unregister this observer outside of that you can call
+ * {@link #clearSlice}.
+ *
+ * @return true if a slice was found for the provided intent.
* @hide
*/
- public void showSlice(Intent intent) {
- // TODO
+ public boolean setSlice(@Nullable Intent intent) {
+ Slice s = Slice.bindSlice(mContext, intent);
+ if (s != null) {
+ return setSlice(s.getUri());
+ }
+ return s != null;
}
/**
@@ -197,8 +214,7 @@ public class SliceView extends ViewGroup {
* is handled by SliceView in {@link #onAttachedToWindow()} and {@link #onDetachedFromWindow()}.
* To unregister this observer outside of that you can call {@link #clearSlice}.
*
- * @return true if the a slice was found for the provided uri.
- * @see #clearSlice
+ * @return true if a slice was found for the provided uri.
*/
public boolean setSlice(@NonNull Uri sliceUri) {
Preconditions.checkNotNull(sliceUri,
@@ -210,11 +226,15 @@ public class SliceView extends ViewGroup {
validate(sliceUri);
Slice s = Slice.bindSlice(mContext.getContentResolver(), sliceUri);
if (s != null) {
+ if (mObserver != null) {
+ getContext().getContentResolver().unregisterContentObserver(mObserver);
+ }
mObserver = new SliceObserver(new Handler(Looper.getMainLooper()));
if (isAttachedToWindow()) {
registerSlice(sliceUri);
}
- showSlice(s);
+ mCurrentSlice = s;
+ reinflate();
}
return s != null;
}
diff --git a/core/java/android/app/slice/widget/SliceViewUtil.java b/core/java/android/app/slice/widget/SliceViewUtil.java
index 036699834927..1cf0055bcfe8 100644
--- a/core/java/android/app/slice/widget/SliceViewUtil.java
+++ b/core/java/android/app/slice/widget/SliceViewUtil.java
@@ -28,6 +28,7 @@ import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.view.Gravity;
@@ -141,6 +142,21 @@ public class SliceViewUtil {
/**
* @hide
*/
+ public static Icon createIconFromDrawable(Drawable d) {
+ if (d instanceof BitmapDrawable) {
+ return Icon.createWithBitmap(((BitmapDrawable) d).getBitmap());
+ }
+ Bitmap b = Bitmap.createBitmap(d.getIntrinsicWidth(), d.getIntrinsicHeight(),
+ Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(b);
+ d.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ d.draw(canvas);
+ return Icon.createWithBitmap(b);
+ }
+
+ /**
+ * @hide
+ */
public static void createCircledIcon(Context context, int color, int iconSize, Icon icon,
boolean isLarge, ViewGroup parent) {
ImageView v = new ImageView(context);
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index c827432a8b0b..3a3e16e0956c 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -261,7 +261,10 @@ public final class UsageStatsManager {
/**
* @hide
+ * Changes the app standby state to the provided bucket.
*/
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE)
public void setAppStandbyBucket(String packageName, @StandbyBuckets int bucket) {
try {
mService.setAppStandbyBucket(packageName, bucket, mContext.getUserId());
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index dbaace2f0ac9..29e7439f69e2 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -118,7 +118,15 @@ public abstract class UsageStatsManagerInternal {
AppIdleStateChangeListener listener);
public static abstract class AppIdleStateChangeListener {
- public abstract void onAppIdleStateChanged(String packageName, int userId, boolean idle);
+
+ /** Callback to inform listeners that the idle state has changed to a new bucket. */
+ public abstract void onAppIdleStateChanged(String packageName, int userId, boolean idle,
+ int bucket);
+
+ /**
+ * Callback to inform listeners that the parole state has changed. This means apps are
+ * allowed to do work even if they're idle or in a low bucket.
+ */
public abstract void onParoleStateChanged(boolean isParoleOn);
}
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index e3d763ab9b1e..6692e137fa0a 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -350,13 +350,22 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* 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.
*
* @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.
- * @return
+ * The BluetoothHidDeviceCallback object is required.
+ * @return true if the command is successfully sent; otherwise false.
*/
public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
@@ -394,12 +403,15 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* {@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.
*
* @param config {@link BluetoothHidDeviceAppConfiguration} object as obtained from {@link
* BluetoothHidDeviceCallback#onAppStatusChanged(BluetoothDevice,
* BluetoothHidDeviceAppConfiguration,
* boolean)}
- * @return
+ * @return true if the command is successfully sent; otherwise false.
*/
public boolean unregisterApp(BluetoothHidDeviceAppConfiguration config) {
Log.v(TAG, "unregisterApp()");
@@ -426,7 +438,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* @param id Report Id, as defined in descriptor. Can be 0 in case Report Id are not defined in
* descriptor.
* @param data Report data, not including Report Id.
- * @return
+ * @return true if the command is successfully sent; otherwise false.
*/
public boolean sendReport(BluetoothDevice device, int id, byte[] data) {
boolean result = false;
@@ -452,7 +464,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* @param type Report Type, as in request.
* @param id Report Id, as in request.
* @param data Report data, not including Report Id.
- * @return
+ * @return true if the command is successfully sent; otherwise false.
*/
public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) {
Log.v(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id);
@@ -478,7 +490,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* from {@link BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
*
* @param error Error to be sent for SET_REPORT via HANDSHAKE.
- * @return
+ * @return true if the command is successfully sent; otherwise false.
*/
public boolean reportError(BluetoothDevice device, byte error) {
Log.v(TAG, "reportError(): device=" + device + " error=" + error);
@@ -524,10 +536,13 @@ public final class BluetoothHidDevice implements BluetoothProfile {
}
/**
- * Initiates connection to host which currently has Virtual Cable
- * established with device.
+ * 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
+ * @return true if the command is successfully sent; otherwise false.
*/
public boolean connect(BluetoothDevice device) {
Log.v(TAG, "connect(): device=" + device);
@@ -550,8 +565,11 @@ public final class BluetoothHidDevice implements BluetoothProfile {
/**
* 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
+ * @return true if the command is successfully sent; otherwise false.
*/
public boolean disconnect(BluetoothDevice device) {
Log.v(TAG, "disconnect(): device=" + device);
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
index ccc3ef4008fa..881ae98d9889 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
@@ -45,6 +45,21 @@ public final class BluetoothHidDeviceAppQosSettings implements Parcelable {
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 }
+ * @param serviceType L2CAP service type
+ * @param tokenRate L2CAP token rate
+ * @param tokenBucketSize L2CAP token bucket size
+ * @param peakBandwidth L2CAP peak bandwidth
+ * @param latency L2CAP latency
+ * @param delayVariation L2CAP delay variation
+ */
public BluetoothHidDeviceAppQosSettings(int serviceType, int tokenRate, int tokenBucketSize,
int peakBandwidth, int latency, int delayVariation) {
this.serviceType = serviceType;
@@ -59,7 +74,12 @@ public final class BluetoothHidDeviceAppQosSettings implements Parcelable {
public boolean equals(Object o) {
if (o instanceof BluetoothHidDeviceAppQosSettings) {
BluetoothHidDeviceAppQosSettings qos = (BluetoothHidDeviceAppQosSettings) o;
- return false;
+ return this.serviceType == qos.serviceType
+ && this.tokenRate == qos.tokenRate
+ && this.tokenBucketSize == qos.tokenBucketSize
+ && this.peakBandwidth == qos.peakBandwidth
+ && this.latency == qos.latency
+ && this.delayVariation == qos.delayVariation;
}
return false;
}
@@ -106,4 +126,85 @@ public final class BluetoothHidDeviceAppQosSettings implements Parcelable {
serviceType, tokenRate, tokenBucketSize, peakBandwidth, latency, delayVariation
};
}
+
+ /**
+ * A helper to build the BluetoothHidDeviceAppQosSettings object.
+ */
+ public static class Builder {
+ // Optional parameters - initialized to default values
+ private int mServiceType = SERVICE_BEST_EFFORT;
+ private int mTokenRate = 0;
+ private int mTokenBucketSize = 0;
+ private int mPeakBandwidth = 0;
+ private int mLatency = MAX;
+ private int mDelayVariation = MAX;
+
+ /**
+ * 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.
+ * @return BluetoothHidDeviceAppQosSettings Builder with specified service type.
+ */
+ public Builder serviceType(int val) {
+ mServiceType = val;
+ return this;
+ }
+ /**
+ * Set the token rate.
+ * @param val token rate
+ * @return BluetoothHidDeviceAppQosSettings Builder with specified token rate.
+ */
+ public Builder tokenRate(int val) {
+ mTokenRate = val;
+ return this;
+ }
+
+ /**
+ * Set the bucket size.
+ * @param val bucket size
+ * @return BluetoothHidDeviceAppQosSettings Builder with specified bucket size.
+ */
+ public Builder tokenBucketSize(int val) {
+ mTokenBucketSize = val;
+ return this;
+ }
+
+ /**
+ * Set the peak bandwidth.
+ * @param val peak bandwidth
+ * @return BluetoothHidDeviceAppQosSettings Builder with specified peak bandwidth.
+ */
+ public Builder peakBandwidth(int val) {
+ mPeakBandwidth = val;
+ return this;
+ }
+ /**
+ * Set the latency.
+ * @param val latency
+ * @return BluetoothHidDeviceAppQosSettings Builder with specified latency.
+ */
+ public Builder latency(int val) {
+ mLatency = val;
+ return this;
+ }
+
+ /**
+ * Set the delay variation.
+ * @param val delay variation
+ * @return BluetoothHidDeviceAppQosSettings Builder with specified delay variation.
+ */
+ public Builder delayVariation(int val) {
+ mDelayVariation = val;
+ return this;
+ }
+
+ /**
+ * Build the BluetoothHidDeviceAppQosSettings object.
+ * @return BluetoothHidDeviceAppQosSettings object with current settings.
+ */
+ public BluetoothHidDeviceAppQosSettings build() {
+ return new BluetoothHidDeviceAppQosSettings(mServiceType, mTokenRate, mTokenBucketSize,
+ mPeakBandwidth, mLatency, mDelayVariation);
+ }
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
index f01c49328968..4669637043af 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
@@ -19,6 +19,8 @@ package android.bluetooth;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Arrays;
+
/**
* Represents the Service Discovery Protocol (SDP) settings for a Bluetooth
* HID Device application.
@@ -39,6 +41,18 @@ public final class BluetoothHidDeviceAppSdpSettings implements Parcelable {
public final byte subclass;
public final byte[] descriptors;
+ /**
+ * 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">
+ * 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">
+ * 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) {
this.name = name;
@@ -52,7 +66,11 @@ public final class BluetoothHidDeviceAppSdpSettings implements Parcelable {
public boolean equals(Object o) {
if (o instanceof BluetoothHidDeviceAppSdpSettings) {
BluetoothHidDeviceAppSdpSettings sdp = (BluetoothHidDeviceAppSdpSettings) o;
- return false;
+ return this.name.equals(sdp.name)
+ && this.description.equals(sdp.description)
+ && this.provider.equals(sdp.provider)
+ && this.subclass == sdp.subclass
+ && Arrays.equals(this.descriptors, sdp.descriptors);
}
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 4035ee1beb8f..0569913435a8 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -375,7 +375,7 @@ public final class BluetoothSocket implements Closeable {
IBluetooth bluetoothProxy =
BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
- mPfd = bluetoothProxy.connectSocket(mDevice, mType,
+ mPfd = bluetoothProxy.getSocketManager().connectSocket(mDevice, mType,
mUuid, mPort, getSecurityFlags());
synchronized (this) {
if (DBG) Log.d(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd);
@@ -417,7 +417,7 @@ public final class BluetoothSocket implements Closeable {
return -1;
}
try {
- mPfd = bluetoothProxy.createSocketChannel(mType, mServiceName,
+ mPfd = bluetoothProxy.getSocketManager().createSocketChannel(mType, mServiceName,
mUuid, mPort, getSecurityFlags());
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
index b7545bf55b58..6e9f09cbef0e 100644
--- a/core/java/android/content/AsyncTaskLoader.java
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -49,7 +49,10 @@ import java.util.concurrent.Executor;
* fragment}
*
* @param <D> the data type to be loaded.
+ *
+ * @deprecated Use {@link android.support.v4.content.AsyncTaskLoader}
*/
+@Deprecated
public abstract class AsyncTaskLoader<D> extends Loader<D> {
static final String TAG = "AsyncTaskLoader";
static final boolean DEBUG = false;
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index f8c139feaae3..2d490a03bd76 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -22,6 +22,7 @@ import android.content.res.AssetFileDescriptor;
import android.database.CrossProcessCursorWrapper;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.DeadObjectException;
@@ -102,8 +103,16 @@ public class ContentProviderClient implements AutoCloseable {
if (sAnrHandler == null) {
sAnrHandler = new Handler(Looper.getMainLooper(), null, true /* async */);
}
+
+ // If the remote process hangs, we're going to kill it, so we're
+ // technically okay doing blocking calls.
+ Binder.allowBlocking(mContentProvider.asBinder());
} else {
mAnrRunnable = null;
+
+ // If we're no longer watching for hangs, revert back to default
+ // blocking behavior.
+ Binder.defaultBlocking(mContentProvider.asBinder());
}
}
}
@@ -511,6 +520,10 @@ public class ContentProviderClient implements AutoCloseable {
private boolean closeInternal() {
mCloseGuard.close();
if (mClosed.compareAndSet(false, true)) {
+ // We can't do ANR checks after we cease to exist! Reset any
+ // blocking behavior changes we might have made.
+ setDetectNotResponding(0);
+
if (mStable) {
return mContentResolver.releaseProvider(mContentProvider);
} else {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c165fb3e925c..19e24ad58ab4 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3413,6 +3413,8 @@ public abstract class Context {
public static final String NETWORK_STATS_SERVICE = "netstats";
/** {@hide} */
public static final String NETWORK_POLICY_SERVICE = "netpolicy";
+ /** {@hide} */
+ public static final String NETWORK_WATCHLIST_SERVICE = "network_watchlist";
/**
* Use with {@link #getSystemService} to retrieve a {@link
@@ -4042,6 +4044,13 @@ public abstract class Context {
public static final String STATS_COMPANION_SERVICE = "statscompanion";
/**
+ * Use with {@link #getSystemService} to retrieve an {@link android.stats.StatsManager}.
+ * @hide
+ */
+ @SystemApi
+ public static final String STATS_MANAGER = "stats";
+
+ /**
* Use with {@link #getSystemService} to retrieve a {@link
* android.content.om.OverlayManager} for managing overlay packages.
*
@@ -4071,6 +4080,14 @@ public abstract class Context {
public static final String TIME_ZONE_RULES_MANAGER_SERVICE = "timezone";
/**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.content.pm.crossprofile.CrossProfileApps} for cross profile operations.
+ *
+ * @see #getSystemService
+ */
+ public static final String CROSS_PROFILE_APPS_SERVICE = "crossprofileapps";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
index c78871c30a80..33386e5ce58a 100644
--- a/core/java/android/content/CursorLoader.java
+++ b/core/java/android/content/CursorLoader.java
@@ -38,7 +38,10 @@ import java.util.Arrays;
* in the desired paramters with {@link #setUri(Uri)}, {@link #setSelection(String)},
* {@link #setSelectionArgs(String[])}, {@link #setSortOrder(String)},
* and {@link #setProjection(String[])}.
+ *
+ * @deprecated Use {@link android.support.v4.content.CursorLoader}
*/
+@Deprecated
public class CursorLoader extends AsyncTaskLoader<Cursor> {
final ForceLoadContentObserver mObserver;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index dd729a36875d..bad452cef977 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1728,6 +1728,9 @@ public class Intent implements Parcelable, Cloneable {
* <p>
* Output: If {@link #EXTRA_RETURN_RESULT}, returns whether the install
* succeeded.
+ * <p>
+ * Requires {@link android.Manifest.permission#REQUEST_DELETE_PACKAGES}
+ * since {@link Build.VERSION_CODES#P}.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_UNINSTALL_PACKAGE = "android.intent.action.UNINSTALL_PACKAGE";
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index 3faf13b601ad..80f9a14c6e18 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -48,7 +48,10 @@ import java.io.PrintWriter;
* </div>
*
* @param <D> The result returned when the load is complete
+ *
+ * @deprecated Use {@link android.support.v4.content.Loader}
*/
+@Deprecated
public class Loader<D> {
int mId;
OnLoadCompleteListener<D> mListener;
@@ -66,7 +69,10 @@ public class Loader<D> {
* is told it has changed. You do not normally need to use this yourself;
* it is used for you by {@link CursorLoader} to take care of executing
* an update when the cursor's backing data changes.
+ *
+ * @deprecated Use {@link android.support.v4.content.Loader.ForceLoadContentObserver}
*/
+ @Deprecated
public final class ForceLoadContentObserver extends ContentObserver {
public ForceLoadContentObserver() {
super(new Handler());
@@ -90,7 +96,10 @@ public class Loader<D> {
* to find out when a Loader it is managing has completed so that this can
* be reported to its client. This interface should only be used if a
* Loader is not being used in conjunction with LoaderManager.
+ *
+ * @deprecated Use {@link android.support.v4.content.Loader.OnLoadCompleteListener}
*/
+ @Deprecated
public interface OnLoadCompleteListener<D> {
/**
* Called on the thread that created the Loader when the load is complete.
@@ -108,7 +117,10 @@ public class Loader<D> {
* to find out when a Loader it is managing has been canceled so that it
* can schedule the next Loader. This interface should only be used if a
* Loader is not being used in conjunction with LoaderManager.
+ *
+ * @deprecated Use {@link android.support.v4.content.Loader.OnLoadCanceledListener}
*/
+ @Deprecated
public interface OnLoadCanceledListener<D> {
/**
* Called on the thread that created the Loader when the load is canceled.
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index 4b09feda2173..d3652e8825b5 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -30,6 +30,11 @@ import java.util.Set;
* when they are committed to storage. Objects that are returned from the
* various <code>get</code> methods must be treated as immutable by the application.
*
+ * <p>Note: This class provides strong consistency guarantees. It is using expensive operations
+ * which might slow down an app. Frequently changing properties or properties where loss can be
+ * tolerated should use other mechanisms. For more details read the comments on
+ * {@link Editor#commit()} and {@link Editor#apply()}.
+ *
* <p><em>Note: This class does not support use across multiple processes.</em>
*
* <div class="special reference">
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 05c555685384..9e54e235325c 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -282,13 +282,13 @@ public class LauncherApps {
public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
/**
- * @hide include all pinned shortcuts by any launchers, not just by the caller,
+ * Include all pinned shortcuts by any launchers, not just by the caller,
* in the result.
- * If the caller doesn't havve the {@link android.Manifest.permission#ACCESS_SHORTCUTS}
- * permission, this flag will be ignored.
+ *
+ * The caller must be the selected assistant app to use this flag, or have the system
+ * {@code ACCESS_SHORTCUTS} permission.
*/
- @TestApi
- public static final int FLAG_MATCH_ALL_PINNED = 1 << 10;
+ public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1 << 10;
/**
* FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST
@@ -302,7 +302,7 @@ public class LauncherApps {
* @hide
*/
public static final int FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED =
- FLAG_MATCH_ALL_KINDS | FLAG_MATCH_ALL_PINNED;
+ FLAG_MATCH_ALL_KINDS | FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
/** @hide kept for unit tests */
@Deprecated
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index f4fdcaa44836..86288396ad84 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -444,6 +444,9 @@ public class PackageInstaller {
* @param packageName The package to uninstall.
* @param statusReceiver Where to deliver the result.
*/
+ @RequiresPermission(anyOf = {
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.REQUEST_DELETE_PACKAGES})
public void uninstall(@NonNull String packageName, @NonNull IntentSender statusReceiver) {
uninstall(packageName, 0 /*flags*/, statusReceiver);
}
@@ -476,6 +479,9 @@ public class PackageInstaller {
* @param versionedPackage The versioned package to uninstall.
* @param statusReceiver Where to deliver the result.
*/
+ @RequiresPermission(anyOf = {
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.REQUEST_DELETE_PACKAGES})
public void uninstall(@NonNull VersionedPackage versionedPackage,
@NonNull IntentSender statusReceiver) {
uninstall(versionedPackage, 0 /*flags*/, statusReceiver);
@@ -1184,10 +1190,10 @@ public class PackageInstaller {
}
/**
- * Sets the UID that initiated package installation. This is informational
+ * Sets the UID that initiated the package installation. This is informational
* and may be used as a signal for anti-malware purposes.
*
- * @see PackageManager#EXTRA_VERIFICATION_INSTALLER_UID
+ * @see Intent#EXTRA_ORIGINATING_UID
*/
public void setOriginatingUid(int originatingUid) {
this.originatingUid = originatingUid;
diff --git a/core/java/android/content/pm/crossprofile/CrossProfileApps.java b/core/java/android/content/pm/crossprofile/CrossProfileApps.java
new file mode 100644
index 000000000000..c441b5f376a0
--- /dev/null
+++ b/core/java/android/content/pm/crossprofile/CrossProfileApps.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.content.pm.crossprofile;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import java.util.List;
+
+/**
+ * Class for handling cross profile operations. Apps can use this class to interact with its
+ * instance in any profile that is in {@link #getTargetUserProfiles()}. For example, app can
+ * use this class to start its main activity in managed profile.
+ */
+public class CrossProfileApps {
+ private final Context mContext;
+ private final ICrossProfileApps mService;
+
+ /** @hide */
+ public CrossProfileApps(Context context, ICrossProfileApps service) {
+ mContext = context;
+ mService = service;
+ }
+
+ /**
+ * Starts the specified main activity of the caller package in the specified profile.
+ *
+ * @param component The ComponentName of the activity to launch, it must be exported and has
+ * action {@link android.content.Intent#ACTION_MAIN}, category
+ * {@link android.content.Intent#CATEGORY_LAUNCHER}. Otherwise, SecurityException will
+ * be thrown.
+ * @param user The UserHandle of the profile, must be one of the users returned by
+ * {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will
+ * be thrown.
+ * @param sourceBounds The Rect containing the source bounds of the clicked icon, see
+ * {@link android.content.Intent#setSourceBounds(Rect)}.
+ * @param startActivityOptions Options to pass to startActivity
+ */
+ public void startMainActivity(@NonNull ComponentName component, @NonNull UserHandle user,
+ @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions) {
+ try {
+ mService.startActivityAsUser(mContext.getPackageName(),
+ component, sourceBounds, startActivityOptions, user);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Return a list of user profiles that that the caller can use when calling other APIs in this
+ * class.
+ * <p>
+ * A user profile would be considered as a valid target user profile, provided that:
+ * <ul>
+ * <li>It gets caller app installed</li>
+ * <li>It is not equal to the calling user</li>
+ * <li>It is in the same profile group of calling user profile</li>
+ * <li>It is enabled</li>
+ * </ul>
+ *
+ * @see UserManager#getUserProfiles()
+ */
+ public @NonNull List<UserHandle> getTargetUserProfiles() {
+ try {
+ return mService.getTargetUserProfiles(mContext.getPackageName());
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/java/android/content/pm/crossprofile/ICrossProfileApps.aidl b/core/java/android/content/pm/crossprofile/ICrossProfileApps.aidl
new file mode 100644
index 000000000000..dd8d04f6cf0e
--- /dev/null
+++ b/core/java/android/content/pm/crossprofile/ICrossProfileApps.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 android.content.pm.crossprofile;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+/**
+ * @hide
+ */
+interface ICrossProfileApps {
+ void startActivityAsUser(in String callingPackage, in ComponentName component, in Rect sourceBounds, in Bundle startActivityOptions, in UserHandle user);
+ List<UserHandle> getTargetUserProfiles(in String callingPackage);
+} \ No newline at end of file
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index dfd3bbf04d35..26efda108bb6 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -2105,6 +2105,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
break;
case DENSITY_DPI_NONE:
parts.add("nodpi");
+ break;
default:
parts.add(config.densityDpi + "dpi");
break;
diff --git a/core/java/android/database/MergeCursor.java b/core/java/android/database/MergeCursor.java
index 2c25db765a2b..272cfa24181c 100644
--- a/core/java/android/database/MergeCursor.java
+++ b/core/java/android/database/MergeCursor.java
@@ -17,7 +17,7 @@
package android.database;
/**
- * A convience class that lets you present an array of Cursors as a single linear Cursor.
+ * A convenience class that lets you present an array of Cursors as a single linear Cursor.
* The schema of the cursors presented is entirely up to the creator of the MergeCursor, and
* may be different if that is desired. Calls to getColumns, getColumnIndex, etc will return the
* value for the row that the MergeCursor is currently pointing at.
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 361b81b77f1d..2c93a7fe26cd 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -289,14 +289,19 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
private void setWalModeFromConfiguration() {
if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
- boolean walEnabled =
+ final boolean walEnabled =
(mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
- if (walEnabled || mConfiguration.useCompatibilityWal) {
+ // Use compatibility WAL unless an app explicitly set journal/synchronous mode
+ final boolean useCompatibilityWal = mConfiguration.journalMode == null
+ && mConfiguration.syncMode == null && mConfiguration.useCompatibilityWal;
+ if (walEnabled || useCompatibilityWal) {
setJournalMode("WAL");
setSyncMode(SQLiteGlobal.getWALSyncMode());
} else {
- setJournalMode(SQLiteGlobal.getDefaultJournalMode());
- setSyncMode(SQLiteGlobal.getDefaultSyncMode());
+ setJournalMode(mConfiguration.journalMode == null
+ ? SQLiteGlobal.getDefaultJournalMode() : mConfiguration.journalMode);
+ setSyncMode(mConfiguration.syncMode == null
+ ? SQLiteGlobal.getDefaultSyncMode() : mConfiguration.syncMode);
}
}
}
@@ -310,12 +315,10 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
}
private static String canonicalizeSyncMode(String value) {
- if (value.equals("0")) {
- return "OFF";
- } else if (value.equals("1")) {
- return "NORMAL";
- } else if (value.equals("2")) {
- return "FULL";
+ switch (value) {
+ case "0": return "OFF";
+ case "1": return "NORMAL";
+ case "2": return "FULL";
}
return value;
}
@@ -416,7 +419,8 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
boolean foreignKeyModeChanged = configuration.foreignKeyConstraintsEnabled
!= mConfiguration.foreignKeyConstraintsEnabled;
boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags)
- & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
+ & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0
+ || configuration.useCompatibilityWal != mConfiguration.useCompatibilityWal;
boolean localeChanged = !configuration.locale.equals(mConfiguration.locale);
// Update configuration parameters.
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 83b8dc76bfc3..863fb1986e06 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -262,7 +262,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
private SQLiteDatabase(final String path, final int openFlags,
CursorFactory cursorFactory, DatabaseErrorHandler errorHandler,
- int lookasideSlotSize, int lookasideSlotCount, long idleConnectionTimeoutMs) {
+ int lookasideSlotSize, int lookasideSlotCount, long idleConnectionTimeoutMs,
+ String journalMode, String syncMode) {
mCursorFactory = cursorFactory;
mErrorHandler = errorHandler != null ? errorHandler : new DefaultDatabaseErrorHandler();
mConfigurationLocked = new SQLiteDatabaseConfiguration(path, openFlags);
@@ -285,6 +286,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
}
}
mConfigurationLocked.idleConnectionTimeoutMs = effectiveTimeoutMs;
+ mConfigurationLocked.journalMode = journalMode;
+ mConfigurationLocked.syncMode = syncMode;
mConfigurationLocked.useCompatibilityWal = SQLiteGlobal.isCompatibilityWalSupported();
}
@@ -721,7 +724,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
SQLiteDatabase db = new SQLiteDatabase(path, openParams.mOpenFlags,
openParams.mCursorFactory, openParams.mErrorHandler,
openParams.mLookasideSlotSize, openParams.mLookasideSlotCount,
- openParams.mIdleConnectionTimeout);
+ openParams.mIdleConnectionTimeout, openParams.mJournalMode, openParams.mSyncMode);
db.open();
return db;
}
@@ -747,7 +750,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
*/
public static SQLiteDatabase openDatabase(@NonNull String path, @Nullable CursorFactory factory,
@DatabaseOpenFlags int flags, @Nullable DatabaseErrorHandler errorHandler) {
- SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler, -1, -1, -1);
+ SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler, -1, -1, -1, null,
+ null);
db.open();
return db;
}
@@ -2302,17 +2306,21 @@ public final class SQLiteDatabase extends SQLiteClosable {
private final DatabaseErrorHandler mErrorHandler;
private final int mLookasideSlotSize;
private final int mLookasideSlotCount;
- private long mIdleConnectionTimeout;
+ private final long mIdleConnectionTimeout;
+ private final String mJournalMode;
+ private final String mSyncMode;
private OpenParams(int openFlags, CursorFactory cursorFactory,
DatabaseErrorHandler errorHandler, int lookasideSlotSize, int lookasideSlotCount,
- long idleConnectionTimeout) {
+ long idleConnectionTimeout, String journalMode, String syncMode) {
mOpenFlags = openFlags;
mCursorFactory = cursorFactory;
mErrorHandler = errorHandler;
mLookasideSlotSize = lookasideSlotSize;
mLookasideSlotCount = lookasideSlotCount;
mIdleConnectionTimeout = idleConnectionTimeout;
+ mJournalMode = journalMode;
+ mSyncMode = syncMode;
}
/**
@@ -2379,6 +2387,28 @@ public final class SQLiteDatabase extends SQLiteClosable {
}
/**
+ * Returns <a href="https://sqlite.org/pragma.html#pragma_journal_mode">journal mode</a>.
+ * This journal mode will only be used if {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING}
+ * flag is not set, otherwise a platform will use "WAL" journal mode.
+ * @see Builder#setJournalMode(String)
+ */
+ @Nullable
+ public String getJournalMode() {
+ return mJournalMode;
+ }
+
+ /**
+ * Returns <a href="https://sqlite.org/pragma.html#pragma_synchronous">synchronous mode</a>.
+ * This value will only be used when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} flag
+ * is not set, otherwise a system wide default will be used.
+ * @see Builder#setSynchronousMode(String)
+ */
+ @Nullable
+ public String getSynchronousMode() {
+ return mSyncMode;
+ }
+
+ /**
* Creates a new instance of builder {@link Builder#Builder(OpenParams) initialized} with
* {@code this} parameters.
* @hide
@@ -2398,6 +2428,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
private int mOpenFlags;
private CursorFactory mCursorFactory;
private DatabaseErrorHandler mErrorHandler;
+ private String mJournalMode;
+ private String mSyncMode;
public Builder() {
}
@@ -2408,6 +2440,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
mOpenFlags = params.mOpenFlags;
mCursorFactory = params.mCursorFactory;
mErrorHandler = params.mErrorHandler;
+ mJournalMode = params.mJournalMode;
+ mSyncMode = params.mSyncMode;
}
/**
@@ -2539,6 +2573,30 @@ public final class SQLiteDatabase extends SQLiteClosable {
return this;
}
+
+ /**
+ * Sets <a href="https://sqlite.org/pragma.html#pragma_journal_mode">journal mode</a>
+ * to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} flag is not set.
+ */
+ @NonNull
+ public Builder setJournalMode(@NonNull String journalMode) {
+ Preconditions.checkNotNull(journalMode);
+ mJournalMode = journalMode;
+ return this;
+ }
+
+ /**
+ * Sets <a href="https://sqlite.org/pragma.html#pragma_synchronous">synchronous mode</a>
+ * to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} flag is not set.
+ * @return
+ */
+ @NonNull
+ public Builder setSynchronousMode(@NonNull String syncMode) {
+ Preconditions.checkNotNull(syncMode);
+ mSyncMode = syncMode;
+ return this;
+ }
+
/**
* Creates an instance of {@link OpenParams} with the options that were previously set
* on this builder
@@ -2546,7 +2604,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
@NonNull
public OpenParams build() {
return new OpenParams(mOpenFlags, mCursorFactory, mErrorHandler, mLookasideSlotSize,
- mLookasideSlotCount, mIdleConnectionTimeout);
+ mLookasideSlotCount, mIdleConnectionTimeout, mJournalMode, mSyncMode);
}
}
}
@@ -2561,4 +2619,6 @@ public final class SQLiteDatabase extends SQLiteClosable {
})
@Retention(RetentionPolicy.SOURCE)
public @interface DatabaseOpenFlags {}
+
}
+
diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
index 905da7247308..a14df1ebcbc6 100644
--- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
+++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
@@ -120,6 +120,18 @@ public final class SQLiteDatabaseConfiguration {
public boolean useCompatibilityWal;
/**
+ * Journal mode to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} is not set.
+ * <p>Default is returned by {@link SQLiteGlobal#getDefaultJournalMode()}
+ */
+ public String journalMode;
+
+ /**
+ * Synchronous mode to use when {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} is not set.
+ * <p>Default is returned by {@link SQLiteGlobal#getDefaultSyncMode()}
+ */
+ public String syncMode;
+
+ /**
* Creates a database configuration with the required parameters for opening a
* database and default values for all other parameters.
*
@@ -180,6 +192,8 @@ public final class SQLiteDatabaseConfiguration {
lookasideSlotCount = other.lookasideSlotCount;
idleConnectionTimeoutMs = other.idleConnectionTimeoutMs;
useCompatibilityWal = other.useCompatibilityWal;
+ journalMode = other.journalMode;
+ syncMode = other.syncMode;
}
/**
diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java
index bb2a51706767..d6d9764c7c38 100644
--- a/core/java/android/database/sqlite/SQLiteGlobal.java
+++ b/core/java/android/database/sqlite/SQLiteGlobal.java
@@ -83,7 +83,6 @@ public final class SQLiteGlobal {
/**
* Returns true if compatibility WAL mode is supported. In this mode, only
* database journal mode is changed. Connection pool will use at most one connection.
- * @hide
*/
public static boolean isCompatibilityWalSupported() {
return SystemProperties.getBoolean("debug.sqlite.compatibility_wal_supported",
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index cc9e0f4ded84..49f357e6cb10 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -17,6 +17,8 @@
package android.database.sqlite;
import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.SQLException;
@@ -24,6 +26,8 @@ import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.os.FileUtils;
import android.util.Log;
+import com.android.internal.util.Preconditions;
+
import java.io.File;
/**
@@ -69,7 +73,8 @@ public abstract class SQLiteOpenHelper {
* {@link #onUpgrade} will be used to upgrade the database; if the database is
* newer, {@link #onDowngrade} will be used to downgrade the database
*/
- public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
+ public SQLiteOpenHelper(@Nullable Context context, @Nullable String name,
+ @Nullable CursorFactory factory, int version) {
this(context, name, factory, version, null);
}
@@ -90,12 +95,33 @@ public abstract class SQLiteOpenHelper {
* @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
* corruption, or null to use the default error handler.
*/
- public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
- DatabaseErrorHandler errorHandler) {
+ public SQLiteOpenHelper(@Nullable Context context, @Nullable String name,
+ @Nullable CursorFactory factory, int version,
+ @Nullable DatabaseErrorHandler errorHandler) {
this(context, name, factory, version, 0, errorHandler);
}
/**
+ * Create a helper object to create, open, and/or manage a database.
+ * This method always returns very quickly. The database is not actually
+ * created or opened until one of {@link #getWritableDatabase} or
+ * {@link #getReadableDatabase} is called.
+ *
+ * @param context to use to open or create the database
+ * @param name of the database file, or null for an in-memory database
+ * @param version number of the database (starting at 1); if the database is older,
+ * {@link #onUpgrade} will be used to upgrade the database; if the database is
+ * newer, {@link #onDowngrade} will be used to downgrade the database
+ * @param openParams configuration parameters that are used for opening {@link SQLiteDatabase}.
+ * Please note that {@link SQLiteDatabase#CREATE_IF_NECESSARY} flag will always be
+ * set when the helper opens the database
+ */
+ public SQLiteOpenHelper(@Nullable Context context, @Nullable String name, int version,
+ @NonNull SQLiteDatabase.OpenParams openParams) {
+ this(context, name, version, 0, openParams.toBuilder());
+ }
+
+ /**
* Same as {@link #SQLiteOpenHelper(Context, String, CursorFactory, int, DatabaseErrorHandler)}
* but also accepts an integer minimumSupportedVersion as a convenience for upgrading very old
* versions of this database that are no longer supported. If a database with older version that
@@ -118,17 +144,26 @@ public abstract class SQLiteOpenHelper {
* @see #onUpgrade(SQLiteDatabase, int, int)
* @hide
*/
- public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
- int minimumSupportedVersion, DatabaseErrorHandler errorHandler) {
+ public SQLiteOpenHelper(@Nullable Context context, @Nullable String name,
+ @Nullable CursorFactory factory, int version,
+ int minimumSupportedVersion, @Nullable DatabaseErrorHandler errorHandler) {
+ this(context, name, version, minimumSupportedVersion,
+ new SQLiteDatabase.OpenParams.Builder());
+ mOpenParamsBuilder.setCursorFactory(factory);
+ mOpenParamsBuilder.setErrorHandler(errorHandler);
+ }
+
+ private SQLiteOpenHelper(@Nullable Context context, @Nullable String name, int version,
+ int minimumSupportedVersion,
+ @NonNull SQLiteDatabase.OpenParams.Builder openParamsBuilder) {
+ Preconditions.checkNotNull(openParamsBuilder);
if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
mContext = context;
mName = name;
mNewVersion = version;
mMinimumSupportedVersion = Math.max(0, minimumSupportedVersion);
- mOpenParamsBuilder = new SQLiteDatabase.OpenParams.Builder();
- mOpenParamsBuilder.setCursorFactory(factory);
- mOpenParamsBuilder.setErrorHandler(errorHandler);
+ mOpenParamsBuilder = openParamsBuilder;
mOpenParamsBuilder.addOpenFlags(SQLiteDatabase.CREATE_IF_NECESSARY);
}
diff --git a/core/java/android/database/sqlite/package.html b/core/java/android/database/sqlite/package.html
index 864a9bb32702..4d6ba28962d2 100644
--- a/core/java/android/database/sqlite/package.html
+++ b/core/java/android/database/sqlite/package.html
@@ -20,6 +20,8 @@ with adb shell, for example, <code>adb -e shell sqlite3</code>.
<p>The version of SQLite depends on the version of Android. See the following table:
<table style="width:auto;">
<tr><th>Android API</th><th>SQLite Version</th></tr>
+ <tr><td>API 27</td><td>3.19</td></tr>
+ <tr><td>API 26</td><td>3.18</td></tr>
<tr><td>API 24</td><td>3.9</td></tr>
<tr><td>API 21</td><td>3.8</td></tr>
<tr><td>API 11</td><td>3.7</td></tr>
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index da771e48d85e..ff69bd89564c 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -249,7 +249,7 @@ public abstract class CameraCaptureSession implements AutoCloseable {
* <p>This function can also be called in case where multiple surfaces share the same
* OutputConfiguration, and one of the surfaces becomes available after the {@link
* CameraCaptureSession} is created. In that case, the application must first create the
- * OutputConfiguration with the available Surface, then enable furture surface sharing via
+ * OutputConfiguration with the available Surface, then enable further surface sharing via
* {@link OutputConfiguration#enableSurfaceSharing}, before creating the CameraCaptureSession.
* After the CameraCaptureSession is created, and once the extra Surface becomes available, the
* application must then call {@link OutputConfiguration#addSurface} before finalizing the
@@ -645,6 +645,44 @@ public abstract class CameraCaptureSession implements AutoCloseable {
public abstract Surface getInputSurface();
/**
+ * Update {@link OutputConfiguration} after configuration finalization see
+ * {@link #finalizeOutputConfigurations}.
+ *
+ * <p>Any {@link OutputConfiguration} that has been modified via calls to
+ * {@link OutputConfiguration#addSurface} or {@link OutputConfiguration#removeSurface} must be
+ * updated. After the update call returns without throwing exceptions any newly added surfaces
+ * can be referenced in subsequent capture requests.</p>
+ *
+ * <p>Surfaces that get removed must not be part of any active repeating or single/burst
+ * request or have any pending results. Consider updating any repeating requests first via
+ * {@link #setRepeatingRequest} or {@link #setRepeatingBurst} and then wait for the last frame
+ * number when the sequence completes {@link CaptureCallback#onCaptureSequenceCompleted}
+ * before calling updateOutputConfiguration to remove a previously active Surface.</p>
+ *
+ * <p>Surfaces that get added must not be part of any other registered
+ * {@link OutputConfiguration}.</p>
+ *
+ * @param config Modified output configuration.
+ *
+ * @throws CameraAccessException if the camera device is no longer connected or has
+ * encountered a fatal error.
+ * @throws IllegalArgumentException if an attempt was made to add a {@link Surface} already
+ * in use by another buffer-producing API, such as MediaCodec or
+ * a different camera device or {@link OutputConfiguration}; or
+ * new surfaces are not compatible (see
+ * {@link OutputConfiguration#enableSurfaceSharing}); or a
+ * {@link Surface} that was removed from the modified
+ * {@link OutputConfiguration} still has pending requests.
+ * @throws IllegalStateException if this session is no longer active, either because the session
+ * was explicitly closed, a new session has been created
+ * or the camera device has been closed.
+ */
+ public void updateOutputConfiguration(OutputConfiguration config)
+ throws CameraAccessException {
+ throw new UnsupportedOperationException("Subclasses must override this method");
+ }
+
+ /**
* Close this capture session asynchronously.
*
* <p>Closing a session frees up the target output Surfaces of the session for reuse with either
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 46ad3f0eccc9..3a3048ef1de2 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1280,11 +1280,11 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <ul>
* <li>Processed (but stalling): any non-RAW format with a stallDurations &gt; 0.
* Typically {@link android.graphics.ImageFormat#JPEG JPEG format}.</li>
- * <li>Raw formats: {@link android.graphics.ImageFormat#RAW_SENSOR RAW_SENSOR}, {@link android.graphics.ImageFormat#RAW10 RAW10}, or {@link android.graphics.ImageFormat#RAW12 RAW12}.</li>
- * <li>Processed (but not-stalling): any non-RAW format without a stall duration.
- * Typically {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888},
- * {@link android.graphics.ImageFormat#NV21 NV21}, or
- * {@link android.graphics.ImageFormat#YV12 YV12}.</li>
+ * <li>Raw formats: {@link android.graphics.ImageFormat#RAW_SENSOR RAW_SENSOR}, {@link android.graphics.ImageFormat#RAW10 RAW10}, or
+ * {@link android.graphics.ImageFormat#RAW12 RAW12}.</li>
+ * <li>Processed (but not-stalling): any non-RAW format without a stall duration. Typically
+ * {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888},
+ * {@link android.graphics.ImageFormat#NV21 NV21}, or {@link android.graphics.ImageFormat#YV12 YV12}.</li>
* </ul>
* <p><b>Range of valid values:</b><br></p>
* <p>For processed (and stalling) format streams, &gt;= 1.</p>
@@ -1376,8 +1376,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* CPU resources that will consume more power. The image format for this kind of an output stream can
* be any non-<code>RAW</code> and supported format provided by {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}.</p>
* <p>A processed and stalling format is defined as any non-RAW format with a stallDurations
- * &gt; 0. Typically only the {@link android.graphics.ImageFormat#JPEG JPEG format} is a
- * stalling format.</p>
+ * &gt; 0. Typically only the {@link android.graphics.ImageFormat#JPEG JPEG format} is a stalling format.</p>
* <p>For full guarantees, query {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration } with a
* processed format -- it will return a non-0 value for a stalling stream.</p>
* <p>LEGACY devices will support up to 1 processing/stalling stream.</p>
@@ -1535,8 +1534,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
new Key<int[]>("android.request.availableRequestKeys", int[].class);
/**
- * <p>A list of all keys that the camera device has available
- * to use with {@link android.hardware.camera2.CaptureResult }.</p>
+ * <p>A list of all keys that the camera device has available to use with {@link android.hardware.camera2.CaptureResult }.</p>
* <p>Attempting to get a key from a CaptureResult that is not
* listed here will always return a <code>null</code> value. Getting a key from
* a CaptureResult that is listed here will generally never return a <code>null</code>
@@ -1561,8 +1559,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
new Key<int[]>("android.request.availableResultKeys", int[].class);
/**
- * <p>A list of all keys that the camera device has available
- * to use with {@link android.hardware.camera2.CameraCharacteristics }.</p>
+ * <p>A list of all keys that the camera device has available to use with {@link android.hardware.camera2.CameraCharacteristics }.</p>
* <p>This entry follows the same rules as
* android.request.availableResultKeys (except that it applies for
* CameraCharacteristics instead of CaptureResult). See above for more
@@ -1843,8 +1840,6 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} and
* android.scaler.availableStallDurations for more details about
* calculating the max frame rate.</p>
- * <p>(Keep in sync with
- * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration })</p>
* <p><b>Units</b>: (format, width, height, ns) x n</p>
* <p>This key is available on all devices.</p>
*
@@ -1905,14 +1900,13 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <ul>
* <li>{@link android.graphics.ImageFormat#YUV_420_888 }</li>
* <li>{@link android.graphics.ImageFormat#RAW10 }</li>
+ * <li>{@link android.graphics.ImageFormat#RAW12 }</li>
* </ul>
* <p>All other formats may or may not have an allowed stall duration on
* a per-capability basis; refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
* for more details.</p>
* <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} for more information about
* calculating the max frame rate (absent stalls).</p>
- * <p>(Keep up to date with
- * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration } )</p>
* <p><b>Units</b>: (format, width, height, ns) x n</p>
* <p>This key is available on all devices.</p>
*
@@ -2195,9 +2189,9 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* the raw buffers produced by this sensor.</p>
* <p>If a camera device supports raw sensor formats, either this or
* {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} is the maximum dimensions for the raw
- * output formats listed in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} (this depends on
- * whether or not the image sensor returns buffers containing pixels that are not
- * part of the active array region for blacklevel calibration or other purposes).</p>
+ * output formats listed in {@link android.hardware.camera2.params.StreamConfigurationMap }
+ * (this depends on whether or not the image sensor returns buffers containing pixels that
+ * are not part of the active array region for blacklevel calibration or other purposes).</p>
* <p>Some parts of the full pixel array may not receive light from the scene,
* or be otherwise inactive. The {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} key
* defines the rectangle of active pixels that will be included in processed image
@@ -2205,7 +2199,6 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p><b>Units</b>: Pixels</p>
* <p>This key is available on all devices.</p>
*
- * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
* @see CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE
* @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
@@ -2838,7 +2831,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p>See the individual level enums for full descriptions of the supported capabilities. The
* {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} entry describes the device's capabilities at a
* finer-grain level, if needed. In addition, many controls have their available settings or
- * ranges defined in individual {@link android.hardware.camera2.CameraCharacteristics } entries.</p>
+ * ranges defined in individual entries from {@link android.hardware.camera2.CameraCharacteristics }.</p>
* <p>Some features are not part of any particular hardware level or capability and must be
* queried separately. These include:</p>
* <ul>
@@ -2973,7 +2966,6 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} and
* android.scaler.availableStallDurations for more details about
* calculating the max frame rate.</p>
- * <p>(Keep in sync with {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration })</p>
* <p><b>Units</b>: (format, width, height, ns) x n</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* <p><b>Limited capability</b> -
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 8c8c49fa6373..4b57018bfddf 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -587,8 +587,8 @@ public abstract class CameraMetadata<TKey> {
* then the list of resolutions for YUV_420_888 from {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes } contains at
* least one resolution &gt;= 8 megapixels, with a minimum frame duration of &lt;= 1/20
* s.</p>
- * <p>If the device supports the {@link android.graphics.ImageFormat#RAW10 }, {@link android.graphics.ImageFormat#RAW12 }, then those can also be captured at the same rate
- * as the maximum-size YUV_420_888 resolution is.</p>
+ * <p>If the device supports the {@link android.graphics.ImageFormat#RAW10 }, {@link android.graphics.ImageFormat#RAW12 }, then those can also be
+ * captured at the same rate as the maximum-size YUV_420_888 resolution is.</p>
* <p>If the device supports the PRIVATE_REPROCESSING capability, then the same guarantees
* as for the YUV_420_888 format also apply to the {@link android.graphics.ImageFormat#PRIVATE } format.</p>
* <p>In addition, the {@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} field is guaranted to have a value between 0
@@ -610,25 +610,22 @@ public abstract class CameraMetadata<TKey> {
* following:</p>
* <ul>
* <li>One input stream is supported, that is, <code>{@link CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS android.request.maxNumInputStreams} == 1</code>.</li>
- * <li>{@link android.graphics.ImageFormat#YUV_420_888 } is supported as an output/input format, that is,
- * YUV_420_888 is included in the lists of formats returned by
- * {@link android.hardware.camera2.params.StreamConfigurationMap#getInputFormats } and
- * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputFormats }.</li>
+ * <li>{@link android.graphics.ImageFormat#YUV_420_888 } is supported as an output/input
+ * format, that is, YUV_420_888 is included in the lists of formats returned by {@link android.hardware.camera2.params.StreamConfigurationMap#getInputFormats } and {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputFormats }.</li>
* <li>{@link android.hardware.camera2.params.StreamConfigurationMap#getValidOutputFormatsForInput }
* returns non-empty int[] for each supported input format returned by {@link android.hardware.camera2.params.StreamConfigurationMap#getInputFormats }.</li>
* <li>Each size returned by {@link android.hardware.camera2.params.StreamConfigurationMap#getInputSizes getInputSizes(YUV_420_888)} is also included in {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes getOutputSizes(YUV_420_888)}</li>
- * <li>Using {@link android.graphics.ImageFormat#YUV_420_888 } does not cause a frame rate drop
- * relative to the sensor's maximum capture rate (at that resolution).</li>
+ * <li>Using {@link android.graphics.ImageFormat#YUV_420_888 } does not cause a frame rate
+ * drop relative to the sensor's maximum capture rate (at that resolution).</li>
* <li>{@link android.graphics.ImageFormat#YUV_420_888 } will be reprocessable into both
* {@link android.graphics.ImageFormat#YUV_420_888 } and {@link android.graphics.ImageFormat#JPEG } formats.</li>
* <li>The maximum available resolution for {@link android.graphics.ImageFormat#YUV_420_888 } streams (both input/output) will match the
* maximum available resolution of {@link android.graphics.ImageFormat#JPEG } streams.</li>
* <li>Static metadata {@link CameraCharacteristics#REPROCESS_MAX_CAPTURE_STALL android.reprocess.maxCaptureStall}.</li>
* <li>Only the below controls are effective for reprocessing requests and will be present
- * in capture results. The reprocess requests are from the original capture results that
- * are associated with the intermediate {@link android.graphics.ImageFormat#YUV_420_888 }
- * output buffers. All other controls in the reprocess requests will be ignored by the
- * camera device.<ul>
+ * in capture results. The reprocess requests are from the original capture results
+ * that are associated with the intermediate {@link android.graphics.ImageFormat#YUV_420_888 } output buffers. All other controls in the
+ * reprocess requests will be ignored by the camera device.<ul>
* <li>android.jpeg.*</li>
* <li>{@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode}</li>
* <li>{@link CaptureRequest#EDGE_MODE android.edge.mode}</li>
@@ -654,13 +651,13 @@ public abstract class CameraMetadata<TKey> {
* <p>The camera device can produce depth measurements from its field of view.</p>
* <p>This capability requires the camera device to support the following:</p>
* <ul>
- * <li>{@link android.graphics.ImageFormat#DEPTH16 } is supported as an output format.</li>
- * <li>{@link android.graphics.ImageFormat#DEPTH_POINT_CLOUD } is optionally supported as an
- * output format.</li>
- * <li>This camera device, and all camera devices with the same {@link CameraCharacteristics#LENS_FACING android.lens.facing},
- * will list the following calibration entries in both
- * {@link android.hardware.camera2.CameraCharacteristics } and
- * {@link android.hardware.camera2.CaptureResult }:<ul>
+ * <li>{@link android.graphics.ImageFormat#DEPTH16 } is supported as
+ * an output format.</li>
+ * <li>{@link android.graphics.ImageFormat#DEPTH_POINT_CLOUD } is
+ * optionally supported as an output format.</li>
+ * <li>This camera device, and all camera devices with the same {@link CameraCharacteristics#LENS_FACING android.lens.facing}, will
+ * list the following calibration metadata entries in both {@link android.hardware.camera2.CameraCharacteristics }
+ * and {@link android.hardware.camera2.CaptureResult }:<ul>
* <li>{@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}</li>
* <li>{@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}</li>
* <li>{@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}</li>
@@ -674,8 +671,7 @@ public abstract class CameraMetadata<TKey> {
* </ul>
* <p>Generally, depth output operates at a slower frame rate than standard color capture,
* so the DEPTH16 and DEPTH_POINT_CLOUD formats will commonly have a stall duration that
- * should be accounted for (see
- * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }).
+ * should be accounted for (see {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }).
* On a device that supports both depth and color-based output, to enable smooth preview,
* using a repeating burst is recommended, where a depth-output target is only included
* once every N frames, where N is the ratio between preview output rate and depth output
@@ -692,23 +688,19 @@ public abstract class CameraMetadata<TKey> {
public static final int REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT = 8;
/**
- * <p>The device supports constrained high speed video recording (frame rate &gt;=120fps)
- * use case. The camera device will support high speed capture session created by
- * {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession }, which
- * only accepts high speed request lists created by
- * {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList }.</p>
- * <p>A camera device can still support high speed video streaming by advertising the high speed
- * FPS ranges in {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES android.control.aeAvailableTargetFpsRanges}. For this case, all normal
- * capture request per frame control and synchronization requirements will apply to
- * the high speed fps ranges, the same as all other fps ranges. This capability describes
- * the capability of a specialized operating mode with many limitations (see below), which
- * is only targeted at high speed video recording.</p>
- * <p>The supported high speed video sizes and fps ranges are specified in
- * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoFpsRanges }.
- * To get desired output frame rates, the application is only allowed to select video size
- * and FPS range combinations provided by
- * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoSizes }.
- * The fps range can be controlled via {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange}.</p>
+ * <p>The device supports constrained high speed video recording (frame rate &gt;=120fps) use
+ * case. The camera device will support high speed capture session created by {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession }, which
+ * only accepts high speed request lists created by {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList }.</p>
+ * <p>A camera device can still support high speed video streaming by advertising the high
+ * speed FPS ranges in {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES android.control.aeAvailableTargetFpsRanges}. For this case, all
+ * normal capture request per frame control and synchronization requirements will apply
+ * to the high speed fps ranges, the same as all other fps ranges. This capability
+ * describes the capability of a specialized operating mode with many limitations (see
+ * below), which is only targeted at high speed video recording.</p>
+ * <p>The supported high speed video sizes and fps ranges are specified in {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoFpsRanges }.
+ * To get desired output frame rates, the application is only allowed to select video
+ * size and FPS range combinations provided by {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoSizes }. The
+ * fps range can be controlled via {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange}.</p>
* <p>In this capability, the camera device will override aeMode, awbMode, and afMode to
* ON, AUTO, and CONTINUOUS_VIDEO, respectively. All post-processing block mode
* controls will be overridden to be FAST. Therefore, no manual control of capture
@@ -743,19 +735,16 @@ public abstract class CameraMetadata<TKey> {
* frame rate. If the destination surface is from preview window, the actual preview frame
* rate will be bounded by the screen refresh rate.</p>
* <p>The camera device will only support up to 2 high speed simultaneous output surfaces
- * (preview and recording surfaces)
- * in this mode. Above controls will be effective only if all of below conditions are true:</p>
+ * (preview and recording surfaces) in this mode. Above controls will be effective only
+ * if all of below conditions are true:</p>
* <ul>
* <li>The application creates a camera capture session with no more than 2 surfaces via
* {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession }. The
- * targeted surfaces must be preview surface (either from
- * {@link android.view.SurfaceView } or {@link android.graphics.SurfaceTexture }) or
- * recording surface(either from {@link android.media.MediaRecorder#getSurface } or
- * {@link android.media.MediaCodec#createInputSurface }).</li>
+ * targeted surfaces must be preview surface (either from {@link android.view.SurfaceView } or {@link android.graphics.SurfaceTexture }) or recording
+ * surface(either from {@link android.media.MediaRecorder#getSurface } or {@link android.media.MediaCodec#createInputSurface }).</li>
* <li>The stream sizes are selected from the sizes reported by
* {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoSizes }.</li>
- * <li>The FPS ranges are selected from
- * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoFpsRanges }.</li>
+ * <li>The FPS ranges are selected from {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoFpsRanges }.</li>
* </ul>
* <p>When above conditions are NOT satistied,
* {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession }
@@ -1038,8 +1027,7 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>This camera device is running in backward compatibility mode.</p>
- * <p>Only the stream configurations listed in the <code>LEGACY</code> table in the {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession}
- * documentation are supported.</p>
+ * <p>Only the stream configurations listed in the <code>LEGACY</code> table in the {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession} documentation are supported.</p>
* <p>A <code>LEGACY</code> device does not support per-frame control, manual sensor control, manual
* post-processing, arbitrary cropping regions, and has relaxed performance constraints.
* No additional capabilities beyond <code>BACKWARD_COMPATIBLE</code> will ever be listed by a
@@ -1061,8 +1049,7 @@ public abstract class CameraMetadata<TKey> {
* <p>This camera device is capable of YUV reprocessing and RAW data capture, in addition to
* FULL-level capabilities.</p>
* <p>The stream configurations listed in the <code>LEVEL_3</code>, <code>RAW</code>, <code>FULL</code>, <code>LEGACY</code> and
- * <code>LIMITED</code> tables in the {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession}
- * documentation are guaranteed to be supported.</p>
+ * <code>LIMITED</code> tables in the {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession} documentation are guaranteed to be supported.</p>
* <p>The following additional capabilities are guaranteed to be supported:</p>
* <ul>
* <li><code>YUV_REPROCESSING</code> capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
@@ -2155,12 +2142,13 @@ public abstract class CameraMetadata<TKey> {
public static final int EDGE_MODE_HIGH_QUALITY = 2;
/**
- * <p>Edge enhancement is applied at different levels for different output streams,
- * based on resolution. Streams at maximum recording resolution (see {@link android.hardware.camera2.CameraDevice#createCaptureSession }) or below have
- * edge enhancement applied, while higher-resolution streams have no edge enhancement
- * applied. The level of edge enhancement for low-resolution streams is tuned so that
- * frame rate is not impacted, and the quality is equal to or better than FAST (since it
- * is only applied to lower-resolution outputs, quality may improve from FAST).</p>
+ * <p>Edge enhancement is applied at different
+ * levels for different output streams, based on resolution. Streams at maximum recording
+ * resolution (see {@link android.hardware.camera2.CameraDevice#createCaptureSession })
+ * or below have edge enhancement applied, while higher-resolution streams have no edge
+ * enhancement applied. The level of edge enhancement for low-resolution streams is tuned
+ * so that frame rate is not impacted, and the quality is equal to or better than FAST
+ * (since it is only applied to lower-resolution outputs, quality may improve from FAST).</p>
* <p>This mode is intended to be used by applications operating in a zero-shutter-lag mode
* with YUV or PRIVATE reprocessing, where the application continuously captures
* high-resolution intermediate buffers into a circular buffer, from which a final image is
@@ -2287,12 +2275,12 @@ public abstract class CameraMetadata<TKey> {
/**
* <p>Noise reduction is applied at different levels for different output streams,
- * based on resolution. Streams at maximum recording resolution (see {@link android.hardware.camera2.CameraDevice#createCaptureSession }) or below have noise
- * reduction applied, while higher-resolution streams have MINIMAL (if supported) or no
- * noise reduction applied (if MINIMAL is not supported.) The degree of noise reduction
- * for low-resolution streams is tuned so that frame rate is not impacted, and the quality
- * is equal to or better than FAST (since it is only applied to lower-resolution outputs,
- * quality may improve from FAST).</p>
+ * based on resolution. Streams at maximum recording resolution (see {@link android.hardware.camera2.CameraDevice#createCaptureSession })
+ * or below have noise reduction applied, while higher-resolution streams have MINIMAL (if
+ * supported) or no noise reduction applied (if MINIMAL is not supported.) The degree of
+ * noise reduction for low-resolution streams is tuned so that frame rate is not impacted,
+ * and the quality is equal to or better than FAST (since it is only applied to
+ * lower-resolution outputs, quality may improve from FAST).</p>
* <p>This mode is intended to be used by applications operating in a zero-shutter-lag mode
* with YUV or PRIVATE reprocessing, where the application continuously captures
* high-resolution intermediate buffers into a circular buffer, from which a final image is
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index c41fc0207d92..0262ecb54f0d 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -680,7 +680,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* FAST or HIGH_QUALITY will yield a picture with the same white point
* as what was produced by the camera device in the earlier frame.</p>
* <p>The expected processing pipeline is as follows:</p>
- * <p><img alt="White balance processing pipeline" src="../../../../images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png" /></p>
+ * <p><img alt="White balance processing pipeline" src="/reference/images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png" /></p>
* <p>The white balance is encoded by two values, a 4-channel white-balance
* gain vector (applied in the Bayer domain), and a 3x3 color transform
* matrix (applied after demosaic).</p>
@@ -1470,10 +1470,10 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* <p>When set to AUTO, the individual algorithm controls in
* android.control.* are in effect, such as {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}.</p>
* <p>When set to USE_SCENE_MODE, the individual controls in
- * android.control.* are mostly disabled, and the camera device implements
- * one of the scene mode settings (such as ACTION, SUNSET, or PARTY)
- * as it wishes. The camera device scene mode 3A settings are provided by
- * {@link android.hardware.camera2.CaptureResult capture results}.</p>
+ * android.control.* are mostly disabled, and the camera device
+ * implements one of the scene mode settings (such as ACTION,
+ * SUNSET, or PARTY) as it wishes. The camera device scene mode
+ * 3A settings are provided by {@link android.hardware.camera2.CaptureResult capture results}.</p>
* <p>When set to OFF_KEEP_STATE, it is similar to OFF mode, the only difference
* is that this frame will not be used by camera device background 3A statistics
* update, as if this frame is never captured. This mode can be used in the scenario
@@ -2268,45 +2268,35 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* can run concurrently to the rest of the camera pipeline, but
* cannot process more than 1 capture at a time.</li>
* </ul>
- * <p>The necessary information for the application, given the model above,
- * is provided via the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} field using
+ * <p>The necessary information for the application, given the model above, is provided via
* {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }.
- * These are used to determine the maximum frame rate / minimum frame
- * duration that is possible for a given stream configuration.</p>
+ * These are used to determine the maximum frame rate / minimum frame duration that is
+ * possible for a given stream configuration.</p>
* <p>Specifically, the application can use the following rules to
* determine the minimum frame duration it can request from the camera
* device:</p>
* <ol>
- * <li>Let the set of currently configured input/output streams
- * be called <code>S</code>.</li>
- * <li>Find the minimum frame durations for each stream in <code>S</code>, by looking
- * it up in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} using {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }
- * (with its respective size/format). Let this set of frame durations be
- * called <code>F</code>.</li>
- * <li>For any given request <code>R</code>, the minimum frame duration allowed
- * for <code>R</code> is the maximum out of all values in <code>F</code>. Let the streams
- * used in <code>R</code> be called <code>S_r</code>.</li>
+ * <li>Let the set of currently configured input/output streams be called <code>S</code>.</li>
+ * <li>Find the minimum frame durations for each stream in <code>S</code>, by looking it up in {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }
+ * (with its respective size/format). Let this set of frame durations be called <code>F</code>.</li>
+ * <li>For any given request <code>R</code>, the minimum frame duration allowed for <code>R</code> is the maximum
+ * out of all values in <code>F</code>. Let the streams used in <code>R</code> be called <code>S_r</code>.</li>
* </ol>
* <p>If none of the streams in <code>S_r</code> have a stall time (listed in {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }
- * using its respective size/format), then the frame duration in <code>F</code>
- * determines the steady state frame rate that the application will get
- * if it uses <code>R</code> as a repeating request. Let this special kind of
- * request be called <code>Rsimple</code>.</p>
- * <p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved
- * by a single capture of a new request <code>Rstall</code> (which has at least
- * one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the
- * same minimum frame duration this will not cause a frame rate loss
- * if all buffers from the previous <code>Rstall</code> have already been
- * delivered.</p>
- * <p>For more details about stalling, see
- * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }.</p>
+ * using its respective size/format), then the frame duration in <code>F</code> determines the steady
+ * state frame rate that the application will get if it uses <code>R</code> as a repeating request. Let
+ * this special kind of request be called <code>Rsimple</code>.</p>
+ * <p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved by a single capture of a
+ * new request <code>Rstall</code> (which has at least one in-use stream with a non-0 stall time) and if
+ * <code>Rstall</code> has the same minimum frame duration this will not cause a frame rate loss if all
+ * buffers from the previous <code>Rstall</code> have already been delivered.</p>
+ * <p>For more details about stalling, see {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }.</p>
* <p>This control is only effective if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} or {@link CaptureRequest#CONTROL_MODE android.control.mode} is set to
* OFF; otherwise the auto-exposure algorithm will override this value.</p>
* <p><b>Units</b>: Nanoseconds</p>
* <p><b>Range of valid values:</b><br>
- * See {@link CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION android.sensor.info.maxFrameDuration},
- * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}. The duration
- * is capped to <code>max(duration, exposureTime + overhead)</code>.</p>
+ * See {@link CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION android.sensor.info.maxFrameDuration}, {@link android.hardware.camera2.params.StreamConfigurationMap }.
+ * The duration is capped to <code>max(duration, exposureTime + overhead)</code>.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* <p><b>Full capability</b> -
* Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -2315,7 +2305,6 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#CONTROL_MODE
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
- * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
* @see CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION
*/
@PublicKey
@@ -2584,11 +2573,11 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* <p>Linear mapping:</p>
* <pre><code>android.tonemap.curveRed = [ 0, 0, 1.0, 1.0 ]
* </code></pre>
- * <p><img alt="Linear mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
+ * <p><img alt="Linear mapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
* <p>Invert mapping:</p>
* <pre><code>android.tonemap.curveRed = [ 0, 1.0, 1.0, 0 ]
* </code></pre>
- * <p><img alt="Inverting mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
+ * <p><img alt="Inverting mapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
* <p>Gamma 1/2.2 mapping, with 16 control points:</p>
* <pre><code>android.tonemap.curveRed = [
* 0.0000, 0.0000, 0.0667, 0.2920, 0.1333, 0.4002, 0.2000, 0.4812,
@@ -2596,7 +2585,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* 0.5333, 0.7515, 0.6000, 0.7928, 0.6667, 0.8317, 0.7333, 0.8685,
* 0.8000, 0.9035, 0.8667, 0.9370, 0.9333, 0.9691, 1.0000, 1.0000 ]
* </code></pre>
- * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
+ * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
* <p>Standard sRGB gamma mapping, per IEC 61966-2-1:1999, with 16 control points:</p>
* <pre><code>android.tonemap.curveRed = [
* 0.0000, 0.0000, 0.0667, 0.2864, 0.1333, 0.4007, 0.2000, 0.4845,
@@ -2604,7 +2593,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* 0.5333, 0.7569, 0.6000, 0.7977, 0.6667, 0.8360, 0.7333, 0.8721,
* 0.8000, 0.9063, 0.8667, 0.9389, 0.9333, 0.9701, 1.0000, 1.0000 ]
* </code></pre>
- * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+ * <p><img alt="sRGB tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
* <p><b>Range of valid values:</b><br>
* 0-1 on both input and output coordinates, normalized
* as a floating-point value such that 0 == black and 1 == white.</p>
@@ -2646,11 +2635,11 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* <p>Linear mapping:</p>
* <pre><code>curveRed = [ (0, 0), (1.0, 1.0) ]
* </code></pre>
- * <p><img alt="Linear mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
+ * <p><img alt="Linear mapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
* <p>Invert mapping:</p>
* <pre><code>curveRed = [ (0, 1.0), (1.0, 0) ]
* </code></pre>
- * <p><img alt="Inverting mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
+ * <p><img alt="Inverting mapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
* <p>Gamma 1/2.2 mapping, with 16 control points:</p>
* <pre><code>curveRed = [
* (0.0000, 0.0000), (0.0667, 0.2920), (0.1333, 0.4002), (0.2000, 0.4812),
@@ -2658,7 +2647,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* (0.5333, 0.7515), (0.6000, 0.7928), (0.6667, 0.8317), (0.7333, 0.8685),
* (0.8000, 0.9035), (0.8667, 0.9370), (0.9333, 0.9691), (1.0000, 1.0000) ]
* </code></pre>
- * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
+ * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
* <p>Standard sRGB gamma mapping, per IEC 61966-2-1:1999, with 16 control points:</p>
* <pre><code>curveRed = [
* (0.0000, 0.0000), (0.0667, 0.2864), (0.1333, 0.4007), (0.2000, 0.4845),
@@ -2666,7 +2655,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* (0.5333, 0.7569), (0.6000, 0.7977), (0.6667, 0.8360), (0.7333, 0.8721),
* (0.8000, 0.9063), (0.8667, 0.9389), (0.9333, 0.9701), (1.0000, 1.0000) ]
* </code></pre>
- * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+ * <p><img alt="sRGB tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* <p><b>Full capability</b> -
* Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -2756,9 +2745,9 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* PRESET_CURVE</p>
* <p>The tonemap curve will be defined by specified standard.</p>
* <p>sRGB (approximated by 16 control points):</p>
- * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+ * <p><img alt="sRGB tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
* <p>Rec. 709 (approximated by 16 control points):</p>
- * <p><img alt="Rec. 709 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png" /></p>
+ * <p><img alt="Rec. 709 tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png" /></p>
* <p>Note that above figures show a 16 control points approximation of preset
* curves. Camera devices may apply a different approximation to the curve.</p>
* <p><b>Possible values:</b>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 6d80c20a84af..cfad098c0cd2 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -390,7 +390,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* FAST or HIGH_QUALITY will yield a picture with the same white point
* as what was produced by the camera device in the earlier frame.</p>
* <p>The expected processing pipeline is as follows:</p>
- * <p><img alt="White balance processing pipeline" src="../../../../images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png" /></p>
+ * <p><img alt="White balance processing pipeline" src="/reference/images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png" /></p>
* <p>The white balance is encoded by two values, a 4-channel white-balance
* gain vector (applied in the Bayer domain), and a 3x3 color transform
* matrix (applied after demosaic).</p>
@@ -1975,10 +1975,10 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <p>When set to AUTO, the individual algorithm controls in
* android.control.* are in effect, such as {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}.</p>
* <p>When set to USE_SCENE_MODE, the individual controls in
- * android.control.* are mostly disabled, and the camera device implements
- * one of the scene mode settings (such as ACTION, SUNSET, or PARTY)
- * as it wishes. The camera device scene mode 3A settings are provided by
- * {@link android.hardware.camera2.CaptureResult capture results}.</p>
+ * android.control.* are mostly disabled, and the camera device
+ * implements one of the scene mode settings (such as ACTION,
+ * SUNSET, or PARTY) as it wishes. The camera device scene mode
+ * 3A settings are provided by {@link android.hardware.camera2.CaptureResult capture results}.</p>
* <p>When set to OFF_KEEP_STATE, it is similar to OFF mode, the only difference
* is that this frame will not be used by camera device background 3A statistics
* update, as if this frame is never captured. This mode can be used in the scenario
@@ -3108,45 +3108,35 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* can run concurrently to the rest of the camera pipeline, but
* cannot process more than 1 capture at a time.</li>
* </ul>
- * <p>The necessary information for the application, given the model above,
- * is provided via the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} field using
+ * <p>The necessary information for the application, given the model above, is provided via
* {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }.
- * These are used to determine the maximum frame rate / minimum frame
- * duration that is possible for a given stream configuration.</p>
+ * These are used to determine the maximum frame rate / minimum frame duration that is
+ * possible for a given stream configuration.</p>
* <p>Specifically, the application can use the following rules to
* determine the minimum frame duration it can request from the camera
* device:</p>
* <ol>
- * <li>Let the set of currently configured input/output streams
- * be called <code>S</code>.</li>
- * <li>Find the minimum frame durations for each stream in <code>S</code>, by looking
- * it up in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} using {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }
- * (with its respective size/format). Let this set of frame durations be
- * called <code>F</code>.</li>
- * <li>For any given request <code>R</code>, the minimum frame duration allowed
- * for <code>R</code> is the maximum out of all values in <code>F</code>. Let the streams
- * used in <code>R</code> be called <code>S_r</code>.</li>
+ * <li>Let the set of currently configured input/output streams be called <code>S</code>.</li>
+ * <li>Find the minimum frame durations for each stream in <code>S</code>, by looking it up in {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputMinFrameDuration }
+ * (with its respective size/format). Let this set of frame durations be called <code>F</code>.</li>
+ * <li>For any given request <code>R</code>, the minimum frame duration allowed for <code>R</code> is the maximum
+ * out of all values in <code>F</code>. Let the streams used in <code>R</code> be called <code>S_r</code>.</li>
* </ol>
* <p>If none of the streams in <code>S_r</code> have a stall time (listed in {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }
- * using its respective size/format), then the frame duration in <code>F</code>
- * determines the steady state frame rate that the application will get
- * if it uses <code>R</code> as a repeating request. Let this special kind of
- * request be called <code>Rsimple</code>.</p>
- * <p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved
- * by a single capture of a new request <code>Rstall</code> (which has at least
- * one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the
- * same minimum frame duration this will not cause a frame rate loss
- * if all buffers from the previous <code>Rstall</code> have already been
- * delivered.</p>
- * <p>For more details about stalling, see
- * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }.</p>
+ * using its respective size/format), then the frame duration in <code>F</code> determines the steady
+ * state frame rate that the application will get if it uses <code>R</code> as a repeating request. Let
+ * this special kind of request be called <code>Rsimple</code>.</p>
+ * <p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved by a single capture of a
+ * new request <code>Rstall</code> (which has at least one in-use stream with a non-0 stall time) and if
+ * <code>Rstall</code> has the same minimum frame duration this will not cause a frame rate loss if all
+ * buffers from the previous <code>Rstall</code> have already been delivered.</p>
+ * <p>For more details about stalling, see {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputStallDuration }.</p>
* <p>This control is only effective if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} or {@link CaptureRequest#CONTROL_MODE android.control.mode} is set to
* OFF; otherwise the auto-exposure algorithm will override this value.</p>
* <p><b>Units</b>: Nanoseconds</p>
* <p><b>Range of valid values:</b><br>
- * See {@link CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION android.sensor.info.maxFrameDuration},
- * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}. The duration
- * is capped to <code>max(duration, exposureTime + overhead)</code>.</p>
+ * See {@link CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION android.sensor.info.maxFrameDuration}, {@link android.hardware.camera2.params.StreamConfigurationMap }.
+ * The duration is capped to <code>max(duration, exposureTime + overhead)</code>.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* <p><b>Full capability</b> -
* Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -3155,7 +3145,6 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#CONTROL_MODE
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
- * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
* @see CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION
*/
@PublicKey
@@ -3408,9 +3397,8 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* layout key (see {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT android.sensor.info.colorFilterArrangement}), i.e. the
* nth value given corresponds to the black level offset for the nth
* color channel listed in the CFA.</p>
- * <p>This key will be available if {@link CameraCharacteristics#SENSOR_OPTICAL_BLACK_REGIONS android.sensor.opticalBlackRegions} is
- * available or the camera device advertises this key via
- * {@link android.hardware.camera2.CameraCharacteristics#getAvailableCaptureResultKeys }.</p>
+ * <p>This key will be available if {@link CameraCharacteristics#SENSOR_OPTICAL_BLACK_REGIONS android.sensor.opticalBlackRegions} is available or the
+ * camera device advertises this key via {@link android.hardware.camera2.CameraCharacteristics#getAvailableCaptureResultKeys }.</p>
* <p><b>Range of valid values:</b><br>
* &gt;= 0 for each.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
@@ -3640,13 +3628,13 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* </code></pre>
* <p>The low-resolution scaling map images for each channel are
* (displayed using nearest-neighbor interpolation):</p>
- * <p><img alt="Red lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png" />
- * <img alt="Green (even rows) lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png" />
- * <img alt="Green (odd rows) lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png" />
- * <img alt="Blue lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png" /></p>
+ * <p><img alt="Red lens shading map" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png" />
+ * <img alt="Green (even rows) lens shading map" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png" />
+ * <img alt="Green (odd rows) lens shading map" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png" />
+ * <img alt="Blue lens shading map" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png" /></p>
* <p>As a visualization only, inverting the full-color map to recover an
* image of a gray wall (using bicubic interpolation for visual quality) as captured by the sensor gives:</p>
- * <p><img alt="Image of a uniform white wall (inverse shading map)" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png" /></p>
+ * <p><img alt="Image of a uniform white wall (inverse shading map)" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png" /></p>
* <p><b>Range of valid values:</b><br>
* Each gain factor is &gt;= 1</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
@@ -3707,14 +3695,14 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* </code></pre>
* <p>The low-resolution scaling map images for each channel are
* (displayed using nearest-neighbor interpolation):</p>
- * <p><img alt="Red lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png" />
- * <img alt="Green (even rows) lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png" />
- * <img alt="Green (odd rows) lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png" />
- * <img alt="Blue lens shading map" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png" /></p>
+ * <p><img alt="Red lens shading map" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png" />
+ * <img alt="Green (even rows) lens shading map" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png" />
+ * <img alt="Green (odd rows) lens shading map" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png" />
+ * <img alt="Blue lens shading map" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png" /></p>
* <p>As a visualization only, inverting the full-color map to recover an
* image of a gray wall (using bicubic interpolation for visual quality)
* as captured by the sensor gives:</p>
- * <p><img alt="Image of a uniform white wall (inverse shading map)" src="../../../../images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png" /></p>
+ * <p><img alt="Image of a uniform white wall (inverse shading map)" src="/reference/images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png" /></p>
* <p>Note that the RAW image data might be subject to lens shading
* correction not reported on this map. Query
* {@link CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED android.sensor.info.lensShadingApplied} to see if RAW image data has subject
@@ -3947,11 +3935,11 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <p>Linear mapping:</p>
* <pre><code>android.tonemap.curveRed = [ 0, 0, 1.0, 1.0 ]
* </code></pre>
- * <p><img alt="Linear mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
+ * <p><img alt="Linear mapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
* <p>Invert mapping:</p>
* <pre><code>android.tonemap.curveRed = [ 0, 1.0, 1.0, 0 ]
* </code></pre>
- * <p><img alt="Inverting mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
+ * <p><img alt="Inverting mapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
* <p>Gamma 1/2.2 mapping, with 16 control points:</p>
* <pre><code>android.tonemap.curveRed = [
* 0.0000, 0.0000, 0.0667, 0.2920, 0.1333, 0.4002, 0.2000, 0.4812,
@@ -3959,7 +3947,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* 0.5333, 0.7515, 0.6000, 0.7928, 0.6667, 0.8317, 0.7333, 0.8685,
* 0.8000, 0.9035, 0.8667, 0.9370, 0.9333, 0.9691, 1.0000, 1.0000 ]
* </code></pre>
- * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
+ * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
* <p>Standard sRGB gamma mapping, per IEC 61966-2-1:1999, with 16 control points:</p>
* <pre><code>android.tonemap.curveRed = [
* 0.0000, 0.0000, 0.0667, 0.2864, 0.1333, 0.4007, 0.2000, 0.4845,
@@ -3967,7 +3955,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* 0.5333, 0.7569, 0.6000, 0.7977, 0.6667, 0.8360, 0.7333, 0.8721,
* 0.8000, 0.9063, 0.8667, 0.9389, 0.9333, 0.9701, 1.0000, 1.0000 ]
* </code></pre>
- * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+ * <p><img alt="sRGB tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
* <p><b>Range of valid values:</b><br>
* 0-1 on both input and output coordinates, normalized
* as a floating-point value such that 0 == black and 1 == white.</p>
@@ -4009,11 +3997,11 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <p>Linear mapping:</p>
* <pre><code>curveRed = [ (0, 0), (1.0, 1.0) ]
* </code></pre>
- * <p><img alt="Linear mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
+ * <p><img alt="Linear mapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png" /></p>
* <p>Invert mapping:</p>
* <pre><code>curveRed = [ (0, 1.0), (1.0, 0) ]
* </code></pre>
- * <p><img alt="Inverting mapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
+ * <p><img alt="Inverting mapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png" /></p>
* <p>Gamma 1/2.2 mapping, with 16 control points:</p>
* <pre><code>curveRed = [
* (0.0000, 0.0000), (0.0667, 0.2920), (0.1333, 0.4002), (0.2000, 0.4812),
@@ -4021,7 +4009,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* (0.5333, 0.7515), (0.6000, 0.7928), (0.6667, 0.8317), (0.7333, 0.8685),
* (0.8000, 0.9035), (0.8667, 0.9370), (0.9333, 0.9691), (1.0000, 1.0000) ]
* </code></pre>
- * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
+ * <p><img alt="Gamma = 1/2.2 tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png" /></p>
* <p>Standard sRGB gamma mapping, per IEC 61966-2-1:1999, with 16 control points:</p>
* <pre><code>curveRed = [
* (0.0000, 0.0000), (0.0667, 0.2864), (0.1333, 0.4007), (0.2000, 0.4845),
@@ -4029,7 +4017,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* (0.5333, 0.7569), (0.6000, 0.7977), (0.6667, 0.8360), (0.7333, 0.8721),
* (0.8000, 0.9063), (0.8667, 0.9389), (0.9333, 0.9701), (1.0000, 1.0000) ]
* </code></pre>
- * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+ * <p><img alt="sRGB tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* <p><b>Full capability</b> -
* Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -4119,9 +4107,9 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* PRESET_CURVE</p>
* <p>The tonemap curve will be defined by specified standard.</p>
* <p>sRGB (approximated by 16 control points):</p>
- * <p><img alt="sRGB tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
+ * <p><img alt="sRGB tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png" /></p>
* <p>Rec. 709 (approximated by 16 control points):</p>
- * <p><img alt="Rec. 709 tonemapping curve" src="../../../../images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png" /></p>
+ * <p><img alt="Rec. 709 tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png" /></p>
* <p>Note that above figures show a 16 control points approximation of preset
* curves. Camera devices may apply a different approximation to the curve.</p>
* <p><b>Possible values:</b>
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index c7654c9e74e1..374789c6cf05 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -314,6 +314,20 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
}
@Override
+ public void updateOutputConfiguration(OutputConfiguration config)
+ throws CameraAccessException {
+ synchronized (mDeviceImpl.mInterfaceLock) {
+ checkNotClosed();
+
+ if (DEBUG) {
+ Log.v(TAG, mIdString + "updateOutputConfiguration");
+ }
+
+ mDeviceImpl.updateOutputConfiguration(config);
+ }
+ }
+
+ @Override
public boolean isReprocessable() {
return mInput != null;
}
diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
index fec7fd97764c..8c4dbfa58d05 100644
--- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
@@ -235,6 +235,13 @@ public class CameraConstrainedHighSpeedCaptureSessionImpl
}
@Override
+ public void updateOutputConfiguration(OutputConfiguration config)
+ throws CameraAccessException {
+ throw new UnsupportedOperationException("Constrained high speed session doesn't support"
+ + " this method");
+ }
+
+ @Override
public void close() {
mSessionImpl.close();
}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index bfeb14dedb5c..6787d84b57d3 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -764,6 +764,24 @@ public class CameraDeviceImpl extends CameraDevice
}
}
+ public void updateOutputConfiguration(OutputConfiguration config)
+ throws CameraAccessException {
+ synchronized(mInterfaceLock) {
+ int streamId = -1;
+ for (int i = 0; i < mConfiguredOutputs.size(); i++) {
+ if (config.getSurface() == mConfiguredOutputs.valueAt(i).getSurface()) {
+ streamId = mConfiguredOutputs.keyAt(i);
+ break;
+ }
+ }
+ if (streamId == -1) {
+ throw new IllegalArgumentException("Invalid output configuration");
+ }
+
+ mRemoteDevice.updateOutputConfiguration(streamId, config);
+ }
+ }
+
public void tearDown(Surface surface) throws CameraAccessException {
if (surface == null) throw new IllegalArgumentException("Surface is null");
diff --git a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
index 27087a2e4881..0978ff87b38b 100644
--- a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
+++ b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
@@ -215,6 +215,16 @@ public class ICameraDeviceUserWrapper {
}
}
+ public void updateOutputConfiguration(int streamId, OutputConfiguration config)
+ throws CameraAccessException {
+ try {
+ mRemoteDevice.updateOutputConfiguration(streamId, config);
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
public void finalizeOutputConfigurations(int streamId, OutputConfiguration deferredConfig)
throws CameraAccessException {
try {
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index 49d4096e3f3e..119cca8d4715 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -646,6 +646,11 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
}
@Override
+ public void updateOutputConfiguration(int streamId, OutputConfiguration config) {
+ // TODO: b/63912484 implement updateOutputConfiguration.
+ }
+
+ @Override
public void waitUntilIdle() throws RemoteException {
if (DEBUG) {
Log.d(TAG, "waitUntilIdle called.");
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 2b317d679d1c..7409671f9b9f 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -42,6 +42,53 @@ import static com.android.internal.util.Preconditions.*;
* A class for describing camera output, which contains a {@link Surface} and its specific
* configuration for creating capture session.
*
+ * <p>There are several ways to instantiate, modify and use OutputConfigurations. The most common
+ * and recommended usage patterns are summarized in the following list:</p>
+ *<ul>
+ * <li>Passing a {@link Surface} to the constructor and using the OutputConfiguration instance as
+ * argument to {@link CameraDevice#createCaptureSessionByOutputConfigurations}. This is the most
+ * frequent usage and clients should consider it first before other more complicated alternatives.
+ * </li>
+ *
+ * <li>Passing only a surface source class as an argument to the constructor. This is usually
+ * followed by a call to create a capture session
+ * (see {@link CameraDevice#createCaptureSessionByOutputConfigurations} and a {@link Surface} add
+ * call {@link #addSurface} with a valid {@link Surface}. The sequence completes with
+ * {@link CameraCaptureSession#finalizeOutputConfigurations}. This is the deferred usage case which
+ * aims to enhance performance by allowing the resource-intensive capture session create call to
+ * execute in parallel with any {@link Surface} initialization, such as waiting for a
+ * {@link android.view.SurfaceView} to be ready as part of the UI initialization.</li>
+ *
+ * <li>The third and most complex usage pattern inlvolves surface sharing. Once instantiated an
+ * OutputConfiguration can be enabled for surface sharing via {@link #enableSurfaceSharing}. This
+ * must be done before creating a new capture session and enables calls to
+ * {@link CameraCaptureSession#updateOutputConfiguration}. An OutputConfiguration with enabled
+ * surface sharing can be modified via {@link #addSurface} or {@link #removeSurface}. The updates
+ * to this OutputConfiguration will only come into effect after
+ * {@link CameraCaptureSession#updateOutputConfiguration} returns without throwing exceptions.
+ * Such updates can be done as long as the session is active. Clients should always consider the
+ * additional requirements and limitations placed on the output surfaces (for more details see
+ * {@link #enableSurfaceSharing}, {@link #addSurface}, {@link #removeSurface},
+ * {@link CameraCaptureSession#updateOutputConfiguration}). A trade-off exists between additional
+ * complexity and flexibility. If exercised correctly surface sharing can switch between different
+ * output surfaces without interrupting any ongoing repeating capture requests. This saves time and
+ * can significantly improve the user experience.</li>
+ *
+ * <li>Surface sharing can be used in combination with deferred surfaces. The rules from both cases
+ * are combined and clients must call {@link #enableSurfaceSharing} before creating a capture
+ * session. Attach and/or remove output surfaces via {@link #addSurface}/{@link #removeSurface} and
+ * finalize the configuration using {@link CameraCaptureSession#finalizeOutputConfigurations}.
+ * {@link CameraCaptureSession#updateOutputConfiguration} can be called after the configuration
+ * finalize method returns without exceptions.</li>
+ *
+ * </ul>
+ *
+ * <p>Please note that surface sharing is currently only enabled for outputs that use the
+ * {@link ImageFormat#PRIVATE} format. This includes surface sources like
+ * {@link android.view.SurfaceView}, {@link android.media.MediaRecorder},
+ * {@link android.graphics.SurfaceTexture} and {@link android.media.ImageReader}, configured using
+ * the aforementioned format.</p>
+ *
* @see CameraDevice#createCaptureSessionByOutputConfigurations
*
*/
@@ -123,7 +170,7 @@ public final class OutputConfiguration implements Parcelable {
* {@link OutputConfiguration#addSurface} should not exceed this value.</p>
*
*/
- private static final int MAX_SURFACES_COUNT = 2;
+ private static final int MAX_SURFACES_COUNT = 4;
/**
* Create a new {@link OutputConfiguration} instance with a {@link Surface},
@@ -280,7 +327,10 @@ public final class OutputConfiguration implements Parcelable {
* <p>For advanced use cases, a camera application may require more streams than the combination
* guaranteed by {@link CameraDevice#createCaptureSession}. In this case, more than one
* compatible surface can be attached to an OutputConfiguration so that they map to one
- * camera stream, and the outputs share memory buffers when possible. </p>
+ * camera stream, and the outputs share memory buffers when possible. Due to buffer sharing
+ * clients should be careful when adding surface outputs that modify their input data. If such
+ * case exists, camera clients should have an additional mechanism to synchronize read and write
+ * access between individual consumers.</p>
*
* <p>Two surfaces are compatible in the below cases:</p>
*
@@ -301,9 +351,9 @@ public final class OutputConfiguration implements Parcelable {
* CameraDevice#createCaptureSessionByOutputConfigurations}. Calling this function after {@link
* CameraDevice#createCaptureSessionByOutputConfigurations} has no effect.</p>
*
- * <p>Up to 2 surfaces can be shared for an OutputConfiguration. The supported surfaces for
- * sharing must be of type SurfaceTexture, SurfaceView, MediaRecorder, MediaCodec, or
- * implementation defined ImageReader.</p>
+ * <p>Up to {@link #getMaxSharedSurfaceCount} surfaces can be shared for an OutputConfiguration.
+ * The supported surfaces for sharing must be of type SurfaceTexture, SurfaceView,
+ * MediaRecorder, MediaCodec, or implementation defined ImageReader.</p>
*/
public void enableSurfaceSharing() {
mIsShared = true;
@@ -329,8 +379,10 @@ public final class OutputConfiguration implements Parcelable {
* <p> This function can be called before or after {@link
* CameraDevice#createCaptureSessionByOutputConfigurations}. If it's called after,
* the application must finalize the capture session with
- * {@link CameraCaptureSession#finalizeOutputConfigurations}.
- * </p>
+ * {@link CameraCaptureSession#finalizeOutputConfigurations}. It is possible to call this method
+ * after the output configurations have been finalized only in cases of enabled surface sharing
+ * see {@link #enableSurfaceSharing}. The modified output configuration must be updated with
+ * {@link CameraCaptureSession#updateOutputConfiguration}.</p>
*
* <p> If the OutputConfiguration was constructed with a deferred surface by {@link
* OutputConfiguration#OutputConfiguration(Size, Class)}, the added surface must be obtained
@@ -388,6 +440,31 @@ public final class OutputConfiguration implements Parcelable {
}
/**
+ * Remove a surface from this OutputConfiguration.
+ *
+ * <p> Surfaces added via calls to {@link #addSurface} can also be removed from the
+ * OutputConfiguration. The only notable exception is the surface associated with
+ * the OutputConfigration see {@link #getSurface} which was passed as part of the constructor
+ * or was added first in the deferred case
+ * {@link OutputConfiguration#OutputConfiguration(Size, Class)}.</p>
+ *
+ * @param surface The surface to be removed.
+ *
+ * @throws IllegalArgumentException If the surface is associated with this OutputConfiguration
+ * (see {@link #getSurface}) or the surface didn't get added
+ * with {@link #addSurface}.
+ */
+ public void removeSurface(@NonNull Surface surface) {
+ if (getSurface() == surface) {
+ throw new IllegalArgumentException(
+ "Cannot remove surface associated with this output configuration");
+ }
+ if (!mSurfaces.remove(surface)) {
+ throw new IllegalArgumentException("Surface is not part of this output configuration");
+ }
+ }
+
+ /**
* Create a new {@link OutputConfiguration} instance with another {@link OutputConfiguration}
* instance.
*
@@ -447,6 +524,17 @@ public final class OutputConfiguration implements Parcelable {
}
/**
+ * Get the maximum supported shared {@link Surface} count.
+ *
+ * @return the maximum number of surfaces that can be added per each OutputConfiguration.
+ *
+ * @see #enableSurfaceSharing
+ */
+ public static int getMaxSharedSurfaceCount() {
+ return MAX_SURFACES_COUNT;
+ }
+
+ /**
* Get the {@link Surface} associated with this {@link OutputConfiguration}.
*
* If more than one surface is associated with this {@link OutputConfiguration}, return the
diff --git a/core/java/android/hardware/display/BrightnessChangeEvent.aidl b/core/java/android/hardware/display/BrightnessChangeEvent.aidl
new file mode 100644
index 000000000000..942e0db2d43c
--- /dev/null
+++ b/core/java/android/hardware/display/BrightnessChangeEvent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+parcelable BrightnessChangeEvent;
diff --git a/core/java/android/hardware/display/BrightnessChangeEvent.java b/core/java/android/hardware/display/BrightnessChangeEvent.java
new file mode 100644
index 000000000000..fe24e32e3e62
--- /dev/null
+++ b/core/java/android/hardware/display/BrightnessChangeEvent.java
@@ -0,0 +1,103 @@
+/*
+ * 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.display;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Data about a brightness settings change.
+ * TODO make this SystemAPI
+ * @hide
+ */
+public final class BrightnessChangeEvent implements Parcelable {
+ /** Brightness in nits */
+ public int brightness;
+
+ /** Timestamp of the change {@see System.currentTimeMillis()} */
+ public long timeStamp;
+
+ /** Package name of focused activity when brightness was changed. */
+ public String packageName;
+
+ /** User id of of the user running when brightness was changed.
+ * @hide */
+ public int userId;
+
+ /** Lux values of recent sensor data */
+ public float[] luxValues;
+
+ /** Timestamps of the lux sensor readings {@see System.currentTimeMillis()} */
+ public long[] luxTimestamps;
+
+ /** Most recent battery level when brightness was changed or Float.NaN */
+ public float batteryLevel;
+
+ /** Color filter active to provide night mode */
+ public boolean nightMode;
+
+ /** If night mode color filter is active this will be the temperature in kelvin */
+ public int colorTemperature;
+
+ /** Brightness level before slider adjustment */
+ public int lastBrightness;
+
+ public BrightnessChangeEvent() {
+ }
+
+ private BrightnessChangeEvent(Parcel source) {
+ brightness = source.readInt();
+ timeStamp = source.readLong();
+ packageName = source.readString();
+ userId = source.readInt();
+ luxValues = source.createFloatArray();
+ luxTimestamps = source.createLongArray();
+ batteryLevel = source.readFloat();
+ nightMode = source.readBoolean();
+ colorTemperature = source.readInt();
+ lastBrightness = source.readInt();
+ }
+
+ public static final Creator<BrightnessChangeEvent> CREATOR =
+ new Creator<BrightnessChangeEvent>() {
+ public BrightnessChangeEvent createFromParcel(Parcel source) {
+ return new BrightnessChangeEvent(source);
+ }
+ public BrightnessChangeEvent[] newArray(int size) {
+ return new BrightnessChangeEvent[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(brightness);
+ dest.writeLong(timeStamp);
+ dest.writeString(packageName);
+ dest.writeInt(userId);
+ dest.writeFloatArray(luxValues);
+ dest.writeLongArray(luxTimestamps);
+ dest.writeFloat(batteryLevel);
+ dest.writeBoolean(nightMode);
+ dest.writeInt(colorTemperature);
+ dest.writeInt(lastBrightness);
+ }
+}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index b2af44ecf0fd..ef77d6e6815e 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -30,6 +30,7 @@ import android.view.Surface;
import android.view.WindowManagerPolicy;
import java.util.ArrayList;
+import java.util.List;
/**
* Manages the properties of attached displays.
@@ -615,6 +616,21 @@ public final class DisplayManager {
}
/**
+ * Fetch {@link BrightnessChangeEvent}s.
+ * @hide until we make it a system api.
+ */
+ public List<BrightnessChangeEvent> getBrightnessEvents() {
+ return mGlobal.getBrightnessEvents();
+ }
+
+ /**
+ * @hide STOPSHIP - remove when adaptive brightness accepts curves.
+ */
+ public void setBrightness(int brightness) {
+ mGlobal.setBrightness(brightness);
+ }
+
+ /**
* 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 a8a4eb67f580..d93d0e4ed135 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -17,6 +17,7 @@
package android.hardware.display;
import android.content.Context;
+import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
import android.graphics.Point;
import android.hardware.display.DisplayManager.DisplayListener;
@@ -37,6 +38,8 @@ import android.view.DisplayInfo;
import android.view.Surface;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
* Manager communication with the display manager service on behalf of
@@ -456,6 +459,33 @@ public final class DisplayManagerGlobal {
}
}
+ /**
+ * Retrieves brightness change events.
+ */
+ public List<BrightnessChangeEvent> getBrightnessEvents() {
+ try {
+ ParceledListSlice<BrightnessChangeEvent> events = mDm.getBrightnessEvents();
+ if (events == null) {
+ return Collections.emptyList();
+ }
+ return events.getList();
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Set brightness but don't add a BrightnessChangeEvent
+ * STOPSHIP remove when adaptive brightness accepts curves.
+ */
+ public void setBrightness(int brightness) {
+ try {
+ mDm.setBrightness(brightness);
+ } 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 505388419c8c..b796cf9aa77b 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -16,6 +16,7 @@
package android.hardware.display;
+import android.content.pm.ParceledListSlice;
import android.graphics.Point;
import android.hardware.display.IDisplayManagerCallback;
import android.hardware.display.IVirtualDisplayCallback;
@@ -81,4 +82,11 @@ interface IDisplayManager {
// Get a stable metric for the device's display size. No permissions required.
Point getStableDisplaySize();
+
+ // Requires BRIGHTNESS_SLIDER_USAGE permission.
+ ParceledListSlice getBrightnessEvents();
+
+ // STOPSHIP remove when adaptive brightness code is updated to accept curves.
+ // Requires BRIGHTNESS_SLIDER_USAGE permission.
+ void setBrightness(int brightness);
}
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 7cbb436c84ee..241172784262 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -271,6 +271,59 @@ public final class ContextHubManager {
throw new UnsupportedOperationException("TODO: Implement this");
}
+ /*
+ * Helper function to generate a stub for a non-query transaction callback.
+ *
+ * @param transaction the transaction to unblock when complete
+ *
+ * @return the callback
+ *
+ * @hide
+ */
+ private IContextHubTransactionCallback createTransactionCallback(
+ ContextHubTransaction<Void> transaction) {
+ return new IContextHubTransactionCallback.Stub() {
+ @Override
+ public void onQueryResponse(int result, List<NanoAppState> nanoappList) {
+ Log.e(TAG, "Received a query callback on a non-query request");
+ transaction.setResponse(new ContextHubTransaction.Response<Void>(
+ ContextHubTransaction.TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE, null));
+ }
+
+ @Override
+ public void onTransactionComplete(int result) {
+ transaction.setResponse(new ContextHubTransaction.Response<Void>(result, null));
+ }
+ };
+ }
+
+ /*
+ * Helper function to generate a stub for a query transaction callback.
+ *
+ * @param transaction the transaction to unblock when complete
+ *
+ * @return the callback
+ *
+ * @hide
+ */
+ private IContextHubTransactionCallback createQueryCallback(
+ ContextHubTransaction<List<NanoAppState>> transaction) {
+ return new IContextHubTransactionCallback.Stub() {
+ @Override
+ public void onQueryResponse(int result, List<NanoAppState> nanoappList) {
+ transaction.setResponse(new ContextHubTransaction.Response<List<NanoAppState>>(
+ result, nanoappList));
+ }
+
+ @Override
+ public void onTransactionComplete(int result) {
+ Log.e(TAG, "Received a non-query callback on a query request");
+ transaction.setResponse(new ContextHubTransaction.Response<List<NanoAppState>>(
+ ContextHubTransaction.TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE, null));
+ }
+ };
+ }
+
/**
* Loads a nanoapp at the specified Context Hub.
*
@@ -411,7 +464,7 @@ public final class ContextHubManager {
*
* @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 current thread Looper
+ * @param handler the handler to invoke the callback, if null uses the main thread's Looper
*
* @return the registered client object
*
diff --git a/core/java/android/hardware/location/ContextHubTransaction.java b/core/java/android/hardware/location/ContextHubTransaction.java
index 4877d38b37e0..a8569ef479a1 100644
--- a/core/java/android/hardware/location/ContextHubTransaction.java
+++ b/core/java/android/hardware/location/ContextHubTransaction.java
@@ -16,11 +16,16 @@
package android.hardware.location;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* A class describing a request sent to the Context Hub Service.
@@ -29,17 +34,15 @@ import java.util.concurrent.TimeUnit;
* through the ContextHubManager APIs. The caller can either retrieve the result
* synchronously through a blocking call ({@link #waitForResponse(long, TimeUnit)}) or
* asynchronously through a user-defined callback
- * ({@link #onComplete(ContextHubTransaction.Callback<T>, Handler)}).
- *
- * A transaction can be invalidated if the caller of the transaction is no longer active
- * and the reference to this object is lost, or if timeout period has passed in
- * {@link #waitForResponse(long, TimeUnit)}.
+ * ({@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)}).
*
* @param <T> the type of the contents in the transaction response
*
* @hide
*/
public class ContextHubTransaction<T> {
+ private static final String TAG = "ContextHubTransaction";
+
/**
* Constants describing the type of a transaction through the Context Hub Service.
*/
@@ -68,7 +71,8 @@ public class ContextHubTransaction<T> {
TRANSACTION_FAILED_UNINITIALIZED,
TRANSACTION_FAILED_PENDING,
TRANSACTION_FAILED_AT_HUB,
- TRANSACTION_FAILED_TIMEOUT})
+ TRANSACTION_FAILED_TIMEOUT,
+ TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE})
public @interface Result {}
public static final int TRANSACTION_SUCCESS = 0;
/**
@@ -95,6 +99,10 @@ public class ContextHubTransaction<T> {
* Failure mode when the transaction has timed out.
*/
public static final int TRANSACTION_FAILED_TIMEOUT = 6;
+ /**
+ * Failure mode when the transaction has failed internally at the service.
+ */
+ public static final int TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE = 7;
/**
* A class describing the response for a ContextHubTransaction.
@@ -146,11 +154,6 @@ public class ContextHubTransaction<T> {
}
/*
- * The unique identifier representing the transaction.
- */
- private int mTransactionId;
-
- /*
* The type of the transaction.
*/
@Type
@@ -171,8 +174,17 @@ public class ContextHubTransaction<T> {
*/
private ContextHubTransaction.Callback<T> mCallback = null;
- ContextHubTransaction(int id, @Type int type) {
- mTransactionId = id;
+ /*
+ * Synchronization latch used to block on response.
+ */
+ private final CountDownLatch mDoneSignal = new CountDownLatch(1);
+
+ /*
+ * true if the response has been set throught setResponse, false otherwise.
+ */
+ private boolean mIsResponseSet = false;
+
+ ContextHubTransaction(@Type int type) {
mTransactionType = type;
}
@@ -191,17 +203,26 @@ public class ContextHubTransaction<T> {
* for the transaction represented by this object by the Context Hub, or a
* specified timeout period has elapsed.
*
- * If the specified timeout has passed, the transaction represented by this object
- * is invalidated by the Context Hub Service (resulting in a timeout failure in the
- * response).
+ * If the specified timeout has passed, a TimeoutException will be thrown and the caller may
+ * retry the invocation of this method at a later time.
*
* @param timeout the timeout duration
* @param unit the unit of the timeout
*
* @return the transaction response
+ *
+ * @throws InterruptedException if the current thread is interrupted while waiting for response
+ * @throws TimeoutException if the timeout period has passed
*/
- public ContextHubTransaction.Response<T> waitForResponse(long timeout, TimeUnit unit) {
- throw new UnsupportedOperationException("TODO: Implement this");
+ public ContextHubTransaction.Response<T> waitForResponse(
+ long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
+ boolean success = mDoneSignal.await(timeout, unit);
+
+ if (!success) {
+ throw new TimeoutException("Timed out while waiting for transaction");
+ }
+
+ return mResponse;
}
/**
@@ -215,15 +236,100 @@ public class ContextHubTransaction<T> {
* will be immediately posted by the handler. If the transaction has been invalidated,
* the callback will never be invoked.
*
+ * 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
+ * invoked once, or an IllegalStateException will be thrown.
+ *
* @param callback the callback to be invoked upon completion
* @param handler the handler to post the callback
+ *
+ * @throws IllegalStateException if this method is called multiple times
+ * @throws NullPointerException if the callback or handler is null
*/
- public void onComplete(ContextHubTransaction.Callback<T> callback, Handler handler) {
- throw new UnsupportedOperationException("TODO: Implement this");
+ public void setCallbackOnComplete(
+ @NonNull ContextHubTransaction.Callback<T> callback, @NonNull Handler handler) {
+ synchronized (this) {
+ if (callback == null) {
+ throw new NullPointerException("Callback cannot be null");
+ }
+ if (handler == null) {
+ throw new NullPointerException("Handler cannot be null");
+ }
+ if (mCallback != null) {
+ throw new IllegalStateException(
+ "Cannot set ContextHubTransaction callback multiple times");
+ }
+
+ mCallback = callback;
+ mHandler = handler;
+
+ if (mDoneSignal.getCount() == 0) {
+ boolean callbackPosted = mHandler.post(() -> {
+ mCallback.onComplete(this, mResponse);
+ });
+
+ if (!callbackPosted) {
+ Log.e(TAG, "Failed to post callback to Handler");
+ }
+ }
+ }
}
- private void setResponse(ContextHubTransaction.Response<T> response) {
- mResponse = response;
- throw new UnsupportedOperationException("TODO: Unblock waitForResponse");
+ /**
+ * Sets a callback to be invoked when the transaction completes.
+ *
+ * Equivalent to {@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)}
+ * with the handler being that of the main thread's Looper.
+ *
+ * This method or {@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)}
+ * can only be invoked once, or an IllegalStateException will be thrown.
+ *
+ * @param callback the callback to be invoked upon completion
+ *
+ * @throws IllegalStateException if this method is called multiple times
+ * @throws NullPointerException if the callback is null
+ */
+ public void setCallbackOnComplete(@NonNull ContextHubTransaction.Callback<T> callback) {
+ setCallbackOnComplete(callback, new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Sets the response of the transaction.
+ *
+ * This method should only be invoked by ContextHubManager as a result of a callback from
+ * the Context Hub Service indicating the response from a transaction. This method should not be
+ * invoked more than once.
+ *
+ * @param response the response to set
+ *
+ * @throws IllegalStateException if this method is invoked multiple times
+ * @throws NullPointerException if the response is null
+ */
+ void setResponse(ContextHubTransaction.Response<T> response) {
+ synchronized (this) {
+ if (response == null) {
+ throw new NullPointerException("Response cannot be null");
+ }
+ if (mIsResponseSet) {
+ throw new IllegalStateException(
+ "Cannot set response of ContextHubTransaction multiple times");
+ }
+
+ mResponse = response;
+ mIsResponseSet = true;
+
+ mDoneSignal.countDown();
+ if (mCallback != null) {
+ boolean callbackPosted = mHandler.post(() -> {
+ mCallback.onComplete(this, mResponse);
+ });
+
+ if (!callbackPosted) {
+ Log.e(TAG, "Failed to post callback to Handler");
+ }
+ }
+ }
}
}
diff --git a/core/java/android/hardware/location/IContextHubTransactionCallback.aidl b/core/java/android/hardware/location/IContextHubTransactionCallback.aidl
new file mode 100644
index 000000000000..5419cd7e60d8
--- /dev/null
+++ b/core/java/android/hardware/location/IContextHubTransactionCallback.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.NanoAppState;
+
+/**
+ * An interface used by the Context Hub Service to invoke callbacks notifying the complete of a
+ * transaction. The callbacks are unique for each type of transaction, and the service is
+ * responsible for invoking the correct callback.
+ *
+ * @hide
+ */
+oneway interface IContextHubTransactionCallback {
+
+ // Callback to be invoked when a query request completes
+ void onQueryResponse(int result, in List<NanoAppState> nanoappList);
+
+ // Callback to be invoked when a non-query request completes
+ void onTransactionComplete(int result);
+}
diff --git a/core/java/android/hardware/location/NanoAppBinary.java b/core/java/android/hardware/location/NanoAppBinary.java
index 545422773aed..934e9e48c01a 100644
--- a/core/java/android/hardware/location/NanoAppBinary.java
+++ b/core/java/android/hardware/location/NanoAppBinary.java
@@ -22,6 +22,7 @@ import android.util.Log;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.Arrays;
/**
* @hide
@@ -57,7 +58,7 @@ public final class NanoAppBinary implements Parcelable {
private static final int EXPECTED_HEADER_VERSION = 1;
/*
- * The magic value expected in the header.
+ * The magic value expected in the header as defined in context_hub.h.
*/
private static final int EXPECTED_MAGIC_VALUE =
(((int) 'N' << 0) | ((int) 'A' << 8) | ((int) 'N' << 16) | ((int) 'O' << 24));
@@ -67,6 +68,17 @@ public final class NanoAppBinary implements Parcelable {
*/
private static final ByteOrder HEADER_ORDER = ByteOrder.LITTLE_ENDIAN;
+ /*
+ * The size of the header in bytes as defined in context_hub.h.
+ */
+ private static final int HEADER_SIZE_BYTES = 40;
+
+ /*
+ * The bit fields for mFlags as defined in context_hub.h.
+ */
+ private static final int NANOAPP_SIGNED_FLAG_BIT = 0x1;
+ private static final int NANOAPP_ENCRYPTED_FLAG_BIT = 0x2;
+
public NanoAppBinary(byte[] appBinary) {
mNanoAppBinary = appBinary;
parseBinaryHeader();
@@ -111,11 +123,26 @@ public final class NanoAppBinary implements Parcelable {
/**
* @return the app binary byte array
*/
- public byte[] getNanoAppBinary() {
+ public byte[] getBinary() {
return mNanoAppBinary;
}
/**
+ * @return the app binary byte array without the leading header
+ *
+ * @throws IndexOutOfBoundsException if the nanoapp binary size is smaller than the header size
+ * @throws NullPointerException if the nanoapp binary is null
+ */
+ public byte[] getBinaryNoHeader() {
+ if (mNanoAppBinary.length < HEADER_SIZE_BYTES) {
+ throw new IndexOutOfBoundsException("NanoAppBinary binary byte size ("
+ + mNanoAppBinary.length + ") is less than header size (" + HEADER_SIZE_BYTES + ")");
+ }
+
+ return Arrays.copyOfRange(mNanoAppBinary, HEADER_SIZE_BYTES, mNanoAppBinary.length);
+ }
+
+ /**
* @return {@code true} if the header is valid, {@code false} otherwise
*/
public boolean hasValidHeader() {
@@ -164,6 +191,31 @@ public final class NanoAppBinary implements Parcelable {
return mTargetChreApiMinorVersion;
}
+ /**
+ * Returns the flags for the nanoapp as defined in context_hub.h.
+ *
+ * This method is meant to be used by the Context Hub Service.
+ *
+ * @return the flags for the nanoapp
+ */
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /**
+ * @return {@code true} if the nanoapp binary is signed, {@code false} otherwise
+ */
+ public boolean isSigned() {
+ return (mFlags & NANOAPP_SIGNED_FLAG_BIT) != 0;
+ }
+
+ /**
+ * @return {@code true} if the nanoapp binary is encrypted, {@code false} otherwise
+ */
+ public boolean isEncrypted() {
+ return (mFlags & NANOAPP_ENCRYPTED_FLAG_BIT) != 0;
+ }
+
private NanoAppBinary(Parcel in) {
int binaryLength = in.readInt();
mNanoAppBinary = new byte[binaryLength];
diff --git a/core/java/android/hardware/radio/ITuner.aidl b/core/java/android/hardware/radio/ITuner.aidl
index 3aaeb5061de3..18287fae1b9b 100644
--- a/core/java/android/hardware/radio/ITuner.aidl
+++ b/core/java/android/hardware/radio/ITuner.aidl
@@ -94,5 +94,17 @@ interface ITuner {
*/
void setAnalogForced(boolean isForced);
+ /**
+ * @param parameters Vendor-specific key-value pairs, must be Map<String, String>
+ * @return Vendor-specific key-value pairs, must be Map<String, String>
+ */
+ Map setParameters(in Map parameters);
+
+ /**
+ * @param keys Parameter keys to fetch
+ * @return Vendor-specific key-value pairs, must be Map<String, String>
+ */
+ Map getParameters(in List<String> keys);
+
boolean isAntennaConnected();
}
diff --git a/core/java/android/hardware/radio/ITunerCallback.aidl b/core/java/android/hardware/radio/ITunerCallback.aidl
index 6ed171bbb8a9..775e25c7e7cf 100644
--- a/core/java/android/hardware/radio/ITunerCallback.aidl
+++ b/core/java/android/hardware/radio/ITunerCallback.aidl
@@ -30,4 +30,9 @@ oneway interface ITunerCallback {
void onBackgroundScanAvailabilityChange(boolean isAvailable);
void onBackgroundScanComplete();
void onProgramListChanged();
+
+ /**
+ * @param parameters Vendor-specific key-value pairs, must be Map<String, String>
+ */
+ void onParametersUpdated(in Map parameters);
}
diff --git a/core/java/android/hardware/radio/RadioTuner.java b/core/java/android/hardware/radio/RadioTuner.java
index 6e8991aa4a4a..e93fd5f1b86b 100644
--- a/core/java/android/hardware/radio/RadioTuner.java
+++ b/core/java/android/hardware/radio/RadioTuner.java
@@ -309,6 +309,58 @@ public abstract class RadioTuner {
public abstract void setAnalogForced(boolean isForced);
/**
+ * Generic method for setting vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * Framework does not make any assumptions on the keys or values, other than
+ * ones stated in VendorKeyValue documentation (a requirement of key
+ * prefixes).
+ *
+ * For each pair in the result map, the key will be one of the keys
+ * contained in the input (possibly with wildcards expanded), and the value
+ * will be a vendor-specific result status (such as "OK" or an error code).
+ * The implementation may choose to return an empty map, or only return
+ * a status for a subset of the provided inputs, at its discretion.
+ *
+ * Application and HAL must not use keys with unknown prefix. In particular,
+ * it must not place a key-value pair in results vector for unknown key from
+ * parameters vector - instead, an unknown key should simply be ignored.
+ * In other words, results vector may contain a subset of parameter keys
+ * (however, the framework doesn't enforce a strict subset - the only
+ * formal requirement is vendor domain prefix for keys).
+ *
+ * @param parameters Vendor-specific key-value pairs.
+ * @return Operation completion status for parameters being set.
+ * @hide FutureFeature
+ */
+ public abstract @NonNull Map<String, String>
+ setParameters(@NonNull Map<String, String> parameters);
+
+ /**
+ * Generic method for retrieving vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * Framework does not cache set/get requests, so it's possible for
+ * getParameter to return a different value than previous setParameter call.
+ *
+ * The syntax and semantics of keys are up to the vendor (as long as prefix
+ * rules are obeyed). For instance, vendors may include some form of
+ * wildcard support. In such case, result vector may be of different size
+ * than requested keys vector. However, wildcards are not recognized by
+ * framework and they are passed as-is to the HAL implementation.
+ *
+ * Unknown keys must be ignored and not placed into results vector.
+ *
+ * @param keys Parameter keys to fetch.
+ * @return Vendor-specific key-value pairs.
+ * @hide FutureFeature
+ */
+ public abstract @NonNull Map<String, String>
+ getParameters(@NonNull List<String> keys);
+
+ /**
* Get current antenna connection state for current configuration.
* Only valid if a configuration has been applied.
* @return {@code true} if the antenna is connected, {@code false} otherwise.
@@ -429,6 +481,22 @@ public abstract class RadioTuner {
* Use {@link RadioTuner#getProgramList(String)} to get an actual list.
*/
public void onProgramListChanged() {}
+
+ /**
+ * Generic callback for passing updates to vendor-specific parameter values.
+ * The framework does not interpret the parameters, they are passed
+ * in an opaque manner between a vendor application and HAL.
+ *
+ * It's up to the HAL implementation if and how to implement this callback,
+ * as long as it obeys the prefix rule. In particular, only selected keys
+ * may be notified this way. However, setParameters must not trigger
+ * this callback, while an internal event can change parameters
+ * asynchronously.
+ *
+ * @param parameters Vendor-specific key-value pairs.
+ * @hide FutureFeature
+ */
+ public void onParametersUpdated(@NonNull Map<String, String> parameters) {}
}
}
diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java
index b62196902570..864d17c2de9f 100644
--- a/core/java/android/hardware/radio/TunerAdapter.java
+++ b/core/java/android/hardware/radio/TunerAdapter.java
@@ -24,6 +24,7 @@ import android.util.Log;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
/**
* Implements the RadioTuner interface by forwarding calls to radio service.
@@ -251,6 +252,24 @@ class TunerAdapter extends RadioTuner {
}
@Override
+ public @NonNull Map<String, String> setParameters(@NonNull Map<String, String> parameters) {
+ try {
+ return mTuner.setParameters(Objects.requireNonNull(parameters));
+ } catch (RemoteException e) {
+ throw new RuntimeException("service died", e);
+ }
+ }
+
+ @Override
+ public @NonNull Map<String, String> getParameters(@NonNull List<String> keys) {
+ try {
+ return mTuner.getParameters(Objects.requireNonNull(keys));
+ } catch (RemoteException e) {
+ throw new RuntimeException("service died", e);
+ }
+ }
+
+ @Override
public boolean isAntennaConnected() {
try {
return mTuner.isAntennaConnected();
diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java
index ffd5b30fa15c..a01f658e80f6 100644
--- a/core/java/android/hardware/radio/TunerCallbackAdapter.java
+++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java
@@ -22,6 +22,8 @@ import android.os.Handler;
import android.os.Looper;
import android.util.Log;
+import java.util.Map;
+
/**
* Implements the ITunerCallback interface by forwarding calls to RadioTuner.Callback.
*/
@@ -94,4 +96,9 @@ class TunerCallbackAdapter extends ITunerCallback.Stub {
public void onProgramListChanged() {
mHandler.post(() -> mCallback.onProgramListChanged());
}
+
+ @Override
+ public void onParametersUpdated(Map parameters) {
+ mHandler.post(() -> mCallback.onParametersUpdated(parameters));
+ }
}
diff --git a/core/java/android/hardware/sidekick/SidekickInternal.java b/core/java/android/hardware/sidekick/SidekickInternal.java
new file mode 100644
index 000000000000..fe3550b24cae
--- /dev/null
+++ b/core/java/android/hardware/sidekick/SidekickInternal.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.sidekick;
+
+
+/**
+ * Sidekick local system service interface.
+ *
+ * @hide Only for use within the system server, and maybe by Clockwork Home.
+ */
+public abstract class SidekickInternal {
+
+ /**
+ * Tell Sidekick to reset back to newly-powered-on state.
+ *
+ * @return true on success (Sidekick is reset), false if Sidekick is not
+ * available (failed or not present). Either way, upon return Sidekick is
+ * guaranteed not to be controlling the display.
+ */
+ public abstract boolean reset();
+
+ /**
+ * Tell Sidekick it can start controlling the display.
+ *
+ * SidekickServer may choose not to actually control the display, if it's been told
+ * via other channels to leave the previous image on the display (same as SUSPEND in
+ * a non-Sidekick system).
+ *
+ * @param displayState - one of Display.STATE_DOZE_SUSPEND, Display.STATE_ON_SUSPEND
+ * @return true on success, false on failure (no sidekick available)
+ */
+ public abstract boolean startDisplayControl(int displayState);
+
+ /**
+ * Tell Sidekick it must stop controlling the display.
+ *
+ * No return code because this must always succeed - after return, Sidekick
+ * is guaranteed to not be controlling the display.
+ */
+ public abstract void endDisplayControl();
+
+}
diff --git a/core/java/android/hardware/usb/AccessoryFilter.java b/core/java/android/hardware/usb/AccessoryFilter.java
new file mode 100644
index 000000000000..d9b7c5be7ddd
--- /dev/null
+++ b/core/java/android/hardware/usb/AccessoryFilter.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.hardware.usb;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * This class is used to describe a USB accessory.
+ * When used in HashMaps all values must be specified,
+ * but wildcards can be used for any of the fields in
+ * the package meta-data.
+ *
+ * @hide
+ */
+public class AccessoryFilter {
+ // USB accessory manufacturer (or null for unspecified)
+ public final String mManufacturer;
+ // USB accessory model (or null for unspecified)
+ public final String mModel;
+ // USB accessory version (or null for unspecified)
+ public final String mVersion;
+
+ public AccessoryFilter(String manufacturer, String model, String version) {
+ mManufacturer = manufacturer;
+ mModel = model;
+ mVersion = version;
+ }
+
+ public AccessoryFilter(UsbAccessory accessory) {
+ mManufacturer = accessory.getManufacturer();
+ mModel = accessory.getModel();
+ mVersion = accessory.getVersion();
+ }
+
+ public static AccessoryFilter read(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ String manufacturer = null;
+ String model = null;
+ String version = null;
+
+ int count = parser.getAttributeCount();
+ for (int i = 0; i < count; i++) {
+ String name = parser.getAttributeName(i);
+ String value = parser.getAttributeValue(i);
+
+ if ("manufacturer".equals(name)) {
+ manufacturer = value;
+ } else if ("model".equals(name)) {
+ model = value;
+ } else if ("version".equals(name)) {
+ version = value;
+ }
+ }
+ return new AccessoryFilter(manufacturer, model, version);
+ }
+
+ public void write(XmlSerializer serializer)throws IOException {
+ serializer.startTag(null, "usb-accessory");
+ if (mManufacturer != null) {
+ serializer.attribute(null, "manufacturer", mManufacturer);
+ }
+ if (mModel != null) {
+ serializer.attribute(null, "model", mModel);
+ }
+ if (mVersion != null) {
+ serializer.attribute(null, "version", mVersion);
+ }
+ serializer.endTag(null, "usb-accessory");
+ }
+
+ public boolean matches(UsbAccessory acc) {
+ if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false;
+ if (mModel != null && !acc.getModel().equals(mModel)) return false;
+ return !(mVersion != null && !acc.getVersion().equals(mVersion));
+ }
+
+ /**
+ * Is the accessories described {@code accessory} covered by this filter?
+ *
+ * @param accessory A filter describing the accessory
+ *
+ * @return {@code true} iff this the filter covers the accessory
+ */
+ public boolean contains(AccessoryFilter accessory) {
+ if (mManufacturer != null && !Objects.equals(accessory.mManufacturer, mManufacturer)) {
+ return false;
+ }
+ if (mModel != null && !Objects.equals(accessory.mModel, mModel)) return false;
+ return !(mVersion != null && !Objects.equals(accessory.mVersion, mVersion));
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ // can't compare if we have wildcard strings
+ if (mManufacturer == null || mModel == null || mVersion == null) {
+ return false;
+ }
+ if (obj instanceof AccessoryFilter) {
+ AccessoryFilter filter = (AccessoryFilter)obj;
+ return (mManufacturer.equals(filter.mManufacturer) &&
+ mModel.equals(filter.mModel) &&
+ mVersion.equals(filter.mVersion));
+ }
+ if (obj instanceof UsbAccessory) {
+ UsbAccessory accessory = (UsbAccessory)obj;
+ return (mManufacturer.equals(accessory.getManufacturer()) &&
+ mModel.equals(accessory.getModel()) &&
+ mVersion.equals(accessory.getVersion()));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
+ (mModel == null ? 0 : mModel.hashCode()) ^
+ (mVersion == null ? 0 : mVersion.hashCode()));
+ }
+
+ @Override
+ public String toString() {
+ return "AccessoryFilter[mManufacturer=\"" + mManufacturer +
+ "\", mModel=\"" + mModel +
+ "\", mVersion=\"" + mVersion + "\"]";
+ }
+}
diff --git a/core/java/android/hardware/usb/DeviceFilter.java b/core/java/android/hardware/usb/DeviceFilter.java
new file mode 100644
index 000000000000..439c629758b0
--- /dev/null
+++ b/core/java/android/hardware/usb/DeviceFilter.java
@@ -0,0 +1,313 @@
+/*
+ * 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.usb;
+
+import android.util.Slog;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * This class is used to describe a USB device.
+ * When used in HashMaps all values must be specified,
+ * but wildcards can be used for any of the fields in
+ * the package meta-data.
+ *
+ * @hide
+ */
+public class DeviceFilter {
+ private static final String TAG = DeviceFilter.class.getSimpleName();
+
+ // USB Vendor ID (or -1 for unspecified)
+ public final int mVendorId;
+ // USB Product ID (or -1 for unspecified)
+ public final int mProductId;
+ // USB device or interface class (or -1 for unspecified)
+ public final int mClass;
+ // USB device subclass (or -1 for unspecified)
+ public final int mSubclass;
+ // USB device protocol (or -1 for unspecified)
+ public final int mProtocol;
+ // USB device manufacturer name string (or null for unspecified)
+ public final String mManufacturerName;
+ // USB device product name string (or null for unspecified)
+ public final String mProductName;
+ // USB device serial number string (or null for unspecified)
+ public final String mSerialNumber;
+
+ public DeviceFilter(int vid, int pid, int clasz, int subclass, int protocol,
+ String manufacturer, String product, String serialnum) {
+ mVendorId = vid;
+ mProductId = pid;
+ mClass = clasz;
+ mSubclass = subclass;
+ mProtocol = protocol;
+ mManufacturerName = manufacturer;
+ mProductName = product;
+ mSerialNumber = serialnum;
+ }
+
+ public DeviceFilter(UsbDevice device) {
+ mVendorId = device.getVendorId();
+ mProductId = device.getProductId();
+ mClass = device.getDeviceClass();
+ mSubclass = device.getDeviceSubclass();
+ mProtocol = device.getDeviceProtocol();
+ mManufacturerName = device.getManufacturerName();
+ mProductName = device.getProductName();
+ mSerialNumber = device.getSerialNumber();
+ }
+
+ public static DeviceFilter read(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ int vendorId = -1;
+ int productId = -1;
+ int deviceClass = -1;
+ int deviceSubclass = -1;
+ int deviceProtocol = -1;
+ String manufacturerName = null;
+ String productName = null;
+ String serialNumber = null;
+
+ int count = parser.getAttributeCount();
+ for (int i = 0; i < count; i++) {
+ String name = parser.getAttributeName(i);
+ String value = parser.getAttributeValue(i);
+ // Attribute values are ints or strings
+ if ("manufacturer-name".equals(name)) {
+ manufacturerName = value;
+ } else if ("product-name".equals(name)) {
+ productName = value;
+ } else if ("serial-number".equals(name)) {
+ serialNumber = value;
+ } else {
+ int intValue;
+ int radix = 10;
+ if (value != null && value.length() > 2 && value.charAt(0) == '0' &&
+ (value.charAt(1) == 'x' || value.charAt(1) == 'X')) {
+ // allow hex values starting with 0x or 0X
+ radix = 16;
+ value = value.substring(2);
+ }
+ try {
+ intValue = Integer.parseInt(value, radix);
+ } catch (NumberFormatException e) {
+ Slog.e(TAG, "invalid number for field " + name, e);
+ continue;
+ }
+ if ("vendor-id".equals(name)) {
+ vendorId = intValue;
+ } else if ("product-id".equals(name)) {
+ productId = intValue;
+ } else if ("class".equals(name)) {
+ deviceClass = intValue;
+ } else if ("subclass".equals(name)) {
+ deviceSubclass = intValue;
+ } else if ("protocol".equals(name)) {
+ deviceProtocol = intValue;
+ }
+ }
+ }
+ return new DeviceFilter(vendorId, productId,
+ deviceClass, deviceSubclass, deviceProtocol,
+ manufacturerName, productName, serialNumber);
+ }
+
+ public void write(XmlSerializer serializer) throws IOException {
+ serializer.startTag(null, "usb-device");
+ if (mVendorId != -1) {
+ serializer.attribute(null, "vendor-id", Integer.toString(mVendorId));
+ }
+ if (mProductId != -1) {
+ serializer.attribute(null, "product-id", Integer.toString(mProductId));
+ }
+ if (mClass != -1) {
+ serializer.attribute(null, "class", Integer.toString(mClass));
+ }
+ if (mSubclass != -1) {
+ serializer.attribute(null, "subclass", Integer.toString(mSubclass));
+ }
+ if (mProtocol != -1) {
+ serializer.attribute(null, "protocol", Integer.toString(mProtocol));
+ }
+ if (mManufacturerName != null) {
+ serializer.attribute(null, "manufacturer-name", mManufacturerName);
+ }
+ if (mProductName != null) {
+ serializer.attribute(null, "product-name", mProductName);
+ }
+ if (mSerialNumber != null) {
+ serializer.attribute(null, "serial-number", mSerialNumber);
+ }
+ serializer.endTag(null, "usb-device");
+ }
+
+ private boolean matches(int clasz, int subclass, int protocol) {
+ return ((mClass == -1 || clasz == mClass) &&
+ (mSubclass == -1 || subclass == mSubclass) &&
+ (mProtocol == -1 || protocol == mProtocol));
+ }
+
+ public boolean matches(UsbDevice device) {
+ if (mVendorId != -1 && device.getVendorId() != mVendorId) return false;
+ if (mProductId != -1 && device.getProductId() != mProductId) return false;
+ if (mManufacturerName != null && device.getManufacturerName() == null) return false;
+ if (mProductName != null && device.getProductName() == null) return false;
+ if (mSerialNumber != null && device.getSerialNumber() == null) return false;
+ if (mManufacturerName != null && device.getManufacturerName() != null &&
+ !mManufacturerName.equals(device.getManufacturerName())) return false;
+ if (mProductName != null && device.getProductName() != null &&
+ !mProductName.equals(device.getProductName())) return false;
+ if (mSerialNumber != null && device.getSerialNumber() != null &&
+ !mSerialNumber.equals(device.getSerialNumber())) return false;
+
+ // check device class/subclass/protocol
+ if (matches(device.getDeviceClass(), device.getDeviceSubclass(),
+ device.getDeviceProtocol())) return true;
+
+ // if device doesn't match, check the interfaces
+ int count = device.getInterfaceCount();
+ for (int i = 0; i < count; i++) {
+ UsbInterface intf = device.getInterface(i);
+ if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(),
+ intf.getInterfaceProtocol())) return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * If the device described by {@code device} covered by this filter?
+ *
+ * @param device The device
+ *
+ * @return {@code true} iff this filter covers the {@code device}
+ */
+ public boolean contains(DeviceFilter device) {
+ // -1 and null means "match anything"
+
+ if (mVendorId != -1 && device.mVendorId != mVendorId) return false;
+ if (mProductId != -1 && device.mProductId != mProductId) return false;
+ if (mManufacturerName != null && !Objects.equals(mManufacturerName,
+ device.mManufacturerName)) {
+ return false;
+ }
+ if (mProductName != null && !Objects.equals(mProductName, device.mProductName)) {
+ return false;
+ }
+ if (mSerialNumber != null
+ && !Objects.equals(mSerialNumber, device.mSerialNumber)) {
+ return false;
+ }
+
+ // check device class/subclass/protocol
+ return matches(device.mClass, device.mSubclass, device.mProtocol);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ // can't compare if we have wildcard strings
+ if (mVendorId == -1 || mProductId == -1 ||
+ mClass == -1 || mSubclass == -1 || mProtocol == -1) {
+ return false;
+ }
+ if (obj instanceof DeviceFilter) {
+ DeviceFilter filter = (DeviceFilter)obj;
+
+ if (filter.mVendorId != mVendorId ||
+ filter.mProductId != mProductId ||
+ filter.mClass != mClass ||
+ filter.mSubclass != mSubclass ||
+ filter.mProtocol != mProtocol) {
+ return(false);
+ }
+ if ((filter.mManufacturerName != null &&
+ mManufacturerName == null) ||
+ (filter.mManufacturerName == null &&
+ mManufacturerName != null) ||
+ (filter.mProductName != null &&
+ mProductName == null) ||
+ (filter.mProductName == null &&
+ mProductName != null) ||
+ (filter.mSerialNumber != null &&
+ mSerialNumber == null) ||
+ (filter.mSerialNumber == null &&
+ mSerialNumber != null)) {
+ return(false);
+ }
+ if ((filter.mManufacturerName != null &&
+ mManufacturerName != null &&
+ !mManufacturerName.equals(filter.mManufacturerName)) ||
+ (filter.mProductName != null &&
+ mProductName != null &&
+ !mProductName.equals(filter.mProductName)) ||
+ (filter.mSerialNumber != null &&
+ mSerialNumber != null &&
+ !mSerialNumber.equals(filter.mSerialNumber))) {
+ return false;
+ }
+ return true;
+ }
+ if (obj instanceof UsbDevice) {
+ UsbDevice device = (UsbDevice)obj;
+ if (device.getVendorId() != mVendorId ||
+ device.getProductId() != mProductId ||
+ device.getDeviceClass() != mClass ||
+ device.getDeviceSubclass() != mSubclass ||
+ device.getDeviceProtocol() != mProtocol) {
+ return(false);
+ }
+ if ((mManufacturerName != null && device.getManufacturerName() == null) ||
+ (mManufacturerName == null && device.getManufacturerName() != null) ||
+ (mProductName != null && device.getProductName() == null) ||
+ (mProductName == null && device.getProductName() != null) ||
+ (mSerialNumber != null && device.getSerialNumber() == null) ||
+ (mSerialNumber == null && device.getSerialNumber() != null)) {
+ return(false);
+ }
+ if ((device.getManufacturerName() != null &&
+ !mManufacturerName.equals(device.getManufacturerName())) ||
+ (device.getProductName() != null &&
+ !mProductName.equals(device.getProductName())) ||
+ (device.getSerialNumber() != null &&
+ !mSerialNumber.equals(device.getSerialNumber()))) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return (((mVendorId << 16) | mProductId) ^
+ ((mClass << 16) | (mSubclass << 8) | mProtocol));
+ }
+
+ @Override
+ public String toString() {
+ return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId +
+ ",mClass=" + mClass + ",mSubclass=" + mSubclass +
+ ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName +
+ ",mProductName=" + mProductName + ",mSerialNumber=" + mSerialNumber +
+ "]";
+ }
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index d7ecc81ffdba..8071e8b83738 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -619,6 +619,35 @@ public class ConnectivityManager {
*/
public static final int NETID_UNSET = 0;
+ /**
+ * Private DNS Mode values.
+ *
+ * The "private_dns_mode" global setting stores a String value which is
+ * expected to be one of the following.
+ */
+
+ /**
+ * @hide
+ */
+ public static final String PRIVATE_DNS_MODE_OFF = "off";
+ /**
+ * @hide
+ */
+ public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
+ /**
+ * @hide
+ */
+ public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
+ /**
+ * The default Private DNS mode.
+ *
+ * This may change from release to release or may become dependent upon
+ * the capabilities of the underlying platform.
+ *
+ * @hide
+ */
+ public static final String PRIVATE_DNS_DEFAULT_MODE = PRIVATE_DNS_MODE_OPPORTUNISTIC;
+
private final IConnectivityManager mService;
/**
* A kludge to facilitate static access where a Context pointer isn't available, like in the
diff --git a/core/java/android/net/ConnectivityMetricsEvent.java b/core/java/android/net/ConnectivityMetricsEvent.java
index 46bb34670611..394ac428a03d 100644
--- a/core/java/android/net/ConnectivityMetricsEvent.java
+++ b/core/java/android/net/ConnectivityMetricsEvent.java
@@ -18,6 +18,7 @@ package android.net;
import android.os.Parcel;
import android.os.Parcelable;
+
import com.android.internal.util.BitUtils;
/**
@@ -80,7 +81,7 @@ public final class ConnectivityMetricsEvent implements Parcelable {
StringBuilder buffer = new StringBuilder("ConnectivityMetricsEvent(");
buffer.append(String.format("%tT.%tL", timestamp, timestamp));
if (netId != 0) {
- buffer.append(", ").append(netId);
+ buffer.append(", ").append("netId=").append(netId);
}
if (ifname != null) {
buffer.append(", ").append(ifname);
diff --git a/core/java/android/net/IIpConnectivityMetrics.aidl b/core/java/android/net/IIpConnectivityMetrics.aidl
index 6f07b3153833..aeaf09d8fafe 100644
--- a/core/java/android/net/IIpConnectivityMetrics.aidl
+++ b/core/java/android/net/IIpConnectivityMetrics.aidl
@@ -30,11 +30,11 @@ interface IIpConnectivityMetrics {
int logEvent(in ConnectivityMetricsEvent event);
/**
- * At most one callback can be registered (by DevicePolicyManager).
+ * Callback can be registered by DevicePolicyManager or NetworkWatchlistService only.
* @return status {@code true} if registering/unregistering of the callback was successful,
* {@code false} otherwise (might happen if IIpConnectivityMetrics is not available,
* if it happens make sure you call it when the service is up in the caller)
*/
- boolean registerNetdEventCallback(in INetdEventCallback callback);
- boolean unregisterNetdEventCallback();
+ boolean addNetdEventCallback(in int callerType, in INetdEventCallback callback);
+ boolean removeNetdEventCallback(in int callerType);
}
diff --git a/core/java/android/net/INetdEventCallback.aidl b/core/java/android/net/INetdEventCallback.aidl
index 49436beadc51..1fd9423b6128 100644
--- a/core/java/android/net/INetdEventCallback.aidl
+++ b/core/java/android/net/INetdEventCallback.aidl
@@ -19,6 +19,10 @@ package android.net;
/** {@hide} */
oneway interface INetdEventCallback {
+ // Possible addNetdEventCallback callers.
+ const int CALLBACK_CALLER_DEVICE_POLICY = 0;
+ const int CALLBACK_CALLER_NETWORK_WATCHLIST = 1;
+
/**
* Reports a single DNS lookup function call.
* This method must not block or perform long-running operations.
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index 16b1452311a6..64f8f39e2bca 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -78,7 +78,11 @@ public final class IpSecAlgorithm implements Parcelable {
/**
* AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm.
*
- * <p>Valid lengths for this key are {128, 192, 256}.
+ * <p>Valid lengths for keying material are {160, 224, 288}.
+ *
+ * <p>As per RFC4106 (Section 8.1), keying material consists of a 128, 192, or 256 bit AES key
+ * followed by a 32-bit salt. RFC compliance requires that the salt must be unique per
+ * invocation with the same key.
*
* <p>Valid ICV (truncation) lengths are {64, 96, 128}.
*/
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index d7b325613fee..eccd5f47f2dd 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -136,7 +136,7 @@ public final class IpSecManager {
}
@Override
- protected void finalize() {
+ protected void finalize() throws Throwable {
if (mCloseGuard != null) {
mCloseGuard.warnIfOpen();
}
diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java
index 05c8afb358b0..6e4a231bcd55 100644
--- a/core/java/android/net/LocalSocketImpl.java
+++ b/core/java/android/net/LocalSocketImpl.java
@@ -16,18 +16,18 @@
package android.net;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.InputStream;
-import java.io.FileDescriptor;
-import java.net.SocketOptions;
-
import android.system.ErrnoException;
+import android.system.Int32Ref;
import android.system.Os;
import android.system.OsConstants;
import android.system.StructLinger;
import android.system.StructTimeval;
-import android.util.MutableInt;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.SocketOptions;
/**
* Socket implementation used for android.net.LocalSocket and
@@ -62,7 +62,7 @@ class LocalSocketImpl
FileDescriptor myFd = fd;
if (myFd == null) throw new IOException("socket closed");
- MutableInt avail = new MutableInt(0);
+ Int32Ref avail = new Int32Ref(0);
try {
Os.ioctlInt(myFd, OsConstants.FIONREAD, avail);
} catch (ErrnoException e) {
@@ -167,7 +167,7 @@ class LocalSocketImpl
if (myFd == null) throw new IOException("socket closed");
// Loop until the output buffer is empty.
- MutableInt pending = new MutableInt(0);
+ Int32Ref pending = new Int32Ref(0);
while (true) {
try {
// See linux/net/unix/af_unix.c
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
new file mode 100644
index 000000000000..f6a69bacb319
--- /dev/null
+++ b/core/java/android/net/MacAddress.java
@@ -0,0 +1,274 @@
+/*
+ * 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.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.BitUtils;
+
+import java.util.Arrays;
+import java.util.Random;
+import java.util.StringJoiner;
+
+/**
+ * Represents a mac address.
+ *
+ * @hide
+ */
+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 zero mac address. */
+ public static final MacAddress ALL_ZEROS_ADDRESS = new MacAddress(0);
+
+ /** Represents categories of mac addresses. */
+ public enum MacAddressType {
+ UNICAST,
+ MULTICAST,
+ BROADCAST;
+ }
+
+ 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");
+
+ // 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
+ // 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;
+ }
+
+ /** 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() {
+ if (equals(BROADCAST_ADDRESS)) {
+ return MacAddressType.BROADCAST;
+ }
+ if (isMulticastAddress()) {
+ return MacAddressType.MULTICAST;
+ }
+ return MacAddressType.UNICAST;
+ }
+
+ /** Returns true if this MacAddress corresponds to a multicast address. */
+ public boolean isMulticastAddress() {
+ return (mAddr & MULTICAST_MASK) != 0;
+ }
+
+ /** Returns true if this MacAddress corresponds to a locally assigned address. */
+ public boolean isLocallyAssigned() {
+ return (mAddr & LOCALLY_ASSIGNED_MASK) != 0;
+ }
+
+ /** Returns a byte array representation of this MacAddress. */
+ public byte[] toByteArray() {
+ return byteAddrFromLongAddr(mAddr);
+ }
+
+ @Override
+ public String toString() {
+ return stringAddrFromByteAddr(byteAddrFromLongAddr(mAddr));
+ }
+
+ @Override
+ public int hashCode() {
+ return (int) ((mAddr >> 32) ^ mAddr);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return (o instanceof MacAddress) && ((MacAddress) o).mAddr == mAddr;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(mAddr);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<MacAddress> CREATOR =
+ new Parcelable.Creator<MacAddress>() {
+ public MacAddress createFromParcel(Parcel in) {
+ return new MacAddress(in.readLong());
+ }
+
+ public MacAddress[] newArray(int size) {
+ return new MacAddress[size];
+ }
+ };
+
+ /** Return true if the given byte array is not null and has the length of a mac address. */
+ 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.
+ */
+ public static MacAddressType macAddressType(byte[] addr) {
+ if (!isMacAddress(addr)) {
+ return null;
+ }
+ return new MacAddress(addr).addressType();
+ }
+
+ /** DOCME */
+ public static byte[] byteAddrFromStringAddr(String addr) {
+ if (addr == null) {
+ throw new IllegalArgumentException("cannot convert the null String");
+ }
+ String[] parts = addr.split(":");
+ if (parts.length != ETHER_ADDR_LEN) {
+ throw new IllegalArgumentException(addr + " was not a valid MAC address");
+ }
+ byte[] bytes = new byte[ETHER_ADDR_LEN];
+ for (int i = 0; i < ETHER_ADDR_LEN; i++) {
+ int x = Integer.valueOf(parts[i], 16);
+ if (x < 0 || 0xff < x) {
+ throw new IllegalArgumentException(addr + "was not a valid MAC address");
+ }
+ bytes[i] = (byte) x;
+ }
+ return bytes;
+ }
+
+ /** DOCME */
+ 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();
+ }
+
+ /** @hide */
+ public static byte[] byteAddrFromLongAddr(long addr) {
+ byte[] bytes = new byte[ETHER_ADDR_LEN];
+ int index = ETHER_ADDR_LEN;
+ while (index-- > 0) {
+ bytes[index] = (byte) addr;
+ addr = addr >> 8;
+ }
+ return bytes;
+ }
+
+ /** @hide */
+ public static long longAddrFromByteAddr(byte[] addr) {
+ if (!isMacAddress(addr)) {
+ throw new IllegalArgumentException(
+ Arrays.toString(addr) + " was not a valid MAC address");
+ }
+ long longAddr = 0;
+ for (byte b : addr) {
+ longAddr = (longAddr << 8) + BitUtils.uint8(b);
+ }
+ return longAddr;
+ }
+
+ /** @hide */
+ public static long longAddrFromStringAddr(String addr) {
+ if (addr == null) {
+ throw new IllegalArgumentException("cannot convert the null String");
+ }
+ 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);
+ if (x < 0 || 0xff < x) {
+ throw new IllegalArgumentException(addr + "was not a valid MAC address");
+ }
+ longAddr = x + (longAddr << 8);
+ }
+ 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();
+ }
+
+ /**
+ * Returns a randomely generated mac address with the Android OUI value "DA-A1-19".
+ * The locally assigned bit is always set to 1.
+ */
+ public static MacAddress getRandomAddress() {
+ return getRandomAddress(BASE_ANDROID_MAC, new Random());
+ }
+
+ /**
+ * 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.
+ */
+ 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);
+ }
+
+ // Convenience function for working around the lack of byte literals.
+ private static byte[] addr(int... in) {
+ if (in.length != ETHER_ADDR_LEN) {
+ throw new IllegalArgumentException(Arrays.toString(in)
+ + " was not an array with length equal to " + ETHER_ADDR_LEN);
+ }
+ byte[] out = new byte[ETHER_ADDR_LEN];
+ for (int i = 0; i < ETHER_ADDR_LEN; i++) {
+ out[i] = (byte) in[i];
+ }
+ return out;
+ }
+}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index db12dd9724dc..ee75fd443052 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.IntDef;
+import android.net.ConnectivityManager.NetworkCallback;
import android.os.Parcel;
import android.os.Parcelable;
@@ -30,15 +31,24 @@ import java.util.Objects;
import java.util.StringJoiner;
/**
- * This class represents the capabilities of a network. This is used both to specify
- * needs to {@link ConnectivityManager} and when inspecting a network.
- *
- * Note that this replaces the old {@link ConnectivityManager#TYPE_MOBILE} method
- * of network selection. Rather than indicate a need for Wi-Fi because an application
- * needs high bandwidth and risk obsolescence when a new, fast network appears (like LTE),
- * the application should specify it needs high bandwidth. Similarly if an application
- * needs an unmetered network for a bulk transfer it can specify that rather than assuming
- * all cellular based connections are metered and all Wi-Fi based connections are not.
+ * Representation of the capabilities of a network. This object serves two
+ * purposes:
+ * <ul>
+ * <li>An expression of the current capabilities of an active network, typically
+ * expressed through
+ * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)}
+ * or {@link ConnectivityManager#getNetworkCapabilities(Network)}.
+ * <li>An expression of the future capabilities of a desired network, typically
+ * expressed through {@link NetworkRequest}.
+ * </ul>
+ * <p>
+ * This replaces the old {@link ConnectivityManager#TYPE_MOBILE} method of
+ * network selection. Rather than indicate a need for Wi-Fi because an
+ * application needs high bandwidth and risk obsolescence when a new, fast
+ * network appears (like LTE), the application should specify it needs high
+ * bandwidth. Similarly if an application needs an unmetered network for a bulk
+ * transfer it can specify that rather than assuming all cellular based
+ * connections are metered and all Wi-Fi based connections are not.
*/
public final class NetworkCapabilities implements Parcelable {
private static final String TAG = "NetworkCapabilities";
@@ -101,6 +111,7 @@ public final class NetworkCapabilities implements Parcelable {
NET_CAPABILITY_NOT_VPN,
NET_CAPABILITY_VALIDATED,
NET_CAPABILITY_CAPTIVE_PORTAL,
+ NET_CAPABILITY_NOT_ROAMING,
NET_CAPABILITY_FOREGROUND,
})
public @interface NetCapability { }
@@ -218,11 +229,16 @@ public final class NetworkCapabilities implements Parcelable {
public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17;
/**
+ * Indicates that this network is not roaming.
+ */
+ public static final int NET_CAPABILITY_NOT_ROAMING = 18;
+
+ /**
* Indicates that this network is available for use by apps, and not a network that is being
* kept up in the background to facilitate fast network switching.
* @hide
*/
- public static final int NET_CAPABILITY_FOREGROUND = 18;
+ public static final int NET_CAPABILITY_FOREGROUND = 19;
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_FOREGROUND;
@@ -237,6 +253,7 @@ public final class NetworkCapabilities implements Parcelable {
(1 << NET_CAPABILITY_TRUSTED) |
(1 << NET_CAPABILITY_VALIDATED) |
(1 << NET_CAPABILITY_CAPTIVE_PORTAL) |
+ (1 << NET_CAPABILITY_NOT_ROAMING) |
(1 << NET_CAPABILITY_FOREGROUND);
/**
@@ -316,6 +333,21 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
+ * Sets (or clears) the given capability on this {@link NetworkCapabilities}
+ * instance.
+ *
+ * @hide
+ */
+ public NetworkCapabilities setCapability(@NetCapability int capability, boolean value) {
+ if (value) {
+ addCapability(capability);
+ } else {
+ removeCapability(capability);
+ }
+ return this;
+ }
+
+ /**
* Gets all the capabilities set on this {@code NetworkCapability} instance.
*
* @return an array of capability values for this instance.
@@ -326,6 +358,15 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
+ * Sets all the capabilities set on this {@code NetworkCapability} instance.
+ *
+ * @hide
+ */
+ public void setCapabilities(@NetCapability int[] capabilities) {
+ mNetworkCapabilities = BitUtils.packBits(capabilities);
+ }
+
+ /**
* Tests for the presence of a capabilitity on this instance.
*
* @param capability the capabilities to be tested for.
@@ -515,6 +556,21 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
+ * Sets (or clears) the given transport on this {@link NetworkCapabilities}
+ * instance.
+ *
+ * @hide
+ */
+ public NetworkCapabilities setTransportType(@Transport int transportType, boolean value) {
+ if (value) {
+ addTransportType(transportType);
+ } else {
+ removeTransportType(transportType);
+ }
+ return this;
+ }
+
+ /**
* Gets all the transports set on this {@code NetworkCapability} instance.
*
* @return an array of transport type values for this instance.
@@ -525,6 +581,15 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
+ * Sets all the transports set on this {@code NetworkCapability} instance.
+ *
+ * @hide
+ */
+ public void setTransportTypes(@Transport int[] transportTypes) {
+ mTransportTypes = BitUtils.packBits(transportTypes);
+ }
+
+ /**
* Tests for the presence of a transport on this instance.
*
* @param transportType the transport type to be tested for.
@@ -549,12 +614,18 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
+ * Value indicating that link bandwidth is unspecified.
+ * @hide
+ */
+ public static final int LINK_BANDWIDTH_UNSPECIFIED = 0;
+
+ /**
* Passive link bandwidth. This is a rough guide of the expected peak bandwidth
* for the first hop on the given transport. It is not measured, but may take into account
* link parameters (Radio technology, allocated channels, etc).
*/
- private int mLinkUpBandwidthKbps;
- private int mLinkDownBandwidthKbps;
+ private int mLinkUpBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
+ private int mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
/**
* Sets the upstream bandwidth for this network in Kbps. This always only refers to
@@ -571,8 +642,9 @@ public final class NetworkCapabilities implements Parcelable {
* @param upKbps the estimated first hop upstream (device to network) bandwidth.
* @hide
*/
- public void setLinkUpstreamBandwidthKbps(int upKbps) {
+ public NetworkCapabilities setLinkUpstreamBandwidthKbps(int upKbps) {
mLinkUpBandwidthKbps = upKbps;
+ return this;
}
/**
@@ -600,8 +672,9 @@ public final class NetworkCapabilities implements Parcelable {
* @param downKbps the estimated first hop downstream (network to device) bandwidth.
* @hide
*/
- public void setLinkDownstreamBandwidthKbps(int downKbps) {
+ public NetworkCapabilities setLinkDownstreamBandwidthKbps(int downKbps) {
mLinkDownBandwidthKbps = downKbps;
+ return this;
}
/**
@@ -628,6 +701,20 @@ public final class NetworkCapabilities implements Parcelable {
return (this.mLinkUpBandwidthKbps == nc.mLinkUpBandwidthKbps &&
this.mLinkDownBandwidthKbps == nc.mLinkDownBandwidthKbps);
}
+ /** @hide */
+ public static int minBandwidth(int a, int b) {
+ if (a == LINK_BANDWIDTH_UNSPECIFIED) {
+ return b;
+ } else if (b == LINK_BANDWIDTH_UNSPECIFIED) {
+ return a;
+ } else {
+ return Math.min(a, b);
+ }
+ }
+ /** @hide */
+ public static int maxBandwidth(int a, int b) {
+ return Math.max(a, b);
+ }
private NetworkSpecifier mNetworkSpecifier = null;
@@ -708,8 +795,9 @@ public final class NetworkCapabilities implements Parcelable {
* @param signalStrength the bearer-specific signal strength.
* @hide
*/
- public void setSignalStrength(int signalStrength) {
+ public NetworkCapabilities setSignalStrength(int signalStrength) {
mSignalStrength = signalStrength;
+ return this;
}
/**
@@ -968,6 +1056,7 @@ public final class NetworkCapabilities implements Parcelable {
case NET_CAPABILITY_NOT_VPN: return "NOT_VPN";
case NET_CAPABILITY_VALIDATED: return "VALIDATED";
case NET_CAPABILITY_CAPTIVE_PORTAL: return "CAPTIVE_PORTAL";
+ case NET_CAPABILITY_NOT_ROAMING: return "NOT_ROAMING";
case NET_CAPABILITY_FOREGROUND: return "FOREGROUND";
default: return Integer.toString(capability);
}
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index acd7b56027d9..d3b35998be13 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -189,7 +189,8 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
String subscriberId = null;
String networkId = null;
- boolean roaming = false;
+ boolean roaming = !state.networkCapabilities.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
boolean metered = !state.networkCapabilities.hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
@@ -203,7 +204,6 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
}
subscriberId = state.subscriberId;
- roaming = state.networkInfo.isRoaming();
} else if (type == TYPE_WIFI) {
if (state.networkId != null) {
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 818aa211625d..e6ad89a20bbd 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -305,11 +305,17 @@ public class NetworkInfo implements Parcelable {
}
/**
- * Indicates whether the device is currently roaming on this network.
- * When {@code true}, it suggests that use of data on this network
- * may incur extra costs.
+ * Indicates whether the device is currently roaming on this network. When
+ * {@code true}, it suggests that use of data on this network may incur
+ * extra costs.
+ *
* @return {@code true} if roaming is in effect, {@code false} otherwise.
+ * @deprecated Callers should switch to checking
+ * {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING}
+ * instead, since that handles more complex situations, such as
+ * VPNs.
*/
+ @Deprecated
public boolean isRoaming() {
synchronized (this) {
return mIsRoaming;
@@ -318,6 +324,7 @@ public class NetworkInfo implements Parcelable {
/** {@hide} */
@VisibleForTesting
+ @Deprecated
public void setRoaming(boolean isRoaming) {
synchronized (this) {
mIsRoaming = isRoaming;
diff --git a/core/java/android/net/NetworkWatchlistManager.java b/core/java/android/net/NetworkWatchlistManager.java
new file mode 100644
index 000000000000..42e43c8aea1e
--- /dev/null
+++ b/core/java/android/net/NetworkWatchlistManager.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.net;
+
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import com.android.internal.net.INetworkWatchlistManager;
+import com.android.internal.util.Preconditions;
+
+/**
+ * Class that manage network watchlist in system.
+ * @hide
+ */
+@SystemService(Context.NETWORK_WATCHLIST_SERVICE)
+public class NetworkWatchlistManager {
+
+ private static final String TAG = "NetworkWatchlistManager";
+ private static final String SHARED_MEMORY_TAG = "NETWORK_WATCHLIST_SHARED_MEMORY";
+
+ private final Context mContext;
+ private final INetworkWatchlistManager mNetworkWatchlistManager;
+
+ /**
+ * @hide
+ */
+ public NetworkWatchlistManager(Context context, INetworkWatchlistManager manager) {
+ mContext = context;
+ mNetworkWatchlistManager = manager;
+ }
+
+ /**
+ * @hide
+ */
+ public NetworkWatchlistManager(Context context) {
+ mContext = Preconditions.checkNotNull(context, "missing context");
+ mNetworkWatchlistManager = (INetworkWatchlistManager)
+ INetworkWatchlistManager.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_WATCHLIST_SERVICE));
+ }
+
+ /**
+ * Report network watchlist records if necessary.
+ *
+ * Watchlist report process will run summarize records into a single report, then the
+ * report will be processed by differential privacy framework and store it on disk.
+ *
+ * @hide
+ */
+ public void reportWatchlistIfNecessary() {
+ try {
+ mNetworkWatchlistManager.reportWatchlistIfNecessary();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Cannot report records", e);
+ e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 0b1569ca4ff5..4817813cab1b 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -63,7 +63,12 @@ import javax.net.ssl.X509TrustManager;
* This implementation does check the server's certificate hostname, but only
* for createSocket variants that specify a hostname. When using methods that
* use {@link InetAddress} or which return an unconnected socket, you MUST
- * verify the server's identity yourself to ensure a secure connection.</p>
+ * verify the server's identity yourself to ensure a secure connection.
+ *
+ * Refer to
+ * <a href="https://developer.android.com/training/articles/security-gms-provider.html">
+ * Updating Your Security Provider to Protect Against SSL Exploits</a>
+ * for further information.</p>
*
* <p>One way to verify the server's identity is to use
* {@link HttpsURLConnection#getDefaultHostnameVerifier()} to get a
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index d5377c717366..9edcc0e9b8d4 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -1066,7 +1066,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
return null;
}
- int end = authority.indexOf('@');
+ int end = authority.lastIndexOf('@');
return end == NOT_FOUND ? null : authority.substring(0, end);
}
@@ -1090,7 +1090,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
}
// Parse out user info and then port.
- int userInfoSeparator = authority.indexOf('@');
+ int userInfoSeparator = authority.lastIndexOf('@');
int portSeparator = authority.indexOf(':', userInfoSeparator);
String encodedHost = portSeparator == NOT_FOUND
@@ -1116,7 +1116,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
// Make sure we look for the port separtor *after* the user info
// separator. We have URLs with a ':' in the user info.
- int userInfoSeparator = authority.indexOf('@');
+ int userInfoSeparator = authority.lastIndexOf('@');
int portSeparator = authority.indexOf(':', userInfoSeparator);
if (portSeparator == NOT_FOUND) {
diff --git a/core/java/android/net/metrics/ConnectStats.java b/core/java/android/net/metrics/ConnectStats.java
index 2495cab1adf9..b320b755f3f4 100644
--- a/core/java/android/net/metrics/ConnectStats.java
+++ b/core/java/android/net/metrics/ConnectStats.java
@@ -119,7 +119,8 @@ public class ConnectStats {
@Override
public String toString() {
- StringBuilder builder = new StringBuilder("ConnectStats(").append(netId).append(", ");
+ StringBuilder builder =
+ new StringBuilder("ConnectStats(").append("netId=").append(netId).append(", ");
for (int t : BitUtils.unpackBits(transports)) {
builder.append(NetworkCapabilities.transportNameOf(t)).append(", ");
}
diff --git a/core/java/android/net/metrics/DefaultNetworkEvent.java b/core/java/android/net/metrics/DefaultNetworkEvent.java
index eb61c1532d49..8ff8e4f38d6d 100644
--- a/core/java/android/net/metrics/DefaultNetworkEvent.java
+++ b/core/java/android/net/metrics/DefaultNetworkEvent.java
@@ -20,44 +20,72 @@ import static android.net.ConnectivityManager.NETID_UNSET;
import android.net.NetworkCapabilities;
+import com.android.internal.util.BitUtils;
+
+import java.util.StringJoiner;
+
/**
* An event recorded by ConnectivityService when there is a change in the default network.
* {@hide}
*/
public class DefaultNetworkEvent {
- // The ID of the network that has become the new default or NETID_UNSET if none.
+ // The creation time in milliseconds of this DefaultNetworkEvent.
+ public final long creationTimeMs;
+ // The network ID of the network or NETID_UNSET if none.
public int netId = NETID_UNSET;
- // The list of transport types of the new default network, for example TRANSPORT_WIFI, as
- // defined in NetworkCapabilities.java.
- public int[] transportTypes = new int[0];
- // The ID of the network that was the default before or NETID_UNSET if none.
- public int prevNetId = NETID_UNSET;
- // Whether the previous network had IPv4/IPv6 connectivity.
- public boolean prevIPv4;
- public boolean prevIPv6;
+ // The list of transport types, as defined in NetworkCapabilities.java.
+ public int transports;
+ // The list of transport types of the last previous default network.
+ public int previousTransports;
+ // Whether the network has IPv4/IPv6 connectivity.
+ public boolean ipv4;
+ public boolean ipv6;
+ // The initial network score when this network became the default network.
+ public int initialScore;
+ // The initial network score when this network stopped being the default network.
+ public int finalScore;
+ // The total duration in milliseconds this network was the default network.
+ public long durationMs;
+ // The total duration in milliseconds this network was the default network and was validated.
+ public long validatedMs;
+
+ public DefaultNetworkEvent(long timeMs) {
+ creationTimeMs = timeMs;
+ }
+
+ /** Update the durationMs of this DefaultNetworkEvent for the given current time. */
+ public void updateDuration(long timeMs) {
+ durationMs = timeMs - creationTimeMs;
+ }
@Override
public String toString() {
- String prevNetwork = String.valueOf(prevNetId);
- String newNetwork = String.valueOf(netId);
- if (prevNetId != 0) {
- prevNetwork += ":" + ipSupport();
+ StringJoiner j = new StringJoiner(", ", "DefaultNetworkEvent(", ")");
+ j.add("netId=" + netId);
+ for (int t : BitUtils.unpackBits(transports)) {
+ j.add(NetworkCapabilities.transportNameOf(t));
+ }
+ j.add("ip=" + ipSupport());
+ if (initialScore > 0) {
+ j.add("initial_score=" + initialScore);
}
- if (netId != 0) {
- newNetwork += ":" + NetworkCapabilities.transportNamesOf(transportTypes);
+ if (finalScore > 0) {
+ j.add("final_score=" + finalScore);
}
- return String.format("DefaultNetworkEvent(%s -> %s)", prevNetwork, newNetwork);
+ j.add(String.format("duration=%.0fs", durationMs / 1000.0));
+ j.add(String.format("validation=%4.1f%%", (validatedMs * 100.0) / durationMs));
+ return j.toString();
}
private String ipSupport() {
- if (prevIPv4 && prevIPv6) {
+ if (ipv4 && ipv6) {
return "IPv4v6";
}
- if (prevIPv6) {
+ if (ipv6) {
return "IPv6";
}
- if (prevIPv4) {
+ if (ipv4) {
return "IPv4";
}
return "NONE";
diff --git a/core/java/android/net/metrics/DnsEvent.java b/core/java/android/net/metrics/DnsEvent.java
index 81b098bbb38e..5aa705b0edf3 100644
--- a/core/java/android/net/metrics/DnsEvent.java
+++ b/core/java/android/net/metrics/DnsEvent.java
@@ -85,7 +85,8 @@ final public class DnsEvent {
@Override
public String toString() {
- StringBuilder builder = new StringBuilder("DnsEvent(").append(netId).append(", ");
+ StringBuilder builder =
+ new StringBuilder("DnsEvent(").append("netId=").append(netId).append(", ");
for (int t : BitUtils.unpackBits(transports)) {
builder.append(NetworkCapabilities.transportNameOf(t)).append(", ");
}
diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java
index 4df3bf095056..1999e78decc4 100644
--- a/core/java/android/net/metrics/NetworkEvent.java
+++ b/core/java/android/net/metrics/NetworkEvent.java
@@ -60,29 +60,25 @@ public final class NetworkEvent implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface EventType {}
- public final int netId;
public final @EventType int eventType;
public final long durationMs;
- public NetworkEvent(int netId, @EventType int eventType, long durationMs) {
- this.netId = netId;
+ public NetworkEvent(@EventType int eventType, long durationMs) {
this.eventType = eventType;
this.durationMs = durationMs;
}
- public NetworkEvent(int netId, @EventType int eventType) {
- this(netId, eventType, 0);
+ public NetworkEvent(@EventType int eventType) {
+ this(eventType, 0);
}
private NetworkEvent(Parcel in) {
- netId = in.readInt();
eventType = in.readInt();
durationMs = in.readLong();
}
@Override
public void writeToParcel(Parcel out, int flags) {
- out.writeInt(netId);
out.writeInt(eventType);
out.writeLong(durationMs);
}
@@ -105,8 +101,8 @@ public final class NetworkEvent implements Parcelable {
@Override
public String toString() {
- return String.format("NetworkEvent(%d, %s, %dms)",
- netId, Decoder.constants.get(eventType), durationMs);
+ return String.format("NetworkEvent(%s, %dms)",
+ Decoder.constants.get(eventType), durationMs);
}
final static class Decoder {
diff --git a/core/java/android/net/metrics/WakeupEvent.java b/core/java/android/net/metrics/WakeupEvent.java
index cbf3fc8c81da..8f1a5c42e6ac 100644
--- a/core/java/android/net/metrics/WakeupEvent.java
+++ b/core/java/android/net/metrics/WakeupEvent.java
@@ -16,6 +16,10 @@
package android.net.metrics;
+import android.net.MacAddress;
+
+import java.util.StringJoiner;
+
/**
* An event logged when NFLOG notifies userspace of a wakeup packet for
* watched interfaces.
@@ -23,12 +27,35 @@ package android.net.metrics;
*/
public class WakeupEvent {
public String iface;
- public long timestampMs;
public int uid;
+ public int ethertype;
+ public byte[] dstHwAddr;
+ public String srcIp;
+ public String dstIp;
+ public int ipNextHeader;
+ public int srcPort;
+ public int dstPort;
+ public long timestampMs;
@Override
public String toString() {
- return String.format("WakeupEvent(%tT.%tL, %s, uid: %d)",
- timestampMs, timestampMs, iface, uid);
+ StringJoiner j = new StringJoiner(", ", "WakeupEvent(", ")");
+ j.add(String.format("%tT.%tL", timestampMs, timestampMs));
+ j.add(iface);
+ j.add("uid: " + Integer.toString(uid));
+ j.add("eth=0x" + Integer.toHexString(ethertype));
+ j.add("dstHw=" + MacAddress.stringAddrFromByteAddr(dstHwAddr));
+ if (ipNextHeader > 0) {
+ j.add("ipNxtHdr=" + ipNextHeader);
+ j.add("srcIp=" + srcIp);
+ j.add("dstIp=" + dstIp);
+ if (srcPort > -1) {
+ j.add("srcPort=" + srcPort);
+ }
+ if (dstPort > -1) {
+ j.add("dstPort=" + dstPort);
+ }
+ }
+ return j.toString();
}
}
diff --git a/core/java/android/net/metrics/WakeupStats.java b/core/java/android/net/metrics/WakeupStats.java
index 97e83f969c38..1ba97771b595 100644
--- a/core/java/android/net/metrics/WakeupStats.java
+++ b/core/java/android/net/metrics/WakeupStats.java
@@ -16,8 +16,12 @@
package android.net.metrics;
+import android.net.MacAddress;
import android.os.Process;
import android.os.SystemClock;
+import android.util.SparseIntArray;
+
+import java.util.StringJoiner;
/**
* An event logged per interface and that aggregates WakeupEvents for that interface.
@@ -38,6 +42,13 @@ public class WakeupStats {
public long noUidWakeups = 0;
public long durationSec = 0;
+ public long l2UnicastCount = 0;
+ public long l2MulticastCount = 0;
+ public long l2BroadcastCount = 0;
+
+ public final SparseIntArray ethertypes = new SparseIntArray();
+ public final SparseIntArray ipNextHeaders = new SparseIntArray();
+
public WakeupStats(String iface) {
this.iface = iface;
}
@@ -68,20 +79,56 @@ public class WakeupStats {
}
break;
}
+
+ switch (MacAddress.macAddressType(ev.dstHwAddr)) {
+ case UNICAST:
+ l2UnicastCount++;
+ break;
+ case MULTICAST:
+ l2MulticastCount++;
+ break;
+ case BROADCAST:
+ l2BroadcastCount++;
+ break;
+ default:
+ break;
+ }
+
+ increment(ethertypes, ev.ethertype);
+ if (ev.ipNextHeader >= 0) {
+ increment(ipNextHeaders, ev.ipNextHeader);
+ }
}
@Override
public String toString() {
updateDuration();
- return new StringBuilder()
- .append("WakeupStats(").append(iface)
- .append(", total: ").append(totalWakeups)
- .append(", root: ").append(rootWakeups)
- .append(", system: ").append(systemWakeups)
- .append(", apps: ").append(applicationWakeups)
- .append(", non-apps: ").append(nonApplicationWakeups)
- .append(", no uid: ").append(noUidWakeups)
- .append(", ").append(durationSec).append("s)")
- .toString();
+ StringJoiner j = new StringJoiner(", ", "WakeupStats(", ")");
+ j.add(iface);
+ j.add("" + durationSec + "s");
+ j.add("total: " + totalWakeups);
+ j.add("root: " + rootWakeups);
+ j.add("system: " + systemWakeups);
+ j.add("apps: " + applicationWakeups);
+ j.add("non-apps: " + nonApplicationWakeups);
+ j.add("no uid: " + noUidWakeups);
+ j.add(String.format("l2 unicast/multicast/broadcast: %d/%d/%d",
+ l2UnicastCount, l2MulticastCount, l2BroadcastCount));
+ for (int i = 0; i < ethertypes.size(); i++) {
+ int eth = ethertypes.keyAt(i);
+ int count = ethertypes.valueAt(i);
+ j.add(String.format("ethertype 0x%x: %d", eth, count));
+ }
+ for (int i = 0; i < ipNextHeaders.size(); i++) {
+ int proto = ipNextHeaders.keyAt(i);
+ int count = ipNextHeaders.valueAt(i);
+ j.add(String.format("ipNxtHdr %d: %d", proto, count));
+ }
+ return j.toString();
+ }
+
+ private static void increment(SparseIntArray counters, int key) {
+ int newcount = counters.get(key, 0) + 1;
+ counters.put(key, newcount);
}
}
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index f715f507f6c9..6e0f70c14781 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -19,6 +19,7 @@ package android.os;
import android.annotation.SystemService;
import android.content.Context;
import android.hardware.health.V1_0.Constants;
+
import com.android.internal.app.IBatteryStats;
/**
@@ -33,39 +34,39 @@ public class BatteryManager {
* integer containing the current status constant.
*/
public static final String EXTRA_STATUS = "status";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* integer containing the current health constant.
*/
public static final String EXTRA_HEALTH = "health";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* boolean indicating whether a battery is present.
*/
public static final String EXTRA_PRESENT = "present";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* integer field containing the current battery level, from 0 to
* {@link #EXTRA_SCALE}.
*/
public static final String EXTRA_LEVEL = "level";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* integer containing the maximum battery level.
*/
public static final String EXTRA_SCALE = "scale";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* integer containing the resource ID of a small status bar icon
* indicating the current battery state.
*/
public static final String EXTRA_ICON_SMALL = "icon-small";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* integer indicating whether the device is plugged in to a power
@@ -73,19 +74,19 @@ public class BatteryManager {
* types of power sources.
*/
public static final String EXTRA_PLUGGED = "plugged";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* integer containing the current battery voltage level.
*/
public static final String EXTRA_VOLTAGE = "voltage";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* integer containing the current battery temperature.
*/
public static final String EXTRA_TEMPERATURE = "temperature";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* String describing the technology of the current battery.
@@ -216,6 +217,7 @@ public class BatteryManager {
*/
public static final int BATTERY_PROPERTY_STATUS = 6;
+ private final Context mContext;
private final IBatteryStats mBatteryStats;
private final IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
@@ -223,6 +225,7 @@ public class BatteryManager {
* @removed Was previously made visible by accident.
*/
public BatteryManager() {
+ mContext = null;
mBatteryStats = IBatteryStats.Stub.asInterface(
ServiceManager.getService(BatteryStats.SERVICE_NAME));
mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(
@@ -230,8 +233,10 @@ public class BatteryManager {
}
/** {@hide} */
- public BatteryManager(IBatteryStats batteryStats,
+ public BatteryManager(Context context,
+ IBatteryStats batteryStats,
IBatteryPropertiesRegistrar batteryPropertiesRegistrar) {
+ mContext = context;
mBatteryStats = batteryStats;
mBatteryPropertiesRegistrar = batteryPropertiesRegistrar;
}
@@ -278,16 +283,23 @@ public class BatteryManager {
}
/**
- * Return the value of a battery property of integer type. If the
- * platform does not provide the property queried, this value will
- * be Integer.MIN_VALUE.
+ * Return the value of a battery property of integer type.
*
* @param id identifier of the requested property
*
- * @return the property value, or Integer.MIN_VALUE if not supported.
+ * @return the property value. If the property is not supported or there is any other error,
+ * return (a) 0 if {@code targetSdkVersion < VERSION_CODES.P} or (b) Integer.MIN_VALUE
+ * if {@code targetSdkVersion >= VERSION_CODES.P}.
*/
public int getIntProperty(int id) {
- return (int)queryProperty(id);
+ long value = queryProperty(id);
+ if (value == Long.MIN_VALUE && mContext != null
+ && mContext.getApplicationInfo().targetSdkVersion
+ >= android.os.Build.VERSION_CODES.P) {
+ return Integer.MIN_VALUE;
+ }
+
+ return (int) value;
}
/**
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 2bfb0138b7dd..b5bcd02c1a18 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -193,6 +193,19 @@ public class Binder implements IBinder {
}
/**
+ * Reset the given interface back to the default blocking behavior,
+ * reverting any changes made by {@link #allowBlocking(IBinder)}.
+ *
+ * @hide
+ */
+ public static IBinder defaultBlocking(IBinder binder) {
+ if (binder instanceof BinderProxy) {
+ ((BinderProxy) binder).mWarnOnBlocking = sWarnOnBlocking;
+ }
+ return binder;
+ }
+
+ /**
* Inherit the current {@link #allowBlocking(IBinder)} value from one given
* interface to another.
*
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 935f5f3b78a7..6ebf3b9a5e9c 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -103,7 +103,7 @@ public class Build {
/**
* A hardware serial number, if available. Alphanumeric only, case-insensitive.
- * For apps targeting SDK higher than {@link Build.VERSION_CODES#N_MR1} this
+ * For apps targeting SDK higher than {@link Build.VERSION_CODES#O_MR1} this
* field is set to {@link Build#UNKNOWN}.
*
* @deprecated Use {@link #getSerial()} instead.
diff --git a/core/java/android/os/ConfigUpdate.java b/core/java/android/os/ConfigUpdate.java
index 139687795430..94a44ec3729a 100644
--- a/core/java/android/os/ConfigUpdate.java
+++ b/core/java/android/os/ConfigUpdate.java
@@ -68,13 +68,6 @@ public final class ConfigUpdate {
= "android.intent.action.UPDATE_CT_LOGS";
/**
- * Update system wide timezone data.
- * @hide
- */
- @SystemApi
- public static final String ACTION_UPDATE_TZDATA = "android.intent.action.UPDATE_TZDATA";
-
- /**
* Update language detection model file.
* @hide
*/
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 2e62eb6a5f97..2acf36fed85f 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -16,11 +16,14 @@
package android.os;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AppGlobals;
import android.content.Context;
import android.util.Log;
import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.TypedProperties;
import dalvik.system.VMDebug;
@@ -2347,4 +2350,24 @@ public final class Debug
public static String getCaller() {
return getCaller(Thread.currentThread().getStackTrace(), 0);
}
+
+ /**
+ * Attach a library as a jvmti agent to the current runtime.
+ *
+ * @param library library containing the agent
+ * @param options options passed to the agent
+ *
+ * @throws IOException If the agent could not be attached
+ */
+ public static void attachJvmtiAgent(@NonNull String library, @Nullable String options)
+ throws IOException {
+ Preconditions.checkNotNull(library);
+ Preconditions.checkArgument(!library.contains("="));
+
+ if (options == null) {
+ VMDebug.attachAgent(library);
+ } else {
+ VMDebug.attachAgent(library + "=" + options);
+ }
+ }
}
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 56d6e0a62f94..7c53ec198e7d 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -320,8 +320,17 @@ public class FileUtils {
* is {@code filename}.
*/
public static void bytesToFile(String filename, byte[] content) throws IOException {
- try (FileOutputStream fos = new FileOutputStream(filename)) {
- fos.write(content);
+ if (filename.startsWith("/proc/")) {
+ final int oldMask = StrictMode.allowThreadDiskWritesMask();
+ try (FileOutputStream fos = new FileOutputStream(filename)) {
+ fos.write(content);
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
+ }
+ } else {
+ try (FileOutputStream fos = new FileOutputStream(filename)) {
+ fos.write(content);
+ }
}
}
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index dd9e774141e1..5e2a0815b60d 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -63,13 +63,6 @@ public abstract class HwBinder implements IHwBinder {
public static native final void joinRpcThreadpool();
- /**
- * Call configureRpcThreadpool, then actually spawn
- * (maxThreads - (callerWillJoin ? 0 : 1)) threads.
- */
- public static final native void startRpcThreadPool(
- long maxThreads, boolean callerWillJoin);
-
// Returns address of the "freeFunction".
private static native final long native_init();
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index c0a95cc08dec..3314f604f940 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -53,4 +53,7 @@ interface IStatsCompanionService {
/** Pull the specified data. Results will be sent to statsd when complete. */
StatsLogEventWrapper[] pullData(int pullCode);
+
+ /** Send a broadcast to the specified pkg and class that it should getData now. */
+ oneway void sendBroadcast(String pkg, String cls);
}
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index 480296c12e50..a6c3009acba2 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -65,13 +65,26 @@ interface IStatsManager {
oneway void informOnePackageRemoved(in String app, in int uid);
/**
- * Trigger pushLog to force push stats log entries from statsd on client side.
+ * Fetches data for the specified configuration key. Returns a byte array representing proto
+ * wire-encoded of ConfigMetricsReport.
*/
- void requestPush();
+ byte[] getData(in String key);
/**
- * Listen to statsd to send stats log entries.
- * TODO: Limit callbacks with specific configurations.
+ * 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
+ * package and class that should receive these broadcasts.
+ *
+ * Returns if this configuration was correctly registered.
*/
- void subscribeStatsLog(IStatsCallbacks callbacks);
+ boolean addConfiguration(in String configKey, in byte[] config, in String pkg, in String cls);
+
+ /**
+ * Removes the configuration with the matching config key. No-op if this config key does not
+ * exist.
+ *
+ * Returns if this configuration key was removed.
+ */
+ boolean removeConfiguration(in String configKey);
}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index e426356dcc95..5d96fd35a62e 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -94,4 +94,5 @@ interface IUserManager {
boolean isUserUnlocked(int userId);
boolean isUserRunning(int userId);
boolean isUserNameSet(int userHandle);
+ boolean hasRestrictedProfiles();
}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index c2cf396716b8..10adb5a61aaf 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -2020,8 +2020,6 @@ public final class Parcel {
@Deprecated
static native void closeFileDescriptor(FileDescriptor desc) throws IOException;
- static native void clearFileDescriptor(FileDescriptor desc);
-
/**
* Read a byte value from the parcel at the current dataPosition().
*/
diff --git a/core/java/android/os/ParcelFileDescriptor.aidl b/core/java/android/os/ParcelFileDescriptor.aidl
index 5857aae5c599..6bbd99e3f20a 100644
--- a/core/java/android/os/ParcelFileDescriptor.aidl
+++ b/core/java/android/os/ParcelFileDescriptor.aidl
@@ -17,4 +17,4 @@
package android.os;
-parcelable ParcelFileDescriptor;
+parcelable ParcelFileDescriptor cpp_header "android/os/parcel_file_descriptor.h";
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 7f588adbd69d..7556f0921b4d 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -683,7 +683,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
throw new IllegalStateException("Already closed");
}
final int fd = getFd();
- Parcel.clearFileDescriptor(mFd);
+ mFd.setInt$(-1);
writeCommStatusAndClose(Status.DETACHED, null);
mClosed = true;
mGuard.close();
diff --git a/core/java/android/os/ParcelUuid.aidl b/core/java/android/os/ParcelUuid.aidl
index f7e080ac5901..6f3629796bde 100644
--- a/core/java/android/os/ParcelUuid.aidl
+++ b/core/java/android/os/ParcelUuid.aidl
@@ -16,4 +16,4 @@
package android.os;
-parcelable ParcelUuid;
+parcelable ParcelUuid cpp_header "android/os/parcel_uuid.h";
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 7f4dee6ef2da..0fce7a454717 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -513,6 +513,47 @@ public final class PowerManager {
*/
public static final int SHUTDOWN_REASON_BATTERY_THERMAL = 6;
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({ServiceType.GPS,
+ ServiceType.VIBRATION,
+ ServiceType.ANIMATION,
+ ServiceType.FULL_BACKUP,
+ ServiceType.KEYVALUE_BACKUP,
+ ServiceType.NETWORK_FIREWALL,
+ ServiceType.SCREEN_BRIGHTNESS,
+ ServiceType.SOUND,
+ ServiceType.BATTERY_STATS,
+ ServiceType.DATA_SAVER,
+ ServiceType.FORCE_ALL_APPS_STANDBY,
+ ServiceType.OPTIONAL_SENSORS,
+ })
+ public @interface ServiceType {
+ int NULL = 0;
+ int GPS = 1;
+ int VIBRATION = 2;
+ int ANIMATION = 3;
+ int FULL_BACKUP = 4;
+ int KEYVALUE_BACKUP = 5;
+ int NETWORK_FIREWALL = 6;
+ int SCREEN_BRIGHTNESS = 7;
+ int SOUND = 8;
+ int BATTERY_STATS = 9;
+ int DATA_SAVER = 10;
+
+ /**
+ * Whether to enable force-app-standby on all apps or not.
+ */
+ int FORCE_ALL_APPS_STANDBY = 11;
+
+ /**
+ * Whether to disable non-essential sensors. (e.g. edge sensors.)
+ */
+ int OPTIONAL_SENSORS = 13;
+ }
+
final Context mContext;
final IPowerManager mService;
final Handler mHandler;
@@ -1055,15 +1096,14 @@ public final class PowerManager {
/**
* Get data about the battery saver mode for a specific service
- * @param serviceType unique key for the service, one of
- * {@link com.android.server.power.BatterySaverPolicy.ServiceType}
+ * @param serviceType unique key for the service, one of {@link ServiceType}
* @return Battery saver state data.
*
* @hide
* @see com.android.server.power.BatterySaverPolicy
* @see PowerSaveState
*/
- public PowerSaveState getPowerSaveState(int serviceType) {
+ public PowerSaveState getPowerSaveState(@ServiceType int serviceType) {
try {
return mService.getPowerSaveState(serviceType);
} catch (RemoteException e) {
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index a01b8ed2c905..77ac26511769 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -18,6 +18,8 @@ package android.os;
import android.view.Display;
+import java.util.function.Consumer;
+
/**
* Power manager local system service interface.
*
@@ -125,6 +127,23 @@ public abstract class PowerManagerInternal {
public abstract void registerLowPowerModeObserver(LowPowerModeListener listener);
+ /**
+ * Same as {@link #registerLowPowerModeObserver} but can take a lambda.
+ */
+ public void registerLowPowerModeObserver(int serviceType, Consumer<PowerSaveState> listener) {
+ registerLowPowerModeObserver(new LowPowerModeListener() {
+ @Override
+ public int getServiceType() {
+ return serviceType;
+ }
+
+ @Override
+ public void onLowPowerModeChanged(PowerSaveState state) {
+ listener.accept(state);
+ }
+ });
+ }
+
public interface LowPowerModeListener {
int getServiceType();
void onLowPowerModeChanged(PowerSaveState state);
diff --git a/core/java/android/os/PowerSaveState.java b/core/java/android/os/PowerSaveState.java
index 7058a1dca34d..de1128dfdef5 100644
--- a/core/java/android/os/PowerSaveState.java
+++ b/core/java/android/os/PowerSaveState.java
@@ -27,7 +27,7 @@ public class PowerSaveState implements Parcelable {
/**
* Whether we should enable battery saver for this service.
*
- * @see com.android.server.power.BatterySaverPolicy.ServiceType
+ * @see com.android.server.power.BatterySaverPolicy
*/
public final boolean batterySaverEnabled;
/**
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index b5d62e555edc..0874d93e8262 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -151,6 +151,9 @@ public class Process {
*/
public static final int OTA_UPDATE_UID = 1061;
+ /** {@hide} */
+ public static final int NOBODY_UID = 9999;
+
/**
* Defines the start of a range of UIDs (and GIDs), going from this
* number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 2281fb6d5cc2..b9b9a18e361d 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -19,6 +19,7 @@ package android.os;
import android.util.ArrayMap;
import android.util.Slog;
+import java.io.PrintWriter;
import java.util.function.Consumer;
/**
@@ -399,6 +400,13 @@ public class RemoteCallbackList<E extends IInterface> {
}
}
+ /** @hide */
+ public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix); pw.print("callbacks: "); pw.println(mCallbacks.size());
+ pw.print(prefix); pw.print("killed: "); pw.println(mKilled);
+ pw.print(prefix); pw.print("broadcasts count: "); pw.println(mBroadcastCount);
+ }
+
private void logExcessiveCallbacks() {
final long size = mCallbacks.size();
final long TOO_MANY = 3000;
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 6ce12c161714..f90604abf293 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -16,6 +16,7 @@
package android.os;
import android.animation.ValueAnimator;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.app.ActivityManager;
@@ -25,8 +26,26 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
import android.net.TrafficStats;
import android.net.Uri;
+import android.os.strictmode.CleartextNetworkViolation;
+import android.os.strictmode.ContentUriWithoutPermissionViolation;
+import android.os.strictmode.CustomViolation;
+import android.os.strictmode.DiskReadViolation;
+import android.os.strictmode.DiskWriteViolation;
+import android.os.strictmode.FileUriExposedViolation;
+import android.os.strictmode.InstanceCountViolation;
+import android.os.strictmode.IntentReceiverLeakedViolation;
+import android.os.strictmode.LeakedClosableViolation;
+import android.os.strictmode.NetworkViolation;
+import android.os.strictmode.ResourceMismatchViolation;
+import android.os.strictmode.ServiceConnectionLeakedViolation;
+import android.os.strictmode.SqliteObjectLeakedViolation;
+import android.os.strictmode.UnbufferedIoViolation;
+import android.os.strictmode.UntaggedSocketViolation;
+import android.os.strictmode.Violation;
+import android.os.strictmode.WebViewMethodCalledOnWrongThreadViolation;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Printer;
@@ -35,6 +54,7 @@ import android.util.Slog;
import android.view.IWindowManager;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.os.RuntimeInit;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.HexDump;
@@ -53,6 +73,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.HashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -140,6 +162,15 @@ public final class StrictMode {
*/
private static final String CLEARTEXT_PROPERTY = "persist.sys.strictmode.clear";
+ /**
+ * Quick feature-flag that can be used to disable the defaults provided by {@link
+ * #initThreadDefaults(ApplicationInfo)} and {@link #initVmDefaults(ApplicationInfo)}.
+ */
+ private static final boolean DISABLE = false;
+
+ // Only apply VM penalties for the same violation at this interval.
+ private static final long MIN_VM_INTERVAL_MS = 1000;
+
// Only log a duplicate stack trace to the logs every second.
private static final long MIN_LOG_INTERVAL_MS = 1000;
@@ -156,36 +187,30 @@ public final class StrictMode {
// Byte 1: Thread-policy
/** @hide */
- @TestApi
- public static final int DETECT_DISK_WRITE = 0x01; // for ThreadPolicy
+ @TestApi public static final int DETECT_DISK_WRITE = 0x01; // for ThreadPolicy
/** @hide */
- @TestApi
- public static final int DETECT_DISK_READ = 0x02; // for ThreadPolicy
+ @TestApi public static final int DETECT_DISK_READ = 0x02; // for ThreadPolicy
/** @hide */
- @TestApi
- public static final int DETECT_NETWORK = 0x04; // for ThreadPolicy
+ @TestApi public static final int DETECT_NETWORK = 0x04; // for ThreadPolicy
/**
* For StrictMode.noteSlowCall()
*
* @hide
*/
- @TestApi
- public static final int DETECT_CUSTOM = 0x08; // for ThreadPolicy
+ @TestApi public static final int DETECT_CUSTOM = 0x08; // for ThreadPolicy
/**
* For StrictMode.noteResourceMismatch()
*
* @hide
*/
- @TestApi
- public static final int DETECT_RESOURCE_MISMATCH = 0x10; // for ThreadPolicy
+ @TestApi public static final int DETECT_RESOURCE_MISMATCH = 0x10; // for ThreadPolicy
/** @hide */
- @TestApi
- public static final int DETECT_UNBUFFERED_IO = 0x20; // for ThreadPolicy
+ @TestApi public static final int DETECT_UNBUFFERED_IO = 0x20; // for ThreadPolicy
private static final int ALL_THREAD_DETECT_BITS =
DETECT_DISK_WRITE
@@ -202,48 +227,40 @@ public final class StrictMode {
*
* @hide
*/
- @TestApi
- public static final int DETECT_VM_CURSOR_LEAKS = 0x01 << 8; // for VmPolicy
+ @TestApi public static final int DETECT_VM_CURSOR_LEAKS = 0x01 << 8; // for VmPolicy
/**
* Note, a "VM_" bit, not thread.
*
* @hide
*/
- @TestApi
- public static final int DETECT_VM_CLOSABLE_LEAKS = 0x02 << 8; // for VmPolicy
+ @TestApi public static final int DETECT_VM_CLOSABLE_LEAKS = 0x02 << 8; // for VmPolicy
/**
* Note, a "VM_" bit, not thread.
*
* @hide
*/
- @TestApi
- public static final int DETECT_VM_ACTIVITY_LEAKS = 0x04 << 8; // for VmPolicy
+ @TestApi public static final int DETECT_VM_ACTIVITY_LEAKS = 0x04 << 8; // for VmPolicy
/** @hide */
- @TestApi
- public static final int DETECT_VM_INSTANCE_LEAKS = 0x08 << 8; // for VmPolicy
+ @TestApi public static final int DETECT_VM_INSTANCE_LEAKS = 0x08 << 8; // for VmPolicy
/** @hide */
- @TestApi
- public static final int DETECT_VM_REGISTRATION_LEAKS = 0x10 << 8; // for VmPolicy
+ @TestApi public static final int DETECT_VM_REGISTRATION_LEAKS = 0x10 << 8; // for VmPolicy
/** @hide */
- @TestApi
- public static final int DETECT_VM_FILE_URI_EXPOSURE = 0x20 << 8; // for VmPolicy
+ @TestApi public static final int DETECT_VM_FILE_URI_EXPOSURE = 0x20 << 8; // for VmPolicy
/** @hide */
- @TestApi
- public static final int DETECT_VM_CLEARTEXT_NETWORK = 0x40 << 8; // for VmPolicy
+ @TestApi public static final int DETECT_VM_CLEARTEXT_NETWORK = 0x40 << 8; // for VmPolicy
/** @hide */
@TestApi
public static final int DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION = 0x80 << 8; // for VmPolicy
/** @hide */
- @TestApi
- public static final int DETECT_VM_UNTAGGED_SOCKET = 0x80 << 24; // for VmPolicy
+ @TestApi public static final int DETECT_VM_UNTAGGED_SOCKET = 0x80 << 24; // for VmPolicy
private static final int ALL_VM_DETECT_BITS =
DETECT_VM_CURSOR_LEAKS
@@ -354,15 +371,33 @@ public final class StrictMode {
} else {
msg = "StrictMode policy violation:";
}
- if (info.hasStackTrace()) {
- Log.d(TAG, msg + " " + info.getStackTrace());
- } else {
- Log.d(TAG, msg + " missing stack trace!");
- }
+ Log.d(TAG, msg + " " + info.getStackTrace());
};
private static volatile ViolationLogger sLogger = LOGCAT_LOGGER;
+ private static final ThreadLocal<OnThreadViolationListener> sThreadViolationListener =
+ new ThreadLocal<>();
+ private static final ThreadLocal<Executor> sThreadViolationExecutor = new ThreadLocal<>();
+
+ /**
+ * When #{@link ThreadPolicy.Builder#penaltyListener} is enabled, the listener is called on the
+ * provided executor when a Thread violation occurs.
+ */
+ public interface OnThreadViolationListener {
+ /** Called on a thread policy violation. */
+ void onThreadViolation(Violation v);
+ }
+
+ /**
+ * When #{@link VmPolicy.Builder#penaltyListener} is enabled, the listener is called on the
+ * provided executor when a VM violation occurs.
+ */
+ public interface OnVmViolationListener {
+ /** Called on a VM policy violation. */
+ void onVmViolation(Violation v);
+ }
+
/** {@hide} */
@TestApi
public static void setViolationLogger(ViolationLogger listener) {
@@ -392,12 +427,16 @@ public final class StrictMode {
*/
public static final class ThreadPolicy {
/** The default, lax policy which doesn't catch anything. */
- public static final ThreadPolicy LAX = new ThreadPolicy(0);
+ public static final ThreadPolicy LAX = new ThreadPolicy(0, null, null);
final int mask;
+ final OnThreadViolationListener mListener;
+ final Executor mCallbackExecutor;
- private ThreadPolicy(int mask) {
+ private ThreadPolicy(int mask, OnThreadViolationListener listener, Executor executor) {
this.mask = mask;
+ mListener = listener;
+ mCallbackExecutor = executor;
}
@Override
@@ -425,6 +464,8 @@ public final class StrictMode {
*/
public static final class Builder {
private int mMask = 0;
+ private OnThreadViolationListener mListener;
+ private Executor mExecutor;
/**
* Create a Builder that detects nothing and has no violations. (but note that {@link
@@ -590,6 +631,20 @@ public final class StrictMode {
return enable(PENALTY_DROPBOX);
}
+ /**
+ * Call #{@link OnThreadViolationListener#onThreadViolation(Violation)} on specified
+ * executor every violation.
+ */
+ public Builder penaltyListener(
+ @NonNull OnThreadViolationListener listener, @NonNull Executor executor) {
+ if (executor == null) {
+ throw new NullPointerException("executor must not be null");
+ }
+ mListener = listener;
+ mExecutor = executor;
+ return this;
+ }
+
private Builder enable(int bit) {
mMask |= bit;
return this;
@@ -609,7 +664,8 @@ public final class StrictMode {
public ThreadPolicy build() {
// If there are detection bits set but no violation bits
// set, enable simple logging.
- if (mMask != 0
+ if (mListener == null
+ && mMask != 0
&& (mMask
& (PENALTY_DEATH
| PENALTY_LOG
@@ -618,7 +674,7 @@ public final class StrictMode {
== 0) {
penaltyLog();
}
- return new ThreadPolicy(mMask);
+ return new ThreadPolicy(mMask, mListener, mExecutor);
}
}
}
@@ -630,19 +686,27 @@ public final class StrictMode {
*/
public static final class VmPolicy {
/** The default, lax policy which doesn't catch anything. */
- public static final VmPolicy LAX = new VmPolicy(0, EMPTY_CLASS_LIMIT_MAP);
+ public static final VmPolicy LAX = new VmPolicy(0, EMPTY_CLASS_LIMIT_MAP, null, null);
final int mask;
+ final OnVmViolationListener mListener;
+ final Executor mCallbackExecutor;
// Map from class to max number of allowed instances in memory.
final HashMap<Class, Integer> classInstanceLimit;
- private VmPolicy(int mask, HashMap<Class, Integer> classInstanceLimit) {
+ private VmPolicy(
+ int mask,
+ HashMap<Class, Integer> classInstanceLimit,
+ OnVmViolationListener listener,
+ Executor executor) {
if (classInstanceLimit == null) {
throw new NullPointerException("classInstanceLimit == null");
}
this.mask = mask;
this.classInstanceLimit = classInstanceLimit;
+ mListener = listener;
+ mCallbackExecutor = executor;
}
@Override
@@ -670,6 +734,8 @@ public final class StrictMode {
*/
public static final class Builder {
private int mMask;
+ private OnVmViolationListener mListener;
+ private Executor mExecutor;
private HashMap<Class, Integer> mClassInstanceLimit; // null until needed
private boolean mClassInstanceLimitNeedCow = false; // need copy-on-write
@@ -683,6 +749,8 @@ public final class StrictMode {
mMask = base.mask;
mClassInstanceLimitNeedCow = true;
mClassInstanceLimit = base.classInstanceLimit;
+ mListener = base.mListener;
+ mExecutor = base.mCallbackExecutor;
}
/**
@@ -714,6 +782,11 @@ public final class StrictMode {
return enable(DETECT_VM_ACTIVITY_LEAKS);
}
+ /** @hide */
+ public Builder permitActivityLeaks() {
+ return disable(DETECT_VM_ACTIVITY_LEAKS);
+ }
+
/**
* Detect everything that's potentially suspect.
*
@@ -847,6 +920,11 @@ public final class StrictMode {
return enable(DETECT_VM_UNTAGGED_SOCKET);
}
+ /** @hide */
+ public Builder permitUntaggedSockets() {
+ return disable(DETECT_VM_UNTAGGED_SOCKET);
+ }
+
/**
* Crashes the whole process on violation. This penalty runs at the end of all enabled
* penalties so you'll still get your logging or other violations before the process
@@ -889,6 +967,19 @@ public final class StrictMode {
return enable(PENALTY_DROPBOX);
}
+ /**
+ * Call #{@link OnVmViolationListener#onVmViolation(Violation)} on every violation.
+ */
+ public Builder penaltyListener(
+ @NonNull OnVmViolationListener listener, @NonNull Executor executor) {
+ if (executor == null) {
+ throw new NullPointerException("executor must not be null");
+ }
+ mListener = listener;
+ mExecutor = executor;
+ return this;
+ }
+
private Builder enable(int bit) {
mMask |= bit;
return this;
@@ -908,7 +999,8 @@ public final class StrictMode {
public VmPolicy build() {
// If there are detection bits set but no violation bits
// set, enable simple logging.
- if (mMask != 0
+ if (mListener == null
+ && mMask != 0
&& (mMask
& (PENALTY_DEATH
| PENALTY_LOG
@@ -919,7 +1011,9 @@ public final class StrictMode {
}
return new VmPolicy(
mMask,
- mClassInstanceLimit != null ? mClassInstanceLimit : EMPTY_CLASS_LIMIT_MAP);
+ mClassInstanceLimit != null ? mClassInstanceLimit : EMPTY_CLASS_LIMIT_MAP,
+ mListener,
+ mExecutor);
}
}
}
@@ -952,9 +1046,12 @@ public final class StrictMode {
*/
public static void setThreadPolicy(final ThreadPolicy policy) {
setThreadPolicyMask(policy.mask);
+ sThreadViolationListener.set(policy.mListener);
+ sThreadViolationExecutor.set(policy.mCallbackExecutor);
}
- private static void setThreadPolicyMask(final int policyMask) {
+ /** @hide */
+ public static void setThreadPolicyMask(final int policyMask) {
// In addition to the Java-level thread-local in Dalvik's
// BlockGuard, we also need to keep a native thread-local in
// Binder in order to propagate the value across Binder calls,
@@ -991,55 +1088,6 @@ public final class StrictMode {
CloseGuard.setEnabled(enabled);
}
- /** @hide */
- public static class StrictModeViolation extends BlockGuard.BlockGuardPolicyException {
- public StrictModeViolation(int policyState, int policyViolated, String message) {
- super(policyState, policyViolated, message);
- }
- }
-
- /** @hide */
- public static class StrictModeNetworkViolation extends StrictModeViolation {
- public StrictModeNetworkViolation(int policyMask) {
- super(policyMask, DETECT_NETWORK, null);
- }
- }
-
- /** @hide */
- private static class StrictModeDiskReadViolation extends StrictModeViolation {
- public StrictModeDiskReadViolation(int policyMask) {
- super(policyMask, DETECT_DISK_READ, null);
- }
- }
-
- /** @hide */
- private static class StrictModeDiskWriteViolation extends StrictModeViolation {
- public StrictModeDiskWriteViolation(int policyMask) {
- super(policyMask, DETECT_DISK_WRITE, null);
- }
- }
-
- /** @hide */
- private static class StrictModeCustomViolation extends StrictModeViolation {
- public StrictModeCustomViolation(int policyMask, String name) {
- super(policyMask, DETECT_CUSTOM, name);
- }
- }
-
- /** @hide */
- private static class StrictModeResourceMismatchViolation extends StrictModeViolation {
- public StrictModeResourceMismatchViolation(int policyMask, Object tag) {
- super(policyMask, DETECT_RESOURCE_MISMATCH, tag != null ? tag.toString() : null);
- }
- }
-
- /** @hide */
- private static class StrictModeUnbufferedIOViolation extends StrictModeViolation {
- public StrictModeUnbufferedIOViolation(int policyMask) {
- super(policyMask, DETECT_UNBUFFERED_IO, null);
- }
- }
-
/**
* Returns the bitmask of the current thread's policy.
*
@@ -1056,7 +1104,10 @@ public final class StrictMode {
// introduce VmPolicy cleanly) but this isn't particularly
// optimal for users who might call this method often. This
// should be in a thread-local and not allocate on each call.
- return new ThreadPolicy(getThreadPolicyMask());
+ return new ThreadPolicy(
+ getThreadPolicyMask(),
+ sThreadViolationListener.get(),
+ sThreadViolationExecutor.get());
}
/**
@@ -1069,12 +1120,20 @@ public final class StrictMode {
* end of a block
*/
public static ThreadPolicy allowThreadDiskWrites() {
+ return new ThreadPolicy(
+ allowThreadDiskWritesMask(),
+ sThreadViolationListener.get(),
+ sThreadViolationExecutor.get());
+ }
+
+ /** @hide */
+ public static int allowThreadDiskWritesMask() {
int oldPolicyMask = getThreadPolicyMask();
int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_WRITE | DETECT_DISK_READ);
if (newPolicyMask != oldPolicyMask) {
setThreadPolicyMask(newPolicyMask);
}
- return new ThreadPolicy(oldPolicyMask);
+ return oldPolicyMask;
}
/**
@@ -1085,31 +1144,66 @@ public final class StrictMode {
* @return the old policy, to be passed to setThreadPolicy to restore the policy.
*/
public static ThreadPolicy allowThreadDiskReads() {
+ return new ThreadPolicy(
+ allowThreadDiskReadsMask(),
+ sThreadViolationListener.get(),
+ sThreadViolationExecutor.get());
+ }
+
+ /** @hide */
+ public static int allowThreadDiskReadsMask() {
int oldPolicyMask = getThreadPolicyMask();
int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_READ);
if (newPolicyMask != oldPolicyMask) {
setThreadPolicyMask(newPolicyMask);
}
- return new ThreadPolicy(oldPolicyMask);
+ return oldPolicyMask;
}
- // We don't want to flash the screen red in the system server
- // process, nor do we want to modify all the call sites of
- // conditionallyEnableDebugLogging() in the system server,
- // so instead we use this to determine if we are the system server.
- private static boolean amTheSystemServerProcess() {
- // Fast path. Most apps don't have the system server's UID.
- if (Process.myUid() != Process.SYSTEM_UID) {
- return false;
- }
+ private static ThreadPolicy allowThreadViolations() {
+ ThreadPolicy oldPolicy = getThreadPolicy();
+ setThreadPolicyMask(0);
+ return oldPolicy;
+ }
+
+ private static VmPolicy allowVmViolations() {
+ VmPolicy oldPolicy = getVmPolicy();
+ sVmPolicy = VmPolicy.LAX;
+ return oldPolicy;
+ }
- // The settings app, though, has the system server's UID so
- // look up our stack to see if we came from the system server.
- Throwable stack = new Throwable();
- stack.fillInStackTrace();
- for (StackTraceElement ste : stack.getStackTrace()) {
- String clsName = ste.getClassName();
- if (clsName != null && clsName.startsWith("com.android.server.")) {
+ /**
+ * Determine if the given app is "bundled" as part of the system image. These bundled apps are
+ * developed in lock-step with the OS, and they aren't updated outside of an OTA, so we want to
+ * chase any {@link StrictMode} regressions by enabling detection when running on {@link
+ * Build#IS_USERDEBUG} or {@link Build#IS_ENG} builds.
+ *
+ * <p>Unbundled apps included in the system image are expected to detect and triage their own
+ * {@link StrictMode} issues separate from the OS release process, which is why we don't enable
+ * them here.
+ *
+ * @hide
+ */
+ public static boolean isBundledSystemApp(ApplicationInfo ai) {
+ if (ai == null || ai.packageName == null) {
+ // Probably system server
+ return true;
+ } else if (ai.isSystemApp()) {
+ // Ignore unbundled apps living in the wrong namespace
+ if (ai.packageName.equals("com.android.vending")
+ || ai.packageName.equals("com.android.chrome")) {
+ return false;
+ }
+
+ // Ignore bundled apps that are way too spammy
+ // STOPSHIP: burn this list down to zero
+ if (ai.packageName.equals("com.android.phone")) {
+ return false;
+ }
+
+ if (ai.packageName.equals("android")
+ || ai.packageName.startsWith("android.")
+ || ai.packageName.startsWith("com.android.")) {
return true;
}
}
@@ -1117,81 +1211,81 @@ public final class StrictMode {
}
/**
- * Enable DropBox logging for debug phone builds.
+ * Initialize default {@link ThreadPolicy} for the current thread.
*
* @hide
*/
- public static boolean conditionallyEnableDebugLogging() {
- boolean doFlashes =
- SystemProperties.getBoolean(VISUAL_PROPERTY, false) && !amTheSystemServerProcess();
- final boolean suppress = SystemProperties.getBoolean(DISABLE_PROPERTY, false);
-
- // For debug builds, log event loop stalls to dropbox for analysis.
- // Similar logic also appears in ActivityThread.java for system apps.
- if (!doFlashes && (Build.IS_USER || suppress)) {
- setCloseGuardEnabled(false);
- return false;
+ public static void initThreadDefaults(ApplicationInfo ai) {
+ final ThreadPolicy.Builder builder = new ThreadPolicy.Builder();
+ final int targetSdkVersion =
+ (ai != null) ? ai.targetSdkVersion : Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+ // Starting in HC, we don't allow network usage on the main thread
+ if (targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
+ builder.detectNetwork();
+ builder.penaltyDeathOnNetwork();
+ }
+
+ if (Build.IS_USER || DISABLE || SystemProperties.getBoolean(DISABLE_PROPERTY, false)) {
+ // Detect nothing extra
+ } else if (Build.IS_USERDEBUG) {
+ // Detect everything in bundled apps
+ if (isBundledSystemApp(ai)) {
+ builder.detectAll();
+ builder.penaltyDropBox();
+ if (SystemProperties.getBoolean(VISUAL_PROPERTY, false)) {
+ builder.penaltyFlashScreen();
+ }
+ }
+ } else if (Build.IS_ENG) {
+ // Detect everything in bundled apps
+ if (isBundledSystemApp(ai)) {
+ builder.detectAll();
+ builder.penaltyDropBox();
+ builder.penaltyLog();
+ builder.penaltyFlashScreen();
+ }
}
- // Eng builds have flashes on all the time. The suppression property
- // overrides this, so we force the behavior only after the short-circuit
- // check above.
- if (Build.IS_ENG) {
- doFlashes = true;
- }
+ setThreadPolicy(builder.build());
+ }
- // Thread policy controls BlockGuard.
- int threadPolicyMask =
- StrictMode.DETECT_DISK_WRITE
- | StrictMode.DETECT_DISK_READ
- | StrictMode.DETECT_NETWORK;
+ /**
+ * Initialize default {@link VmPolicy} for the current VM.
+ *
+ * @hide
+ */
+ public static void initVmDefaults(ApplicationInfo ai) {
+ final VmPolicy.Builder builder = new VmPolicy.Builder();
+ final int targetSdkVersion =
+ (ai != null) ? ai.targetSdkVersion : Build.VERSION_CODES.CUR_DEVELOPMENT;
- if (!Build.IS_USER) {
- threadPolicyMask |= StrictMode.PENALTY_DROPBOX;
- }
- if (doFlashes) {
- threadPolicyMask |= StrictMode.PENALTY_FLASH;
+ // Starting in N, we don't allow file:// Uri exposure
+ if (targetSdkVersion >= Build.VERSION_CODES.N) {
+ builder.detectFileUriExposure();
+ builder.penaltyDeathOnFileUriExposure();
}
- StrictMode.setThreadPolicyMask(threadPolicyMask);
-
- // VM Policy controls CloseGuard, detection of Activity leaks,
- // and instance counting.
- if (Build.IS_USER) {
- setCloseGuardEnabled(false);
- } else {
- VmPolicy.Builder policyBuilder = new VmPolicy.Builder().detectAll();
- if (!Build.IS_ENG) {
- // Activity leak detection causes too much slowdown for userdebug because of the
- // GCs.
- policyBuilder = policyBuilder.disable(DETECT_VM_ACTIVITY_LEAKS);
- }
- policyBuilder = policyBuilder.penaltyDropBox();
- if (Build.IS_ENG) {
- policyBuilder.penaltyLog();
- }
- // All core system components need to tag their sockets to aid
- // system health investigations
- if (android.os.Process.myUid() < android.os.Process.FIRST_APPLICATION_UID) {
- policyBuilder.enable(DETECT_VM_UNTAGGED_SOCKET);
- } else {
- policyBuilder.disable(DETECT_VM_UNTAGGED_SOCKET);
+ if (Build.IS_USER || DISABLE || SystemProperties.getBoolean(DISABLE_PROPERTY, false)) {
+ // Detect nothing extra
+ } else if (Build.IS_USERDEBUG) {
+ // Detect everything in bundled apps (except activity leaks, which
+ // are expensive to track)
+ if (isBundledSystemApp(ai)) {
+ builder.detectAll();
+ builder.permitActivityLeaks();
+ builder.penaltyDropBox();
+ }
+ } else if (Build.IS_ENG) {
+ // Detect everything in bundled apps
+ if (isBundledSystemApp(ai)) {
+ builder.detectAll();
+ builder.penaltyDropBox();
+ builder.penaltyLog();
}
- setVmPolicy(policyBuilder.build());
- setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
}
- return true;
- }
- /**
- * Used by the framework to make network usage on the main thread a fatal error.
- *
- * @hide
- */
- public static void enableDeathOnNetwork() {
- int oldPolicy = getThreadPolicyMask();
- int newPolicy = oldPolicy | DETECT_NETWORK | PENALTY_DEATH_ON_NETWORK;
- setThreadPolicyMask(newPolicy);
+ setVmPolicy(builder.build());
}
/**
@@ -1205,7 +1299,9 @@ public final class StrictMode {
sVmPolicy.mask
| DETECT_VM_FILE_URI_EXPOSURE
| PENALTY_DEATH_ON_FILE_URI_EXPOSURE,
- sVmPolicy.classInstanceLimit);
+ sVmPolicy.classInstanceLimit,
+ sVmPolicy.mListener,
+ sVmPolicy.mCallbackExecutor);
}
/**
@@ -1220,7 +1316,9 @@ public final class StrictMode {
sVmPolicy.mask
& ~(DETECT_VM_FILE_URI_EXPOSURE
| PENALTY_DEATH_ON_FILE_URI_EXPOSURE),
- sVmPolicy.classInstanceLimit);
+ sVmPolicy.classInstanceLimit,
+ sVmPolicy.mListener,
+ sVmPolicy.mCallbackExecutor);
}
/**
@@ -1308,9 +1406,7 @@ public final class StrictMode {
if (tooManyViolationsThisLoop()) {
return;
}
- BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask);
- e.fillInStackTrace();
- startHandlingViolationException(e);
+ startHandlingViolationException(new DiskWriteViolation());
}
// Not part of BlockGuard.Policy; just part of StrictMode:
@@ -1321,10 +1417,7 @@ public final class StrictMode {
if (tooManyViolationsThisLoop()) {
return;
}
- BlockGuard.BlockGuardPolicyException e =
- new StrictModeCustomViolation(mPolicyMask, name);
- e.fillInStackTrace();
- startHandlingViolationException(e);
+ startHandlingViolationException(new CustomViolation(name));
}
// Not part of BlockGuard.Policy; just part of StrictMode:
@@ -1335,13 +1428,10 @@ public final class StrictMode {
if (tooManyViolationsThisLoop()) {
return;
}
- BlockGuard.BlockGuardPolicyException e =
- new StrictModeResourceMismatchViolation(mPolicyMask, tag);
- e.fillInStackTrace();
- startHandlingViolationException(e);
+ startHandlingViolationException(new ResourceMismatchViolation(tag));
}
- // Part of BlockGuard.Policy; just part of StrictMode:
+ // Not part of BlockGuard.Policy; just part of StrictMode:
public void onUnbufferedIO() {
if ((mPolicyMask & DETECT_UNBUFFERED_IO) == 0) {
return;
@@ -1349,10 +1439,7 @@ public final class StrictMode {
if (tooManyViolationsThisLoop()) {
return;
}
- BlockGuard.BlockGuardPolicyException e =
- new StrictModeUnbufferedIOViolation(mPolicyMask);
- e.fillInStackTrace();
- startHandlingViolationException(e);
+ startHandlingViolationException(new UnbufferedIoViolation());
}
// Part of BlockGuard.Policy interface:
@@ -1363,9 +1450,7 @@ public final class StrictMode {
if (tooManyViolationsThisLoop()) {
return;
}
- BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask);
- e.fillInStackTrace();
- startHandlingViolationException(e);
+ startHandlingViolationException(new DiskReadViolation());
}
// Part of BlockGuard.Policy interface:
@@ -1379,9 +1464,7 @@ public final class StrictMode {
if (tooManyViolationsThisLoop()) {
return;
}
- BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask);
- e.fillInStackTrace();
- startHandlingViolationException(e);
+ startHandlingViolationException(new NetworkViolation());
}
public void setPolicyMask(int policyMask) {
@@ -1393,8 +1476,8 @@ public final class StrictMode {
// has yet occurred). This sees if we're in an event loop
// thread and, if so, uses it to roughly measure how long the
// violation took.
- void startHandlingViolationException(BlockGuard.BlockGuardPolicyException e) {
- final ViolationInfo info = new ViolationInfo(e, e.getPolicy());
+ void startHandlingViolationException(Violation e) {
+ final ViolationInfo info = new ViolationInfo(e, mPolicyMask);
info.violationUptimeMillis = SystemClock.uptimeMillis();
handleViolationWithTimingAttempt(info);
}
@@ -1423,9 +1506,9 @@ public final class StrictMode {
//
// TODO: if in gather mode, ignore Looper.myLooper() and always
// go into this immediate mode?
- if (looper == null || (info.policy & THREAD_PENALTY_MASK) == PENALTY_DEATH) {
+ if (looper == null || (info.mPolicy & THREAD_PENALTY_MASK) == PENALTY_DEATH) {
info.durationMillis = -1; // unknown (redundant, already set)
- handleViolation(info);
+ onThreadPolicyViolation(info);
return;
}
@@ -1443,7 +1526,7 @@ public final class StrictMode {
}
final IWindowManager windowManager =
- (info.policy & PENALTY_FLASH) != 0 ? sWindowManager.get() : null;
+ info.penaltyEnabled(PENALTY_FLASH) ? sWindowManager.get() : null;
if (windowManager != null) {
try {
windowManager.showStrictModeViolation(true);
@@ -1463,30 +1546,28 @@ public final class StrictMode {
THREAD_HANDLER
.get()
.postAtFrontOfQueue(
- new Runnable() {
- public void run() {
- long loopFinishTime = SystemClock.uptimeMillis();
-
- // Note: we do this early, before handling the
- // violation below, as handling the violation
- // may include PENALTY_DEATH and we don't want
- // to keep the red border on.
- if (windowManager != null) {
- try {
- windowManager.showStrictModeViolation(false);
- } catch (RemoteException unused) {
- }
+ () -> {
+ long loopFinishTime = SystemClock.uptimeMillis();
+
+ // Note: we do this early, before handling the
+ // violation below, as handling the violation
+ // may include PENALTY_DEATH and we don't want
+ // to keep the red border on.
+ if (windowManager != null) {
+ try {
+ windowManager.showStrictModeViolation(false);
+ } catch (RemoteException unused) {
}
+ }
- for (int n = 0; n < records.size(); ++n) {
- ViolationInfo v = records.get(n);
- v.violationNumThisLoop = n + 1;
- v.durationMillis =
- (int) (loopFinishTime - v.violationUptimeMillis);
- handleViolation(v);
- }
- records.clear();
+ for (int n = 0; n < records.size(); ++n) {
+ ViolationInfo v = records.get(n);
+ v.violationNumThisLoop = n + 1;
+ v.durationMillis =
+ (int) (loopFinishTime - v.violationUptimeMillis);
+ onThreadPolicyViolation(v);
}
+ records.clear();
});
}
@@ -1495,18 +1576,13 @@ public final class StrictMode {
// violation fired and now (after the violating code ran) due
// to people who push/pop temporary policy in regions of code,
// hence the policy being passed around.
- void handleViolation(final ViolationInfo info) {
- if (info == null || !info.hasStackTrace()) {
- Log.wtf(TAG, "unexpected null stacktrace");
- return;
- }
-
- if (LOG_V) Log.d(TAG, "handleViolation; policy=" + info.policy);
+ void onThreadPolicyViolation(final ViolationInfo info) {
+ if (LOG_V) Log.d(TAG, "onThreadPolicyViolation; policy=" + info.mPolicy);
- if ((info.policy & PENALTY_GATHER) != 0) {
+ if (info.penaltyEnabled(PENALTY_GATHER)) {
ArrayList<ViolationInfo> violations = gatheredViolations.get();
if (violations == null) {
- violations = new ArrayList<ViolationInfo>(1);
+ violations = new ArrayList<>(1);
gatheredViolations.set(violations);
}
for (ViolationInfo previous : violations) {
@@ -1535,31 +1611,32 @@ public final class StrictMode {
long timeSinceLastViolationMillis =
lastViolationTime == 0 ? Long.MAX_VALUE : (now - lastViolationTime);
- if ((info.policy & PENALTY_LOG) != 0
+ if (info.penaltyEnabled(PENALTY_LOG)
&& timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
sLogger.log(info);
}
+ final Violation violation = info.mViolation;
+
// The violationMaskSubset, passed to ActivityManager, is a
// subset of the original StrictMode policy bitmask, with
// only the bit violated and penalty bits to be executed
// by the ActivityManagerService remaining set.
int violationMaskSubset = 0;
- if ((info.policy & PENALTY_DIALOG) != 0
+ if (info.penaltyEnabled(PENALTY_DIALOG)
&& timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) {
violationMaskSubset |= PENALTY_DIALOG;
}
- if ((info.policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) {
+ if (info.penaltyEnabled(PENALTY_DROPBOX) && lastViolationTime == 0) {
violationMaskSubset |= PENALTY_DROPBOX;
}
if (violationMaskSubset != 0) {
violationMaskSubset |= info.getViolationBit();
- final int savedPolicyMask = getThreadPolicyMask();
- final boolean justDropBox = (info.policy & THREAD_PENALTY_MASK) == PENALTY_DROPBOX;
+ final boolean justDropBox = (info.mPolicy & THREAD_PENALTY_MASK) == PENALTY_DROPBOX;
if (justDropBox) {
// If all we're going to ask the activity manager
// to do is dropbox it (the common case during
@@ -1568,42 +1645,38 @@ public final class StrictMode {
// isn't always super fast, despite the implementation
// in the ActivityManager trying to be mostly async.
dropboxViolationAsync(violationMaskSubset, info);
- return;
+ } else {
+ handleApplicationStrictModeViolation(violationMaskSubset, info);
}
+ }
- // Normal synchronous call to the ActivityManager.
- try {
- // First, remove any policy before we call into the Activity Manager,
- // otherwise we'll infinite recurse as we try to log policy violations
- // to disk, thus violating policy, thus requiring logging, etc...
- // We restore the current policy below, in the finally block.
- setThreadPolicyMask(0);
-
- ActivityManager.getService()
- .handleApplicationStrictModeViolation(
- RuntimeInit.getApplicationObject(), violationMaskSubset, info);
- } catch (RemoteException e) {
- if (e instanceof DeadObjectException) {
- // System process is dead; ignore
- } else {
- Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
- }
- } finally {
- // Restore the policy.
- setThreadPolicyMask(savedPolicyMask);
- }
+ if ((info.getPolicyMask() & PENALTY_DEATH) != 0) {
+ throw new RuntimeException("StrictMode ThreadPolicy violation", violation);
}
- if ((info.policy & PENALTY_DEATH) != 0) {
- executeDeathPenalty(info);
+ // penaltyDeath will cause penaltyCallback to no-op since we cannot guarantee the
+ // executor finishes before crashing.
+ final OnThreadViolationListener listener = sThreadViolationListener.get();
+ final Executor executor = sThreadViolationExecutor.get();
+ if (listener != null && executor != null) {
+ try {
+ executor.execute(
+ () -> {
+ // Lift violated policy to prevent infinite recursion.
+ ThreadPolicy oldPolicy = allowThreadViolations();
+ try {
+ listener.onThreadViolation(violation);
+ } finally {
+ setThreadPolicy(oldPolicy);
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ Log.e(TAG, "ThreadPolicy penaltyCallback failed", e);
+ }
}
}
}
- private static void executeDeathPenalty(ViolationInfo info) {
- throw new StrictModeViolation(info.policy, info.getViolationBit(), null);
- }
-
/**
* In the common case, as set by conditionallyEnableDebugLogging, we're just dropboxing any
* violations but not showing a dialog, not loggging, and not killing the process. In these
@@ -1622,33 +1695,44 @@ public final class StrictMode {
if (LOG_V) Log.d(TAG, "Dropboxing async; in-flight=" + outstanding);
- new Thread("callActivityManagerForStrictModeDropbox") {
- public void run() {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- try {
- IActivityManager am = ActivityManager.getService();
- if (am == null) {
- Log.d(TAG, "No activity manager; failed to Dropbox violation.");
- } else {
- am.handleApplicationStrictModeViolation(
- RuntimeInit.getApplicationObject(), violationMaskSubset, info);
- }
- } catch (RemoteException e) {
- if (e instanceof DeadObjectException) {
- // System process is dead; ignore
- } else {
- Log.e(TAG, "RemoteException handling StrictMode violation", e);
- }
- }
- int outstanding = sDropboxCallsInFlight.decrementAndGet();
- if (LOG_V) Log.d(TAG, "Dropbox complete; in-flight=" + outstanding);
+ BackgroundThread.getHandler().post(() -> {
+ handleApplicationStrictModeViolation(violationMaskSubset, info);
+ int outstandingInner = sDropboxCallsInFlight.decrementAndGet();
+ if (LOG_V) Log.d(TAG, "Dropbox complete; in-flight=" + outstandingInner);
+ });
+ }
+
+ private static void handleApplicationStrictModeViolation(int violationMaskSubset,
+ ViolationInfo info) {
+ final int oldMask = getThreadPolicyMask();
+ try {
+ // First, remove any policy before we call into the Activity Manager,
+ // otherwise we'll infinite recurse as we try to log policy violations
+ // to disk, thus violating policy, thus requiring logging, etc...
+ // We restore the current policy below, in the finally block.
+ setThreadPolicyMask(0);
+
+ IActivityManager am = ActivityManager.getService();
+ if (am == null) {
+ Log.w(TAG, "No activity manager; failed to Dropbox violation.");
+ } else {
+ am.handleApplicationStrictModeViolation(
+ RuntimeInit.getApplicationObject(), violationMaskSubset, info);
}
- }.start();
+ } catch (RemoteException e) {
+ if (e instanceof DeadObjectException) {
+ // System process is dead; ignore
+ } else {
+ Log.e(TAG, "RemoteException handling StrictMode violation", e);
+ }
+ } finally {
+ setThreadPolicyMask(oldMask);
+ }
}
private static class AndroidCloseGuardReporter implements CloseGuard.Reporter {
public void report(String message, Throwable allocationSite) {
- onVmPolicyViolation(allocationSite);
+ onVmPolicyViolation(new LeakedClosableViolation(message, allocationSite));
}
}
@@ -1686,8 +1770,7 @@ public final class StrictMode {
int limit = policy.classInstanceLimit.get(klass);
long instances = instanceCounts[i];
if (instances > limit) {
- Throwable tr = new InstanceCountViolation(klass, instances, limit);
- onVmPolicyViolation(tr);
+ onVmPolicyViolation(new InstanceCountViolation(klass, instances, limit));
}
}
}
@@ -1769,9 +1852,8 @@ public final class StrictMode {
* #setThreadPolicy}.
*/
public static void enableDefaults() {
- StrictMode.setThreadPolicy(
- new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
- StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());
+ setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
+ setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());
}
/** @hide */
@@ -1811,24 +1893,22 @@ public final class StrictMode {
/** @hide */
public static void onSqliteObjectLeaked(String message, Throwable originStack) {
- Throwable t = new Throwable(message);
- t.setStackTrace(originStack.getStackTrace());
- onVmPolicyViolation(t);
+ onVmPolicyViolation(new SqliteObjectLeakedViolation(message, originStack));
}
/** @hide */
public static void onWebViewMethodCalledOnWrongThread(Throwable originStack) {
- onVmPolicyViolation(originStack);
+ onVmPolicyViolation(new WebViewMethodCalledOnWrongThreadViolation(originStack));
}
/** @hide */
public static void onIntentReceiverLeaked(Throwable originStack) {
- onVmPolicyViolation(originStack);
+ onVmPolicyViolation(new IntentReceiverLeakedViolation(originStack));
}
/** @hide */
public static void onServiceConnectionLeaked(Throwable originStack) {
- onVmPolicyViolation(originStack);
+ onVmPolicyViolation(new ServiceConnectionLeakedViolation(originStack));
}
/** @hide */
@@ -1837,19 +1917,13 @@ public final class StrictMode {
if ((sVmPolicy.mask & PENALTY_DEATH_ON_FILE_URI_EXPOSURE) != 0) {
throw new FileUriExposedException(message);
} else {
- onVmPolicyViolation(new Throwable(message));
+ onVmPolicyViolation(new FileUriExposedViolation(message));
}
}
/** @hide */
public static void onContentUriWithoutPermission(Uri uri, String location) {
- final String message =
- uri
- + " exposed beyond app through "
- + location
- + " without permission grant flags; did you forget"
- + " FLAG_GRANT_READ_URI_PERMISSION?";
- onVmPolicyViolation(new Throwable(message));
+ onVmPolicyViolation(new ContentUriWithoutPermissionViolation(uri, location));
}
/** @hide */
@@ -1881,33 +1955,28 @@ public final class StrictMode {
}
msg += HexDump.dumpHexString(firstPacket).trim() + " ";
final boolean forceDeath = (sVmPolicy.mask & PENALTY_DEATH_ON_CLEARTEXT_NETWORK) != 0;
- onVmPolicyViolation(new Throwable(msg), forceDeath);
+ onVmPolicyViolation(new CleartextNetworkViolation(msg), forceDeath);
}
/** @hide */
- public static final String UNTAGGED_SOCKET_VIOLATION_MESSAGE =
- "Untagged socket detected; use"
- + " TrafficStats.setThreadSocketTag() to track all network usage";
-
- /** @hide */
public static void onUntaggedSocket() {
- onVmPolicyViolation(new Throwable(UNTAGGED_SOCKET_VIOLATION_MESSAGE));
+ onVmPolicyViolation(new UntaggedSocketViolation());
}
// Map from VM violation fingerprint to uptime millis.
- private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>();
+ private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<>();
/** @hide */
- public static void onVmPolicyViolation(Throwable originStack) {
+ public static void onVmPolicyViolation(Violation originStack) {
onVmPolicyViolation(originStack, false);
}
/** @hide */
- public static void onVmPolicyViolation(Throwable originStack, boolean forceDeath) {
+ public static void onVmPolicyViolation(Violation violation, boolean forceDeath) {
final boolean penaltyDropbox = (sVmPolicy.mask & PENALTY_DROPBOX) != 0;
final boolean penaltyDeath = ((sVmPolicy.mask & PENALTY_DEATH) != 0) || forceDeath;
final boolean penaltyLog = (sVmPolicy.mask & PENALTY_LOG) != 0;
- final ViolationInfo info = new ViolationInfo(originStack, sVmPolicy.mask);
+ final ViolationInfo info = new ViolationInfo(violation, sVmPolicy.mask);
// Erase stuff not relevant for process-wide violations
info.numAnimationsRunning = 0;
@@ -1916,60 +1985,36 @@ public final class StrictMode {
final Integer fingerprint = info.hashCode();
final long now = SystemClock.uptimeMillis();
- long lastViolationTime = 0;
+ long lastViolationTime;
long timeSinceLastViolationMillis = Long.MAX_VALUE;
synchronized (sLastVmViolationTime) {
if (sLastVmViolationTime.containsKey(fingerprint)) {
lastViolationTime = sLastVmViolationTime.get(fingerprint);
timeSinceLastViolationMillis = now - lastViolationTime;
}
- if (timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
+ if (timeSinceLastViolationMillis > MIN_VM_INTERVAL_MS) {
sLastVmViolationTime.put(fingerprint, now);
}
}
-
- if (penaltyLog && sLogger != null) {
- sLogger.log(info);
+ if (timeSinceLastViolationMillis <= MIN_VM_INTERVAL_MS) {
+ // Rate limit all penalties.
+ return;
}
- if (penaltyLog && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
+
+ if (penaltyLog && sLogger != null && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
sLogger.log(info);
}
int violationMaskSubset = PENALTY_DROPBOX | (ALL_VM_DETECT_BITS & sVmPolicy.mask);
- if (penaltyDropbox && !penaltyDeath) {
- // Common case for userdebug/eng builds. If no death and
- // just dropboxing, we can do the ActivityManager call
- // asynchronously.
- dropboxViolationAsync(violationMaskSubset, info);
- return;
- }
-
- if (penaltyDropbox && lastViolationTime == 0) {
- // The violationMask, passed to ActivityManager, is a
- // subset of the original StrictMode policy bitmask, with
- // only the bit violated and penalty bits to be executed
- // by the ActivityManagerService remaining set.
- final int savedPolicyMask = getThreadPolicyMask();
- try {
- // First, remove any policy before we call into the Activity Manager,
- // otherwise we'll infinite recurse as we try to log policy violations
- // to disk, thus violating policy, thus requiring logging, etc...
- // We restore the current policy below, in the finally block.
- setThreadPolicyMask(0);
-
- ActivityManager.getService()
- .handleApplicationStrictModeViolation(
- RuntimeInit.getApplicationObject(), violationMaskSubset, info);
- } catch (RemoteException e) {
- if (e instanceof DeadObjectException) {
- // System process is dead; ignore
- } else {
- Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
- }
- } finally {
- // Restore the policy.
- setThreadPolicyMask(savedPolicyMask);
+ if (penaltyDropbox) {
+ if (penaltyDeath) {
+ handleApplicationStrictModeViolation(violationMaskSubset, info);
+ } else {
+ // Common case for userdebug/eng builds. If no death and
+ // just dropboxing, we can do the ActivityManager call
+ // asynchronously.
+ dropboxViolationAsync(violationMaskSubset, info);
}
}
@@ -1978,6 +2023,26 @@ public final class StrictMode {
Process.killProcess(Process.myPid());
System.exit(10);
}
+
+ // If penaltyDeath, we can't guarantee this callback finishes before the process dies for
+ // all executors. penaltyDeath supersedes penaltyCallback.
+ if (sVmPolicy.mListener != null && sVmPolicy.mCallbackExecutor != null) {
+ final OnVmViolationListener listener = sVmPolicy.mListener;
+ try {
+ sVmPolicy.mCallbackExecutor.execute(
+ () -> {
+ // Lift violated policy to prevent infinite recursion.
+ VmPolicy oldPolicy = allowVmViolations();
+ try {
+ listener.onVmViolation(violation);
+ } finally {
+ setVmPolicy(oldPolicy);
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ Log.e(TAG, "VmPolicy penaltyCallback failed", e);
+ }
+ }
}
/** Called from Parcel.writeNoException() */
@@ -1998,14 +2063,12 @@ public final class StrictMode {
gatheredViolations.set(null);
}
- private static class LogStackTrace extends Exception {}
-
/**
* Called from Parcel.readException() when the exception is EX_STRICT_MODE_VIOLATIONS, we here
* read back all the encoded violations.
*/
/* package */ static void readAndHandleBinderCallViolations(Parcel p) {
- LogStackTrace localCallSite = new LogStackTrace();
+ Throwable localCallSite = new Throwable();
final int policyMask = getThreadPolicyMask();
final boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0;
@@ -2323,8 +2386,7 @@ public final class StrictMode {
long instances = VMDebug.countInstancesOfClass(klass, false);
if (instances > limit) {
- Throwable tr = new InstanceCountViolation(klass, instances, limit);
- onVmPolicyViolation(tr);
+ onVmPolicyViolation(new InstanceCountViolation(klass, instances, limit));
}
}
@@ -2337,18 +2399,16 @@ public final class StrictMode {
@TestApi
public static final class ViolationInfo implements Parcelable {
/** Stack and violation details. */
- @Nullable private final Throwable mThrowable;
+ private final Violation mViolation;
/** Path leading to a violation that occurred across binder. */
private final Deque<StackTraceElement[]> mBinderStack = new ArrayDeque<>();
/** Memoized stack trace of full violation. */
@Nullable private String mStackTrace;
- /** Memoized violation bit. */
- private int mViolationBit;
/** The strict mode policy mask at the time of violation. */
- public final int policy;
+ private final int mPolicy;
/** The wall time duration of the violation, when known. -1 when not known. */
public int durationMillis = -1;
@@ -2378,17 +2438,11 @@ public final class StrictMode {
/** If this is a instance count violation, the number of instances in memory, else -1. */
public long numInstances = -1;
- /** Create an uninitialized instance of ViolationInfo */
- public ViolationInfo() {
- mThrowable = null;
- policy = 0;
- }
-
/** Create an instance of ViolationInfo initialized from an exception. */
- public ViolationInfo(Throwable tr, int policy) {
- this.mThrowable = tr;
+ ViolationInfo(Violation tr, int policy) {
+ this.mViolation = tr;
+ this.mPolicy = policy;
violationUptimeMillis = SystemClock.uptimeMillis();
- this.policy = policy;
this.numAnimationsRunning = ValueAnimator.getCurrentAnimationsCount();
Intent broadcastIntent = ActivityThread.getIntentBeingBroadcast();
if (broadcastIntent != null) {
@@ -2396,7 +2450,7 @@ public final class StrictMode {
}
ThreadSpanState state = sThisThreadSpanState.get();
if (tr instanceof InstanceCountViolation) {
- this.numInstances = ((InstanceCountViolation) tr).mInstances;
+ this.numInstances = ((InstanceCountViolation) tr).getNumberOfInstances();
}
synchronized (state) {
int spanActiveCount = state.mActiveSize;
@@ -2418,10 +2472,10 @@ public final class StrictMode {
/** Equivalent output to {@link ApplicationErrorReport.CrashInfo#stackTrace}. */
public String getStackTrace() {
- if (mThrowable != null && mStackTrace == null) {
+ if (mStackTrace == null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new FastPrintWriter(sw, false, 256);
- mThrowable.printStackTrace(pw);
+ mViolation.printStackTrace(pw);
for (StackTraceElement[] traces : mBinderStack) {
pw.append("# via Binder call with stack:\n");
for (StackTraceElement traceElement : traces) {
@@ -2444,20 +2498,21 @@ public final class StrictMode {
*/
@TestApi
public String getViolationDetails() {
- if (mThrowable != null) {
- return mThrowable.getMessage();
- } else {
- return "";
- }
+ return mViolation.getMessage();
}
/**
- * If this violation has a useful stack trace.
+ * Policy mask at time of violation.
*
* @hide
*/
- public boolean hasStackTrace() {
- return mThrowable != null;
+ @TestApi
+ public int getPolicyMask() {
+ return mPolicy;
+ }
+
+ boolean penaltyEnabled(int p) {
+ return (mPolicy & p) != 0;
}
/**
@@ -2475,37 +2530,47 @@ public final class StrictMode {
*
* @hide
*/
- int getViolationBit() {
- if (mThrowable == null || mThrowable.getMessage() == null) {
- return 0;
- }
- if (mViolationBit != 0) {
- return mViolationBit;
- }
- String message = mThrowable.getMessage();
- int violationIndex = message.indexOf("violation=");
- if (violationIndex == -1) {
- return 0;
- }
- int numberStartIndex = violationIndex + "violation=".length();
- int numberEndIndex = message.indexOf(' ', numberStartIndex);
- if (numberEndIndex == -1) {
- numberEndIndex = message.length();
- }
- String violationString = message.substring(numberStartIndex, numberEndIndex);
- try {
- mViolationBit = Integer.parseInt(violationString);
- return mViolationBit;
- } catch (NumberFormatException e) {
- return 0;
- }
+ @TestApi
+ public int getViolationBit() {
+ if (mViolation instanceof DiskWriteViolation) {
+ return DETECT_DISK_WRITE;
+ } else if (mViolation instanceof DiskReadViolation) {
+ return DETECT_DISK_READ;
+ } else if (mViolation instanceof NetworkViolation) {
+ return DETECT_NETWORK;
+ } else if (mViolation instanceof CustomViolation) {
+ return DETECT_CUSTOM;
+ } else if (mViolation instanceof ResourceMismatchViolation) {
+ return DETECT_RESOURCE_MISMATCH;
+ } else if (mViolation instanceof UnbufferedIoViolation) {
+ return DETECT_UNBUFFERED_IO;
+ } else if (mViolation instanceof SqliteObjectLeakedViolation) {
+ return DETECT_VM_CURSOR_LEAKS;
+ } else if (mViolation instanceof LeakedClosableViolation) {
+ return DETECT_VM_CLOSABLE_LEAKS;
+ } else if (mViolation instanceof InstanceCountViolation) {
+ return DETECT_VM_INSTANCE_LEAKS;
+ } else if (mViolation instanceof IntentReceiverLeakedViolation) {
+ return DETECT_VM_REGISTRATION_LEAKS;
+ } else if (mViolation instanceof ServiceConnectionLeakedViolation) {
+ return DETECT_VM_REGISTRATION_LEAKS;
+ } else if (mViolation instanceof FileUriExposedViolation) {
+ return DETECT_VM_FILE_URI_EXPOSURE;
+ } else if (mViolation instanceof CleartextNetworkViolation) {
+ return DETECT_VM_CLEARTEXT_NETWORK;
+ } else if (mViolation instanceof ContentUriWithoutPermissionViolation) {
+ return DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION;
+ } else if (mViolation instanceof UntaggedSocketViolation) {
+ return DETECT_VM_UNTAGGED_SOCKET;
+ }
+ throw new IllegalStateException("missing violation bit");
}
@Override
public int hashCode() {
int result = 17;
- if (mThrowable != null) {
- result = 37 * result + mThrowable.hashCode();
+ if (mViolation != null) {
+ result = 37 * result + mViolation.hashCode();
}
if (numAnimationsRunning != 0) {
result *= 37;
@@ -2533,7 +2598,7 @@ public final class StrictMode {
* should be removed.
*/
public ViolationInfo(Parcel in, boolean unsetGatheringBit) {
- mThrowable = (Throwable) in.readSerializable();
+ mViolation = (Violation) in.readSerializable();
int binderStackSize = in.readInt();
for (int i = 0; i < binderStackSize; i++) {
StackTraceElement[] traceElements = new StackTraceElement[in.readInt()];
@@ -2550,9 +2615,9 @@ public final class StrictMode {
}
int rawPolicy = in.readInt();
if (unsetGatheringBit) {
- policy = rawPolicy & ~PENALTY_GATHER;
+ mPolicy = rawPolicy & ~PENALTY_GATHER;
} else {
- policy = rawPolicy;
+ mPolicy = rawPolicy;
}
durationMillis = in.readInt();
violationNumThisLoop = in.readInt();
@@ -2566,7 +2631,7 @@ public final class StrictMode {
/** Save a ViolationInfo instance to a parcel. */
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeSerializable(mThrowable);
+ dest.writeSerializable(mViolation);
dest.writeInt(mBinderStack.size());
for (StackTraceElement[] traceElements : mBinderStack) {
dest.writeInt(traceElements.length);
@@ -2578,7 +2643,7 @@ public final class StrictMode {
}
}
int start = dest.dataPosition();
- dest.writeInt(policy);
+ dest.writeInt(mPolicy);
dest.writeInt(durationMillis);
dest.writeInt(violationNumThisLoop);
dest.writeInt(numAnimationsRunning);
@@ -2591,7 +2656,7 @@ public final class StrictMode {
Slog.d(
TAG,
"VIO: policy="
- + policy
+ + mPolicy
+ " dur="
+ durationMillis
+ " numLoop="
@@ -2610,10 +2675,8 @@ public final class StrictMode {
/** Dump a ViolationInfo instance to a Printer. */
public void dump(Printer pw, String prefix) {
- if (mThrowable != null) {
- pw.println(prefix + "stackTrace: " + getStackTrace());
- }
- pw.println(prefix + "policy: " + policy);
+ pw.println(prefix + "stackTrace: " + getStackTrace());
+ pw.println(prefix + "policy: " + mPolicy);
if (durationMillis != -1) {
pw.println(prefix + "durationMillis: " + durationMillis);
}
@@ -2657,27 +2720,6 @@ public final class StrictMode {
};
}
- // Dummy throwable, for now, since we don't know when or where the
- // leaked instances came from. We might in the future, but for
- // now we suppress the stack trace because it's useless and/or
- // misleading.
- private static class InstanceCountViolation extends Throwable {
- private final long mInstances;
- private final int mLimit;
-
- private static final StackTraceElement[] FAKE_STACK = {
- new StackTraceElement(
- "android.os.StrictMode", "setClassInstanceLimit", "StrictMode.java", 1)
- };
-
- public InstanceCountViolation(Class klass, long instances, int limit) {
- super(klass.toString() + "; instances=" + instances + "; limit=" + limit);
- setStackTrace(FAKE_STACK);
- mInstances = instances;
- mLimit = limit;
- }
- }
-
private static final class InstanceTracker {
private static final HashMap<Class<?>, Integer> sInstanceCounts =
new HashMap<Class<?>, Integer>();
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index b3d76d73ac34..c52c22d60ade 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -16,12 +16,18 @@
package android.os;
+import android.annotation.NonNull;
import android.app.IAlarmManager;
import android.content.Context;
import android.util.Slog;
import dalvik.annotation.optimization.CriticalNative;
+import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+
/**
* Core timekeeping facilities.
*
@@ -168,6 +174,31 @@ public final class SystemClock {
native public static long uptimeMillis();
/**
+ * Return {@link Clock} that starts at system boot, not counting time spent
+ * in deep sleep.
+ */
+ public static @NonNull Clock uptimeMillisClock() {
+ return new Clock() {
+ @Override
+ public ZoneId getZone() {
+ return ZoneOffset.UTC;
+ }
+ @Override
+ public Clock withZone(ZoneId zone) {
+ throw new UnsupportedOperationException();
+ }
+ @Override
+ public long millis() {
+ return SystemClock.uptimeMillis();
+ }
+ @Override
+ public Instant instant() {
+ return Instant.ofEpochMilli(millis());
+ }
+ };
+ }
+
+ /**
* Returns milliseconds since boot, including time spent in sleep.
*
* @return elapsed milliseconds since boot.
@@ -176,6 +207,31 @@ public final class SystemClock {
native public static long elapsedRealtime();
/**
+ * Return {@link Clock} that starts at system boot, including time spent in
+ * sleep.
+ */
+ public static @NonNull Clock elapsedRealtimeClock() {
+ return new Clock() {
+ @Override
+ public ZoneId getZone() {
+ return ZoneOffset.UTC;
+ }
+ @Override
+ public Clock withZone(ZoneId zone) {
+ throw new UnsupportedOperationException();
+ }
+ @Override
+ public long millis() {
+ return SystemClock.elapsedRealtime();
+ }
+ @Override
+ public Instant instant() {
+ return Instant.ofEpochMilli(millis());
+ }
+ };
+ }
+
+ /**
* Returns nanoseconds since boot, including time spent in sleep.
*
* @return elapsed nanoseconds since boot.
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index ee0b6230fade..c6149bed9d6d 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -67,6 +67,7 @@ public class UpdateEngine {
public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10;
public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11;
public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12;
+ public static final int UPDATED_BUT_NOT_ACTIVE = 52;
}
/**
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index e8ebf6312cdd..6381b56a6503 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -27,6 +27,8 @@ import java.io.PrintWriter;
* Representation of a user on the device.
*/
public final class UserHandle implements Parcelable {
+ // NOTE: keep logic in sync with system/core/libcutils/multiuser.c
+
/**
* @hide Range of uids allocated for a user.
*/
@@ -88,6 +90,19 @@ public final class UserHandle implements Parcelable {
*/
public static final boolean MU_ENABLED = true;
+ /** @hide */
+ public static final int ERR_GID = -1;
+ /** @hide */
+ public static final int AID_ROOT = android.os.Process.ROOT_UID;
+ /** @hide */
+ public static final int AID_APP_START = android.os.Process.FIRST_APPLICATION_UID;
+ /** @hide */
+ public static final int AID_APP_END = android.os.Process.LAST_APPLICATION_UID;
+ /** @hide */
+ public static final int AID_SHARED_GID_START = android.os.Process.FIRST_SHARED_APPLICATION_GID;
+ /** @hide */
+ public static final int AID_CACHE_GID_START = android.os.Process.FIRST_APPLICATION_CACHE_GID;
+
final int mHandle;
/**
@@ -197,13 +212,20 @@ public final class UserHandle implements Parcelable {
return getUid(userId, Process.SHARED_USER_GID);
}
- /**
- * Returns the shared app gid for a given uid or appId.
- * @hide
- */
- public static int getSharedAppGid(int id) {
- return Process.FIRST_SHARED_APPLICATION_GID + (id % PER_USER_RANGE)
- - Process.FIRST_APPLICATION_UID;
+ /** @hide */
+ public static int getSharedAppGid(int uid) {
+ return getSharedAppGid(getUserId(uid), getAppId(uid));
+ }
+
+ /** @hide */
+ public static int getSharedAppGid(int userId, int appId) {
+ if (appId >= AID_APP_START && appId <= AID_APP_END) {
+ return (appId - AID_APP_START) + AID_SHARED_GID_START;
+ } else if (appId >= AID_ROOT && appId <= AID_APP_START) {
+ return appId;
+ } else {
+ return -1;
+ }
}
/**
@@ -219,13 +241,18 @@ public final class UserHandle implements Parcelable {
return appId;
}
- /**
- * Returns the cache GID for a given UID or appId.
- * @hide
- */
- public static int getCacheAppGid(int id) {
- return Process.FIRST_APPLICATION_CACHE_GID + (id % PER_USER_RANGE)
- - Process.FIRST_APPLICATION_UID;
+ /** @hide */
+ public static int getCacheAppGid(int uid) {
+ return getCacheAppGid(getUserId(uid), getAppId(uid));
+ }
+
+ /** @hide */
+ public static int getCacheAppGid(int userId, int appId) {
+ if (appId >= AID_APP_START && appId <= AID_APP_END) {
+ return getUid(userId, (appId - AID_APP_START) + AID_CACHE_GID_START);
+ } else {
+ return -1;
+ }
}
/**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index c54b72d40387..22967af7fc59 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -140,6 +140,18 @@ public class UserManager {
public static final String DISALLOW_CONFIG_WIFI = "no_config_wifi";
/**
+ * Specifies if a user is disallowed from changing the device
+ * language. The default value is <code>false</code>.
+ *
+ * <p>Key for user restrictions.
+ * <p>Type: Boolean
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_LOCALE = "no_config_locale";
+
+ /**
* Specifies if a user is disallowed from installing applications.
* The default value is <code>false</code>.
*
@@ -792,6 +804,19 @@ public class UserManager {
public static final String DISALLOW_AUTOFILL = "no_autofill";
/**
+ * Specifies if user switching is blocked on the current user.
+ *
+ * <p> This restriction can only be set by the device owner, it will be applied to all users.
+ *
+ * <p>The default value is <code>false</code>.
+ *
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_USER_SWITCH = "no_user_switch";
+
+ /**
* Application restriction key that is used to indicate the pending arrival
* of real restrictions for the app.
*
@@ -917,7 +942,7 @@ public class UserManager {
/**
* Returns whether switching users is currently allowed.
* <p>For instance switching users is not allowed if the current user is in a phone call,
- * or system user hasn't been unlocked yet
+ * system user hasn't been unlocked yet, or {@link #DISALLOW_USER_SWITCH} is set.
* @hide
*/
public boolean canSwitchUsers() {
@@ -927,7 +952,9 @@ public class UserManager {
boolean isSystemUserUnlocked = isUserUnlocked(UserHandle.SYSTEM);
boolean inCall = TelephonyManager.getDefault().getCallState()
!= TelephonyManager.CALL_STATE_IDLE;
- return (allowUserSwitchingWhenSystemUserLocked || isSystemUserUnlocked) && !inCall;
+ boolean isUserSwitchDisallowed = hasUserRestriction(DISALLOW_USER_SWITCH);
+ return (allowUserSwitchingWhenSystemUserLocked || isSystemUserUnlocked) && !inCall
+ && !isUserSwitchDisallowed;
}
/**
@@ -1022,12 +1049,22 @@ public class UserManager {
}
/**
- * Used to check if the user making this call is linked to another user. Linked users may have
+ * @hide
+ * @deprecated Use {@link #isRestrictedProfile()}
+ */
+ @Deprecated
+ public boolean isLinkedUser() {
+ return isRestrictedProfile();
+ }
+
+ /**
+ * Returns whether the caller is running as restricted profile. Restricted profile may have
* a reduced number of available apps, app restrictions and account restrictions.
* @return whether the user making this call is a linked user
* @hide
*/
- public boolean isLinkedUser() {
+ @SystemApi
+ public boolean isRestrictedProfile() {
try {
return mService.isRestricted();
} catch (RemoteException re) {
@@ -1048,6 +1085,20 @@ public class UserManager {
}
/**
+ * Returns whether the calling user has at least one restricted profile associated with it.
+ * @return
+ * @hide
+ */
+ @SystemApi
+ public boolean hasRestrictedProfiles() {
+ try {
+ return mService.hasRestrictedProfiles();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Checks if a user is a guest user.
* @return whether user is a guest user.
* @hide
@@ -1067,6 +1118,7 @@ public class UserManager {
return user != null && user.isGuest();
}
+
/**
* Checks if the calling app is running in a demo user. When running in a demo user,
* apps can be more helpful to the user, or explain their features in more detail.
@@ -2298,6 +2350,9 @@ public class UserManager {
if (!supportsMultipleUsers()) {
return false;
}
+ if (hasUserRestriction(DISALLOW_USER_SWITCH)) {
+ return false;
+ }
// If Demo Mode is on, don't show user switcher
if (isDeviceInDemoMode(mContext)) {
return false;
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index e865ed16fd24..2ffc7b028d9b 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -17,6 +17,7 @@
package android.os.storage;
import android.content.pm.IPackageMoveObserver;
+import android.os.IVoldTaskListener;
import android.os.ParcelFileDescriptor;
import android.os.storage.DiskInfo;
import android.os.storage.IStorageEventListener;
@@ -165,7 +166,7 @@ interface IStorageManager {
void forgetAllVolumes() = 56;
String getPrimaryStorageUuid() = 57;
void setPrimaryStorageUuid(in String volumeUuid, IPackageMoveObserver callback) = 58;
- long benchmark(in String volId) = 59;
+ void benchmark(in String volId, IVoldTaskListener listener) = 59;
void setDebugFlags(int flags, int mask) = 60;
void createUserKey(int userId, int serialNumber, boolean ephemeral) = 61;
void destroyUserKey(int userId) = 62;
@@ -177,7 +178,7 @@ interface IStorageManager {
boolean isConvertibleToFBE() = 68;
void addUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 70;
void fixateNewestUserKeyAuth(int userId) = 71;
- void fstrim(int flags) = 72;
+ void fstrim(int flags, IVoldTaskListener listener) = 72;
AppFuseMount mountProxyFileDescriptorBridge() = 73;
ParcelFileDescriptor openProxyFileDescriptor(int mountPointId, int fileId, int mode) = 74;
long getCacheQuotaBytes(String volumeUuid, int uid) = 75;
@@ -185,4 +186,6 @@ interface IStorageManager {
long getAllocatableBytes(String volumeUuid, int flags, String callingPackage) = 77;
void allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage) = 78;
void secdiscard(in String path) = 79;
+ void runIdleMaintenance() = 80;
+ void abortIdleMaintenance() = 81;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 6594cd070d24..0b007ddf50a1 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -42,10 +42,12 @@ import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IVold;
+import android.os.IVoldTaskListener;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.ParcelableException;
+import android.os.PersistableBundle;
import android.os.ProxyFileDescriptorCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -87,7 +89,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -884,9 +888,32 @@ public class StorageManager {
}
/** {@hide} */
+ @Deprecated
public long benchmark(String volId) {
+ final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
+ benchmark(volId, new IVoldTaskListener.Stub() {
+ @Override
+ public void onStatus(int status, PersistableBundle extras) {
+ // Ignored
+ }
+
+ @Override
+ public void onFinished(int status, PersistableBundle extras) {
+ result.complete(extras);
+ }
+ });
+ try {
+ // Convert ms to ns
+ return result.get(3, TimeUnit.MINUTES).getLong("run", Long.MAX_VALUE) * 1000000;
+ } catch (Exception e) {
+ return Long.MAX_VALUE;
+ }
+ }
+
+ /** {@hide} */
+ public void benchmark(String volId, IVoldTaskListener listener) {
try {
- return mStorageManager.benchmark(volId);
+ mStorageManager.benchmark(volId, listener);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/android/os/strictmode/CleartextNetworkViolation.java
index e28e1b38dfcd..6a0d381d9b14 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/android/os/strictmode/CleartextNetworkViolation.java
@@ -11,16 +11,13 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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 android.os.strictmode;
-package android.telephony.ims.feature;
-
-/**
- * Feature interface that provides access to RCS APIs. Currently empty until RCS support is added
- * in the framework.
- * @hide
- */
-
-public interface IRcsFeature {
+public final class CleartextNetworkViolation extends Violation {
+ /** @hide */
+ public CleartextNetworkViolation(String msg) {
+ super(msg);
+ }
}
diff --git a/core/java/android/os/strictmode/ContentUriWithoutPermissionViolation.java b/core/java/android/os/strictmode/ContentUriWithoutPermissionViolation.java
new file mode 100644
index 000000000000..e78dc79d9628
--- /dev/null
+++ b/core/java/android/os/strictmode/ContentUriWithoutPermissionViolation.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.strictmode;
+
+import android.net.Uri;
+
+public final class ContentUriWithoutPermissionViolation extends Violation {
+ /** @hide */
+ public ContentUriWithoutPermissionViolation(Uri uri, String location) {
+ super(
+ uri
+ + " exposed beyond app through "
+ + location
+ + " without permission grant flags; did you forget"
+ + " FLAG_GRANT_READ_URI_PERMISSION?");
+ }
+}
diff --git a/core/java/android/os/strictmode/CustomViolation.java b/core/java/android/os/strictmode/CustomViolation.java
new file mode 100644
index 000000000000..d4ad06715004
--- /dev/null
+++ b/core/java/android/os/strictmode/CustomViolation.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.strictmode;
+
+public final class CustomViolation extends Violation {
+ /** @hide */
+ public CustomViolation(String name) {
+ super(name);
+ }
+}
diff --git a/core/java/android/os/strictmode/DiskReadViolation.java b/core/java/android/os/strictmode/DiskReadViolation.java
new file mode 100644
index 000000000000..fad32dbf89ed
--- /dev/null
+++ b/core/java/android/os/strictmode/DiskReadViolation.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.strictmode;
+
+public final class DiskReadViolation extends Violation {
+ /** @hide */
+ public DiskReadViolation() {
+ super(null);
+ }
+}
diff --git a/core/java/android/os/strictmode/DiskWriteViolation.java b/core/java/android/os/strictmode/DiskWriteViolation.java
new file mode 100644
index 000000000000..cb9ca3815fe1
--- /dev/null
+++ b/core/java/android/os/strictmode/DiskWriteViolation.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.strictmode;
+
+public final class DiskWriteViolation extends Violation {
+ /** @hide */
+ public DiskWriteViolation() {
+ super(null);
+ }
+}
diff --git a/core/java/android/os/strictmode/FileUriExposedViolation.java b/core/java/android/os/strictmode/FileUriExposedViolation.java
new file mode 100644
index 000000000000..e3e6f8334a98
--- /dev/null
+++ b/core/java/android/os/strictmode/FileUriExposedViolation.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.strictmode;
+
+public final class FileUriExposedViolation extends Violation {
+ /** @hide */
+ public FileUriExposedViolation(String msg) {
+ super(msg);
+ }
+}
diff --git a/core/java/android/os/strictmode/InstanceCountViolation.java b/core/java/android/os/strictmode/InstanceCountViolation.java
new file mode 100644
index 000000000000..9ee2c8e5dc26
--- /dev/null
+++ b/core/java/android/os/strictmode/InstanceCountViolation.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.strictmode;
+
+public class InstanceCountViolation extends Violation {
+ private final long mInstances;
+
+ private static final StackTraceElement[] FAKE_STACK = {
+ new StackTraceElement(
+ "android.os.StrictMode", "setClassInstanceLimit", "StrictMode.java", 1)
+ };
+
+ /** @hide */
+ public InstanceCountViolation(Class klass, long instances, int limit) {
+ super(klass.toString() + "; instances=" + instances + "; limit=" + limit);
+ setStackTrace(FAKE_STACK);
+ mInstances = instances;
+ }
+
+ public long getNumberOfInstances() {
+ return mInstances;
+ }
+}
diff --git a/core/java/android/os/strictmode/IntentReceiverLeakedViolation.java b/core/java/android/os/strictmode/IntentReceiverLeakedViolation.java
new file mode 100644
index 000000000000..f416c94034c3
--- /dev/null
+++ b/core/java/android/os/strictmode/IntentReceiverLeakedViolation.java
@@ -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.
+ */
+package android.os.strictmode;
+
+public final class IntentReceiverLeakedViolation extends Violation {
+ /** @hide */
+ public IntentReceiverLeakedViolation(Throwable originStack) {
+ super(null);
+ setStackTrace(originStack.getStackTrace());
+ }
+}
diff --git a/core/java/android/os/strictmode/LeakedClosableViolation.java b/core/java/android/os/strictmode/LeakedClosableViolation.java
new file mode 100644
index 000000000000..c795a6b89ec0
--- /dev/null
+++ b/core/java/android/os/strictmode/LeakedClosableViolation.java
@@ -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.
+ */
+package android.os.strictmode;
+
+public final class LeakedClosableViolation extends Violation {
+ /** @hide */
+ public LeakedClosableViolation(String message, Throwable allocationSite) {
+ super(message);
+ initCause(allocationSite);
+ }
+}
diff --git a/core/java/android/os/strictmode/NetworkViolation.java b/core/java/android/os/strictmode/NetworkViolation.java
new file mode 100644
index 000000000000..abcf009dd98b
--- /dev/null
+++ b/core/java/android/os/strictmode/NetworkViolation.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.strictmode;
+
+public final class NetworkViolation extends Violation {
+ /** @hide */
+ public NetworkViolation() {
+ super(null);
+ }
+}
diff --git a/core/java/android/os/strictmode/ResourceMismatchViolation.java b/core/java/android/os/strictmode/ResourceMismatchViolation.java
new file mode 100644
index 000000000000..97c449938ede
--- /dev/null
+++ b/core/java/android/os/strictmode/ResourceMismatchViolation.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.strictmode;
+
+public final class ResourceMismatchViolation extends Violation {
+ /** @hide */
+ public ResourceMismatchViolation(Object tag) {
+ super(tag.toString());
+ }
+}
diff --git a/core/java/android/os/strictmode/ServiceConnectionLeakedViolation.java b/core/java/android/os/strictmode/ServiceConnectionLeakedViolation.java
new file mode 100644
index 000000000000..2d6b58f031c8
--- /dev/null
+++ b/core/java/android/os/strictmode/ServiceConnectionLeakedViolation.java
@@ -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.
+ */
+package android.os.strictmode;
+
+public final class ServiceConnectionLeakedViolation extends Violation {
+ /** @hide */
+ public ServiceConnectionLeakedViolation(Throwable originStack) {
+ super(null);
+ setStackTrace(originStack.getStackTrace());
+ }
+}
diff --git a/core/java/android/os/strictmode/SqliteObjectLeakedViolation.java b/core/java/android/os/strictmode/SqliteObjectLeakedViolation.java
new file mode 100644
index 000000000000..020022070475
--- /dev/null
+++ b/core/java/android/os/strictmode/SqliteObjectLeakedViolation.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.strictmode;
+
+public final class SqliteObjectLeakedViolation extends Violation {
+
+ /** @hide */
+ public SqliteObjectLeakedViolation(String message, Throwable originStack) {
+ super(message);
+ initCause(originStack);
+ }
+}
diff --git a/core/java/android/os/strictmode/UnbufferedIoViolation.java b/core/java/android/os/strictmode/UnbufferedIoViolation.java
new file mode 100644
index 000000000000..a5c326d1b98e
--- /dev/null
+++ b/core/java/android/os/strictmode/UnbufferedIoViolation.java
@@ -0,0 +1,28 @@
+/*
+ * 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.os.strictmode;
+
+import android.os.StrictMode.ThreadPolicy.Builder;
+
+/**
+ * See #{@link Builder#detectUnbufferedIo()}
+ */
+public final class UnbufferedIoViolation extends Violation {
+ /** @hide */
+ public UnbufferedIoViolation() {
+ super(null);
+ }
+}
diff --git a/core/java/android/os/strictmode/UntaggedSocketViolation.java b/core/java/android/os/strictmode/UntaggedSocketViolation.java
new file mode 100644
index 000000000000..836a8b9dc633
--- /dev/null
+++ b/core/java/android/os/strictmode/UntaggedSocketViolation.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.strictmode;
+
+public final class UntaggedSocketViolation extends Violation {
+ /** @hide */
+ public static final String MESSAGE =
+ "Untagged socket detected; use"
+ + " TrafficStats.setThreadSocketTag() to track all network usage";
+
+ /** @hide */
+ public UntaggedSocketViolation() {
+ super(MESSAGE);
+ }
+}
diff --git a/core/java/android/os/strictmode/Violation.java b/core/java/android/os/strictmode/Violation.java
new file mode 100644
index 000000000000..31c7d584fd65
--- /dev/null
+++ b/core/java/android/os/strictmode/Violation.java
@@ -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.
+ */
+
+package android.os.strictmode;
+
+/** Root class for all StrictMode violations. */
+public abstract class Violation extends Throwable {
+ Violation(String message) {
+ super(message);
+ }
+}
diff --git a/core/java/android/os/strictmode/WebViewMethodCalledOnWrongThreadViolation.java b/core/java/android/os/strictmode/WebViewMethodCalledOnWrongThreadViolation.java
new file mode 100644
index 000000000000..c328d1470b53
--- /dev/null
+++ b/core/java/android/os/strictmode/WebViewMethodCalledOnWrongThreadViolation.java
@@ -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.
+ */
+package android.os.strictmode;
+
+public final class WebViewMethodCalledOnWrongThreadViolation extends Violation {
+ /** @hide */
+ public WebViewMethodCalledOnWrongThreadViolation(Throwable originStack) {
+ super(null);
+ setStackTrace(originStack.getStackTrace());
+ }
+}
diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java
index 73fa01e59201..4c556efaecd0 100644
--- a/core/java/android/preference/PreferenceFragment.java
+++ b/core/java/android/preference/PreferenceFragment.java
@@ -23,7 +23,6 @@ import android.app.Fragment;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -105,7 +104,10 @@ import android.widget.TextView;
*
* @see Preference
* @see PreferenceScreen
+ *
+ * @deprecated Use {@link android.support.v7.preference.PreferenceFragmentCompat}
*/
+@Deprecated
public abstract class PreferenceFragment extends Fragment implements
PreferenceManager.OnPreferenceTreeClickListener {
@@ -146,7 +148,11 @@ public abstract class PreferenceFragment extends Fragment implements
* Interface that PreferenceFragment's containing activity should
* implement to be able to process preference items that wish to
* switch to a new fragment.
+ *
+ * @deprecated Use {@link
+ * android.support.v7.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCallback}
*/
+ @Deprecated
public interface OnPreferenceStartFragmentCallback {
/**
* Called when the user has clicked on a Preference that has
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 13e1e26b51c3..32d68cd9f869 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -81,6 +81,13 @@ public final class MediaStore {
public static final String UNHIDE_CALL = "unhide";
/**
+ * The method name used by the media scanner service to reload all localized ringtone titles due
+ * to a locale change.
+ * @hide
+ */
+ public static final String RETRANSLATE_CALL = "update_titles";
+
+ /**
* This is for internal use by the media scanner only.
* Name of the (optional) Uri parameter that determines whether to skip deleting
* the file pointed to by the _data column, when deleting the database entry.
@@ -1358,6 +1365,18 @@ public final class MediaStore {
* @hide
*/
public static final String GENRE = "genre";
+
+ /**
+ * The resource URI of a localized title, if any
+ * <P>Type: TEXT</P>
+ * Conforms to this pattern:
+ * Scheme: {@link ContentResolver.SCHEME_ANDROID_RESOURCE}
+ * Authority: Package Name of ringtone title provider
+ * First Path Segment: Type of resource (must be "string")
+ * Second Path Segment: Resource ID of title
+ * @hide
+ */
+ public static final String TITLE_RESOURCE_URI = "title_resource_uri";
}
/**
diff --git a/core/java/android/provider/SearchIndexableData.java b/core/java/android/provider/SearchIndexableData.java
index 5e0a76de8d27..a60be5363d62 100644
--- a/core/java/android/provider/SearchIndexableData.java
+++ b/core/java/android/provider/SearchIndexableData.java
@@ -56,6 +56,8 @@ public abstract class SearchIndexableData {
/**
* The key for the data. This is application specific. Should be unique per data as the data
* should be able to be retrieved by the key.
+ * <p/>
+ * This is required for indexing to work.
*/
public String key;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2d6a7b0133aa..6decc3050f64 100755..100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -66,6 +66,7 @@ import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.speech.tts.TextToSpeech;
+import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.AndroidException;
import android.util.ArrayMap;
@@ -211,8 +212,13 @@ public final class Settings {
/** @hide */
public static final String EXTRA_NETWORK_TEMPLATE = "network_template";
- /** @hide */
- public static final String EXTRA_SUB_ID = "sub_id";
+
+ /**
+ * An int extra specifying a subscription ID.
+ *
+ * @see android.telephony.SubscriptionInfo#getSubscriptionId
+ */
+ public static final String EXTRA_SUB_ID = "android.provider.extra.SUB_ID";
/**
* Activity Action: Modify Airplane mode settings using a voice command.
@@ -916,6 +922,9 @@ public final class Settings {
* In some cases, a matching Activity may not exist, so ensure you
* safeguard against this.
* <p>
+ * The subscription ID of the subscription for which available network operators should be
+ * displayed may be optionally specified with {@link #EXTRA_SUB_ID}.
+ * <p>
* Input: Nothing.
* <p>
* Output: Nothing.
@@ -2105,6 +2114,9 @@ public final class Settings {
* functions for accessing individual settings entries.
*/
public static final class System extends NameValueTable {
+ // NOTE: If you add new settings here, be sure to add them to
+ // com.android.providers.settings.SettingsProtoDumpUtil#dumpProtoSystemSettingsLocked.
+
private static final float DEFAULT_FONT_SCALE = 1.0f;
/** @hide */
@@ -4554,6 +4566,9 @@ public final class Settings {
* APIs for those values, not modified directly by applications.
*/
public static final class Secure extends NameValueTable {
+ // NOTE: If you add new settings here, be sure to add them to
+ // com.android.providers.settings.SettingsProtoDumpUtil#dumpProtoSecureSettingsLocked.
+
/**
* The content:// style URL for this table
*/
@@ -5309,6 +5324,15 @@ public final class Settings {
public static final String AUTOFILL_SERVICE = "autofill_service";
/**
+ * Experimental autofill feature.
+ *
+ * <p>TODO(b/67867469): remove once feature is finished
+ * @hide
+ */
+ @TestApi
+ public static final String AUTOFILL_FEATURE_FIELD_DETECTION = "autofill_field_detection";
+
+ /**
* @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead
*/
@Deprecated
@@ -7547,6 +7571,9 @@ public final class Settings {
* explicitly modify through the system UI or specialized APIs for those values.
*/
public static final class Global extends NameValueTable {
+ // NOTE: If you add new settings here, be sure to add them to
+ // com.android.providers.settings.SettingsProtoDumpUtil#dumpProtoGlobalSettingsLocked.
+
/**
* The content:// style URL for global secure settings items. Not public.
*/
@@ -8012,28 +8039,40 @@ public final class Settings {
public static final String HDMI_SYSTEM_AUDIO_CONTROL_ENABLED =
"hdmi_system_audio_control_enabled";
- /**
- * Whether TV will automatically turn on upon reception of the CEC command
- * &lt;Text View On&gt; or &lt;Image View On&gt;. (0 = false, 1 = true)
- * @hide
- */
- public static final String HDMI_CONTROL_AUTO_WAKEUP_ENABLED =
- "hdmi_control_auto_wakeup_enabled";
+ /**
+ * Whether TV will automatically turn on upon reception of the CEC command
+ * &lt;Text View On&gt; or &lt;Image View On&gt;. (0 = false, 1 = true)
+ *
+ * @hide
+ */
+ public static final String HDMI_CONTROL_AUTO_WAKEUP_ENABLED =
+ "hdmi_control_auto_wakeup_enabled";
- /**
- * Whether TV will also turn off other CEC devices when it goes to standby mode.
- * (0 = false, 1 = true)
- * @hide
- */
- public static final String HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED =
- "hdmi_control_auto_device_off_enabled";
+ /**
+ * Whether TV will also turn off other CEC devices when it goes to standby mode.
+ * (0 = false, 1 = true)
+ *
+ * @hide
+ */
+ public static final String HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED =
+ "hdmi_control_auto_device_off_enabled";
- /**
- * The interval in milliseconds at which location requests will be throttled when they are
- * coming from the background.
- * @hide
- */
- public static final String LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS =
+ /**
+ * If <b>true</b>, enables out-of-the-box execution for priv apps.
+ * Default: false
+ * Values: 0 = false, 1 = true
+ *
+ * @hide
+ */
+ public static final String PRIV_APP_OOB_ENABLED = "priv_app_oob_enabled";
+
+ /**
+ * The interval in milliseconds at which location requests will be throttled when they are
+ * coming from the background.
+ *
+ * @hide
+ */
+ public static final String LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS =
"location_background_throttle_interval_ms";
/**
@@ -8493,6 +8532,13 @@ public final class Settings {
public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
"network_metered_multipath_preference";
+ /**
+ * Network watchlist last report time.
+ * @hide
+ */
+ public static final String NETWORK_WATCHLIST_LAST_REPORT_TIME =
+ "network_watchlist_last_report_time";
+
/**
* The thresholds of the wifi throughput badging (SD, HD etc.) as a comma-delimited list of
* colon-delimited key-value pairs. The key is the badging enum value defined in
@@ -9285,11 +9331,20 @@ public final class Settings {
public static final String DEFAULT_DNS_SERVER = "default_dns_server";
/**
- * Whether to disable DNS over TLS (boolean)
+ * The requested Private DNS mode (string), and an accompanying specifier (string).
+ *
+ * Currently, the specifier holds the chosen provider name when the mode requests
+ * a specific provider. It may be used to store the provider name even when the
+ * mode changes so that temporarily disabling and re-enabling the specific
+ * provider mode does not necessitate retyping the provider hostname.
*
* @hide
*/
- public static final String DNS_TLS_DISABLED = "dns_tls_disabled";
+ public static final String PRIVATE_DNS_MODE = "private_dns_mode";
+ /**
+ * @hide
+ */
+ public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
/** {@hide} */
public static final String
@@ -9423,6 +9478,16 @@ public final class Settings {
public static final String BATTERY_SAVER_CONSTANTS = "battery_saver_constants";
/**
+ * Battery Saver device specific settings
+ * This is encoded as a key=value list, separated by commas.
+ * See {@link com.android.server.power.BatterySaverPolicy} for the details.
+ *
+ * @hide
+ */
+ public static final String BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS =
+ "battery_saver_device_specific_constants";
+
+ /**
* Battery anomaly detection specific settings
* This is encoded as a key=value list, separated by commas.
* wakeup_blacklisted_tags is a string, encoded as a set of tags, encoded via
@@ -10099,12 +10164,17 @@ public final class Settings {
public static final String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt";
/**
- * Whether the Volte is enabled
+ * Whether the Volte is enabled. If this setting is not set then we use the Carrier Config
+ * value {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
* <p>
* Type: int (0 for false, 1 for true)
* @hide
+ * @deprecated Use {@link android.telephony.SubscriptionManager#ENHANCED_4G_MODE_ENABLED}
+ * instead.
*/
- public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+ @Deprecated
+ public static final String ENHANCED_4G_MODE_ENABLED =
+ SubscriptionManager.ENHANCED_4G_MODE_ENABLED;
/**
* Whether VT (Video Telephony over IMS) is enabled
@@ -10112,8 +10182,10 @@ public final class Settings {
* Type: int (0 for false, 1 for true)
*
* @hide
+ * @deprecated Use {@link android.telephony.SubscriptionManager#VT_IMS_ENABLED} instead.
*/
- public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+ @Deprecated
+ public static final String VT_IMS_ENABLED = SubscriptionManager.VT_IMS_ENABLED;
/**
* Whether WFC is enabled
@@ -10121,8 +10193,10 @@ public final class Settings {
* Type: int (0 for false, 1 for true)
*
* @hide
+ * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ENABLED} instead.
*/
- public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+ @Deprecated
+ public static final String WFC_IMS_ENABLED = SubscriptionManager.WFC_IMS_ENABLED;
/**
* WFC mode on home/non-roaming network.
@@ -10130,8 +10204,10 @@ public final class Settings {
* Type: int - 2=Wi-Fi preferred, 1=Cellular preferred, 0=Wi-Fi only
*
* @hide
+ * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_MODE} instead.
*/
- public static final String WFC_IMS_MODE = "wfc_ims_mode";
+ @Deprecated
+ public static final String WFC_IMS_MODE = SubscriptionManager.WFC_IMS_MODE;
/**
* WFC mode on roaming network.
@@ -10139,8 +10215,11 @@ public final class Settings {
* Type: int - see {@link #WFC_IMS_MODE} for values
*
* @hide
+ * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ROAMING_MODE}
+ * instead.
*/
- public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
+ @Deprecated
+ public static final String WFC_IMS_ROAMING_MODE = SubscriptionManager.WFC_IMS_ROAMING_MODE;
/**
* Whether WFC roaming is enabled
@@ -10148,8 +10227,12 @@ public final class Settings {
* Type: int (0 for false, 1 for true)
*
* @hide
+ * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ROAMING_ENABLED}
+ * instead
*/
- public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+ @Deprecated
+ public static final String WFC_IMS_ROAMING_ENABLED =
+ SubscriptionManager.WFC_IMS_ROAMING_ENABLED;
/**
* Whether user can enable/disable LTE as a preferred network. A carrier might control
@@ -10375,7 +10458,9 @@ public final class Settings {
DOCK_AUDIO_MEDIA_ENABLED,
ENCODED_SURROUND_OUTPUT,
LOW_POWER_MODE_TRIGGER_LEVEL,
- BLUETOOTH_ON
+ BLUETOOTH_ON,
+ PRIVATE_DNS_MODE,
+ PRIVATE_DNS_SPECIFIER
};
/** @hide */
@@ -10828,7 +10913,7 @@ public final class Settings {
/** User preferred subscriptions setting.
* This holds the details of the user selected subscription from the card and
- * the activation status. Each settings string have the coma separated values
+ * the activation status. Each settings string have the comma separated values
* iccId,appType,appId,activationStatus,3gppIndex,3gpp2Index
* @hide
*/
diff --git a/core/java/android/security/KeystoreArguments.aidl b/core/java/android/security/KeystoreArguments.aidl
index d636414a05e3..dc8ed50182ed 100644
--- a/core/java/android/security/KeystoreArguments.aidl
+++ b/core/java/android/security/KeystoreArguments.aidl
@@ -17,4 +17,4 @@
package android.security;
/* @hide */
-parcelable KeystoreArguments;
+parcelable KeystoreArguments cpp_header "keystore/KeystoreArguments.h";
diff --git a/core/java/android/security/keymaster/ExportResult.aidl b/core/java/android/security/keymaster/ExportResult.aidl
index 4d9b2de6632f..17486531a3f0 100644
--- a/core/java/android/security/keymaster/ExportResult.aidl
+++ b/core/java/android/security/keymaster/ExportResult.aidl
@@ -17,4 +17,4 @@
package android.security.keymaster;
/* @hide */
-parcelable ExportResult;
+parcelable ExportResult cpp_header "keystore/ExportResult.h";
diff --git a/core/java/android/security/keymaster/KeyCharacteristics.aidl b/core/java/android/security/keymaster/KeyCharacteristics.aidl
index be739d3223ab..32e75ad267b2 100644
--- a/core/java/android/security/keymaster/KeyCharacteristics.aidl
+++ b/core/java/android/security/keymaster/KeyCharacteristics.aidl
@@ -17,4 +17,4 @@
package android.security.keymaster;
/* @hide */
-parcelable KeyCharacteristics;
+parcelable KeyCharacteristics cpp_header "keystore/KeyCharacteristics.h";
diff --git a/core/java/android/security/keymaster/KeymasterArguments.aidl b/core/java/android/security/keymaster/KeymasterArguments.aidl
index 1a73206512e9..44d9f0954781 100644
--- a/core/java/android/security/keymaster/KeymasterArguments.aidl
+++ b/core/java/android/security/keymaster/KeymasterArguments.aidl
@@ -17,4 +17,4 @@
package android.security.keymaster;
/* @hide */
-parcelable KeymasterArguments;
+parcelable KeymasterArguments cpp_header "keystore/KeymasterArguments.h";
diff --git a/core/java/android/security/keymaster/KeymasterBlob.aidl b/core/java/android/security/keymaster/KeymasterBlob.aidl
index b7cd1c900efb..5c5db9ec314b 100644
--- a/core/java/android/security/keymaster/KeymasterBlob.aidl
+++ b/core/java/android/security/keymaster/KeymasterBlob.aidl
@@ -17,4 +17,4 @@
package android.security.keymaster;
/* @hide */
-parcelable KeymasterBlob;
+parcelable KeymasterBlob cpp_header "keystore/KeymasterBlob.h";
diff --git a/core/java/android/security/keymaster/KeymasterCertificateChain.aidl b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
index dc1876aaaebd..ddb5cae1a254 100644
--- a/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
+++ b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
@@ -17,4 +17,4 @@
package android.security.keymaster;
/* @hide */
-parcelable KeymasterCertificateChain;
+parcelable KeymasterCertificateChain cpp_header "keystore/KeymasterCertificateChain.h";
diff --git a/core/java/android/security/keymaster/OperationResult.aidl b/core/java/android/security/keymaster/OperationResult.aidl
index ed26c8dd404b..db689d46521a 100644
--- a/core/java/android/security/keymaster/OperationResult.aidl
+++ b/core/java/android/security/keymaster/OperationResult.aidl
@@ -17,4 +17,4 @@
package android.security.keymaster;
/* @hide */
-parcelable OperationResult;
+parcelable OperationResult cpp_header "keystore/OperationResult.h";
diff --git a/core/java/android/service/autofill/FieldsDetection.java b/core/java/android/service/autofill/FieldsDetection.java
new file mode 100644
index 000000000000..550ecf687349
--- /dev/null
+++ b/core/java/android/service/autofill/FieldsDetection.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.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 b1857b303b36..736d9ef48d04 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -19,6 +19,7 @@ package android.service.autofill;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.content.IntentSender;
import android.os.Bundle;
import android.os.Parcel;
@@ -164,6 +165,10 @@ public final class FillEventHistory implements Parcelable {
dest.writeStringList(event.mManuallyFilledDatasetIds.get(j));
}
}
+ dest.writeString(event.mDetectedRemoteId);
+ if (event.mDetectedRemoteId != null) {
+ dest.writeInt(event.mDetectedFieldScore);
+ }
}
}
}
@@ -226,6 +231,7 @@ public final class FillEventHistory implements Parcelable {
* <p>See {@link android.view.autofill.AutofillManager} for more information about autofill
* contexts.
*/
+ // TODO(b/67867469): update with field detection behavior
public static final int TYPE_CONTEXT_COMMITTED = 4;
/** @hide */
@@ -253,6 +259,9 @@ public final class FillEventHistory implements Parcelable {
@Nullable private final ArrayList<AutofillId> mManuallyFilledFieldIds;
@Nullable private final ArrayList<ArrayList<String>> mManuallyFilledDatasetIds;
+ @Nullable private final String mDetectedRemoteId;
+ private final int mDetectedFieldScore;
+
/**
* Returns the type of the event.
*
@@ -355,6 +364,39 @@ public final class FillEventHistory implements Parcelable {
}
/**
+ * 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.
+ *
+ * <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}.
+ *
+ * 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) {
+ return Collections.emptyMap();
+ }
+
+ final ArrayMap<String, Integer> map = new ArrayMap<>(1);
+ map.put(mDetectedRemoteId, mDetectedFieldScore);
+ return map;
+ }
+
+ /**
* Returns which fields were available on datasets provided by the service but manually
* entered by the user.
*
@@ -430,7 +472,6 @@ public final class FillEventHistory implements Parcelable {
* and belonged to datasets.
* @param manuallyFilledDatasetIds The ids of datasets that had values matching the
* respective entry on {@code manuallyFilledFieldIds}.
- *
* @throws IllegalArgumentException If the length of {@code changedFieldIds} and
* {@code changedDatasetIds} doesn't match.
* @throws IllegalArgumentException If the length of {@code manuallyFilledFieldIds} and
@@ -438,13 +479,15 @@ public final class FillEventHistory implements Parcelable {
*
* @hide
*/
+ // TODO(b/67867469): document detection field parameters once stable
public Event(int eventType, @Nullable String datasetId, @Nullable Bundle clientState,
@Nullable List<String> selectedDatasetIds,
@Nullable ArraySet<String> ignoredDatasetIds,
@Nullable ArrayList<AutofillId> changedFieldIds,
@Nullable ArrayList<String> changedDatasetIds,
@Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
- @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds) {
+ @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
+ @Nullable String detectedRemoteId, int detectedFieldScore) {
mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_CONTEXT_COMMITTED,
"eventType");
mDatasetId = datasetId;
@@ -467,6 +510,8 @@ public final class FillEventHistory implements Parcelable {
}
mManuallyFilledFieldIds = manuallyFilledFieldIds;
mManuallyFilledDatasetIds = manuallyFilledDatasetIds;
+ mDetectedRemoteId = detectedRemoteId;
+ mDetectedFieldScore = detectedFieldScore;
}
@Override
@@ -479,6 +524,8 @@ public final class FillEventHistory implements Parcelable {
+ ", changedDatasetsIds=" + mChangedDatasetIds
+ ", manuallyFilledFieldIds=" + mManuallyFilledFieldIds
+ ", manuallyFilledDatasetIds=" + mManuallyFilledDatasetIds
+ + ", detectedRemoteId=" + mDetectedRemoteId
+ + ", detectedFieldScore=" + mDetectedFieldScore
+ "]";
}
}
@@ -514,11 +561,15 @@ public final class FillEventHistory implements Parcelable {
} else {
manuallyFilledDatasetIds = null;
}
+ final String detectedRemoteId = parcel.readString();
+ final int detectedFieldScore = detectedRemoteId == null ? -1
+ : parcel.readInt();
selection.addEvent(new Event(eventType, datasetId, clientState,
selectedDatasetIds, ignoredDatasets,
changedFieldIds, changedDatasetIds,
- manuallyFilledFieldIds, manuallyFilledDatasetIds));
+ manuallyFilledFieldIds, manuallyFilledDatasetIds,
+ detectedRemoteId, detectedFieldScore));
}
return selection;
}
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 2f6342af2b3b..4e6a88457484 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -22,6 +22,7 @@ import static android.view.autofill.Helper.sDebug;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.app.Activity;
import android.content.IntentSender;
import android.content.pm.ParceledListSlice;
@@ -75,6 +76,7 @@ public final class FillResponse implements Parcelable {
private final @Nullable AutofillId[] mAuthenticationIds;
private final @Nullable AutofillId[] mIgnoredIds;
private final long mDisableDuration;
+ private final @Nullable FieldsDetection mFieldsDetection;
private final int mFlags;
private int mRequestId;
@@ -87,6 +89,7 @@ public final class FillResponse implements Parcelable {
mAuthenticationIds = builder.mAuthenticationIds;
mIgnoredIds = builder.mIgnoredIds;
mDisableDuration = builder.mDisableDuration;
+ mFieldsDetection = builder.mFieldsDetection;
mFlags = builder.mFlags;
mRequestId = INVALID_REQUEST_ID;
}
@@ -132,6 +135,11 @@ public final class FillResponse implements Parcelable {
}
/** @hide */
+ public @Nullable FieldsDetection getFieldsDetection() {
+ return mFieldsDetection;
+ }
+
+ /** @hide */
public int getFlags() {
return mFlags;
}
@@ -167,6 +175,7 @@ public final class FillResponse implements Parcelable {
private AutofillId[] mAuthenticationIds;
private AutofillId[] mIgnoredIds;
private long mDisableDuration;
+ private FieldsDetection mFieldsDetection;
private int mFlags;
private boolean mDestroyed;
@@ -315,6 +324,25 @@ public final class FillResponse implements Parcelable {
}
/**
+ * TODO(b/67867469):
+ * - javadoc it
+ * - javadoc how to check results
+ * - unhide
+ * - unhide / remove testApi
+ * - throw exception (and document) if response has datasets or saveinfo
+ * - throw exception (and document) if id on fieldsDetection is ignored
+ *
+ * @hide
+ */
+ @TestApi
+ public Builder setFieldsDetection(@NonNull FieldsDetection fieldsDetection) {
+ throwIfDestroyed();
+ throwIfDisableAutofillCalled();
+ mFieldsDetection = Preconditions.checkNotNull(fieldsDetection);
+ return this;
+ }
+
+ /**
* Sets flags changing the response behavior.
*
* @param flags a combination of {@link #FLAG_TRACK_CONTEXT_COMMITED} and
@@ -365,7 +393,8 @@ public final class FillResponse implements Parcelable {
if (duration <= 0) {
throw new IllegalArgumentException("duration must be greater than 0");
}
- if (mAuthentication != null || mDatasets != null || mSaveInfo != null) {
+ if (mAuthentication != null || mDatasets != null || mSaveInfo != null
+ || mFieldsDetection != null) {
throw new IllegalStateException("disableAutofill() must be the only method called");
}
@@ -388,11 +417,11 @@ public final class FillResponse implements Parcelable {
*/
public FillResponse build() {
throwIfDestroyed();
-
if (mAuthentication == null && mDatasets == null && mSaveInfo == null
- && mDisableDuration == 0) {
- throw new IllegalStateException("need to provide at least one DataSet or a "
- + "SaveInfo or an authentication with a presentation or disable autofill");
+ && mDisableDuration == 0 && mFieldsDetection == null) {
+ throw new IllegalStateException("need to provide: at least one DataSet, or a "
+ + "SaveInfo, or an authentication with a presentation, "
+ + "or a FieldsDetection, or disable autofill");
}
mDestroyed = true;
return new FillResponse(this);
@@ -430,6 +459,7 @@ public final class FillResponse implements Parcelable {
.append(", ignoredIds=").append(Arrays.toString(mIgnoredIds))
.append(", disableDuration=").append(mDisableDuration)
.append(", flags=").append(mFlags)
+ .append(", fieldDetection=").append(mFieldsDetection)
.append("]")
.toString();
}
@@ -453,6 +483,7 @@ public final class FillResponse implements Parcelable {
parcel.writeParcelable(mPresentation, flags);
parcel.writeParcelableArray(mIgnoredIds, flags);
parcel.writeLong(mDisableDuration);
+ parcel.writeParcelable(mFieldsDetection, flags);
parcel.writeInt(mFlags);
parcel.writeInt(mRequestId);
}
@@ -488,6 +519,10 @@ public final class FillResponse implements Parcelable {
if (disableDuration > 0) {
builder.disableAutofill(disableDuration);
}
+ final FieldsDetection fieldsDetection = parcel.readParcelable(null);
+ if (fieldsDetection != null) {
+ builder.setFieldsDetection(fieldsDetection);
+ }
builder.setFlags(parcel.readInt());
final FillResponse response = builder.build();
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 6a15adeda9ab..2a245d046486 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -680,8 +680,8 @@ public class DreamService extends Service implements Window.Callback {
*
* @return The screen state to use while dozing, such as {@link Display#STATE_ON},
* {@link Display#STATE_DOZE}, {@link Display#STATE_DOZE_SUSPEND},
- * or {@link Display#STATE_OFF}, or {@link Display#STATE_UNKNOWN} for the default
- * behavior.
+ * {@link Display#STATE_ON_SUSPEND}, {@link Display#STATE_OFF}, or {@link Display#STATE_UNKNOWN}
+ * for the default behavior.
*
* @see #setDozeScreenState
* @hide For use by system UI components only.
@@ -700,12 +700,18 @@ public class DreamService extends Service implements Window.Callback {
* perform transitions between states while dozing to conserve power and
* achieve various effects.
* </p><p>
- * It is recommended that the state be set to {@link Display#STATE_DOZE_SUSPEND}
- * once the dream has completely finished drawing and before it releases its wakelock
- * to allow the display hardware to be fully suspended. While suspended, the
- * display will preserve its on-screen contents or hand off control to dedicated
- * doze hardware if the devices supports it. If the doze suspend state is
- * used, the dream must make sure to set the mode back
+ * Some devices will have dedicated hardware ("Sidekick") to animate
+ * the display content while the CPU sleeps. If the dream and the hardware support
+ * this, {@link Display#STATE_ON_SUSPEND} or {@link Display#STATE_DOZE_SUSPEND}
+ * will switch control to the Sidekick.
+ * </p><p>
+ * If not using Sidekick, it is recommended that the state be set to
+ * {@link Display#STATE_DOZE_SUSPEND} once the dream has completely
+ * finished drawing and before it releases its wakelock
+ * to allow the display hardware to be fully suspended. While suspended,
+ * the display will preserve its on-screen contents.
+ * </p><p>
+ * If the doze suspend state is used, the dream must make sure to set the mode back
* to {@link Display#STATE_DOZE} or {@link Display#STATE_ON} before drawing again
* since the display updates may be ignored and not seen by the user otherwise.
* </p><p>
@@ -716,8 +722,8 @@ public class DreamService extends Service implements Window.Callback {
*
* @param state The screen state to use while dozing, such as {@link Display#STATE_ON},
* {@link Display#STATE_DOZE}, {@link Display#STATE_DOZE_SUSPEND},
- * or {@link Display#STATE_OFF}, or {@link Display#STATE_UNKNOWN} for the default
- * behavior.
+ * {@link Display#STATE_ON_SUSPEND}, {@link Display#STATE_OFF}, or {@link Display#STATE_UNKNOWN}
+ * for the default behavior.
*
* @hide For use by system UI components only.
*/
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index 0c2e4b7ada26..cd233b831522 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -97,6 +97,10 @@ public abstract class EuiccService extends Service {
public static final String ACTION_RESOLVE_NO_PRIVILEGES =
"android.service.euicc.action.RESOLVE_NO_PRIVILEGES";
+ /** Ask the user to input carrier confirmation code. */
+ public static final String ACTION_RESOLVE_CONFIRMATION_CODE =
+ "android.service.euicc.action.RESOLVE_CONFIRMATION_CODE";
+
/** Intent extra set for resolution requests containing the package name of the calling app. */
public static final String EXTRA_RESOLUTION_CALLING_PACKAGE =
"android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE";
@@ -105,6 +109,8 @@ public abstract class EuiccService extends Service {
public static final int RESULT_OK = 0;
/** Result code indicating that an active SIM must be deactivated to perform the operation. */
public static final int RESULT_MUST_DEACTIVATE_SIM = -1;
+ /** Result code indicating that the user must input a carrier confirmation code. */
+ public static final int RESULT_NEED_CONFIRMATION_CODE = -2;
// New predefined codes should have negative values.
/** Start of implementation-specific error results. */
@@ -119,10 +125,13 @@ public abstract class EuiccService extends Service {
RESOLUTION_ACTIONS = new ArraySet<>();
RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM);
RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_NO_PRIVILEGES);
+ RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_CONFIRMATION_CODE);
}
/** Boolean extra for resolution actions indicating whether the user granted consent. */
public static final String RESOLUTION_EXTRA_CONSENT = "consent";
+ /** String extra for resolution actions indicating the carrier confirmation code. */
+ public static final String RESOLUTION_EXTRA_CONFIRMATION_CODE = "confirmation_code";
private final IEuiccService.Stub mStubWrapper;
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
index 3e992ec36426..6fc689ab07cf 100644
--- a/core/java/android/service/notification/ConditionProviderService.java
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -18,6 +18,8 @@ package android.service.notification;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.app.ActivityManager;
import android.app.INotificationManager;
import android.app.Service;
import android.content.ComponentName;
@@ -56,6 +58,8 @@ import android.util.Log;
* &lt;/meta-data>
* &lt;/service></pre>
*
+ * <p> Condition providers cannot be bound by the system on
+ * {@link ActivityManager#isLowRamDevice() low ram} devices</p>
*/
public abstract class ConditionProviderService extends Service {
private final String TAG = ConditionProviderService.class.getSimpleName()
@@ -197,7 +201,11 @@ public abstract class ConditionProviderService extends Service {
return mProvider;
}
- private boolean isBound() {
+ /**
+ * @hide
+ */
+ @TestApi
+ public boolean isBound() {
if (mProvider == null) {
Log.w(TAG, "Condition provider service not yet bound.");
return false;
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 08d3118b09f6..dac663e765ea 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.app.ActivityManager;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.Notification.Builder;
@@ -82,6 +83,8 @@ import java.util.List;
* method is the <i>only</i> one that is safe to call before {@link #onListenerConnected()}
* or after {@link #onListenerDisconnected()}.
* </p>
+ * <p> Notification listeners cannot get notification access or be bound by the system on
+ * {@link ActivityManager#isLowRamDevice() low ram} devices</p>
*/
public abstract class NotificationListenerService extends Service {
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index fc1d4873c9cb..2a2722082a7d 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -16,6 +16,7 @@
package android.util;
+import android.content.Context;
import android.os.SystemProperties;
import android.text.TextUtils;
@@ -37,7 +38,7 @@ public class FeatureFlagUtils {
* @param feature the flag name
* @return true if the flag is enabled (either by default in system, or override by user)
*/
- public static boolean isEnabled(String feature) {
+ public static boolean isEnabled(Context context, String feature) {
// Tries to get feature flag from system property.
// Step 1: check if feature flag has any override. Flag name: sys.fflag.override.<feature>
String value = SystemProperties.get(FFLAG_OVERRIDE_PREFIX + feature);
diff --git a/core/java/android/util/KeyValueListParser.java b/core/java/android/util/KeyValueListParser.java
index be531ff35991..d50395e223e5 100644
--- a/core/java/android/util/KeyValueListParser.java
+++ b/core/java/android/util/KeyValueListParser.java
@@ -147,4 +147,18 @@ public class KeyValueListParser {
}
return def;
}
+
+ /**
+ * @return the number of keys.
+ */
+ public int size() {
+ return mValues.size();
+ }
+
+ /**
+ * @return the key at {@code index}. Use with {@link #size()} to enumerate all key-value pairs.
+ */
+ public String keyAt(int index) {
+ return mValues.keyAt(index);
+ }
}
diff --git a/core/java/android/util/StatsManager.java b/core/java/android/util/StatsManager.java
new file mode 100644
index 000000000000..55b33a617a60
--- /dev/null
+++ b/core/java/android/util/StatsManager.java
@@ -0,0 +1,134 @@
+/*
+ * 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.util;
+
+import android.Manifest;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.os.IBinder;
+import android.os.IStatsManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+/**
+ * API for StatsD clients to send configurations and retrieve data.
+ *
+ * @hide
+ */
+@SystemApi
+public final class StatsManager {
+ IStatsManager mService;
+ private static final String TAG = "StatsManager";
+
+ /**
+ * Constructor for StatsManagerClient.
+ *
+ * @hide
+ */
+ public StatsManager() {
+ }
+
+ /**
+ * Clients can send a configuration and simultaneously registers the name of a broadcast
+ * receiver that listens for when it should request data.
+ *
+ * @param configKey An arbitrary string that allows clients to track the configuration.
+ * @param config Wire-encoded StatsDConfig proto that specifies metrics (and all
+ * dependencies eg, conditions and matchers).
+ * @param pkg The package name to receive the broadcast.
+ * @param cls The name of the class that receives the broadcast.
+ * @return true if successful
+ */
+ @RequiresPermission(Manifest.permission.DUMP)
+ public boolean addConfiguration(String configKey, byte[] config, String pkg, String cls) {
+ synchronized (this) {
+ try {
+ IStatsManager service = getIStatsManagerLocked();
+ if (service == null) {
+ throw new RuntimeException("StatsD service connection lost");
+ }
+ return service.addConfiguration(configKey, config, pkg, cls);
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Failed to connect to statsd when getting data");
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Remove a configuration from logging.
+ *
+ * @param configKey Configuration key to remove.
+ * @return true if successful
+ */
+ @RequiresPermission(Manifest.permission.DUMP)
+ public boolean removeConfiguration(String configKey) {
+ synchronized (this) {
+ try {
+ IStatsManager service = getIStatsManagerLocked();
+ if (service == null) {
+ throw new RuntimeException("StatsD service connection lost");
+ }
+ return service.removeConfiguration(configKey);
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Failed to connect to statsd when getting data");
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Clients can request data with a binder call.
+ *
+ * @param configKey Configuration key to retrieve data from.
+ * @return Serialized ConfigMetricsReport proto. Returns null on failure.
+ */
+ @RequiresPermission(Manifest.permission.DUMP)
+ public byte[] getData(String configKey) {
+ synchronized (this) {
+ try {
+ IStatsManager service = getIStatsManagerLocked();
+ if (service == null) {
+ throw new RuntimeException("StatsD service connection lost");
+ }
+ return service.getData(configKey);
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Failed to connecto statsd when getting data");
+ return null;
+ }
+ }
+ }
+
+ private class StatsdDeathRecipient implements IBinder.DeathRecipient {
+ @Override
+ public void binderDied() {
+ synchronized (this) {
+ mService = null;
+ }
+ }
+ }
+
+ private IStatsManager getIStatsManagerLocked() throws RemoteException {
+ if (mService != null) {
+ return mService;
+ }
+ mService = IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
+ if (mService != null) {
+ mService.asBinder().linkToDeath(new StatsdDeathRecipient(), 0);
+ }
+ return mService;
+ }
+}
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 2b03ed6c3ae1..cc4a0b60dd0a 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -340,6 +340,14 @@ public class TimeUtils {
}
/** @hide Just for debugging; not internationalized. */
+ public static String formatDuration(long duration) {
+ synchronized (sFormatSync) {
+ int len = formatDurationLocked(duration, 0);
+ return new String(sFormatStr, 0, len);
+ }
+ }
+
+ /** @hide Just for debugging; not internationalized. */
public static void formatDuration(long duration, PrintWriter pw) {
formatDuration(duration, pw, 0);
}
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index a9ccae114ba8..180812340ba8 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -16,9 +16,6 @@
package android.util.apk;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
import android.util.ArrayMap;
import android.util.Pair;
@@ -30,7 +27,6 @@ import java.math.BigInteger;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.nio.DirectByteBuffer;
import java.security.DigestException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
@@ -122,40 +118,6 @@ public class ApkSignatureSchemeV2Verifier {
}
/**
- * APK Signature Scheme v2 block and additional information relevant to verifying the signatures
- * contained in the block against the file.
- */
- private static class SignatureInfo {
- /** Contents of APK Signature Scheme v2 block. */
- private final ByteBuffer signatureBlock;
-
- /** Position of the APK Signing Block in the file. */
- private final long apkSigningBlockOffset;
-
- /** Position of the ZIP Central Directory in the file. */
- private final long centralDirOffset;
-
- /** Position of the ZIP End of Central Directory (EoCD) in the file. */
- private final long eocdOffset;
-
- /** Contents of ZIP End of Central Directory (EoCD) of the file. */
- private final ByteBuffer eocd;
-
- private SignatureInfo(
- ByteBuffer signatureBlock,
- long apkSigningBlockOffset,
- long centralDirOffset,
- long eocdOffset,
- ByteBuffer eocd) {
- this.signatureBlock = signatureBlock;
- this.apkSigningBlockOffset = apkSigningBlockOffset;
- this.centralDirOffset = centralDirOffset;
- this.eocdOffset = eocdOffset;
- this.eocd = eocd;
- }
- }
-
- /**
* Returns the APK Signature Scheme v2 block contained in the provided APK file and the
* additional information relevant for verifying the block against the file.
*
@@ -497,6 +459,7 @@ public class ApkSignatureSchemeV2Verifier {
// TODO: Compute digests of chunks in parallel when beneficial. This requires some research
// into how to parallelize (if at all) based on the capabilities of the hardware on which
// this code is running and based on the size of input.
+ DataDigester digester = new MultipleDigestDataDigester(mds);
int dataSourceIndex = 0;
for (DataSource input : contents) {
long inputOffset = 0;
@@ -508,7 +471,7 @@ public class ApkSignatureSchemeV2Verifier {
mds[i].update(chunkContentPrefix);
}
try {
- input.feedIntoMessageDigests(mds, inputOffset, chunkSize);
+ input.feedIntoDataDigester(digester, inputOffset, chunkSize);
} catch (IOException e) {
throw new DigestException(
"Failed to digest chunk #" + chunkIndex + " of section #"
@@ -967,155 +930,26 @@ public class ApkSignatureSchemeV2Verifier {
}
/**
- * Source of data to be digested.
+ * {@link DataDigester} that updates multiple {@link MessageDigest}s whenever data is feeded.
*/
- private static interface DataSource {
-
- /**
- * Returns the size (in bytes) of the data offered by this source.
- */
- long size();
-
- /**
- * Feeds the specified region of this source's data into the provided digests. Each digest
- * instance gets the same data.
- *
- * @param offset offset of the region inside this data source.
- * @param size size (in bytes) of the region.
- */
- void feedIntoMessageDigests(MessageDigest[] mds, long offset, int size) throws IOException;
- }
+ private static class MultipleDigestDataDigester implements DataDigester {
+ private final MessageDigest[] mMds;
- /**
- * {@link DataSource} which provides data from a file descriptor by memory-mapping the sections
- * of the file requested by
- * {@link DataSource#feedIntoMessageDigests(MessageDigest[], long, int) feedIntoMessageDigests}.
- */
- private static final class MemoryMappedFileDataSource implements DataSource {
- private static final long MEMORY_PAGE_SIZE_BYTES = Os.sysconf(OsConstants._SC_PAGESIZE);
-
- private final FileDescriptor mFd;
- private final long mFilePosition;
- private final long mSize;
-
- /**
- * Constructs a new {@code MemoryMappedFileDataSource} for the specified region of the file.
- *
- * @param position start position of the region in the file.
- * @param size size (in bytes) of the region.
- */
- public MemoryMappedFileDataSource(FileDescriptor fd, long position, long size) {
- mFd = fd;
- mFilePosition = position;
- mSize = size;
+ MultipleDigestDataDigester(MessageDigest[] mds) {
+ mMds = mds;
}
@Override
- public long size() {
- return mSize;
- }
-
- @Override
- public void feedIntoMessageDigests(
- MessageDigest[] mds, long offset, int size) throws IOException {
- // IMPLEMENTATION NOTE: After a lot of experimentation, the implementation of this
- // method was settled on a straightforward mmap with prefaulting.
- //
- // This method is not using FileChannel.map API because that API does not offset a way
- // to "prefault" the resulting memory pages. Without prefaulting, performance is about
- // 10% slower on small to medium APKs, but is significantly worse for APKs in 500+ MB
- // range. FileChannel.load (which currently uses madvise) doesn't help. Finally,
- // invoking madvise (MADV_SEQUENTIAL) after mmap with prefaulting wastes quite a bit of
- // time, which is not compensated for by faster reads.
-
- // We mmap the smallest region of the file containing the requested data. mmap requires
- // that the start offset in the file must be a multiple of memory page size. We thus may
- // need to mmap from an offset less than the requested offset.
- long filePosition = mFilePosition + offset;
- long mmapFilePosition =
- (filePosition / MEMORY_PAGE_SIZE_BYTES) * MEMORY_PAGE_SIZE_BYTES;
- int dataStartOffsetInMmapRegion = (int) (filePosition - mmapFilePosition);
- long mmapRegionSize = size + dataStartOffsetInMmapRegion;
- long mmapPtr = 0;
- try {
- mmapPtr = Os.mmap(
- 0, // let the OS choose the start address of the region in memory
- mmapRegionSize,
- OsConstants.PROT_READ,
- OsConstants.MAP_SHARED | OsConstants.MAP_POPULATE, // "prefault" all pages
- mFd,
- mmapFilePosition);
- // Feeding a memory region into MessageDigest requires the region to be represented
- // as a direct ByteBuffer.
- ByteBuffer buf = new DirectByteBuffer(
- size,
- mmapPtr + dataStartOffsetInMmapRegion,
- mFd, // not really needed, but just in case
- null, // no need to clean up -- it's taken care of by the finally block
- true // read only buffer
- );
- for (MessageDigest md : mds) {
- buf.position(0);
- md.update(buf);
- }
- } catch (ErrnoException e) {
- throw new IOException("Failed to mmap " + mmapRegionSize + " bytes", e);
- } finally {
- if (mmapPtr != 0) {
- try {
- Os.munmap(mmapPtr, mmapRegionSize);
- } catch (ErrnoException ignored) {}
- }
+ public void consume(ByteBuffer buffer) {
+ buffer = buffer.slice();
+ for (MessageDigest md : mMds) {
+ buffer.position(0);
+ md.update(buffer);
}
}
- }
-
- /**
- * {@link DataSource} which provides data from a {@link ByteBuffer}.
- */
- private static final class ByteBufferDataSource implements DataSource {
- /**
- * Underlying buffer. The data is stored between position 0 and the buffer's capacity.
- * The buffer's position is 0 and limit is equal to capacity.
- */
- private final ByteBuffer mBuf;
-
- public ByteBufferDataSource(ByteBuffer buf) {
- // Defensive copy, to avoid changes to mBuf being visible in buf.
- mBuf = buf.slice();
- }
@Override
- public long size() {
- return mBuf.capacity();
- }
-
- @Override
- public void feedIntoMessageDigests(
- MessageDigest[] mds, long offset, int size) throws IOException {
- // There's no way to tell MessageDigest to read data from ByteBuffer from a position
- // other than the buffer's current position. We thus need to change the buffer's
- // position to match the requested offset.
- //
- // In the future, it may be necessary to compute digests of multiple regions in
- // parallel. Given that digest computation is a slow operation, we enable multiple
- // such requests to be fulfilled by this instance. This is achieved by serially
- // creating a new ByteBuffer corresponding to the requested data range and then,
- // potentially concurrently, feeding these buffers into MessageDigest instances.
- ByteBuffer region;
- synchronized (mBuf) {
- mBuf.position((int) offset);
- mBuf.limit((int) offset + size);
- region = mBuf.slice();
- }
-
- for (MessageDigest md : mds) {
- // Need to reset position to 0 at the start of each iteration because
- // MessageDigest.update below sets it to the buffer's limit.
- region.position(0);
- md.update(region);
- }
- }
+ public void finish() {}
}
/**
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java
new file mode 100644
index 000000000000..7412ef411fb4
--- /dev/null
+++ b/core/java/android/util/apk/ApkVerityBuilder.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+
+/**
+ * ApkVerityBuilder builds the APK verity tree and the verity header, which will be used by the
+ * kernel to verity the APK content on access.
+ *
+ * <p>Unlike a regular Merkle tree, APK verity tree does not cover the content fully. Due to
+ * the existing APK format, it has to skip APK Signing Block and also has some special treatment for
+ * the "Central Directory offset" field of ZIP End of Central Directory.
+ *
+ * @hide
+ */
+abstract class ApkVerityBuilder {
+ private ApkVerityBuilder() {}
+
+ private static final int CHUNK_SIZE_BYTES = 4096; // Typical Linux block size
+ private static final int DIGEST_SIZE_BYTES = 32; // SHA-256 size
+ private static final int FSVERITY_HEADER_SIZE_BYTES = 64;
+ private static final int ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE = 4;
+ private static final int ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET = 16;
+ private static final String JCA_DIGEST_ALGORITHM = "SHA-256";
+ private static final byte[] DEFAULT_SALT = new byte[8];
+
+ static class ApkVerityResult {
+ public final ByteBuffer fsverityData;
+ public final byte[] rootHash;
+
+ ApkVerityResult(ByteBuffer fsverityData, byte[] rootHash) {
+ this.fsverityData = fsverityData;
+ this.rootHash = rootHash;
+ }
+ }
+
+ /**
+ * Generates fsverity metadata and the Merkle tree into the {@link ByteBuffer} created by the
+ * {@link ByteBufferFactory}. The bytes layout in the buffer will be used by the kernel and is
+ * ready to be appended to the target file to set up fsverity. For fsverity to work, this data
+ * must be placed at the next page boundary, and the caller must add additional padding in that
+ * case.
+ *
+ * @return ApkVerityResult containing the fsverity data and the root hash of the Merkle tree.
+ */
+ static ApkVerityResult generateApkVerity(RandomAccessFile apk,
+ SignatureInfo signatureInfo, ByteBufferFactory bufferFactory)
+ throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
+ assertSigningBlockAlignedAndHasFullPages(signatureInfo);
+
+ long signingBlockSize =
+ signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
+ long dataSize = apk.length() - signingBlockSize - ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
+ int[] levelOffset = calculateVerityLevelOffset(dataSize);
+ ByteBuffer output = bufferFactory.create(
+ CHUNK_SIZE_BYTES + // fsverity header + extensions + padding
+ levelOffset[levelOffset.length - 1] + // Merkle tree size
+ FSVERITY_HEADER_SIZE_BYTES); // second fsverity header (verbatim copy)
+
+ // Start generating the tree from the block boundary as the kernel will expect.
+ ByteBuffer treeOutput = slice(output, CHUNK_SIZE_BYTES,
+ output.limit() - FSVERITY_HEADER_SIZE_BYTES);
+ byte[] rootHash = generateApkVerityTree(apk, signatureInfo, DEFAULT_SALT, levelOffset,
+ treeOutput);
+
+ ByteBuffer integrityHeader = generateFsverityHeader(apk.length(), DEFAULT_SALT);
+ output.put(integrityHeader);
+ output.put(generateFsverityExtensions());
+
+ integrityHeader.rewind();
+ output.put(integrityHeader);
+ output.rewind();
+ return new ApkVerityResult(output, rootHash);
+ }
+
+ /**
+ * A helper class to consume and digest data by block continuously, and write into a buffer.
+ */
+ private static class BufferedDigester implements DataDigester {
+ /** Amount of the data to digest in each cycle before writting out the digest. */
+ private static final int BUFFER_SIZE = CHUNK_SIZE_BYTES;
+
+ /**
+ * Amount of data the {@link MessageDigest} has consumed since the last reset. This must be
+ * always less than BUFFER_SIZE since {@link MessageDigest} is reset whenever it has
+ * consumed BUFFER_SIZE of data.
+ */
+ private int mBytesDigestedSinceReset;
+
+ /** The final output {@link ByteBuffer} to write the digest to sequentially. */
+ private final ByteBuffer mOutput;
+
+ private final MessageDigest mMd;
+ private final byte[] mDigestBuffer = new byte[DIGEST_SIZE_BYTES];
+ private final byte[] mSalt;
+
+ private BufferedDigester(byte[] salt, ByteBuffer output) throws NoSuchAlgorithmException {
+ mSalt = salt;
+ mOutput = output.slice();
+ mMd = MessageDigest.getInstance(JCA_DIGEST_ALGORITHM);
+ mMd.update(mSalt);
+ mBytesDigestedSinceReset = 0;
+ }
+
+ /**
+ * Consumes and digests data up to BUFFER_SIZE (may continue from the previous remaining),
+ * then writes the final digest to the output buffer. Repeat until all data are consumed.
+ * If the last consumption is not enough for BUFFER_SIZE, the state will stay and future
+ * consumption will continuous from there.
+ */
+ @Override
+ public void consume(ByteBuffer buffer) throws DigestException {
+ int offset = buffer.position();
+ int remaining = buffer.remaining();
+ while (remaining > 0) {
+ int allowance = (int) Math.min(remaining, BUFFER_SIZE - mBytesDigestedSinceReset);
+ // Optimization: set the buffer limit to avoid allocating a new ByteBuffer object.
+ buffer.limit(buffer.position() + allowance);
+ mMd.update(buffer);
+ offset += allowance;
+ remaining -= allowance;
+ mBytesDigestedSinceReset += allowance;
+
+ if (mBytesDigestedSinceReset == BUFFER_SIZE) {
+ mMd.digest(mDigestBuffer, 0, mDigestBuffer.length);
+ mOutput.put(mDigestBuffer);
+ // After digest, MessageDigest resets automatically, so no need to reset again.
+ mMd.update(mSalt);
+ mBytesDigestedSinceReset = 0;
+ }
+ }
+ }
+
+ /** Finish the current digestion if any. */
+ @Override
+ public void finish() throws DigestException {
+ if (mBytesDigestedSinceReset == 0) {
+ return;
+ }
+ mMd.digest(mDigestBuffer, 0, mDigestBuffer.length);
+ mOutput.put(mDigestBuffer);
+ }
+
+ private void fillUpLastOutputChunk() {
+ int extra = (int) (BUFFER_SIZE - mOutput.position() % BUFFER_SIZE);
+ if (extra == 0) {
+ return;
+ }
+ mOutput.put(ByteBuffer.allocate(extra));
+ }
+ }
+
+ /**
+ * Digest the source by chunk in the given range. If the last chunk is not a full chunk,
+ * digest the remaining.
+ */
+ private static void consumeByChunk(DataDigester digester, DataSource source, int chunkSize)
+ throws IOException, DigestException {
+ long inputRemaining = source.size();
+ long inputOffset = 0;
+ while (inputRemaining > 0) {
+ int size = (int) Math.min(inputRemaining, chunkSize);
+ source.feedIntoDataDigester(digester, inputOffset, size);
+ inputOffset += size;
+ inputRemaining -= size;
+ }
+ }
+
+ // Rationale: 1) 1 MB should fit in memory space on all devices. 2) It is not too granular
+ // thus the syscall overhead is not too big.
+ private static final int MMAP_REGION_SIZE_BYTES = 1024 * 1024;
+
+ private static void generateApkVerityDigestAtLeafLevel(RandomAccessFile apk,
+ SignatureInfo signatureInfo, byte[] salt, ByteBuffer output)
+ throws IOException, NoSuchAlgorithmException, DigestException {
+ BufferedDigester digester = new BufferedDigester(salt, output);
+
+ // 1. Digest from the beginning of the file, until APK Signing Block is reached.
+ consumeByChunk(digester,
+ new MemoryMappedFileDataSource(apk.getFD(), 0, signatureInfo.apkSigningBlockOffset),
+ MMAP_REGION_SIZE_BYTES);
+
+ // 2. Skip APK Signing Block and continue digesting, until the Central Directory offset
+ // field in EoCD is reached.
+ long eocdCdOffsetFieldPosition =
+ signatureInfo.eocdOffset + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET;
+ consumeByChunk(digester,
+ new MemoryMappedFileDataSource(apk.getFD(), signatureInfo.centralDirOffset,
+ eocdCdOffsetFieldPosition - signatureInfo.centralDirOffset),
+ MMAP_REGION_SIZE_BYTES);
+
+ // 3. Fill up the rest of buffer with 0s.
+ ByteBuffer alternativeCentralDirOffset = ByteBuffer.allocate(
+ ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE).order(ByteOrder.LITTLE_ENDIAN);
+ alternativeCentralDirOffset.putInt(Math.toIntExact(signatureInfo.apkSigningBlockOffset));
+ alternativeCentralDirOffset.flip();
+ digester.consume(alternativeCentralDirOffset);
+
+ // 4. Read from end of the Central Directory offset field in EoCD to the end of the file.
+ long offsetAfterEocdCdOffsetField =
+ eocdCdOffsetFieldPosition + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
+ consumeByChunk(digester,
+ new MemoryMappedFileDataSource(apk.getFD(), offsetAfterEocdCdOffsetField,
+ apk.length() - offsetAfterEocdCdOffsetField),
+ MMAP_REGION_SIZE_BYTES);
+ digester.finish();
+
+ // 5. Fill up the rest of buffer with 0s.
+ digester.fillUpLastOutputChunk();
+ }
+
+ private static byte[] generateApkVerityTree(RandomAccessFile apk, SignatureInfo signatureInfo,
+ byte[] salt, int[] levelOffset, ByteBuffer output)
+ throws IOException, NoSuchAlgorithmException, DigestException {
+ // 1. Digest the apk to generate the leaf level hashes.
+ generateApkVerityDigestAtLeafLevel(apk, signatureInfo, salt, slice(output,
+ levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1]));
+
+ // 2. Digest the lower level hashes bottom up.
+ for (int level = levelOffset.length - 3; level >= 0; level--) {
+ ByteBuffer inputBuffer = slice(output, levelOffset[level + 1], levelOffset[level + 2]);
+ ByteBuffer outputBuffer = slice(output, levelOffset[level], levelOffset[level + 1]);
+
+ DataSource source = new ByteBufferDataSource(inputBuffer);
+ BufferedDigester digester = new BufferedDigester(salt, outputBuffer);
+ consumeByChunk(digester, source, CHUNK_SIZE_BYTES);
+ digester.finish();
+
+ digester.fillUpLastOutputChunk();
+ }
+
+ // 3. Digest the first block (i.e. first level) to generate the root hash.
+ byte[] rootHash = new byte[DIGEST_SIZE_BYTES];
+ BufferedDigester digester = new BufferedDigester(salt, ByteBuffer.wrap(rootHash));
+ digester.consume(slice(output, 0, CHUNK_SIZE_BYTES));
+ digester.finish();
+ return rootHash;
+ }
+
+ private static ByteBuffer generateFsverityHeader(long fileSize, byte[] salt) {
+ if (salt.length != 8) {
+ throw new IllegalArgumentException("salt is not 8 bytes long");
+ }
+
+ ByteBuffer buffer = ByteBuffer.allocate(FSVERITY_HEADER_SIZE_BYTES);
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
+
+ // TODO(b/30972906): insert a reference when there is a public one.
+ buffer.put("TrueBrew".getBytes()); // magic
+ buffer.put((byte) 1); // major version
+ buffer.put((byte) 0); // minor version
+ buffer.put((byte) 12); // log2(block-size) == log2(4096)
+ buffer.put((byte) 7); // log2(leaves-per-node) == log2(block-size / digest-size)
+ // == log2(4096 / 32)
+ buffer.putShort((short) 1); // meta algorithm, 1: SHA-256 FIXME finalize constant
+ buffer.putShort((short) 1); // data algorithm, 1: SHA-256 FIXME finalize constant
+ buffer.putInt(0x1); // flags, 0x1: has extension, FIXME also hide it
+ buffer.putInt(0); // reserved
+ buffer.putLong(fileSize); // original i_size
+ buffer.put(salt); // salt (8 bytes)
+
+ // TODO(b/30972906): Add extension.
+
+ buffer.rewind();
+ return buffer;
+ }
+
+ private static ByteBuffer generateFsverityExtensions() {
+ return ByteBuffer.allocate(64); // TODO(b/30972906): implement this.
+ }
+
+ /**
+ * Returns an array of summed area table of level size in the verity tree. In other words, the
+ * returned array is offset of each level in the verity tree file format, plus an additional
+ * offset of the next non-existing level (i.e. end of the last level + 1). Thus the array size
+ * is level + 1. Thus, the returned array is guarantee to have at least 2 elements.
+ */
+ private static int[] calculateVerityLevelOffset(long fileSize) {
+ ArrayList<Long> levelSize = new ArrayList<>();
+ while (true) {
+ long levelDigestSize = divideRoundup(fileSize, CHUNK_SIZE_BYTES) * DIGEST_SIZE_BYTES;
+ long chunksSize = CHUNK_SIZE_BYTES * divideRoundup(levelDigestSize, CHUNK_SIZE_BYTES);
+ levelSize.add(chunksSize);
+ if (levelDigestSize <= CHUNK_SIZE_BYTES) {
+ break;
+ }
+ fileSize = levelDigestSize;
+ }
+
+ // Reverse and convert to summed area table.
+ int[] levelOffset = new int[levelSize.size() + 1];
+ levelOffset[0] = 0;
+ for (int i = 0; i < levelSize.size(); i++) {
+ // We don't support verity tree if it is larger then Integer.MAX_VALUE.
+ levelOffset[i + 1] = levelOffset[i]
+ + Math.toIntExact(levelSize.get(levelSize.size() - i - 1));
+ }
+ return levelOffset;
+ }
+
+ private static void assertSigningBlockAlignedAndHasFullPages(SignatureInfo signatureInfo) {
+ if (signatureInfo.apkSigningBlockOffset % CHUNK_SIZE_BYTES != 0) {
+ throw new IllegalArgumentException(
+ "APK Signing Block does not start at the page boundary: "
+ + signatureInfo.apkSigningBlockOffset);
+ }
+
+ if ((signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset)
+ % CHUNK_SIZE_BYTES != 0) {
+ throw new IllegalArgumentException(
+ "Size of APK Signing Block is not a multiple of 4096: "
+ + (signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset));
+ }
+ }
+
+ /** Returns a slice of the buffer which shares content with the provided buffer. */
+ private static ByteBuffer slice(ByteBuffer buffer, int begin, int end) {
+ ByteBuffer b = buffer.duplicate();
+ b.position(0); // to ensure position <= limit invariant.
+ b.limit(end);
+ b.position(begin);
+ return b.slice();
+ }
+
+ /** Divides a number and round up to the closest integer. */
+ private static long divideRoundup(long dividend, long divisor) {
+ return (dividend + divisor - 1) / divisor;
+ }
+}
diff --git a/core/java/android/util/apk/ByteBufferDataSource.java b/core/java/android/util/apk/ByteBufferDataSource.java
new file mode 100644
index 000000000000..3976568a429d
--- /dev/null
+++ b/core/java/android/util/apk/ByteBufferDataSource.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 android.util.apk;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.security.DigestException;
+
+/**
+ * {@link DataSource} which provides data from a {@link ByteBuffer}.
+ */
+class ByteBufferDataSource implements DataSource {
+ /**
+ * Underlying buffer. The data is stored between position 0 and the buffer's capacity.
+ * The buffer's position is 0 and limit is equal to capacity.
+ */
+ private final ByteBuffer mBuf;
+
+ ByteBufferDataSource(ByteBuffer buf) {
+ // Defensive copy, to avoid changes to mBuf being visible in buf, and to ensure position is
+ // 0 and limit == capacity.
+ mBuf = buf.slice();
+ }
+
+ @Override
+ public long size() {
+ return mBuf.capacity();
+ }
+
+ @Override
+ public void feedIntoDataDigester(DataDigester md, long offset, int size)
+ throws IOException, DigestException {
+ // There's no way to tell MessageDigest to read data from ByteBuffer from a position
+ // other than the buffer's current position. We thus need to change the buffer's
+ // position to match the requested offset.
+ //
+ // In the future, it may be necessary to compute digests of multiple regions in
+ // parallel. Given that digest computation is a slow operation, we enable multiple
+ // such requests to be fulfilled by this instance. This is achieved by serially
+ // creating a new ByteBuffer corresponding to the requested data range and then,
+ // potentially concurrently, feeding these buffers into MessageDigest instances.
+ ByteBuffer region;
+ synchronized (mBuf) {
+ mBuf.position(0);
+ mBuf.limit((int) offset + size);
+ mBuf.position((int) offset);
+ region = mBuf.slice();
+ }
+
+ md.consume(region);
+ }
+}
diff --git a/core/java/android/util/apk/ByteBufferFactory.java b/core/java/android/util/apk/ByteBufferFactory.java
new file mode 100644
index 000000000000..7a998822c870
--- /dev/null
+++ b/core/java/android/util/apk/ByteBufferFactory.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 java.nio.ByteBuffer;
+
+/**
+ * Provider of {@link ByteBuffer} instances.
+ * @hide
+ */
+public interface ByteBufferFactory {
+ /** Initiates a {@link ByteBuffer} with the given size. */
+ ByteBuffer create(int capacity);
+}
diff --git a/core/java/android/util/apk/DataDigester.java b/core/java/android/util/apk/DataDigester.java
new file mode 100644
index 000000000000..278be8037b0e
--- /dev/null
+++ b/core/java/android/util/apk/DataDigester.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 java.nio.ByteBuffer;
+import java.security.DigestException;
+
+interface DataDigester {
+ /** Consumes the {@link ByteBuffer}. */
+ void consume(ByteBuffer buffer) throws DigestException;
+
+ /** Finishes the digestion. Must be called after the last {@link #consume(ByteBuffer)}. */
+ void finish() throws DigestException;
+}
diff --git a/core/java/android/util/apk/DataSource.java b/core/java/android/util/apk/DataSource.java
new file mode 100644
index 000000000000..82f3800aa6d3
--- /dev/null
+++ b/core/java/android/util/apk/DataSource.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 android.util.apk;
+
+import java.io.IOException;
+import java.security.DigestException;
+
+/** Source of data to be digested. */
+interface DataSource {
+
+ /**
+ * Returns the size (in bytes) of the data offered by this source.
+ */
+ long size();
+
+ /**
+ * Feeds the specified region of this source's data into the provided digester.
+ *
+ * @param offset offset of the region inside this data source.
+ * @param size size (in bytes) of the region.
+ */
+ void feedIntoDataDigester(DataDigester md, long offset, int size)
+ throws IOException, DigestException;
+}
diff --git a/core/java/android/util/apk/MemoryMappedFileDataSource.java b/core/java/android/util/apk/MemoryMappedFileDataSource.java
new file mode 100644
index 000000000000..8d2b1e328862
--- /dev/null
+++ b/core/java/android/util/apk/MemoryMappedFileDataSource.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 android.util.apk;
+
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.DirectByteBuffer;
+import java.security.DigestException;
+
+/**
+ * {@link DataSource} which provides data from a file descriptor by memory-mapping the sections
+ * of the file.
+ */
+class MemoryMappedFileDataSource implements DataSource {
+ private static final long MEMORY_PAGE_SIZE_BYTES = Os.sysconf(OsConstants._SC_PAGESIZE);
+
+ private final FileDescriptor mFd;
+ private final long mFilePosition;
+ private final long mSize;
+
+ /**
+ * Constructs a new {@code MemoryMappedFileDataSource} for the specified region of the file.
+ *
+ * @param position start position of the region in the file.
+ * @param size size (in bytes) of the region.
+ */
+ MemoryMappedFileDataSource(FileDescriptor fd, long position, long size) {
+ mFd = fd;
+ mFilePosition = position;
+ mSize = size;
+ }
+
+ @Override
+ public long size() {
+ return mSize;
+ }
+
+ @Override
+ public void feedIntoDataDigester(DataDigester md, long offset, int size)
+ throws IOException, DigestException {
+ // IMPLEMENTATION NOTE: After a lot of experimentation, the implementation of this
+ // method was settled on a straightforward mmap with prefaulting.
+ //
+ // This method is not using FileChannel.map API because that API does not offset a way
+ // to "prefault" the resulting memory pages. Without prefaulting, performance is about
+ // 10% slower on small to medium APKs, but is significantly worse for APKs in 500+ MB
+ // range. FileChannel.load (which currently uses madvise) doesn't help. Finally,
+ // invoking madvise (MADV_SEQUENTIAL) after mmap with prefaulting wastes quite a bit of
+ // time, which is not compensated for by faster reads.
+
+ // We mmap the smallest region of the file containing the requested data. mmap requires
+ // that the start offset in the file must be a multiple of memory page size. We thus may
+ // need to mmap from an offset less than the requested offset.
+ long filePosition = mFilePosition + offset;
+ long mmapFilePosition =
+ (filePosition / MEMORY_PAGE_SIZE_BYTES) * MEMORY_PAGE_SIZE_BYTES;
+ int dataStartOffsetInMmapRegion = (int) (filePosition - mmapFilePosition);
+ long mmapRegionSize = size + dataStartOffsetInMmapRegion;
+ long mmapPtr = 0;
+ try {
+ mmapPtr = Os.mmap(
+ 0, // let the OS choose the start address of the region in memory
+ mmapRegionSize,
+ OsConstants.PROT_READ,
+ OsConstants.MAP_SHARED | OsConstants.MAP_POPULATE, // "prefault" all pages
+ mFd,
+ mmapFilePosition);
+ ByteBuffer buf = new DirectByteBuffer(
+ size,
+ mmapPtr + dataStartOffsetInMmapRegion,
+ mFd, // not really needed, but just in case
+ null, // no need to clean up -- it's taken care of by the finally block
+ true // read only buffer
+ );
+ md.consume(buf);
+ } catch (ErrnoException e) {
+ throw new IOException("Failed to mmap " + mmapRegionSize + " bytes", e);
+ } finally {
+ if (mmapPtr != 0) {
+ try {
+ Os.munmap(mmapPtr, mmapRegionSize);
+ } catch (ErrnoException ignored) { }
+ }
+ }
+ }
+}
diff --git a/core/java/android/util/apk/SignatureInfo.java b/core/java/android/util/apk/SignatureInfo.java
new file mode 100644
index 000000000000..8e1233af34a1
--- /dev/null
+++ b/core/java/android/util/apk/SignatureInfo.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 java.nio.ByteBuffer;
+
+/**
+ * APK Signature Scheme v2 block and additional information relevant to verifying the signatures
+ * contained in the block against the file.
+ */
+class SignatureInfo {
+ /** Contents of APK Signature Scheme v2 block. */
+ public final ByteBuffer signatureBlock;
+
+ /** Position of the APK Signing Block in the file. */
+ public final long apkSigningBlockOffset;
+
+ /** Position of the ZIP Central Directory in the file. */
+ public final long centralDirOffset;
+
+ /** Position of the ZIP End of Central Directory (EoCD) in the file. */
+ public final long eocdOffset;
+
+ /** Contents of ZIP End of Central Directory (EoCD) of the file. */
+ public final ByteBuffer eocd;
+
+ SignatureInfo(ByteBuffer signatureBlock, long apkSigningBlockOffset, long centralDirOffset,
+ long eocdOffset, ByteBuffer eocd) {
+ this.signatureBlock = signatureBlock;
+ this.apkSigningBlockOffset = apkSigningBlockOffset;
+ this.centralDirOffset = centralDirOffset;
+ this.eocdOffset = eocdOffset;
+ this.eocd = eocd;
+ }
+}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index e7c3f92da830..6a44cdb9ee57 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -294,11 +294,10 @@ public final class Display {
/**
* Display state: The display is dozing in a suspended low power state; it is still
- * on but is optimized for showing static system-provided content while the device
- * is non-interactive. This mode may be used to conserve even more power by allowing
- * the hardware to stop applying frame buffer updates from the graphics subsystem or
- * to take over the display and manage it autonomously to implement low power always-on
- * display functionality.
+ * on but the CPU is not updating it. This may be used in one of two ways: to show
+ * static system-provided content while the device is non-interactive, or to allow
+ * a "Sidekick" compute resource to update the display. For this reason, the
+ * CPU must not control the display in this mode.
*
* @see #getState
* @see android.os.PowerManager#isInteractive
@@ -313,6 +312,18 @@ public final class Display {
*/
public static final int STATE_VR = 5;
+ /**
+ * Display state: The display is in a suspended full power state; it is still
+ * on but the CPU is not updating it. This may be used in one of two ways: to show
+ * static system-provided content while the device is non-interactive, or to allow
+ * a "Sidekick" compute resource to update the display. For this reason, the
+ * CPU must not control the display in this mode.
+ *
+ * @see #getState
+ * @see android.os.PowerManager#isInteractive
+ */
+ public static final int STATE_ON_SUSPEND = 6;
+
/* The color mode constants defined below must be kept in sync with the ones in
* system/core/include/system/graphics-base.h */
@@ -994,7 +1005,7 @@ public final class Display {
* Gets the state of the display, such as whether it is on or off.
*
* @return The state of the display: one of {@link #STATE_OFF}, {@link #STATE_ON},
- * {@link #STATE_DOZE}, {@link #STATE_DOZE_SUSPEND}, or
+ * {@link #STATE_DOZE}, {@link #STATE_DOZE_SUSPEND}, {@link #STATE_ON_SUSPEND}, or
* {@link #STATE_UNKNOWN}.
*/
public int getState() {
@@ -1113,6 +1124,8 @@ public final class Display {
return "DOZE_SUSPEND";
case STATE_VR:
return "VR";
+ case STATE_ON_SUSPEND:
+ return "ON_SUSPEND";
default:
return Integer.toString(state);
}
@@ -1120,11 +1133,11 @@ public final class Display {
/**
* Returns true if display updates may be suspended while in the specified
- * display power state.
+ * display power state. In SUSPEND states, updates are absolutely forbidden.
* @hide
*/
public static boolean isSuspendedState(int state) {
- return state == STATE_OFF || state == STATE_DOZE_SUSPEND;
+ return state == STATE_OFF || state == STATE_DOZE_SUSPEND || state == STATE_ON_SUSPEND;
}
/**
diff --git a/core/java/android/view/DisplayFrames.java b/core/java/android/view/DisplayFrames.java
new file mode 100644
index 000000000000..e6861d83d2fd
--- /dev/null
+++ b/core/java/android/view/DisplayFrames.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 android.view;
+
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+import static com.android.server.wm.proto.DisplayFramesProto.STABLE_BOUNDS;
+
+import android.graphics.Rect;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.PrintWriter;
+
+/**
+ * Container class for all the display frames that affect how we do window layout on a display.
+ * @hide
+ */
+public class DisplayFrames {
+ public final int mDisplayId;
+
+ /**
+ * The current size of the screen; really; extends into the overscan area of the screen and
+ * doesn't account for any system elements like the status bar.
+ */
+ public final Rect mOverscan = new Rect();
+
+ /**
+ * The current visible size of the screen; really; (ir)regardless of whether the status bar can
+ * be hidden but not extending into the overscan area.
+ */
+ public final Rect mUnrestricted = new Rect();
+
+ /** Like mOverscan*, but allowed to move into the overscan region where appropriate. */
+ public final Rect mRestrictedOverscan = new Rect();
+
+ /**
+ * The current size of the screen; these may be different than (0,0)-(dw,dh) if the status bar
+ * can't be hidden; in that case it effectively carves out that area of the display from all
+ * other windows.
+ */
+ public final Rect mRestricted = new Rect();
+
+ /**
+ * During layout, the current screen borders accounting for any currently visible system UI
+ * elements.
+ */
+ public final Rect mSystem = new Rect();
+
+ /** For applications requesting stable content insets, these are them. */
+ public final Rect mStable = new Rect();
+
+ /**
+ * For applications requesting stable content insets but have also set the fullscreen window
+ * flag, these are the stable dimensions without the status bar.
+ */
+ public final Rect mStableFullscreen = new Rect();
+
+ /**
+ * During layout, the current screen borders with all outer decoration (status bar, input method
+ * dock) accounted for.
+ */
+ public final Rect mCurrent = new Rect();
+
+ /**
+ * During layout, the frame in which content should be displayed to the user, accounting for all
+ * screen decoration except for any space they deem as available for other content. This is
+ * usually the same as mCurrent*, but may be larger if the screen decor has supplied content
+ * insets.
+ */
+ public final Rect mContent = new Rect();
+
+ /**
+ * During layout, the frame in which voice content should be displayed to the user, accounting
+ * for all screen decoration except for any space they deem as available for other content.
+ */
+ public final Rect mVoiceContent = new Rect();
+
+ /** During layout, the current screen borders along which input method windows are placed. */
+ public final Rect mDock = new Rect();
+
+ private final Rect mDisplayInfoOverscan = new Rect();
+ private final Rect mRotatedDisplayInfoOverscan = new Rect();
+ public int mDisplayWidth;
+ public int mDisplayHeight;
+
+ public int mRotation;
+
+ public DisplayFrames(int displayId, DisplayInfo info) {
+ mDisplayId = displayId;
+ onDisplayInfoUpdated(info);
+ }
+
+ public void onDisplayInfoUpdated(DisplayInfo info) {
+ mDisplayWidth = info.logicalWidth;
+ mDisplayHeight = info.logicalHeight;
+ mRotation = info.rotation;
+ mDisplayInfoOverscan.set(
+ info.overscanLeft, info.overscanTop, info.overscanRight, info.overscanBottom);
+ }
+
+ public void onBeginLayout() {
+ switch (mRotation) {
+ case ROTATION_90:
+ mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.top;
+ mRotatedDisplayInfoOverscan.top = mDisplayInfoOverscan.right;
+ mRotatedDisplayInfoOverscan.right = mDisplayInfoOverscan.bottom;
+ mRotatedDisplayInfoOverscan.bottom = mDisplayInfoOverscan.left;
+ break;
+ case ROTATION_180:
+ mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.right;
+ mRotatedDisplayInfoOverscan.top = mDisplayInfoOverscan.bottom;
+ mRotatedDisplayInfoOverscan.right = mDisplayInfoOverscan.left;
+ mRotatedDisplayInfoOverscan.bottom = mDisplayInfoOverscan.top;
+ break;
+ case ROTATION_270:
+ mRotatedDisplayInfoOverscan.left = mDisplayInfoOverscan.bottom;
+ mRotatedDisplayInfoOverscan.top = mDisplayInfoOverscan.left;
+ mRotatedDisplayInfoOverscan.right = mDisplayInfoOverscan.top;
+ mRotatedDisplayInfoOverscan.bottom = mDisplayInfoOverscan.right;
+ break;
+ default:
+ mRotatedDisplayInfoOverscan.set(mDisplayInfoOverscan);
+ break;
+ }
+
+ mRestrictedOverscan.set(0, 0, mDisplayWidth, mDisplayHeight);
+ mOverscan.set(mRestrictedOverscan);
+ mSystem.set(mRestrictedOverscan);
+ mUnrestricted.set(mRotatedDisplayInfoOverscan);
+ mUnrestricted.right = mDisplayWidth - mUnrestricted.right;
+ mUnrestricted.bottom = mDisplayHeight - mUnrestricted.bottom;
+ mRestricted.set(mUnrestricted);
+ mDock.set(mUnrestricted);
+ mContent.set(mUnrestricted);
+ mVoiceContent.set(mUnrestricted);
+ mStable.set(mUnrestricted);
+ mStableFullscreen.set(mUnrestricted);
+ mCurrent.set(mUnrestricted);
+
+ }
+
+ public int getInputMethodWindowVisibleHeight() {
+ return mDock.bottom - mCurrent.bottom;
+ }
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ mStable.writeToProto(proto, STABLE_BOUNDS);
+ proto.end(token);
+ }
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + "DisplayFrames w=" + mDisplayWidth + " h=" + mDisplayHeight
+ + " r=" + mRotation);
+ final String myPrefix = prefix + " ";
+ dumpFrame(mStable, "mStable", myPrefix, pw);
+ dumpFrame(mStableFullscreen, "mStableFullscreen", myPrefix, pw);
+ dumpFrame(mDock, "mDock", myPrefix, pw);
+ dumpFrame(mCurrent, "mCurrent", myPrefix, pw);
+ dumpFrame(mSystem, "mSystem", myPrefix, pw);
+ dumpFrame(mContent, "mContent", myPrefix, pw);
+ dumpFrame(mVoiceContent, "mVoiceContent", myPrefix, pw);
+ dumpFrame(mOverscan, "mOverscan", myPrefix, pw);
+ dumpFrame(mRestrictedOverscan, "mRestrictedOverscan", myPrefix, pw);
+ dumpFrame(mRestricted, "mRestricted", myPrefix, pw);
+ dumpFrame(mUnrestricted, "mUnrestricted", myPrefix, pw);
+ dumpFrame(mDisplayInfoOverscan, "mDisplayInfoOverscan", myPrefix, pw);
+ dumpFrame(mRotatedDisplayInfoOverscan, "mRotatedDisplayInfoOverscan", myPrefix, pw);
+ }
+
+ private void dumpFrame(Rect frame, String name, String prefix, PrintWriter pw) {
+ pw.print(prefix + name + "="); frame.printShortString(pw); pw.println();
+ }
+}
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 74555de5f291..713cfb48c95f 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -530,7 +530,7 @@ public class FocusFinder {
* axis distances. Warning: this fudge factor is finely tuned, be sure to
* run all focus tests if you dare tweak it.
*/
- int getWeightedDistanceFor(int majorAxisDistance, int minorAxisDistance) {
+ long getWeightedDistanceFor(long majorAxisDistance, long minorAxisDistance) {
return 13 * majorAxisDistance * majorAxisDistance
+ minorAxisDistance * minorAxisDistance;
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 65bde49520d3..29032a7bbc73 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -16,13 +16,13 @@
package android.view;
-import com.android.internal.app.IAssistDataReceiver;
import com.android.internal.os.IResultReceiver;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
+import android.app.IAssistDataReceiver;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index ea6e63c3b9de..5070151815f5 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -353,6 +353,11 @@ public class RenderNode {
return nHasShadow(mNativeRenderNode);
}
+ /** setShadowColor */
+ public boolean setShadowColor(int color) {
+ return nSetShadowColor(mNativeRenderNode, color);
+ }
+
/**
* Enables or disables clipping to the outline.
*
@@ -910,6 +915,8 @@ public class RenderNode {
@CriticalNative
private static native boolean nHasShadow(long renderNode);
@CriticalNative
+ private static native boolean nSetShadowColor(long renderNode, int color);
+ @CriticalNative
private static native boolean nSetClipToOutline(long renderNode, boolean clipToOutline);
@CriticalNative
private static native boolean nSetRevealClip(long renderNode,
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 6f8315ae51bf..5641009c1320 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -295,6 +295,12 @@ public class SurfaceControl {
public static final int POWER_MODE_DOZE_SUSPEND = 3;
/**
+ * Display power mode on: used while putting the screen into a suspended
+ * full power mode. Use only with {@link SurfaceControl#setDisplayPowerMode}.
+ */
+ public static final int POWER_MODE_ON_SUSPEND = 4;
+
+ /**
* A value for windowType used to indicate that the window should be omitted from screenshots
* and display mirroring. A temporary workaround until we express such things with
* the hierarchy.
@@ -1206,56 +1212,65 @@ public class SurfaceControl {
}
public Transaction show(SurfaceControl sc) {
+ sc.checkNotReleased();
nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN);
return this;
}
public Transaction hide(SurfaceControl sc) {
+ sc.checkNotReleased();
nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN);
return this;
}
public Transaction setPosition(SurfaceControl sc, float x, float y) {
+ sc.checkNotReleased();
nativeSetPosition(mNativeObject, sc.mNativeObject, x, y);
return this;
}
public Transaction setSize(SurfaceControl sc, int w, int h) {
- nativeSetSize(mNativeObject, sc.mNativeObject,
- w, h);
+ sc.checkNotReleased();
+ nativeSetSize(mNativeObject, sc.mNativeObject, w, h);
return this;
}
public Transaction setLayer(SurfaceControl sc, int z) {
+ sc.checkNotReleased();
nativeSetLayer(mNativeObject, sc.mNativeObject, z);
return this;
}
public Transaction setRelativeLayer(SurfaceControl sc, SurfaceControl relativeTo, int z) {
+ sc.checkNotReleased();
nativeSetRelativeLayer(mNativeObject, sc.mNativeObject,
relativeTo.getHandle(), z);
return this;
}
public Transaction setTransparentRegionHint(SurfaceControl sc, Region transparentRegion) {
+ sc.checkNotReleased();
nativeSetTransparentRegionHint(mNativeObject,
sc.mNativeObject, transparentRegion);
return this;
}
public Transaction setAlpha(SurfaceControl sc, float alpha) {
+ sc.checkNotReleased();
nativeSetAlpha(mNativeObject, sc.mNativeObject, alpha);
return this;
}
public Transaction setMatrix(SurfaceControl sc,
float dsdx, float dtdx, float dtdy, float dsdy) {
+ sc.checkNotReleased();
nativeSetMatrix(mNativeObject, sc.mNativeObject,
dsdx, dtdx, dtdy, dsdy);
return this;
}
public Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
+ sc.checkNotReleased();
if (crop != null) {
nativeSetWindowCrop(mNativeObject, sc.mNativeObject,
crop.left, crop.top, crop.right, crop.bottom);
@@ -1267,6 +1282,7 @@ public class SurfaceControl {
}
public Transaction setFinalCrop(SurfaceControl sc, Rect crop) {
+ sc.checkNotReleased();
if (crop != null) {
nativeSetFinalCrop(mNativeObject, sc.mNativeObject,
crop.left, crop.top, crop.right, crop.bottom);
@@ -1278,40 +1294,48 @@ public class SurfaceControl {
}
public Transaction setLayerStack(SurfaceControl sc, int layerStack) {
+ sc.checkNotReleased();
nativeSetLayerStack(mNativeObject, sc.mNativeObject, layerStack);
return this;
}
- public Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle, long frameNumber) {
+ public Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle,
+ long frameNumber) {
+ sc.checkNotReleased();
nativeDeferTransactionUntil(mNativeObject, sc.mNativeObject, handle, frameNumber);
return this;
}
public Transaction deferTransactionUntilSurface(SurfaceControl sc, Surface barrierSurface,
long frameNumber) {
+ sc.checkNotReleased();
nativeDeferTransactionUntilSurface(mNativeObject, sc.mNativeObject,
barrierSurface.mNativeObject, frameNumber);
return this;
}
public Transaction reparentChildren(SurfaceControl sc, IBinder newParentHandle) {
+ sc.checkNotReleased();
nativeReparentChildren(mNativeObject, sc.mNativeObject, newParentHandle);
return this;
}
/** Re-parents a specific child layer to a new parent */
public Transaction reparent(SurfaceControl sc, IBinder newParentHandle) {
+ sc.checkNotReleased();
nativeReparent(mNativeObject, sc.mNativeObject,
newParentHandle);
return this;
}
public Transaction detachChildren(SurfaceControl sc) {
+ sc.checkNotReleased();
nativeSeverChildren(mNativeObject, sc.mNativeObject);
return this;
}
public Transaction setOverrideScalingMode(SurfaceControl sc, int overrideScalingMode) {
+ sc.checkNotReleased();
nativeSetOverrideScalingMode(mNativeObject, sc.mNativeObject,
overrideScalingMode);
return this;
@@ -1322,6 +1346,7 @@ public class SurfaceControl {
* @param color A float array with three values to represent r, g, b in range [0..1]
*/
public Transaction setColor(SurfaceControl sc, @Size(3) float[] color) {
+ sc.checkNotReleased();
nativeSetColor(mNativeObject, sc.mNativeObject, color);
return this;
}
@@ -1334,6 +1359,7 @@ public class SurfaceControl {
* (at which point the geometry influencing aspects of this transaction will then occur)
*/
public Transaction setGeometryAppliesWithResize(SurfaceControl sc) {
+ sc.checkNotReleased();
nativeSetGeometryAppliesWithResize(mNativeObject, sc.mNativeObject);
return this;
}
@@ -1343,6 +1369,7 @@ public class SurfaceControl {
* Surface with the {@link #SECURE} flag.
*/
Transaction setSecure(SurfaceControl sc, boolean isSecure) {
+ sc.checkNotReleased();
if (isSecure) {
nativeSetFlags(mNativeObject, sc.mNativeObject, SECURE, SECURE);
} else {
@@ -1356,6 +1383,7 @@ public class SurfaceControl {
* Surface with the {@link #OPAQUE} flag.
*/
public Transaction setOpaque(SurfaceControl sc, boolean isOpaque) {
+ sc.checkNotReleased();
if (isOpaque) {
nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_OPAQUE, SURFACE_OPAQUE);
} else {
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 2166f6e4742b..7c76bab2343d 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -70,6 +70,7 @@ public final class ThreadedRenderer {
* Name of the file that holds the shaders cache.
*/
private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache";
+ private static final String CACHE_PATH_SKIASHADERS = "com.android.skia.shaders_cache";
/**
* System property used to enable or disable threaded rendering profiling.
@@ -272,7 +273,9 @@ public final class ThreadedRenderer {
* @hide
*/
public static void setupDiskCache(File cacheDir) {
- ThreadedRenderer.setupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
+ ThreadedRenderer.setupShadersDiskCache(
+ new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath(),
+ new File(cacheDir, CACHE_PATH_SKIASHADERS).getAbsolutePath());
}
/**
@@ -1007,7 +1010,7 @@ public final class ThreadedRenderer {
/** Not actually public - internal use only. This doc to make lint happy */
public static native void disableVsync();
- static native void setupShadersDiskCache(String cacheFile);
+ static native void setupShadersDiskCache(String cacheFile, String skiaCacheFile);
private static native void nRotateProcessStatsBuffer();
private static native void nSetProcessStatsBuffer(int fd);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 499a4c8c4abd..e36a2989afbc 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -14220,6 +14220,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public void setScaleX(float scaleX) {
if (scaleX != getScaleX()) {
+ requireIsFinite(scaleX, "scaleX");
invalidateViewProperty(true, false);
mRenderNode.setScaleX(scaleX);
invalidateViewProperty(false, true);
@@ -14256,6 +14257,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public void setScaleY(float scaleY) {
if (scaleY != getScaleY()) {
+ requireIsFinite(scaleY, "scaleY");
invalidateViewProperty(true, false);
mRenderNode.setScaleY(scaleY);
invalidateViewProperty(false, true);
@@ -14805,6 +14807,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
+ private static void requireIsFinite(float transform, String propertyName) {
+ if (Float.isNaN(transform)) {
+ throw new IllegalArgumentException("Cannot set '" + propertyName + "' to Float.NaN");
+ }
+ if (Float.isInfinite(transform)) {
+ throw new IllegalArgumentException("Cannot set '" + propertyName + "' to infinity");
+ }
+ }
+
/**
* The visual x position of this view, in pixels. This is equivalent to the
* {@link #setTranslationX(float) translationX} property plus the current
@@ -14891,6 +14902,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public void setElevation(float elevation) {
if (elevation != getElevation()) {
+ requireIsFinite(elevation, "elevation");
invalidateViewProperty(true, false);
mRenderNode.setElevation(elevation);
invalidateViewProperty(false, true);
@@ -14983,6 +14995,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public void setTranslationZ(float translationZ) {
if (translationZ != getTranslationZ()) {
+ requireIsFinite(translationZ, "translationZ");
invalidateViewProperty(true, false);
mRenderNode.setTranslationZ(translationZ);
invalidateViewProperty(false, true);
@@ -15171,6 +15184,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return mRenderNode.hasShadow();
}
+ /**
+ * @hide
+ */
+ public void setShadowColor(@ColorInt int color) {
+ if (mRenderNode.setShadowColor(color)) {
+ invalidateViewProperty(true, true);
+ }
+ }
+
/** @hide */
public void setRevealClip(boolean shouldClip, float x, float y, float radius) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1c1933f2ba6e..e9509b798c76 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -516,7 +516,7 @@ public final class ViewRootImpl implements ViewParent,
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
if (!sCompatibilityDone) {
- sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P;
+ sAlwaysAssignFocus = true;
sCompatibilityDone = true;
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c29a1daf11ff..eb5fc92e5ccc 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1422,7 +1422,7 @@ public interface WindowManager extends ViewManager {
* this window is visible.
* @hide
*/
- @RequiresPermission(android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS)
+ @RequiresPermission(permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS)
public static final int PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 0x00080000;
/**
@@ -1443,6 +1443,15 @@ public interface WindowManager extends ViewManager {
public static final int PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN = 0x00200000;
/**
+ * Flag to indicate that this window should be considered a screen decoration similar to the
+ * nav bar and status bar. This will cause this window to affect the window insets reported
+ * to other windows when it is visible.
+ * @hide
+ */
+ @RequiresPermission(permission.STATUS_BAR_SERVICE)
+ public static final int PRIVATE_FLAG_IS_SCREEN_DECOR = 0x00400000;
+
+ /**
* Control flags that are private to the platform.
* @hide
*/
@@ -1526,7 +1535,11 @@ public interface WindowManager extends ViewManager {
@ViewDebug.FlagToString(
mask = PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN,
equals = PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN,
- name = "ACQUIRES_SLEEP_TOKEN")
+ name = "ACQUIRES_SLEEP_TOKEN"),
+ @ViewDebug.FlagToString(
+ mask = PRIVATE_FLAG_IS_SCREEN_DECOR,
+ equals = PRIVATE_FLAG_IS_SCREEN_DECOR,
+ name = "IS_SCREEN_DECOR")
})
@TestApi
public int privateFlags;
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index c7e8dee3da83..cca66d6b8ae0 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -605,9 +605,10 @@ public final class WindowManagerGlobal {
public void setStoppedState(IBinder token, boolean stopped) {
synchronized (mLock) {
int count = mViews.size();
- for (int i = 0; i < count; i++) {
+ for (int i = count - 1; i >= 0; i--) {
if (token == null || mParams.get(i).token == token) {
ViewRootImpl root = mRoots.get(i);
+ // Client might remove the view by "stopped" event.
root.setWindowStopped(stopped);
}
}
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index 69cc1002c5ba..cd1b1908e4d8 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -18,6 +18,7 @@ package android.view;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ClipData;
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManagerInternal;
@@ -140,6 +141,30 @@ public abstract class WindowManagerInternal {
}
/**
+ * An interface to customize drag and drop behaviors.
+ */
+ public interface IDragDropCallback {
+ /**
+ * Called when drag operation is started.
+ */
+ default boolean performDrag(IWindow window, IBinder dragToken,
+ int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
+ ClipData data) {
+ return true;
+ }
+
+ /**
+ * Called when drop result is reported.
+ */
+ default void reportDropResult(IWindow window, boolean consumed) {}
+
+ /**
+ * Called when drag operation is cancelled.
+ */
+ default void cancelDragAndDrop(IBinder dragToken) {}
+ }
+
+ /**
* Request that the window manager call
* {@link DisplayManagerInternal#performTraversalInTransactionFromWindowManager}
* within a surface transaction at a later time.
@@ -225,9 +250,6 @@ public abstract class WindowManagerInternal {
*/
public abstract boolean isKeyguardLocked();
- /** @return {@code true} if the keyguard is going away. */
- public abstract boolean isKeyguardGoingAway();
-
/**
* @return Whether the keyguard is showing and not occluded.
*/
@@ -354,4 +376,9 @@ public abstract class WindowManagerInternal {
* {@param vr2dDisplayId}.
*/
public abstract void setVr2dDisplayId(int vr2dDisplayId);
+
+ /**
+ * Sets callback to DragDropController.
+ */
+ public abstract void registerDragDropControllerCallback(IDragDropCallback callback);
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 137e551dbc9e..534335bf4743 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -66,7 +66,6 @@ import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.app.ActivityManager.StackId;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.CompatibilityInfo;
@@ -722,12 +721,6 @@ public interface WindowManagerPolicy {
public void setInitialDisplaySize(Display display, int width, int height, int density);
/**
- * Called by window manager to set the overscan region that should be used for the
- * given display.
- */
- public void setDisplayOverscan(Display display, int left, int top, int right, int bottom);
-
- /**
* Check permissions when adding a window.
*
* @param attrs The window's LayoutParams.
@@ -758,7 +751,8 @@ public interface WindowManagerPolicy {
* @param attrs The window layout parameters to be modified. These values
* are modified in-place.
*/
- public void adjustWindowParamsLw(WindowManager.LayoutParams attrs);
+ public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
+ boolean hasStatusBarServicePermission);
/**
* After the window manager has computed the current configuration based
@@ -1172,14 +1166,10 @@ public interface WindowManagerPolicy {
/**
* Called when layout of the windows is about to start.
*
- * @param isDefaultDisplay true if window is on {@link Display#DEFAULT_DISPLAY}.
- * @param displayWidth The current full width of the screen.
- * @param displayHeight The current full height of the screen.
- * @param displayRotation The current rotation being applied to the base window.
+ * @param displayFrames frames of the display we are doing layout on.
* @param uiMode The current uiMode in configuration.
*/
- public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
- int displayRotation, int uiMode);
+ default void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {}
/**
* Returns the bottom-most layer of the system decor, above which no policy decor should
@@ -1188,37 +1178,28 @@ public interface WindowManagerPolicy {
public int getSystemDecorLayerLw();
/**
- * Return the rectangle of the screen that is available for applications to run in.
- * This will be called immediately after {@link #beginLayoutLw}.
- *
- * @param r The rectangle to be filled with the boundaries available to applications.
- */
- public void getContentRectLw(Rect r);
-
- /**
- * Called for each window attached to the window manager as layout is
- * proceeding. The implementation of this function must take care of
- * setting the window's frame, either here or in finishLayout().
+ * Called for each window attached to the window manager as layout is proceeding. The
+ * implementation of this function must take care of setting the window's frame, either here or
+ * in finishLayout().
*
* @param win The window being positioned.
* @param attached For sub-windows, the window it is attached to; this
* window will already have had layoutWindow() called on it
* so you can use its Rect. Otherwise null.
+ * @param displayFrames The display frames.
*/
- public void layoutWindowLw(WindowState win, WindowState attached);
+ default void layoutWindowLw(
+ WindowState win, WindowState attached, DisplayFrames displayFrames) {}
/**
- * Return the insets for the areas covered by system windows. These values
- * are computed on the most recent layout, so they are not guaranteed to
- * be correct.
+ * Return the insets for the areas covered by system windows. These values are computed on the
+ * most recent layout, so they are not guaranteed to be correct.
*
* @param attrs The LayoutParams of the window.
* @param taskBounds The bounds of the task this window is on or {@code null} if no task is
* associated with the window.
- * @param displayRotation Rotation of the display.
- * @param displayWidth The width of the display.
- * @param displayHeight The height of the display.
+ * @param displayFrames display frames.
* @param outContentInsets The areas covered by system windows, expressed as positive insets.
* @param outStableInsets The areas covered by stable system windows irrespective of their
* current visibility. Expressed as positive insets.
@@ -1226,16 +1207,11 @@ public interface WindowManagerPolicy {
* @return Whether to always consume the navigation bar.
* See {@link #isNavBarForcedShownLw(WindowState)}.
*/
- public boolean getInsetHintLw(WindowManager.LayoutParams attrs, Rect taskBounds,
- int displayRotation, int displayWidth, int displayHeight, Rect outContentInsets,
- Rect outStableInsets, Rect outOutsets);
-
- /**
- * Called when layout of the windows is finished. After this function has
- * returned, all windows given to layoutWindow() <em>must</em> have had a
- * frame assigned.
- */
- public void finishLayoutLw();
+ default boolean getInsetHintLw(WindowManager.LayoutParams attrs, Rect taskBounds,
+ DisplayFrames displayFrames, Rect outContentInsets, Rect outStableInsets,
+ Rect outOutsets) {
+ return false;
+ }
/** Layout state may have changed (so another layout will be performed) */
static final int FINISH_LAYOUT_REDO_LAYOUT = 0x0001;
@@ -1652,11 +1628,6 @@ public interface WindowManagerPolicy {
public void showGlobalActions();
/**
- * @return The current height of the input method window.
- */
- public int getInputMethodWindowVisibleHeightLw();
-
- /**
* Called when the current user changes. Guaranteed to be called before the broadcast
* of the new user id is made to all listeners.
*
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 6a0669b022f7..9241ec0046ac 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -54,6 +54,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+// TODO: use java.lang.ref.Cleaner once Android supports Java 9
+import sun.misc.Cleaner;
+
/**
* The {@link AutofillManager} provides ways for apps and custom views to integrate with the
* Autofill Framework lifecycle.
@@ -303,6 +306,9 @@ public final class AutofillManager {
private IAutoFillManagerClient mServiceClient;
@GuardedBy("mLock")
+ private Cleaner mServiceClientCleaner;
+
+ @GuardedBy("mLock")
private AutofillCallback mCallback;
private final Context mContext;
@@ -1172,10 +1178,19 @@ public final class AutofillManager {
if (mServiceClient == null) {
mServiceClient = new AutofillManagerClient(this);
try {
- final int flags = mService.addClient(mServiceClient, mContext.getUserId());
+ final int userId = mContext.getUserId();
+ final int flags = mService.addClient(mServiceClient, userId);
mEnabled = (flags & FLAG_ADD_CLIENT_ENABLED) != 0;
sDebug = (flags & FLAG_ADD_CLIENT_DEBUG) != 0;
sVerbose = (flags & FLAG_ADD_CLIENT_VERBOSE) != 0;
+ final IAutoFillManager service = mService;
+ final IAutoFillManagerClient serviceClient = mServiceClient;
+ mServiceClientCleaner = Cleaner.create(this, () -> {
+ try {
+ service.removeClient(serviceClient, userId);
+ } catch (RemoteException e) {
+ }
+ });
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1294,6 +1309,10 @@ public final class AutofillManager {
if ((flags & SET_STATE_FLAG_RESET_CLIENT) != 0) {
// Reset connection to system
mServiceClient = null;
+ if (mServiceClientCleaner != null) {
+ mServiceClientCleaner.clean();
+ mServiceClientCleaner = null;
+ }
}
}
sDebug = (flags & SET_STATE_FLAG_DEBUG) != 0;
@@ -1897,7 +1916,7 @@ public final class AutofillManager {
public abstract static class AutofillCallback {
/** @hide */
- @IntDef({EVENT_INPUT_SHOWN, EVENT_INPUT_HIDDEN})
+ @IntDef({EVENT_INPUT_SHOWN, EVENT_INPUT_HIDDEN, EVENT_INPUT_UNAVAILABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface AutofillEventType {}
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 9329c4dcff6a..d6db3fe573f5 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -33,6 +33,7 @@ import android.view.autofill.IAutoFillManagerClient;
interface IAutoFillManager {
// Returns flags: FLAG_ADD_CLIENT_ENABLED | FLAG_ADD_CLIENT_DEBUG | FLAG_ADD_CLIENT_VERBOSE
int addClient(in IAutoFillManagerClient client, int userId);
+ void removeClient(in IAutoFillManagerClient client, int userId);
int startSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId,
in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags,
in ComponentName componentName);
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 26d2141e3486..2779aa2db93a 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -23,6 +23,7 @@ import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
+import android.os.LocaleList;
import android.view.View.OnClickListener;
import android.view.textclassifier.TextClassifier.EntityType;
@@ -438,4 +439,31 @@ public final class TextClassification {
mLogType, mVersionInfo);
}
}
+
+ /**
+ * TextClassification optional input parameters.
+ */
+ public static final class Options {
+
+ 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;
+ }
+
+ /**
+ * @return ordered list of locale preferences that can be used to disambiguate
+ * the provided text.
+ */
+ @Nullable
+ public LocaleList getDefaultLocales() {
+ return mDefaultLocales;
+ }
+ }
}
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 46dbd0e34a1c..aeb84897b06b 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -56,23 +56,7 @@ public interface TextClassifier {
* No-op TextClassifier.
* This may be used to turn off TextClassifier features.
*/
- TextClassifier NO_OP = new TextClassifier() {
-
- @Override
- public TextSelection suggestSelection(
- CharSequence text,
- int selectionStartIndex,
- int selectionEndIndex,
- LocaleList defaultLocales) {
- return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
- }
-
- @Override
- public TextClassification classifyText(
- CharSequence text, int startIndex, int endIndex, LocaleList defaultLocales) {
- return TextClassification.EMPTY;
- }
- };
+ TextClassifier NO_OP = new TextClassifier() {};
/**
* Returns suggested text selection start and end indices, recognized entity types, and their
@@ -82,21 +66,34 @@ public interface TextClassifier {
* 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
- * @param defaultLocales ordered list of locale preferences that can be used to disambiguate
- * the provided text. If no locale preferences exist, set this to null or an empty locale
- * list in which case the classifier will decide whether to use no locale information, use
- * a default locale, or use the system default.
+ * @param options optional input parameters
*
* @throws IllegalArgumentException if text is null; selectionStartIndex is negative;
* selectionEndIndex is greater than text.length() or not greater than selectionStartIndex
*/
@WorkerThread
@NonNull
- TextSelection suggestSelection(
+ default TextSelection suggestSelection(
+ @NonNull CharSequence text,
+ @IntRange(from = 0) int selectionStartIndex,
+ @IntRange(from = 0) int selectionEndIndex,
+ @Nullable TextSelection.Options options) {
+ return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
+ }
+
+ /**
+ * @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,
- @Nullable LocaleList defaultLocales);
+ @Nullable LocaleList defaultLocales) {
+ return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
+ }
/**
* Classifies the specified text and returns a {@link TextClassification} object that can be
@@ -106,41 +103,48 @@ public interface TextClassifier {
* 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
- * @param defaultLocales ordered list of locale preferences that can be used to disambiguate
- * the provided text. If no locale preferences exist, set this to null or an empty locale
- * list in which case the classifier will decide whether to use no locale information, use
- * a default locale, or use the system default.
+ * @param options optional input parameters
*
* @throws IllegalArgumentException if text is null; startIndex is negative;
* endIndex is greater than text.length() or not greater than startIndex
*/
@WorkerThread
@NonNull
- TextClassification classifyText(
+ default TextClassification classifyText(
@NonNull CharSequence text,
@IntRange(from = 0) int startIndex,
@IntRange(from = 0) int endIndex,
- @Nullable LocaleList defaultLocales);
+ @Nullable TextClassification.Options options) {
+ return TextClassification.EMPTY;
+ }
/**
- * Returns a {@link LinksInfo} that may be applied to the text to annotate it with links
+ * @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,
+ @Nullable LocaleList defaultLocales) {
+ return TextClassification.EMPTY;
+ }
+
+ /**
+ * Returns a {@link TextLinks} that may be applied to the text to annotate it with links
* information.
*
* @param text the text to generate annotations for
- * @param linkMask See {@link android.text.util.Linkify} for a list of linkMasks that may be
- * specified. Subclasses of this interface may specify additional linkMasks
- * @param defaultLocales ordered list of locale preferences that can be used to disambiguate
- * the provided text. If no locale preferences exist, set this to null or an empty locale
- * list in which case the classifier will decide whether to use no locale information, use
- * a default locale, or use the system default.
+ * @param options configuration for link generation. If null, defaults will be used.
*
* @throws IllegalArgumentException if text is null
- * @hide
*/
@WorkerThread
- default LinksInfo getLinks(
- @NonNull CharSequence text, int linkMask, @Nullable LocaleList defaultLocales) {
- return LinksInfo.NO_OP;
+ default TextLinks generateLinks(
+ @NonNull CharSequence text, @Nullable TextLinks.Options options) {
+ return new TextLinks.Builder(text.toString()).build();
}
/**
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 1c07be4bcd75..2ad6e02c4849 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -30,13 +30,8 @@ import android.os.ParcelFileDescriptor;
import android.provider.Browser;
import android.provider.ContactsContract;
import android.provider.Settings;
-import android.text.Spannable;
-import android.text.TextUtils;
-import android.text.method.WordIterator;
-import android.text.style.ClickableSpan;
import android.text.util.Linkify;
import android.util.Patterns;
-import android.view.View;
import android.widget.TextViewMetrics;
import com.android.internal.annotations.GuardedBy;
@@ -46,13 +41,8 @@ import com.android.internal.util.Preconditions;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.text.BreakIterator;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -100,16 +90,24 @@ final class TextClassifierImpl implements TextClassifier {
@Override
public TextSelection suggestSelection(
@NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex,
- @Nullable LocaleList defaultLocales) {
+ @Nullable TextSelection.Options options) {
validateInput(text, selectionStartIndex, selectionEndIndex);
try {
if (text.length() > 0) {
- final SmartSelection smartSelection = getSmartSelection(defaultLocales);
+ final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
+ final SmartSelection smartSelection = getSmartSelection(locales);
final String string = text.toString();
- final int[] startEnd = smartSelection.suggest(
- string, selectionStartIndex, selectionEndIndex);
- final int start = startEnd[0];
- final int end = startEnd[1];
+ final int start;
+ final int end;
+ if (getSettings().isDarkLaunch() && !options.isDarkLaunchAllowed()) {
+ start = selectionStartIndex;
+ end = selectionEndIndex;
+ } else {
+ final int[] startEnd = smartSelection.suggest(
+ string, selectionStartIndex, selectionEndIndex);
+ start = startEnd[0];
+ end = startEnd[1];
+ }
if (start <= end
&& start >= 0 && end <= string.length()
&& start <= selectionStartIndex && end >= selectionEndIndex) {
@@ -139,18 +137,27 @@ final class TextClassifierImpl implements TextClassifier {
}
// Getting here means something went wrong, return a NO_OP result.
return TextClassifier.NO_OP.suggestSelection(
- text, selectionStartIndex, selectionEndIndex, defaultLocales);
+ text, selectionStartIndex, selectionEndIndex, options);
+ }
+
+ @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 LocaleList defaultLocales) {
+ @Nullable TextClassification.Options options) {
validateInput(text, startIndex, endIndex);
try {
if (text.length() > 0) {
final String string = text.toString();
- SmartSelection.ClassificationResult[] results = getSmartSelection(defaultLocales)
+ final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
+ final SmartSelection.ClassificationResult[] results = getSmartSelection(locales)
.classifyText(string, startIndex, endIndex,
getHintFlags(string, startIndex, endIndex));
if (results.length > 0) {
@@ -165,23 +172,41 @@ final class TextClassifierImpl implements TextClassifier {
Log.e(LOG_TAG, "Error getting text classification info.", t);
}
// Getting here means something went wrong, return a NO_OP result.
- return TextClassifier.NO_OP.classifyText(
- text, startIndex, endIndex, defaultLocales);
+ return TextClassifier.NO_OP.classifyText(text, startIndex, endIndex, options);
}
@Override
- public LinksInfo getLinks(
- @NonNull CharSequence text, int linkMask, @Nullable LocaleList defaultLocales) {
- Preconditions.checkArgument(text != null);
+ 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);
+ final String textString = text.toString();
+ final TextLinks.Builder builder = new TextLinks.Builder(textString);
try {
- return LinksInfoFactory.create(
- mContext, getSmartSelection(defaultLocales), text.toString(), linkMask);
+ LocaleList defaultLocales = options != null ? options.getDefaultLocales() : null;
+ final SmartSelection smartSelection = getSmartSelection(defaultLocales);
+ final SmartSelection.AnnotatedSpan[] annotations = smartSelection.annotate(textString);
+ for (SmartSelection.AnnotatedSpan span : annotations) {
+ final Map<String, Float> entityScores = new HashMap<>();
+ final SmartSelection.ClassificationResult[] results = span.getClassification();
+ for (int i = 0; i < results.length; i++) {
+ entityScores.put(results[i].mCollection, results[i].mScore);
+ }
+ builder.addLink(new TextLinks.TextLink(
+ textString, span.getStartIndex(), span.getEndIndex(), entityScores));
+ }
} catch (Throwable t) {
// Avoid throwing from this method. Log the error.
Log.e(LOG_TAG, "Error getting links info.", t);
}
- // Getting here means something went wrong, return a NO_OP result.
- return TextClassifier.NO_OP.getLinks(text, linkMask, defaultLocales);
+ return builder.build();
}
@Override
@@ -210,7 +235,9 @@ final class TextClassifierImpl implements TextClassifier {
if (mSmartSelection == null || !Objects.equals(mLocale, locale)) {
destroySmartSelectionIfExistsLocked();
final ParcelFileDescriptor fd = getFdLocked(locale);
- mSmartSelection = new SmartSelection(fd.getFd());
+ final int modelFd = fd.getFd();
+ mVersion = SmartSelection.getVersion(modelFd);
+ mSmartSelection = new SmartSelection(modelFd);
closeAndLogError(fd);
mLocale = locale;
}
@@ -231,18 +258,26 @@ final class TextClassifierImpl implements TextClassifier {
@GuardedBy("mSmartSelectionLock") // Do not call outside this lock.
private ParcelFileDescriptor getFdLocked(Locale locale) throws FileNotFoundException {
ParcelFileDescriptor updateFd;
+ int updateVersion = -1;
try {
updateFd = ParcelFileDescriptor.open(
new File(UPDATED_MODEL_FILE_PATH), ParcelFileDescriptor.MODE_READ_ONLY);
+ if (updateFd != null) {
+ updateVersion = SmartSelection.getVersion(updateFd.getFd());
+ }
} catch (FileNotFoundException e) {
updateFd = null;
}
ParcelFileDescriptor factoryFd;
+ int factoryVersion = -1;
try {
final String factoryModelFilePath = getFactoryModelFilePathsLocked().get(locale);
if (factoryModelFilePath != null) {
factoryFd = ParcelFileDescriptor.open(
new File(factoryModelFilePath), ParcelFileDescriptor.MODE_READ_ONLY);
+ if (factoryFd != null) {
+ factoryVersion = SmartSelection.getVersion(factoryFd.getFd());
+ }
} else {
factoryFd = null;
}
@@ -278,15 +313,11 @@ final class TextClassifierImpl implements TextClassifier {
return factoryFd;
}
- final int updateVersion = SmartSelection.getVersion(updateFdInt);
- final int factoryVersion = SmartSelection.getVersion(factoryFd.getFd());
if (updateVersion > factoryVersion) {
closeAndLogError(factoryFd);
- mVersion = updateVersion;
return updateFd;
} else {
closeAndLogError(updateFd);
- mVersion = factoryVersion;
return factoryFd;
}
}
@@ -466,180 +497,6 @@ final class TextClassifierImpl implements TextClassifier {
}
/**
- * Detects and creates links for specified text.
- */
- private static final class LinksInfoFactory {
-
- private LinksInfoFactory() {}
-
- public static LinksInfo create(
- Context context, SmartSelection smartSelection, String text, int linkMask) {
- final WordIterator wordIterator = new WordIterator();
- wordIterator.setCharSequence(text, 0, text.length());
- final List<SpanSpec> spans = new ArrayList<>();
- int start = 0;
- int end;
- while ((end = wordIterator.nextBoundary(start)) != BreakIterator.DONE) {
- final String token = text.substring(start, end);
- if (TextUtils.isEmpty(token)) {
- continue;
- }
-
- final int[] selection = smartSelection.suggest(text, start, end);
- final int selectionStart = selection[0];
- final int selectionEnd = selection[1];
- if (selectionStart >= 0 && selectionEnd <= text.length()
- && selectionStart <= selectionEnd) {
- final SmartSelection.ClassificationResult[] results =
- smartSelection.classifyText(
- text, selectionStart, selectionEnd,
- getHintFlags(text, selectionStart, selectionEnd));
- if (results.length > 0) {
- final String type = getHighestScoringType(results);
- if (matches(type, linkMask)) {
- // For links without disambiguation, we simply use the default intent.
- final List<Intent> intents = IntentFactory.create(
- context, type, text.substring(selectionStart, selectionEnd));
- if (!intents.isEmpty() && hasActivityHandler(context, intents.get(0))) {
- final ClickableSpan span = createSpan(context, intents.get(0));
- spans.add(new SpanSpec(selectionStart, selectionEnd, span));
- }
- }
- }
- }
- start = end;
- }
- return new LinksInfoImpl(text, avoidOverlaps(spans, text));
- }
-
- /**
- * Returns true if the classification type matches the specified linkMask.
- */
- private static boolean matches(String type, int linkMask) {
- type = type.trim().toLowerCase(Locale.ENGLISH);
- if ((linkMask & Linkify.PHONE_NUMBERS) != 0
- && TextClassifier.TYPE_PHONE.equals(type)) {
- return true;
- }
- if ((linkMask & Linkify.EMAIL_ADDRESSES) != 0
- && TextClassifier.TYPE_EMAIL.equals(type)) {
- return true;
- }
- if ((linkMask & Linkify.MAP_ADDRESSES) != 0
- && TextClassifier.TYPE_ADDRESS.equals(type)) {
- return true;
- }
- if ((linkMask & Linkify.WEB_URLS) != 0
- && TextClassifier.TYPE_URL.equals(type)) {
- return true;
- }
- return false;
- }
-
- /**
- * Trim the number of spans so that no two spans overlap.
- *
- * This algorithm first ensures that there is only one span per start index, then it
- * makes sure that no two spans overlap.
- */
- private static List<SpanSpec> avoidOverlaps(List<SpanSpec> spans, String text) {
- Collections.sort(spans, Comparator.comparingInt(span -> span.mStart));
- // Group spans by start index. Take the longest span.
- final Map<Integer, SpanSpec> reps = new LinkedHashMap<>(); // order matters.
- final int size = spans.size();
- for (int i = 0; i < size; i++) {
- final SpanSpec span = spans.get(i);
- final LinksInfoFactory.SpanSpec rep = reps.get(span.mStart);
- if (rep == null || rep.mEnd < span.mEnd) {
- reps.put(span.mStart, span);
- }
- }
- // Avoid span intersections. Take the longer span.
- final LinkedList<SpanSpec> result = new LinkedList<>();
- for (SpanSpec rep : reps.values()) {
- if (result.isEmpty()) {
- result.add(rep);
- continue;
- }
-
- final SpanSpec last = result.getLast();
- if (rep.mStart < last.mEnd) {
- // Spans intersect. Use the one with characters.
- if ((rep.mEnd - rep.mStart) > (last.mEnd - last.mStart)) {
- result.set(result.size() - 1, rep);
- }
- } else {
- result.add(rep);
- }
- }
- return result;
- }
-
- private static ClickableSpan createSpan(final Context context, final Intent intent) {
- return new ClickableSpan() {
- // TODO: Style this span.
- @Override
- public void onClick(View widget) {
- context.startActivity(intent);
- }
- };
- }
-
- private static boolean hasActivityHandler(Context context, Intent intent) {
- if (intent == null) {
- return false;
- }
- final ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, 0);
- return resolveInfo != null && resolveInfo.activityInfo != null;
- }
-
- /**
- * Implementation of LinksInfo that adds ClickableSpans to the specified text.
- */
- private static final class LinksInfoImpl implements LinksInfo {
-
- private final CharSequence mOriginalText;
- private final List<SpanSpec> mSpans;
-
- LinksInfoImpl(CharSequence originalText, List<SpanSpec> spans) {
- mOriginalText = originalText;
- mSpans = spans;
- }
-
- @Override
- public boolean apply(@NonNull CharSequence text) {
- Preconditions.checkArgument(text != null);
- if (text instanceof Spannable && mOriginalText.toString().equals(text.toString())) {
- Spannable spannable = (Spannable) text;
- final int size = mSpans.size();
- for (int i = 0; i < size; i++) {
- final SpanSpec span = mSpans.get(i);
- spannable.setSpan(span.mSpan, span.mStart, span.mEnd, 0);
- }
- return true;
- }
- return false;
- }
- }
-
- /**
- * Span plus its start and end index.
- */
- private static final class SpanSpec {
-
- private final int mStart;
- private final int mEnd;
- private final ClickableSpan mSpan;
-
- SpanSpec(int start, int end, ClickableSpan span) {
- mStart = start;
- mEnd = end;
- mSpan = span;
- }
- }
- }
-
- /**
* Creates intents based on the classification type.
*/
private static final class IntentFactory {
@@ -656,8 +513,8 @@ final class TextClassifierImpl implements TextClassifier {
intents.add(new Intent(Intent.ACTION_SENDTO)
.setData(Uri.parse(String.format("mailto:%s", text))));
intents.add(new Intent(Intent.ACTION_INSERT_OR_EDIT)
- .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
- .putExtra(ContactsContract.Intents.Insert.EMAIL, text));
+ .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
+ .putExtra(ContactsContract.Intents.Insert.EMAIL, text));
break;
case TextClassifier.TYPE_PHONE:
intents.add(new Intent(Intent.ACTION_DIAL)
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
new file mode 100644
index 000000000000..f3cc827f8889
--- /dev/null
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.textclassifier;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.LocaleList;
+import android.text.SpannableString;
+import android.text.style.ClickableSpan;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * A collection of links, representing subsequences of text and the entity types (phone number,
+ * address, url, etc) they may be.
+ */
+public final class TextLinks {
+ private final String mFullText;
+ private final List<TextLink> mLinks;
+
+ private TextLinks(String fullText, Collection<TextLink> links) {
+ mFullText = fullText;
+ mLinks = Collections.unmodifiableList(new ArrayList<>(links));
+ }
+
+ /**
+ * Returns an unmodifiable Collection of the links.
+ */
+ public Collection<TextLink> getLinks() {
+ return mLinks;
+ }
+
+ /**
+ * Annotates the given text with the generated links. It will fail if the provided text doesn't
+ * match the original text used to crete the TextLinks.
+ *
+ * @param text the text to apply the links to. Must match the original text.
+ * @param spanFactory a factory to generate spans from TextLinks. Will use a default if null.
+ *
+ * @return Success or failure.
+ */
+ public boolean apply(
+ @NonNull SpannableString text,
+ @Nullable Function<TextLink, ClickableSpan> spanFactory) {
+ Preconditions.checkNotNull(text);
+ if (!mFullText.equals(text.toString())) {
+ return false;
+ }
+
+ if (spanFactory == null) {
+ spanFactory = DEFAULT_SPAN_FACTORY;
+ }
+ for (TextLink link : mLinks) {
+ final ClickableSpan span = spanFactory.apply(link);
+ if (span != null) {
+ text.setSpan(span, link.getStart(), link.getEnd(), 0);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * A link, identifying a substring of text and possible entity types for it.
+ */
+ public static final class TextLink {
+ private final EntityConfidence<String> mEntityScores;
+ private final String mOriginalText;
+ private final int mStart;
+ private final int mEnd;
+
+ /**
+ * Create a new TextLink.
+ *
+ * @throws IllegalArgumentException if entityScores is null or empty.
+ */
+ public TextLink(String originalText, int start, int end, Map<String, Float> entityScores) {
+ Preconditions.checkNotNull(originalText);
+ Preconditions.checkNotNull(entityScores);
+ Preconditions.checkArgument(!entityScores.isEmpty());
+ Preconditions.checkArgument(start <= end);
+ mOriginalText = originalText;
+ mStart = start;
+ mEnd = end;
+ mEntityScores = new EntityConfidence<>();
+
+ for (Map.Entry<String, Float> entry : entityScores.entrySet()) {
+ mEntityScores.setEntityType(entry.getKey(), entry.getValue());
+ }
+ }
+
+ /**
+ * Returns the start index of this link in the original text.
+ *
+ * @return the start index.
+ */
+ public int getStart() {
+ return mStart;
+ }
+
+ /**
+ * Returns the end index of this link in the original text.
+ *
+ * @return the end index.
+ */
+ public int getEnd() {
+ return mEnd;
+ }
+
+ /**
+ * Returns the number of entity types that have confidence scores.
+ *
+ * @return the entity count.
+ */
+ public int getEntityCount() {
+ return mEntityScores.getEntities().size();
+ }
+
+ /**
+ * Returns the entity type at a given index. Entity types are sorted by confidence.
+ *
+ * @return the entity type at the provided index.
+ */
+ @NonNull public @TextClassifier.EntityType String getEntity(int index) {
+ return mEntityScores.getEntities().get(index);
+ }
+
+ /**
+ * Returns the confidence score for a particular entity type.
+ *
+ * @param entityType the entity type.
+ */
+ public @FloatRange(from = 0.0, to = 1.0) float getConfidenceScore(
+ @TextClassifier.EntityType String entityType) {
+ return mEntityScores.getConfidenceScore(entityType);
+ }
+ }
+
+ /**
+ * Optional input parameters for generating TextLinks.
+ */
+ public static final class Options {
+ private final LocaleList mLocaleList;
+
+ private Options(LocaleList localeList) {
+ this.mLocaleList = localeList;
+ }
+
+ /**
+ * Builder to construct Options.
+ */
+ 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);
+ }
+ }
+ public @Nullable LocaleList getDefaultLocales() {
+ return mLocaleList;
+ }
+ };
+
+ /**
+ * A function to create spans from TextLinks.
+ *
+ * Applies only to TextViews.
+ * We can hide this until we are convinced we want it to be part of the public API.
+ *
+ * @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");
+ }
+ };
+
+ /**
+ * A builder to construct a TextLinks instance.
+ */
+ public static final class Builder {
+ private final String mFullText;
+ private final Collection<TextLink> mLinks;
+
+ /**
+ * Create a new TextLinks.Builder.
+ *
+ * @param fullText The full text that links will be added to.
+ */
+ public Builder(@NonNull String fullText) {
+ mFullText = Preconditions.checkNotNull(fullText);
+ mLinks = new ArrayList<>();
+ }
+
+ /**
+ * Adds a TextLink.
+ *
+ * @return this instance.
+ */
+ public Builder addLink(TextLink link) {
+ Preconditions.checkNotNull(link);
+ mLinks.add(link);
+ return this;
+ }
+
+ /**
+ * Constructs a TextLinks instance.
+ *
+ * @return the constructed TextLinks.
+ */
+ public TextLinks build() {
+ return new TextLinks(mFullText, mLinks);
+ }
+ }
+}
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 11ebe8359b9c..0a67954a2e33 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -19,6 +19,8 @@ package android.view.textclassifier;
import android.annotation.FloatRange;
import android.annotation.IntRange;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.LocaleList;
import android.view.textclassifier.TextClassifier.EntityType;
import com.android.internal.util.Preconditions;
@@ -181,4 +183,55 @@ public final class TextSelection {
mStartIndex, mEndIndex, mEntityConfidence, mLogSource, mVersionInfo);
}
}
+
+ /**
+ * TextSelection optional input parameters.
+ */
+ public static final class Options {
+
+ private LocaleList mDefaultLocales;
+ private boolean mDarkLaunchAllowed;
+
+ /**
+ * @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;
+ }
+
+ /**
+ * @return ordered list of locale preferences that can be used to disambiguate
+ * the provided text.
+ */
+ @Nullable
+ public LocaleList getDefaultLocales() {
+ return mDefaultLocales;
+ }
+
+ /**
+ * @param allowed whether or not the TextClassifier should return selection suggestions
+ * when "dark launched". When a TextClassifier is dark launched, it can suggest
+ * selection changes that should not be used to actually change the user's selection.
+ * Instead, the suggested selection is logged, compared with the user's selection
+ * interaction, and used to generate quality metrics for the TextClassifier.
+ *
+ * @hide
+ */
+ public void setDarkLaunchAllowed(boolean allowed) {
+ mDarkLaunchAllowed = allowed;
+ }
+
+ /**
+ * Returns true if the TextClassifier should return selection suggestions when
+ * "dark launched". Otherwise, returns false.
+ *
+ * @hide
+ */
+ public boolean isDarkLaunchAllowed() {
+ return mDarkLaunchAllowed;
+ }
+ }
}
diff --git a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
index 83af19bbd328..2833564f73c4 100644
--- a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
+++ b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
@@ -48,31 +48,45 @@ public final class SmartSelectionEventTracker {
private static final int START_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_START;
private static final int PREV_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_PREVIOUS;
private static final int INDEX = MetricsEvent.FIELD_SELECTION_SESSION_INDEX;
- private static final int VERSION_TAG = MetricsEvent.FIELD_SELECTION_VERSION_TAG;
- private static final int SMART_INDICES = MetricsEvent.FIELD_SELECTION_SMART_RANGE;
- private static final int EVENT_INDICES = MetricsEvent.FIELD_SELECTION_RANGE;
+ private static final int WIDGET_TYPE = MetricsEvent.FIELD_SELECTION_WIDGET_TYPE;
+ private static final int WIDGET_VERSION = MetricsEvent.FIELD_SELECTION_WIDGET_VERSION;
+ private static final int MODEL_NAME = MetricsEvent.FIELD_TEXTCLASSIFIER_MODEL;
+ private static final int ENTITY_TYPE = MetricsEvent.FIELD_SELECTION_ENTITY_TYPE;
+ private static final int SMART_START = MetricsEvent.FIELD_SELECTION_SMART_RANGE_START;
+ private static final int SMART_END = MetricsEvent.FIELD_SELECTION_SMART_RANGE_END;
+ private static final int EVENT_START = MetricsEvent.FIELD_SELECTION_RANGE_START;
+ private static final int EVENT_END = MetricsEvent.FIELD_SELECTION_RANGE_END;
private static final int SESSION_ID = MetricsEvent.FIELD_SELECTION_SESSION_ID;
private static final String ZERO = "0";
private static final String TEXTVIEW = "textview";
private static final String EDITTEXT = "edittext";
+ private static final String UNSELECTABLE_TEXTVIEW = "nosel-textview";
private static final String WEBVIEW = "webview";
private static final String EDIT_WEBVIEW = "edit-webview";
+ private static final String CUSTOM_TEXTVIEW = "customview";
+ private static final String CUSTOM_EDITTEXT = "customedit";
+ private static final String CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
private static final String UNKNOWN = "unknown";
@Retention(RetentionPolicy.SOURCE)
@IntDef({WidgetType.UNSPECIFIED, WidgetType.TEXTVIEW, WidgetType.WEBVIEW,
WidgetType.EDITTEXT, WidgetType.EDIT_WEBVIEW})
public @interface WidgetType {
- int UNSPECIFIED = 0;
- int TEXTVIEW = 1;
- int WEBVIEW = 2;
- int EDITTEXT = 3;
- int EDIT_WEBVIEW = 4;
+ int UNSPECIFIED = 0;
+ int TEXTVIEW = 1;
+ int WEBVIEW = 2;
+ int EDITTEXT = 3;
+ int EDIT_WEBVIEW = 4;
+ int UNSELECTABLE_TEXTVIEW = 5;
+ int CUSTOM_TEXTVIEW = 6;
+ int CUSTOM_EDITTEXT = 7;
+ int CUSTOM_UNSELECTABLE_TEXTVIEW = 8;
}
private final MetricsLogger mMetricsLogger = new MetricsLogger();
private final int mWidgetType;
+ @Nullable private final String mWidgetVersion;
private final Context mContext;
@Nullable private String mSessionId;
@@ -83,10 +97,18 @@ public final class SmartSelectionEventTracker {
private long mSessionStartTime;
private long mLastEventTime;
private boolean mSmartSelectionTriggered;
- private String mVersionTag;
+ private String mModelName;
public SmartSelectionEventTracker(@NonNull Context context, @WidgetType int widgetType) {
mWidgetType = widgetType;
+ mWidgetVersion = null;
+ mContext = Preconditions.checkNotNull(context);
+ }
+
+ public SmartSelectionEventTracker(
+ @NonNull Context context, @WidgetType int widgetType, @Nullable String widgetVersion) {
+ mWidgetType = widgetType;
+ mWidgetVersion = widgetVersion;
mContext = Preconditions.checkNotNull(context);
}
@@ -115,7 +137,7 @@ public final class SmartSelectionEventTracker {
case SelectionEvent.EventType.SMART_SELECTION_SINGLE: // fall through
case SelectionEvent.EventType.SMART_SELECTION_MULTI:
mSmartSelectionTriggered = true;
- mVersionTag = getVersionTag(event);
+ mModelName = getModelName(event);
mSmartIndices[0] = event.mStart;
mSmartIndices[1] = event.mEnd;
break;
@@ -137,14 +159,19 @@ public final class SmartSelectionEventTracker {
final long prevEventDelta = mLastEventTime == 0 ? 0 : now - mLastEventTime;
final LogMaker log = new LogMaker(MetricsEvent.TEXT_SELECTION_SESSION)
.setType(getLogType(event))
- .setSubtype(getLogSubType(event))
+ .setSubtype(MetricsEvent.TEXT_SELECTION_INVOCATION_MANUAL)
.setPackageName(mContext.getPackageName())
.addTaggedData(START_EVENT_DELTA, now - mSessionStartTime)
.addTaggedData(PREV_EVENT_DELTA, prevEventDelta)
.addTaggedData(INDEX, mIndex)
- .addTaggedData(VERSION_TAG, mVersionTag)
- .addTaggedData(SMART_INDICES, getSmartDelta())
- .addTaggedData(EVENT_INDICES, getEventDelta(event))
+ .addTaggedData(WIDGET_TYPE, getWidgetTypeName())
+ .addTaggedData(WIDGET_VERSION, mWidgetVersion)
+ .addTaggedData(MODEL_NAME, mModelName)
+ .addTaggedData(ENTITY_TYPE, event.mEntityType)
+ .addTaggedData(SMART_START, getSmartRangeDelta(mSmartIndices[0]))
+ .addTaggedData(SMART_END, getSmartRangeDelta(mSmartIndices[1]))
+ .addTaggedData(EVENT_START, getRangeDelta(event.mStart))
+ .addTaggedData(EVENT_END, getRangeDelta(event.mEnd))
.addTaggedData(SESSION_ID, mSessionId);
mMetricsLogger.write(log);
debugLog(log);
@@ -169,7 +196,7 @@ public final class SmartSelectionEventTracker {
mSessionStartTime = 0;
mLastEventTime = 0;
mSmartSelectionTriggered = false;
- mVersionTag = getVersionTag(null);
+ mModelName = getModelName(null);
mSessionId = null;
}
@@ -251,113 +278,75 @@ public final class SmartSelectionEventTracker {
}
}
- private static int getLogSubType(SelectionEvent event) {
- switch (event.mEntityType) {
- case TextClassifier.TYPE_OTHER:
- return MetricsEvent.TEXT_CLASSIFIER_TYPE_OTHER;
- case TextClassifier.TYPE_EMAIL:
- return MetricsEvent.TEXT_CLASSIFIER_TYPE_EMAIL;
- case TextClassifier.TYPE_PHONE:
- return MetricsEvent.TEXT_CLASSIFIER_TYPE_PHONE;
- case TextClassifier.TYPE_ADDRESS:
- return MetricsEvent.TEXT_CLASSIFIER_TYPE_ADDRESS;
- case TextClassifier.TYPE_URL:
- return MetricsEvent.TEXT_CLASSIFIER_TYPE_URL;
- default:
- return MetricsEvent.TEXT_CLASSIFIER_TYPE_UNKNOWN;
- }
- }
-
- private static String getLogSubTypeString(int logSubType) {
- switch (logSubType) {
- case MetricsEvent.TEXT_CLASSIFIER_TYPE_OTHER:
- return TextClassifier.TYPE_OTHER;
- case MetricsEvent.TEXT_CLASSIFIER_TYPE_EMAIL:
- return TextClassifier.TYPE_EMAIL;
- case MetricsEvent.TEXT_CLASSIFIER_TYPE_PHONE:
- return TextClassifier.TYPE_PHONE;
- case MetricsEvent.TEXT_CLASSIFIER_TYPE_ADDRESS:
- return TextClassifier.TYPE_ADDRESS;
- case MetricsEvent.TEXT_CLASSIFIER_TYPE_URL:
- return TextClassifier.TYPE_URL;
- default:
- return TextClassifier.TYPE_UNKNOWN;
- }
- }
-
- private int getSmartDelta() {
- if (mSmartSelectionTriggered) {
- return (clamp(mSmartIndices[0] - mOrigStart) << 16)
- | (clamp(mSmartIndices[1] - mOrigStart) & 0xffff);
- }
- // If the smart selection model was not run, return invalid selection indices [0,0]. This
- // allows us to tell from the terminal event alone whether the model was run.
- return 0;
+ private int getRangeDelta(int offset) {
+ return offset - mOrigStart;
}
- private int getEventDelta(SelectionEvent event) {
- return (clamp(event.mStart - mOrigStart) << 16)
- | (clamp(event.mEnd - mOrigStart) & 0xffff);
+ private int getSmartRangeDelta(int offset) {
+ return mSmartSelectionTriggered ? getRangeDelta(offset) : 0;
}
- private String getVersionTag(@Nullable SelectionEvent event) {
- final String widgetType;
+ private String getWidgetTypeName() {
switch (mWidgetType) {
case WidgetType.TEXTVIEW:
- widgetType = TEXTVIEW;
- break;
+ return TEXTVIEW;
case WidgetType.WEBVIEW:
- widgetType = WEBVIEW;
- break;
+ return WEBVIEW;
case WidgetType.EDITTEXT:
- widgetType = EDITTEXT;
- break;
+ return EDITTEXT;
case WidgetType.EDIT_WEBVIEW:
- widgetType = EDIT_WEBVIEW;
- break;
+ return EDIT_WEBVIEW;
+ case WidgetType.UNSELECTABLE_TEXTVIEW:
+ return UNSELECTABLE_TEXTVIEW;
+ case WidgetType.CUSTOM_TEXTVIEW:
+ return CUSTOM_TEXTVIEW;
+ case WidgetType.CUSTOM_EDITTEXT:
+ return CUSTOM_EDITTEXT;
+ case WidgetType.CUSTOM_UNSELECTABLE_TEXTVIEW:
+ return CUSTOM_UNSELECTABLE_TEXTVIEW;
default:
- widgetType = UNKNOWN;
+ return UNKNOWN;
}
- final String version = event == null
+ }
+
+ private String getModelName(@Nullable SelectionEvent event) {
+ return event == null
? SelectionEvent.NO_VERSION_TAG
: Objects.toString(event.mVersionTag, SelectionEvent.NO_VERSION_TAG);
- return String.format("%s/%s", widgetType, version);
}
private static String createSessionId() {
return UUID.randomUUID().toString();
}
- private static int clamp(int val) {
- return Math.max(Math.min(val, Short.MAX_VALUE), Short.MIN_VALUE);
- }
-
private static void debugLog(LogMaker log) {
if (!DEBUG_LOG_ENABLED) return;
- final String tag = Objects.toString(log.getTaggedData(VERSION_TAG), "tag");
+ final String widgetType = Objects.toString(log.getTaggedData(WIDGET_TYPE), UNKNOWN);
+ final String widgetVersion = Objects.toString(log.getTaggedData(WIDGET_VERSION), "");
+ final String widget = widgetVersion.isEmpty()
+ ? widgetType : widgetType + "-" + widgetVersion;
final int index = Integer.parseInt(Objects.toString(log.getTaggedData(INDEX), ZERO));
if (log.getType() == MetricsEvent.ACTION_TEXT_SELECTION_START) {
String sessionId = Objects.toString(log.getTaggedData(SESSION_ID), "");
sessionId = sessionId.substring(sessionId.lastIndexOf("-") + 1);
- Log.d(LOG_TAG, String.format("New selection session: %s(%s)", tag, sessionId));
+ Log.d(LOG_TAG, String.format("New selection session: %s (%s)", widget, sessionId));
}
+ final String model = Objects.toString(log.getTaggedData(MODEL_NAME), UNKNOWN);
+ final String entity = Objects.toString(log.getTaggedData(ENTITY_TYPE), UNKNOWN);
final String type = getLogTypeString(log.getType());
- final String subType = getLogSubTypeString(log.getSubtype());
-
- final int smartIndices = Integer.parseInt(
- Objects.toString(log.getTaggedData(SMART_INDICES), ZERO));
- final int smartStart = (short) ((smartIndices & 0xffff0000) >> 16);
- final int smartEnd = (short) (smartIndices & 0xffff);
-
- final int eventIndices = Integer.parseInt(
- Objects.toString(log.getTaggedData(EVENT_INDICES), ZERO));
- final int eventStart = (short) ((eventIndices & 0xffff0000) >> 16);
- final int eventEnd = (short) (eventIndices & 0xffff);
-
- Log.d(LOG_TAG, String.format("%2d: %s/%s, context=%d,%d - old=%d,%d (%s)",
- index, type, subType, eventStart, eventEnd, smartStart, smartEnd, tag));
+ final int smartStart = Integer.parseInt(
+ Objects.toString(log.getTaggedData(SMART_START), ZERO));
+ final int smartEnd = Integer.parseInt(
+ Objects.toString(log.getTaggedData(SMART_END), ZERO));
+ final int eventStart = Integer.parseInt(
+ Objects.toString(log.getTaggedData(EVENT_START), ZERO));
+ final int eventEnd = Integer.parseInt(
+ Objects.toString(log.getTaggedData(EVENT_END), ZERO));
+
+ Log.d(LOG_TAG, String.format("%2d: %s/%s, range=%d,%d - smart_range=%d,%d (%s/%s)",
+ index, type, entity, eventStart, eventEnd, smartStart, smartEnd, widget, model));
}
/**
@@ -369,12 +358,12 @@ public final class SmartSelectionEventTracker {
/**
* Use this to specify an indeterminate positive index.
*/
- public static final int OUT_OF_BOUNDS = Short.MAX_VALUE;
+ public static final int OUT_OF_BOUNDS = Integer.MAX_VALUE;
/**
* Use this to specify an indeterminate negative index.
*/
- public static final int OUT_OF_BOUNDS_NEGATIVE = Short.MIN_VALUE;
+ public static final int OUT_OF_BOUNDS_NEGATIVE = Integer.MIN_VALUE;
private static final String NO_VERSION_TAG = "";
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 9295f5cb228a..665d694e492b 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -308,10 +308,15 @@ import java.util.Map;
* WebView may upload anonymous diagnostic data to Google when the user has consented. This data
* helps Google improve WebView. Data is collected on a per-app basis for each app which has
* instantiated a WebView. An individual app can opt out of this feature by putting the following
- * tag in its manifest:
+ * tag in its manifest's {@code <application>} element:
* <pre>
- * &lt;meta-data android:name="android.webkit.WebView.MetricsOptOut"
- * android:value="true" /&gt;
+ * &lt;manifest&gt;
+ * &lt;application&gt;
+ * ...
+ * &lt;meta-data android:name=&quot;android.webkit.WebView.MetricsOptOut&quot;
+ * android:value=&quot;true&quot; /&gt;
+ * &lt;/application&gt;
+ * &lt;/manifest&gt;
* </pre>
* <p>
* Data will only be uploaded for a given app if the user has consented AND the app has not opted
@@ -323,11 +328,17 @@ import java.util.Map;
* If Safe Browsing is enabled, WebView will block malicious URLs and present a warning UI to the
* user to allow them to navigate back safely or proceed to the malicious page.
* <p>
- * The recommended way for apps to enable the feature is putting the following tag in the manifest:
+ * The recommended way for apps to enable the feature is putting the following tag in the manifest's
+ * {@code <application>} element:
* <p>
* <pre>
- * &lt;meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
- * android:value="true" /&gt;
+ * &lt;manifest&gt;
+ * &lt;application&gt;
+ * ...
+ * &lt;meta-data android:name=&quot;android.webkit.WebView.EnableSafeBrowsing&quot;
+ * android:value=&quot;true&quot; /&gt;
+ * &lt;/application&gt;
+ * &lt;/manifest&gt;
* </pre>
*
*/
diff --git a/core/java/android/webkit/WebViewFragment.java b/core/java/android/webkit/WebViewFragment.java
index d803f62da011..e5b7c8d23a09 100644
--- a/core/java/android/webkit/WebViewFragment.java
+++ b/core/java/android/webkit/WebViewFragment.java
@@ -27,7 +27,10 @@ import android.webkit.WebView;
* A fragment that displays a WebView.
* <p>
* The WebView is automically paused or resumed when the Fragment is paused or resumed.
+ *
+ * @deprecated Manually call {@link WebView#onPause()} and {@link WebView#onResume()}
*/
+@Deprecated
public class WebViewFragment extends Fragment {
private WebView mWebView;
private boolean mIsWebViewAvailable;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 170582b3c3f5..e0c897d3e25c 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3866,6 +3866,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
private void onTouchDown(MotionEvent ev) {
mHasPerformedLongPress = false;
mActivePointerId = ev.getPointerId(0);
+ hideSelector();
if (mTouchMode == TOUCH_MODE_OVERFLING) {
// Stopped the fling. It is a scroll.
@@ -5226,17 +5227,21 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
mRecycler.fullyDetachScrapViews();
+ boolean selectorOnScreen = false;
if (!inTouchMode && mSelectedPosition != INVALID_POSITION) {
final int childIndex = mSelectedPosition - mFirstPosition;
if (childIndex >= 0 && childIndex < getChildCount()) {
positionSelector(mSelectedPosition, getChildAt(childIndex));
+ selectorOnScreen = true;
}
} else if (mSelectorPosition != INVALID_POSITION) {
final int childIndex = mSelectorPosition - mFirstPosition;
if (childIndex >= 0 && childIndex < getChildCount()) {
- positionSelector(INVALID_POSITION, getChildAt(childIndex));
+ positionSelector(mSelectorPosition, getChildAt(childIndex));
+ selectorOnScreen = true;
}
- } else {
+ }
+ if (!selectorOnScreen) {
mSelectorRect.setEmpty();
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index e6da69dc95c7..d477ffdf8b2b 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3842,14 +3842,10 @@ public class Editor {
mProcessTextIntentActionsHandler.onInitializeMenu(menu);
}
- if (menu.hasVisibleItems() || mode.getCustomView() != null) {
- if (mHasSelection && !mTextView.hasTransientState()) {
- mTextView.setHasTransientState(true);
- }
- return true;
- } else {
- return false;
+ if (mHasSelection && !mTextView.hasTransientState()) {
+ mTextView.setHasTransientState(true);
}
+ return true;
}
private Callback getCustomCallback() {
@@ -6557,12 +6553,12 @@ public class Editor {
* Adds "PROCESS_TEXT" menu items to the specified menu.
*/
public void onInitializeMenu(Menu menu) {
- final int size = mSupportedActivities.size();
loadSupportedActivities();
+ final int size = mSupportedActivities.size();
for (int i = 0; i < size; i++) {
final ResolveInfo resolveInfo = mSupportedActivities.get(i);
menu.add(Menu.NONE, Menu.NONE,
- Editor.MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START + i++,
+ Editor.MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START + i,
getLabel(resolveInfo))
.setIntent(createProcessTextIntentForResolveInfo(resolveInfo))
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 8dc8cab1c1a1..e91db1390582 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1354,6 +1354,7 @@ public class PopupWindow {
}
mDecorView = createDecorView(mBackgroundView);
+ mDecorView.setIsRootNamespace(true);
// The background owner should be elevated so that it casts a shadow.
mBackgroundView.setElevation(mElevation);
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 5e22650a83cc..d0ad27af0a92 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -20,10 +20,12 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiThread;
import android.annotation.WorkerThread;
+import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.LocaleList;
import android.text.Layout;
import android.text.Selection;
@@ -81,6 +83,7 @@ public final class SelectionActionModeHelper {
mEditor = Preconditions.checkNotNull(editor);
mTextView = mEditor.getTextView();
mTextClassificationHelper = new TextClassificationHelper(
+ mTextView.getContext(),
mTextView.getTextClassifier(),
getText(mTextView),
0, 1, mTextView.getTextLocales());
@@ -385,6 +388,7 @@ public final class SelectionActionModeHelper {
private void resetTextClassificationHelper() {
mTextClassificationHelper.init(
+ mTextView.getContext(),
mTextView.getTextClassifier(),
getText(mTextView),
mTextView.getSelectionStart(), mTextView.getSelectionEnd(),
@@ -587,7 +591,9 @@ public final class SelectionActionModeHelper {
Preconditions.checkNotNull(textView);
final @SmartSelectionEventTracker.WidgetType int widgetType = textView.isTextEditable()
? SmartSelectionEventTracker.WidgetType.EDITTEXT
- : SmartSelectionEventTracker.WidgetType.TEXTVIEW;
+ : (textView.isTextSelectable()
+ ? SmartSelectionEventTracker.WidgetType.TEXTVIEW
+ : SmartSelectionEventTracker.WidgetType.UNSELECTABLE_TEXTVIEW);
mDelegate = new SmartSelectionEventTracker(textView.getContext(), widgetType);
mEditTextLogger = textView.isTextEditable();
mWordIterator = BreakIterator.getWordInstance(textView.getTextLocale());
@@ -787,6 +793,7 @@ public final class SelectionActionModeHelper {
private static final int TRIM_DELTA = 120; // characters
+ private Context mContext;
private TextClassifier mTextClassifier;
/** The original TextView text. **/
@@ -795,7 +802,10 @@ public final class SelectionActionModeHelper {
private int mSelectionStart;
/** End index relative to mText. */
private int mSelectionEnd;
- private LocaleList mLocales;
+
+ private final TextSelection.Options mSelectionOptions = new TextSelection.Options();
+ private final TextClassification.Options mClassificationOptions =
+ new TextClassification.Options();
/** Trimmed text starting from mTrimStart in mText. */
private CharSequence mTrimmedText;
@@ -816,21 +826,24 @@ public final class SelectionActionModeHelper {
/** Whether the TextClassifier has been initialized. */
private boolean mHot;
- TextClassificationHelper(TextClassifier textClassifier,
+ TextClassificationHelper(Context context, TextClassifier textClassifier,
CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
- init(textClassifier, text, selectionStart, selectionEnd, locales);
+ init(context, textClassifier, text, selectionStart, selectionEnd, locales);
}
@UiThread
- public void init(TextClassifier textClassifier,
+ public void init(Context context, TextClassifier textClassifier,
CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
+ mContext = Preconditions.checkNotNull(context);
mTextClassifier = Preconditions.checkNotNull(textClassifier);
mText = Preconditions.checkNotNull(text).toString();
mLastClassificationText = null; // invalidate.
Preconditions.checkArgument(selectionEnd > selectionStart);
mSelectionStart = selectionStart;
mSelectionEnd = selectionEnd;
- mLocales = locales;
+ mClassificationOptions.setDefaultLocales(locales);
+ mSelectionOptions.setDefaultLocales(locales)
+ .setDarkLaunchAllowed(true);
}
@WorkerThread
@@ -843,8 +856,16 @@ public final class SelectionActionModeHelper {
public SelectionResult suggestSelection() {
mHot = true;
trimText();
- final TextSelection selection = mTextClassifier.suggestSelection(
- mTrimmedText, mRelativeStart, mRelativeEnd, mLocales);
+ final TextSelection selection;
+ if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.O_MR1) {
+ selection = mTextClassifier.suggestSelection(
+ mTrimmedText, mRelativeStart, mRelativeEnd, mSelectionOptions);
+ } else {
+ // Use old APIs.
+ selection = mTextClassifier.suggestSelection(
+ mTrimmedText, mRelativeStart, mRelativeEnd,
+ mSelectionOptions.getDefaultLocales());
+ }
// Do not classify new selection boundaries if TextClassifier should be dark launched.
if (!mTextClassifier.getSettings().isDarkLaunch()) {
mSelectionStart = Math.max(0, selection.getSelectionStartIndex() + mTrimStart);
@@ -874,20 +895,28 @@ public final class SelectionActionModeHelper {
if (!Objects.equals(mText, mLastClassificationText)
|| mSelectionStart != mLastClassificationSelectionStart
|| mSelectionEnd != mLastClassificationSelectionEnd
- || !Objects.equals(mLocales, mLastClassificationLocales)) {
+ || !Objects.equals(
+ mClassificationOptions.getDefaultLocales(),
+ mLastClassificationLocales)) {
mLastClassificationText = mText;
mLastClassificationSelectionStart = mSelectionStart;
mLastClassificationSelectionEnd = mSelectionEnd;
- mLastClassificationLocales = mLocales;
+ mLastClassificationLocales = mClassificationOptions.getDefaultLocales();
trimText();
+ final TextClassification classification;
+ if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.O_MR1) {
+ classification = mTextClassifier.classifyText(
+ mTrimmedText, mRelativeStart, mRelativeEnd, mClassificationOptions);
+ } else {
+ // Use old APIs.
+ classification = mTextClassifier.classifyText(
+ mTrimmedText, mRelativeStart, mRelativeEnd,
+ mClassificationOptions.getDefaultLocales());
+ }
mLastClassificationResult = new SelectionResult(
- mSelectionStart,
- mSelectionEnd,
- mTextClassifier.classifyText(
- mTrimmedText, mRelativeStart, mRelativeEnd, mLocales),
- selection);
+ mSelectionStart, mSelectionEnd, classification, selection);
}
return mLastClassificationResult;
diff --git a/core/java/com/android/internal/app/NightDisplayController.java b/core/java/com/android/internal/app/ColorDisplayController.java
index b8bfc6491f70..b8682a89eb95 100644
--- a/core/java/com/android/internal/app/NightDisplayController.java
+++ b/core/java/com/android/internal/app/ColorDisplayController.java
@@ -42,14 +42,14 @@ import java.time.ZoneId;
import java.time.format.DateTimeParseException;
/**
- * Controller for managing Night display settings.
+ * Controller for managing night display and color mode settings.
* <p/>
* Night display tints your screen red at night. This makes it easier to look at your screen in
* dim light and may help you fall asleep more easily.
*/
-public final class NightDisplayController {
+public final class ColorDisplayController {
- private static final String TAG = "NightDisplayController";
+ private static final String TAG = "ColorDisplayController";
private static final boolean DEBUG = false;
@Retention(RetentionPolicy.SOURCE)
@@ -114,11 +114,11 @@ public final class NightDisplayController {
private Callback mCallback;
- public NightDisplayController(@NonNull Context context) {
+ public ColorDisplayController(@NonNull Context context) {
this(context, ActivityManager.getCurrentUser());
}
- public NightDisplayController(@NonNull Context context, int userId) {
+ public ColorDisplayController(@NonNull Context context, int userId) {
mContext = context.getApplicationContext();
mUserId = userId;
diff --git a/core/java/com/android/internal/net/INetworkWatchlistManager.aidl b/core/java/com/android/internal/net/INetworkWatchlistManager.aidl
new file mode 100644
index 000000000000..7e88369055b8
--- /dev/null
+++ b/core/java/com/android/internal/net/INetworkWatchlistManager.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.net;
+
+import android.os.SharedMemory;
+
+/** {@hide} */
+interface INetworkWatchlistManager {
+ boolean startWatchlistLogging();
+ boolean stopWatchlistLogging();
+ void reportWatchlistIfNecessary();
+}
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index 3d3e148fb3c2..5eda81baa364 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -43,6 +43,8 @@ import java.util.Objects;
/**
* Creates {@link NetworkStats} instances by parsing various {@code /proc/}
* files as needed.
+ *
+ * @hide
*/
public class NetworkStatsFactory {
private static final String TAG = "NetworkStatsFactory";
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 0535ebeb7615..f2483c0a71e5 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -3639,6 +3639,7 @@ public class BatteryStatsImpl extends BatteryStats {
public void addIsolatedUidLocked(int isolatedUid, int appUid) {
mIsolatedUids.put(isolatedUid, appUid);
+ StatsLog.write(StatsLog.ISOLATED_UID_CHANGED, appUid, isolatedUid, 1);
}
/**
@@ -3659,9 +3660,11 @@ public class BatteryStatsImpl extends BatteryStats {
* @see #scheduleRemoveIsolatedUidLocked(int, int)
*/
public void removeIsolatedUidLocked(int isolatedUid) {
- mIsolatedUids.delete(isolatedUid);
- mKernelUidCpuTimeReader.removeUid(isolatedUid);
- mKernelUidCpuFreqTimeReader.removeUid(isolatedUid);
+ StatsLog.write(
+ StatsLog.ISOLATED_UID_CHANGED, mIsolatedUids.get(isolatedUid, -1), isolatedUid, 0);
+ mIsolatedUids.delete(isolatedUid);
+ mKernelUidCpuTimeReader.removeUid(isolatedUid);
+ mKernelUidCpuFreqTimeReader.removeUid(isolatedUid);
}
public int mapUid(int uid) {
@@ -9626,7 +9629,8 @@ public class BatteryStatsImpl extends BatteryStats {
}
public boolean isScreenOn(int state) {
- return state == Display.STATE_ON || state == Display.STATE_VR;
+ return state == Display.STATE_ON || state == Display.STATE_VR
+ || state == Display.STATE_ON_SUSPEND;
}
public boolean isScreenOff(int state) {
diff --git a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
index 8884d24ff0ac..a39997d3dce1 100644
--- a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
@@ -20,6 +20,7 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.StrictMode;
import android.os.SystemClock;
import android.util.IntArray;
import android.util.Slog;
@@ -82,6 +83,7 @@ public class KernelUidCpuFreqTimeReader {
if (!mProcFileAvailable && mReadErrorCounter >= TOTAL_READ_ERROR_COUNT) {
return null;
}
+ final int oldMask = StrictMode.allowThreadDiskReadsMask();
try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) {
mProcFileAvailable = true;
return readFreqs(reader, powerProfile);
@@ -89,6 +91,8 @@ public class KernelUidCpuFreqTimeReader {
mReadErrorCounter++;
Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e);
return null;
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
}
}
@@ -106,12 +110,15 @@ public class KernelUidCpuFreqTimeReader {
if (!mProcFileAvailable) {
return;
}
+ final int oldMask = StrictMode.allowThreadDiskReadsMask();
try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) {
mNowTimeMs = SystemClock.elapsedRealtime();
readDelta(reader, callback);
mLastTimeReadMs = mNowTimeMs;
} catch (IOException e) {
Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e);
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
}
}
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
index 37d9d1d475ee..65615c0ffb02 100644
--- a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
@@ -16,6 +16,7 @@
package com.android.internal.os;
import android.annotation.Nullable;
+import android.os.StrictMode;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Slog;
@@ -65,6 +66,7 @@ public class KernelUidCpuTimeReader {
* a fresh delta.
*/
public void readDelta(@Nullable Callback callback) {
+ final int oldMask = StrictMode.allowThreadDiskReadsMask();
long nowUs = SystemClock.elapsedRealtime() * 1000;
try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) {
TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' ');
@@ -121,6 +123,8 @@ public class KernelUidCpuTimeReader {
}
} catch (IOException e) {
Slog.e(TAG, "Failed to read uid_cputime: " + e.getMessage());
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
}
mLastTimeReadUs = nowUs;
}
@@ -160,12 +164,15 @@ public class KernelUidCpuTimeReader {
private void removeUidsFromKernelModule(int startUid, int endUid) {
Slog.d(TAG, "Removing uids " + startUid + "-" + endUid);
+ final int oldMask = StrictMode.allowThreadDiskWritesMask();
try (FileWriter writer = new FileWriter(sRemoveUidProcFile)) {
writer.write(startUid + "-" + endUid);
writer.flush();
} catch (IOException e) {
Slog.e(TAG, "failed to remove uids " + startUid + " - " + endUid
+ " from uid_cputime module", e);
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
}
}
}
diff --git a/core/java/com/android/internal/util/RingBuffer.java b/core/java/com/android/internal/util/RingBuffer.java
index ad84353f23a9..c22be2ccf076 100644
--- a/core/java/com/android/internal/util/RingBuffer.java
+++ b/core/java/com/android/internal/util/RingBuffer.java
@@ -45,6 +45,17 @@ public class RingBuffer<T> {
return (int) Math.min(mBuffer.length, (long) mCursor);
}
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ public void clear() {
+ for (int i = 0; i < size(); ++i) {
+ mBuffer[i] = null;
+ }
+ mCursor = 0;
+ }
+
public void append(T t) {
mBuffer[indexOf(mCursor++)] = t;
}
diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java
index 7870333cd82d..09f7282f097a 100644
--- a/core/java/com/android/internal/widget/ImageFloatingTextView.java
+++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java
@@ -176,8 +176,4 @@ public class ImageFloatingTextView extends TextView {
}
return false;
}
-
- public int getLayoutHeight() {
- return getLayout().getHeight();
- }
}
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
new file mode 100644
index 000000000000..792f9212d93e
--- /dev/null
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.widget;
+
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Pools;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.ViewTreeObserver;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
+
+import com.android.internal.R;
+import com.android.internal.util.NotificationColorUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A message of a {@link MessagingLayout}.
+ */
+@RemoteViews.RemoteView
+public class MessagingGroup extends LinearLayout implements MessagingLinearLayout.MessagingChild {
+ private static Pools.SimplePool<MessagingGroup> sInstancePool
+ = new Pools.SynchronizedPool<>(10);
+ private MessagingLinearLayout mMessageContainer;
+ private ImageFloatingTextView mSenderName;
+ private ImageView mAvatarView;
+ private String mAvatarSymbol = "";
+ private int mLayoutColor;
+ private CharSequence mAvatarName = "";
+ private Icon mAvatarIcon;
+ private ColorFilter mMessageBackgroundFilter;
+ private int mTextColor;
+ private List<MessagingMessage> mMessages;
+ private ArrayList<MessagingMessage> mAddedMessages = new ArrayList<>();
+ private boolean mFirstLayout;
+ private boolean mIsHidingAnimated;
+
+ public MessagingGroup(@NonNull Context context) {
+ super(context);
+ }
+
+ public MessagingGroup(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MessagingGroup(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public MessagingGroup(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mMessageContainer = findViewById(R.id.group_message_container);
+ mSenderName = findViewById(R.id.message_name);
+ mSenderName.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR);
+ mAvatarView = findViewById(R.id.message_icon);
+ }
+
+ public void setSender(CharSequence sender) {
+ if (sender == null) {
+ mAvatarView.setVisibility(GONE);
+ mSenderName.setVisibility(GONE);
+ setGravity(Gravity.END);
+ mMessageBackgroundFilter = new PorterDuffColorFilter(mLayoutColor,
+ PorterDuff.Mode.SRC_ATOP);
+ mTextColor = NotificationColorUtil.isColorLight(mLayoutColor) ? getNormalTextColor()
+ : Color.WHITE;
+ } else {
+ mSenderName.setText(sender);
+ mAvatarView.setVisibility(VISIBLE);
+ mSenderName.setVisibility(VISIBLE);
+ setGravity(Gravity.START);
+ mMessageBackgroundFilter = null;
+ mTextColor = getNormalTextColor();
+ }
+ }
+
+ private int getNormalTextColor() {
+ return mContext.getColor(R.color.notification_primary_text_color_light);
+ }
+
+ public void setAvatar(Icon icon) {
+ mAvatarIcon = icon;
+ mAvatarView.setImageIcon(icon);
+ mAvatarSymbol = "";
+ mLayoutColor = 0;
+ mAvatarName = "";
+ }
+
+ static MessagingGroup createGroup(MessagingLinearLayout layout) {;
+ MessagingGroup createdGroup = sInstancePool.acquire();
+ if (createdGroup == null) {
+ createdGroup = (MessagingGroup) LayoutInflater.from(layout.getContext()).inflate(
+ R.layout.notification_template_messaging_group, layout,
+ false);
+ createdGroup.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR);
+ }
+ layout.addView(createdGroup);
+ return createdGroup;
+ }
+
+ public void removeMessage(MessagingMessage messagingMessage) {
+ mMessageContainer.removeView(messagingMessage);
+ Runnable recycleRunnable = () -> {
+ mMessageContainer.removeTransientView(messagingMessage);
+ messagingMessage.recycle();
+ if (mMessageContainer.getChildCount() == 0
+ && mMessageContainer.getTransientViewCount() == 0) {
+ ViewParent parent = getParent();
+ if (parent instanceof ViewGroup) {
+ ((ViewGroup) parent).removeView(MessagingGroup.this);
+ }
+ setAvatar(null);
+ mAvatarView.setAlpha(1.0f);
+ mAvatarView.setTranslationY(0.0f);
+ mSenderName.setAlpha(1.0f);
+ mSenderName.setTranslationY(0.0f);
+ sInstancePool.release(MessagingGroup.this);
+ }
+ };
+ if (isShown()) {
+ mMessageContainer.addTransientView(messagingMessage, 0);
+ performRemoveAnimation(messagingMessage, recycleRunnable);
+ if (mMessageContainer.getChildCount() == 0) {
+ removeGroupAnimated(null);
+ }
+ } else {
+ recycleRunnable.run();
+ }
+
+ }
+
+ private void removeGroupAnimated(Runnable endAction) {
+ MessagingPropertyAnimator.fadeOut(mAvatarView, null);
+ MessagingPropertyAnimator.startLocalTranslationTo(mAvatarView,
+ (int) (-getHeight() * 0.5f), MessagingLayout.FAST_OUT_LINEAR_IN);
+ MessagingPropertyAnimator.fadeOut(mSenderName, null);
+ MessagingPropertyAnimator.startLocalTranslationTo(mSenderName,
+ (int) (-getHeight() * 0.5f), MessagingLayout.FAST_OUT_LINEAR_IN);
+ boolean endActionTriggered = false;
+ for (int i = mMessageContainer.getChildCount() - 1; i >= 0; i--) {
+ View child = mMessageContainer.getChildAt(i);
+ if (child.getVisibility() == View.GONE) {
+ continue;
+ }
+ final ViewGroup.LayoutParams lp = child.getLayoutParams();
+ if (lp instanceof MessagingLinearLayout.LayoutParams
+ && ((MessagingLinearLayout.LayoutParams) lp).hide
+ && !((MessagingLinearLayout.LayoutParams) lp).visibleBefore) {
+ continue;
+ }
+ Runnable childEndAction = endActionTriggered ? null : endAction;
+ performRemoveAnimation(child, childEndAction);
+ endActionTriggered = true;
+ }
+ if (!endActionTriggered && endAction != null) {
+ endAction.run();
+ }
+ }
+
+ public void performRemoveAnimation(View message,
+ Runnable recycleRunnable) {
+ MessagingPropertyAnimator.fadeOut(message, recycleRunnable);
+ MessagingPropertyAnimator.startLocalTranslationTo(message,
+ (int) (-getHeight() * 0.5f), MessagingLayout.FAST_OUT_LINEAR_IN);
+ }
+
+ public CharSequence getSenderName() {
+ return mSenderName.getText();
+ }
+
+ public void setSenderVisible(boolean visible) {
+ mSenderName.setVisibility(visible ? VISIBLE : GONE);
+ }
+
+ public static void dropCache() {
+ sInstancePool = new Pools.SynchronizedPool<>(10);
+ }
+
+ @Override
+ public int getMeasuredType() {
+ boolean hasNormal = false;
+ for (int i = mMessageContainer.getChildCount() - 1; i >= 0; i--) {
+ View child = mMessageContainer.getChildAt(i);
+ if (child instanceof MessagingLinearLayout.MessagingChild) {
+ int type = ((MessagingLinearLayout.MessagingChild) child).getMeasuredType();
+ if (type == MEASURED_TOO_SMALL) {
+ if (hasNormal) {
+ return MEASURED_SHORTENED;
+ } else {
+ return MEASURED_TOO_SMALL;
+ }
+ } else if (type == MEASURED_SHORTENED) {
+ return MEASURED_SHORTENED;
+ } else {
+ hasNormal = true;
+ }
+ }
+ }
+ return MEASURED_NORMAL;
+ }
+
+ @Override
+ public int getConsumedLines() {
+ int result = 0;
+ for (int i = 0; i < mMessageContainer.getChildCount(); i++) {
+ View child = mMessageContainer.getChildAt(i);
+ if (child instanceof MessagingLinearLayout.MessagingChild) {
+ result += ((MessagingLinearLayout.MessagingChild) child).getConsumedLines();
+ }
+ }
+ // A group is usually taking up quite some space with the padding and the name, let's add 1
+ return result + 1;
+ }
+
+ @Override
+ public void setMaxDisplayedLines(int lines) {
+ mMessageContainer.setMaxDisplayedLines(lines);
+ }
+
+ @Override
+ public void hideAnimated() {
+ setIsHidingAnimated(true);
+ removeGroupAnimated(() -> setIsHidingAnimated(false));
+ }
+
+ @Override
+ public boolean isHidingAnimated() {
+ return mIsHidingAnimated;
+ }
+
+ private void setIsHidingAnimated(boolean isHiding) {
+ ViewParent parent = getParent();
+ mIsHidingAnimated = isHiding;
+ invalidate();
+ if (parent instanceof ViewGroup) {
+ ((ViewGroup) parent).invalidate();
+ }
+ }
+
+ public Icon getAvatarSymbolIfMatching(CharSequence avatarName, String avatarSymbol,
+ int layoutColor) {
+ if (mAvatarName.equals(avatarName) && mAvatarSymbol.equals(avatarSymbol)
+ && layoutColor == mLayoutColor) {
+ return mAvatarIcon;
+ }
+ return null;
+ }
+
+ public void setCreatedAvatar(Icon cachedIcon, CharSequence avatarName, String avatarSymbol,
+ int layoutColor) {
+ if (!mAvatarName.equals(avatarName) || !mAvatarSymbol.equals(avatarSymbol)
+ || layoutColor != mLayoutColor) {
+ setAvatar(cachedIcon);
+ mAvatarSymbol = avatarSymbol;
+ mLayoutColor = layoutColor;
+ mAvatarName = avatarName;
+ }
+ }
+
+ public void setLayoutColor(int layoutColor) {
+ mLayoutColor = layoutColor;
+ }
+
+ public void setMessages(List<MessagingMessage> group) {
+ // Let's now make sure all children are added and in the correct order
+ for (int messageIndex = 0; messageIndex < group.size(); messageIndex++) {
+ MessagingMessage message = group.get(messageIndex);
+ if (message.getGroup() != this) {
+ message.setMessagingGroup(this);
+ ViewParent parent = mMessageContainer.getParent();
+ if (parent instanceof ViewGroup) {
+ ((ViewGroup) parent).removeView(message);
+ }
+ mMessageContainer.addView(message, messageIndex);
+ mAddedMessages.add(message);
+ }
+ if (messageIndex != mMessageContainer.indexOfChild(message)) {
+ mMessageContainer.removeView(message);
+ mMessageContainer.addView(message, messageIndex);
+ }
+ // Let's make sure the message color is correct
+ Drawable targetDrawable = message.getBackground();
+
+ if (targetDrawable != null) {
+ targetDrawable.mutate().setColorFilter(mMessageBackgroundFilter);
+ }
+ message.setTextColor(mTextColor);
+ }
+ mMessages = group;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (!mAddedMessages.isEmpty()) {
+ getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ for (MessagingMessage message : mAddedMessages) {
+ if (!message.isShown()) {
+ continue;
+ }
+ MessagingPropertyAnimator.fadeIn(message);
+ if (!mFirstLayout) {
+ MessagingPropertyAnimator.startLocalTranslationFrom(message,
+ message.getHeight(), MessagingLayout.LINEAR_OUT_SLOW_IN);
+ }
+ }
+ mAddedMessages.clear();
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ return true;
+ }
+ });
+ }
+ mFirstLayout = false;
+ }
+
+ /**
+ * Calculates the group compatibility between this and another group.
+ *
+ * @param otherGroup the other group to compare it with
+ *
+ * @return 0 if the groups are totally incompatible or 1 + the number of matching messages if
+ * they match.
+ */
+ public int calculateGroupCompatibility(MessagingGroup otherGroup) {
+ if (TextUtils.equals(getSenderName(),otherGroup.getSenderName())) {
+ int result = 1;
+ for (int i = 0; i < mMessages.size() && i < otherGroup.mMessages.size(); i++) {
+ MessagingMessage ownMessage = mMessages.get(mMessages.size() - 1 - i);
+ MessagingMessage otherMessage = otherGroup.mMessages.get(
+ otherGroup.mMessages.size() - 1 - i);
+ if (!ownMessage.sameAs(otherMessage)) {
+ return result;
+ }
+ result++;
+ }
+ return result;
+ }
+ return 0;
+ }
+
+ public View getSender() {
+ return mSenderName;
+ }
+
+ public View getAvatar() {
+ return mAvatarView;
+ }
+
+ public MessagingLinearLayout getMessageContainer() {
+ return mMessageContainer;
+ }
+}
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
new file mode 100644
index 000000000000..2acdc015f8ef
--- /dev/null
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.widget;
+
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
+import android.app.Notification;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.RemotableViewMethod;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+import android.widget.FrameLayout;
+import android.widget.RemoteViews;
+import android.widget.TextView;
+
+import com.android.internal.R;
+import com.android.internal.graphics.ColorUtils;
+import com.android.internal.util.NotificationColorUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * A custom-built layout for the Notification.MessagingStyle allows dynamic addition and removal
+ * messages and adapts the layout accordingly.
+ */
+@RemoteViews.RemoteView
+public class MessagingLayout extends FrameLayout {
+
+ private static final float COLOR_SHIFT_AMOUNT = 60;
+ private static final Consumer<MessagingMessage> REMOVE_MESSAGE
+ = MessagingMessage::removeMessage;
+ public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
+ public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
+ public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+ public static final OnLayoutChangeListener MESSAGING_PROPERTY_ANIMATOR
+ = new MessagingPropertyAnimator();
+ private List<MessagingMessage> mMessages = new ArrayList<>();
+ private List<MessagingMessage> mHistoricMessages = new ArrayList<>();
+ private MessagingLinearLayout mMessagingLinearLayout;
+ private View mContractedMessage;
+ private boolean mShowHistoricMessages;
+ private ArrayList<MessagingGroup> mGroups = new ArrayList<>();
+ private TextView mTitleView;
+ private int mLayoutColor;
+ private int mAvatarSize;
+ private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private Paint mTextPaint = new Paint();
+ private CharSequence mConversationTitle;
+ private Icon mLargeIcon;
+ private boolean mIsOneToOne;
+ private ArrayList<MessagingGroup> mAddedGroups = new ArrayList<>();
+
+ public MessagingLayout(@NonNull Context context) {
+ super(context);
+ }
+
+ public MessagingLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MessagingLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public MessagingLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mMessagingLinearLayout = findViewById(R.id.notification_messaging);
+ mMessagingLinearLayout.setMessagingLayout(this);
+ // We still want to clip, but only on the top, since views can temporarily out of bounds
+ // during transitions.
+ DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
+ Rect rect = new Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels);
+ mMessagingLinearLayout.setClipBounds(rect);
+ mTitleView = findViewById(R.id.title);
+ mAvatarSize = getResources().getDimensionPixelSize(R.dimen.messaging_avatar_size);
+ mTextPaint.setTextAlign(Paint.Align.CENTER);
+ mTextPaint.setAntiAlias(true);
+ }
+
+ @RemotableViewMethod
+ public void setLargeIcon(Icon icon) {
+ mLargeIcon = icon;
+ }
+
+ @RemotableViewMethod
+ public void setData(Bundle extras) {
+ Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
+ List<Notification.MessagingStyle.Message> newMessages
+ = Notification.MessagingStyle.Message.getMessagesFromBundleArray(messages);
+ Parcelable[] histMessages = extras.getParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES);
+ List<Notification.MessagingStyle.Message> newHistoricMessages
+ = Notification.MessagingStyle.Message.getMessagesFromBundleArray(histMessages);
+ mConversationTitle = null;
+ TextView headerText = findViewById(R.id.header_text);
+ if (headerText != null) {
+ mConversationTitle = headerText.getText();
+ }
+ bind(newMessages, newHistoricMessages);
+ }
+
+ private void bind(List<Notification.MessagingStyle.Message> newMessages,
+ List<Notification.MessagingStyle.Message> newHistoricMessages) {
+
+ List<MessagingMessage> historicMessages = createMessages(newHistoricMessages,
+ true /* isHistoric */);
+ List<MessagingMessage> messages = createMessages(newMessages, false /* isHistoric */);
+ addMessagesToGroups(historicMessages, messages);
+
+ // Let's remove the remaining messages
+ mMessages.forEach(REMOVE_MESSAGE);
+ mHistoricMessages.forEach(REMOVE_MESSAGE);
+
+ mMessages = messages;
+ mHistoricMessages = historicMessages;
+
+ updateContractedMessage();
+ updateHistoricMessageVisibility();
+ updateTitleAndNamesDisplay();
+ }
+
+ private void updateTitleAndNamesDisplay() {
+ ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>();
+ ArrayMap<Character, CharSequence> uniqueCharacters = new ArrayMap<>();
+ for (int i = 0; i < mGroups.size(); i++) {
+ MessagingGroup group = mGroups.get(i);
+ CharSequence senderName = group.getSenderName();
+ if (TextUtils.isEmpty(senderName)) {
+ continue;
+ }
+ boolean visible = !mIsOneToOne;
+ group.setSenderVisible(visible);
+ if ((visible || mLargeIcon == null) && !uniqueNames.containsKey(senderName)) {
+ char c = senderName.charAt(0);
+ if (uniqueCharacters.containsKey(c)) {
+ // this character was already used, lets make it more unique. We first need to
+ // resolve the existing character if it exists
+ CharSequence existingName = uniqueCharacters.get(c);
+ if (existingName != null) {
+ uniqueNames.put(existingName, findNameSplit((String) existingName));
+ uniqueCharacters.put(c, null);
+ }
+ uniqueNames.put(senderName, findNameSplit((String) senderName));
+ } else {
+ uniqueNames.put(senderName, Character.toString(c));
+ uniqueCharacters.put(c, senderName);
+ }
+ }
+ }
+
+ // Now that we have the correct symbols, let's look what we have cached
+ ArrayMap<CharSequence, Icon> cachedAvatars = new ArrayMap<>();
+ for (int i = 0; i < mGroups.size(); i++) {
+ // Let's now set the avatars
+ MessagingGroup group = mGroups.get(i);
+ CharSequence senderName = group.getSenderName();
+ if (TextUtils.isEmpty(senderName) || (mIsOneToOne && mLargeIcon != null)) {
+ continue;
+ }
+ String symbol = uniqueNames.get(senderName);
+ Icon cachedIcon = group.getAvatarSymbolIfMatching(senderName,
+ symbol, mLayoutColor);
+ if (cachedIcon != null) {
+ cachedAvatars.put(senderName, cachedIcon);
+ }
+ }
+
+ for (int i = 0; i < mGroups.size(); i++) {
+ // Let's now set the avatars
+ MessagingGroup group = mGroups.get(i);
+ CharSequence senderName = group.getSenderName();
+ if (TextUtils.isEmpty(senderName)) {
+ continue;
+ }
+ if (mIsOneToOne && mLargeIcon != null) {
+ group.setAvatar(mLargeIcon);
+ } else {
+ Icon cachedIcon = cachedAvatars.get(senderName);
+ if (cachedIcon == null) {
+ cachedIcon = createAvatarSymbol(senderName, uniqueNames.get(senderName),
+ mLayoutColor);
+ cachedAvatars.put(senderName, cachedIcon);
+ }
+ group.setCreatedAvatar(cachedIcon, senderName, uniqueNames.get(senderName),
+ mLayoutColor);
+ }
+ }
+ }
+
+ public Icon createAvatarSymbol(CharSequence senderName, String symbol, int layoutColor) {
+ Bitmap bitmap = Bitmap.createBitmap(mAvatarSize, mAvatarSize, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ float radius = mAvatarSize / 2.0f;
+ int color = findColor(senderName, layoutColor);
+ mPaint.setColor(color);
+ canvas.drawCircle(radius, radius, radius, mPaint);
+ boolean needDarkText = ColorUtils.calculateLuminance(color) > 0.5f;
+ mTextPaint.setColor(needDarkText ? Color.BLACK : Color.WHITE);
+ mTextPaint.setTextSize(symbol.length() == 1 ? mAvatarSize * 0.75f : mAvatarSize * 0.4f);
+ int yPos = (int) (radius - ((mTextPaint.descent() + mTextPaint.ascent()) / 2)) ;
+ canvas.drawText(symbol, radius, yPos, mTextPaint);
+ return Icon.createWithBitmap(bitmap);
+ }
+
+ private int findColor(CharSequence senderName, int layoutColor) {
+ double luminance = NotificationColorUtil.calculateLuminance(layoutColor);
+ float shift = Math.abs(senderName.hashCode()) % 5 / 4.0f - 0.5f;
+
+ // we need to offset the range if the luminance is too close to the borders
+ shift += Math.max(COLOR_SHIFT_AMOUNT / 2.0f / 100 - luminance, 0);
+ shift -= Math.max(COLOR_SHIFT_AMOUNT / 2.0f / 100 - (1.0f - luminance), 0);
+ return NotificationColorUtil.getShiftedColor(layoutColor,
+ (int) (shift * COLOR_SHIFT_AMOUNT));
+ }
+
+ private String findNameSplit(String existingName) {
+ String[] split = existingName.split(" ");
+ if (split.length > 1) {
+ return Character.toString(split[0].charAt(0))
+ + Character.toString(split[1].charAt(0));
+ }
+ return existingName.substring(0, 1);
+ }
+
+ @RemotableViewMethod
+ public void setLayoutColor(int color) {
+ mLayoutColor = color;
+ }
+
+ @RemotableViewMethod
+ public void setIsOneToOne(boolean oneToOne) {
+ mIsOneToOne = oneToOne;
+ }
+
+ private void addMessagesToGroups(List<MessagingMessage> historicMessages,
+ List<MessagingMessage> messages) {
+ // Let's first find our groups!
+ List<List<MessagingMessage>> groups = new ArrayList<>();
+ List<CharSequence> senders = new ArrayList<>();
+
+ // Lets first find the groups
+ findGroups(historicMessages, messages, groups, senders);
+
+ // Let's now create the views and reorder them accordingly
+ createGroupViews(groups, senders);
+ }
+
+ private void createGroupViews(List<List<MessagingMessage>> groups, List<CharSequence> senders) {
+ mGroups.clear();
+ for (int groupIndex = 0; groupIndex < groups.size(); groupIndex++) {
+ List<MessagingMessage> group = groups.get(groupIndex);
+ MessagingGroup newGroup = null;
+ // we'll just take the first group that exists or create one there is none
+ for (int messageIndex = group.size() - 1; messageIndex >= 0; messageIndex--) {
+ MessagingMessage message = group.get(messageIndex);
+ newGroup = message.getGroup();
+ if (newGroup != null) {
+ break;
+ }
+ }
+ if (newGroup == null) {
+ newGroup = MessagingGroup.createGroup(mMessagingLinearLayout);
+ mAddedGroups.add(newGroup);
+ }
+ newGroup.setLayoutColor(mLayoutColor);
+ newGroup.setSender(senders.get(groupIndex));
+ mGroups.add(newGroup);
+
+ if (mMessagingLinearLayout.indexOfChild(newGroup) != groupIndex) {
+ mMessagingLinearLayout.removeView(newGroup);
+ mMessagingLinearLayout.addView(newGroup, groupIndex);
+ }
+ newGroup.setMessages(group);
+ }
+ }
+
+ private void findGroups(List<MessagingMessage> historicMessages,
+ List<MessagingMessage> messages, List<List<MessagingMessage>> groups,
+ List<CharSequence> senders) {
+ CharSequence currentSender = null;
+ List<MessagingMessage> currentGroup = null;
+ int histSize = historicMessages.size();
+ for (int i = 0; i < histSize + messages.size(); i++) {
+ MessagingMessage message;
+ if (i < histSize) {
+ message = historicMessages.get(i);
+ } else {
+ message = messages.get(i - histSize);
+ }
+ boolean isNewGroup = currentGroup == null;
+ CharSequence sender = message.getMessage().getSender();
+ isNewGroup |= !TextUtils.equals(sender, currentSender);
+ if (isNewGroup) {
+ currentGroup = new ArrayList<>();
+ groups.add(currentGroup);
+ senders.add(sender);
+ currentSender = sender;
+ }
+ currentGroup.add(message);
+ }
+ }
+
+ private void updateContractedMessage() {
+ for (int i = mMessages.size() - 1; i >= 0; i--) {
+ MessagingMessage m = mMessages.get(i);
+ // Incoming messages have a non-empty sender.
+ if (!TextUtils.isEmpty(m.getMessage().getSender())) {
+ mContractedMessage = m;
+ return;
+ }
+ }
+ if (!mMessages.isEmpty()) {
+ // No incoming messages, fall back to outgoing message
+ mContractedMessage = mMessages.get(mMessages.size() - 1);
+ return;
+ }
+ mContractedMessage = null;
+ }
+
+ /**
+ * Creates new messages, reusing existing ones if they are available.
+ *
+ * @param newMessages the messages to parse.
+ */
+ private List<MessagingMessage> createMessages(
+ List<Notification.MessagingStyle.Message> newMessages, boolean historic) {
+ List<MessagingMessage> result = new ArrayList<>();;
+ for (int i = 0; i < newMessages.size(); i++) {
+ Notification.MessagingStyle.Message m = newMessages.get(i);
+ MessagingMessage message = findAndRemoveMatchingMessage(m);
+ if (message == null) {
+ message = MessagingMessage.createMessage(this, m);
+ message.addOnLayoutChangeListener(MESSAGING_PROPERTY_ANIMATOR);
+ }
+ message.setIsHistoric(historic);
+ result.add(message);
+ }
+ return result;
+ }
+
+ private MessagingMessage findAndRemoveMatchingMessage(Notification.MessagingStyle.Message m) {
+ for (int i = 0; i < mMessages.size(); i++) {
+ MessagingMessage existing = mMessages.get(i);
+ if (existing.sameAs(m)) {
+ mMessages.remove(i);
+ return existing;
+ }
+ }
+ for (int i = 0; i < mHistoricMessages.size(); i++) {
+ MessagingMessage existing = mHistoricMessages.get(i);
+ if (existing.sameAs(m)) {
+ mHistoricMessages.remove(i);
+ return existing;
+ }
+ }
+ return null;
+ }
+
+ public void showHistoricMessages(boolean show) {
+ mShowHistoricMessages = show;
+ updateHistoricMessageVisibility();
+ }
+
+ private void updateHistoricMessageVisibility() {
+ for (int i = 0; i < mHistoricMessages.size(); i++) {
+ MessagingMessage existing = mHistoricMessages.get(i);
+ existing.setVisibility(mShowHistoricMessages ? VISIBLE : GONE);
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (!mAddedGroups.isEmpty()) {
+ getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ for (MessagingGroup group : mAddedGroups) {
+ if (!group.isShown()) {
+ continue;
+ }
+ MessagingPropertyAnimator.fadeIn(group.getAvatar());
+ MessagingPropertyAnimator.fadeIn(group.getSender());
+ MessagingPropertyAnimator.startLocalTranslationFrom(group,
+ group.getHeight(), LINEAR_OUT_SLOW_IN);
+ }
+ mAddedGroups.clear();
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ return true;
+ }
+ });
+ }
+ }
+
+ public View getContractedMessage() {
+ return mContractedMessage;
+ }
+
+ public MessagingLinearLayout getMessagingLinearLayout() {
+ return mMessagingLinearLayout;
+ }
+
+ public ArrayList<MessagingGroup> getMessagingGroups() {
+ return mGroups;
+ }
+}
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index 70473a014c0d..f0ef37076618 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -36,28 +36,14 @@ import com.android.internal.R;
@RemoteViews.RemoteView
public class MessagingLinearLayout extends ViewGroup {
- private static final int NOT_MEASURED_BEFORE = -1;
/**
* Spacing to be applied between views.
*/
private int mSpacing;
- /**
- * The maximum height allowed.
- */
- private int mMaxHeight;
+ private int mMaxDisplayedLines = Integer.MAX_VALUE;
- private int mIndentLines;
-
- /**
- * Id of the child that's also visible in the contracted layout.
- */
- private int mContractedChildId;
- /**
- * The last measured with in a layout pass if it was measured before or
- * {@link #NOT_MEASURED_BEFORE} if this is the first layout pass.
- */
- private int mLastMeasuredWidth = NOT_MEASURED_BEFORE;
+ private MessagingLayout mMessagingLayout;
public MessagingLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
@@ -79,7 +65,6 @@ public class MessagingLinearLayout extends ViewGroup {
a.recycle();
}
-
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// This is essentially a bottom-up linear layout that only adds children that fit entirely
@@ -91,118 +76,67 @@ public class MessagingLinearLayout extends ViewGroup {
break;
}
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- boolean recalculateVisibility = mLastMeasuredWidth == NOT_MEASURED_BEFORE
- || getMeasuredHeight() != targetHeight
- || mLastMeasuredWidth != widthSize;
-
- final int count = getChildCount();
- if (recalculateVisibility) {
- // We only need to recalculate the view visibilities if the view wasn't measured already
- // in this pass, otherwise we may drop messages here already since we are measured
- // exactly with what we returned before, which was optimized already with the
- // line-indents.
- for (int i = 0; i < count; ++i) {
- final View child = getChildAt(i);
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- lp.hide = true;
- }
-
- int totalHeight = mPaddingTop + mPaddingBottom;
- boolean first = true;
-
- // Starting from the bottom: we measure every view as if it were the only one. If it still
-
- // fits, we take it, otherwise we stop there.
- for (int i = count - 1; i >= 0 && totalHeight < targetHeight; i--) {
- if (getChildAt(i).getVisibility() == GONE) {
- continue;
- }
- final View child = getChildAt(i);
- LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
- ImageFloatingTextView textChild = null;
- if (child instanceof ImageFloatingTextView) {
- // Pretend we need the image padding for all views, we don't know which
- // one will end up needing to do this (might end up not using all the space,
- // but calculating this exactly would be more expensive).
- textChild = (ImageFloatingTextView) child;
- textChild.setNumIndentLines(mIndentLines == 2 ? 3 : mIndentLines);
- }
-
- int spacing = first ? 0 : mSpacing;
- measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, totalHeight
- - mPaddingTop - mPaddingBottom + spacing);
-
- final int childHeight = child.getMeasuredHeight();
- int newHeight = Math.max(totalHeight, totalHeight + childHeight + lp.topMargin +
- lp.bottomMargin + spacing);
- first = false;
- boolean measuredTooSmall = false;
- if (textChild != null) {
- measuredTooSmall = childHeight < textChild.getLayoutHeight()
- + textChild.getPaddingTop() + textChild.getPaddingBottom();
- }
-
- if (newHeight <= targetHeight && !measuredTooSmall) {
- totalHeight = newHeight;
- lp.hide = false;
- } else {
- break;
- }
- }
- }
// Now that we know which views to take, fix up the indents and see what width we get.
int measuredWidth = mPaddingLeft + mPaddingRight;
- int imageLines = mIndentLines;
- // Need to redo the height because it may change due to changing indents.
- int totalHeight = mPaddingTop + mPaddingBottom;
- boolean first = true;
- for (int i = 0; i < count; i++) {
+ final int count = getChildCount();
+ int totalHeight;
+ for (int i = 0; i < count; ++i) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ lp.hide = true;
+ }
+
+ totalHeight = mPaddingTop + mPaddingBottom;
+ boolean first = true;
+ int linesRemaining = mMaxDisplayedLines;
- if (child.getVisibility() == GONE || lp.hide) {
+ // Starting from the bottom: we measure every view as if it were the only one. If it still
+ // fits, we take it, otherwise we stop there.
+ for (int i = count - 1; i >= 0 && totalHeight < targetHeight; i--) {
+ if (getChildAt(i).getVisibility() == GONE) {
continue;
}
-
- if (child instanceof ImageFloatingTextView) {
- ImageFloatingTextView textChild = (ImageFloatingTextView) child;
- if (imageLines == 2 && textChild.getLineCount() > 2) {
- // HACK: If we need indent for two lines, and they're coming from the same
- // view, we need extra spacing to compensate for the lack of margins,
- // so add an extra line of indent.
- imageLines = 3;
- }
- boolean changed = textChild.setNumIndentLines(Math.max(0, imageLines));
- if (changed || !recalculateVisibility) {
- final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
- mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,
- lp.width);
- // we want to measure it at most as high as it is currently, otherwise we'll
- // drop later lines
- final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
- targetHeight - child.getMeasuredHeight(), lp.height);
-
- child.measure(childWidthMeasureSpec, childHeightMeasureSpec);;
- }
- imageLines -= textChild.getLineCount();
+ final View child = getChildAt(i);
+ LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
+ MessagingChild messagingChild = null;
+ if (child instanceof MessagingChild) {
+ messagingChild = (MessagingChild) child;
+ messagingChild.setMaxDisplayedLines(linesRemaining);
}
+ int spacing = first ? 0 : mSpacing;
+ measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, totalHeight
+ - mPaddingTop - mPaddingBottom + spacing);
- measuredWidth = Math.max(measuredWidth,
- child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin
- + mPaddingLeft + mPaddingRight);
- totalHeight = Math.max(totalHeight, totalHeight + child.getMeasuredHeight() +
- lp.topMargin + lp.bottomMargin + (first ? 0 : mSpacing));
+ final int childHeight = child.getMeasuredHeight();
+ int newHeight = Math.max(totalHeight, totalHeight + childHeight + lp.topMargin +
+ lp.bottomMargin + spacing);
first = false;
+ int measureType = MessagingChild.MEASURED_NORMAL;
+ if (messagingChild != null) {
+ measureType = messagingChild.getMeasuredType();
+ linesRemaining -= messagingChild.getConsumedLines();
+ }
+ boolean isShortened = measureType == MessagingChild.MEASURED_SHORTENED;
+ boolean isTooSmall = measureType == MessagingChild.MEASURED_TOO_SMALL;
+ if (newHeight <= targetHeight && !isTooSmall) {
+ totalHeight = newHeight;
+ measuredWidth = Math.max(measuredWidth,
+ child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin
+ + mPaddingLeft + mPaddingRight);
+ lp.hide = false;
+ if (isShortened || linesRemaining <= 0) {
+ break;
+ }
+ } else {
+ break;
+ }
}
-
setMeasuredDimension(
resolveSize(Math.max(getSuggestedMinimumWidth(), measuredWidth),
widthMeasureSpec),
- resolveSize(Math.max(getSuggestedMinimumHeight(), totalHeight),
- heightMeasureSpec));
- mLastMeasuredWidth = widthSize;
+ Math.max(getSuggestedMinimumHeight(), totalHeight));
}
@Override
@@ -221,13 +155,22 @@ public class MessagingLinearLayout extends ViewGroup {
childTop = mPaddingTop;
boolean first = true;
-
+ final boolean shown = isShown();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
- if (child.getVisibility() == GONE || lp.hide) {
+ MessagingChild messagingChild = (MessagingChild) child;
+ if (lp.hide) {
+ if (shown && lp.visibleBefore) {
+ messagingChild.hideAnimated();
+ }
+ lp.visibleBefore = false;
continue;
+ } else {
+ lp.visibleBefore = true;
}
final int childWidth = child.getMeasuredWidth();
@@ -251,14 +194,16 @@ public class MessagingLinearLayout extends ViewGroup {
first = false;
}
- mLastMeasuredWidth = NOT_MEASURED_BEFORE;
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.hide) {
- return true;
+ MessagingChild messagingChild = (MessagingChild) child;
+ if (!messagingChild.isHidingAnimated()) {
+ return true;
+ }
}
return super.drawChild(canvas, child, drawingTime);
}
@@ -284,31 +229,37 @@ public class MessagingLinearLayout extends ViewGroup {
}
/**
- * Sets how many lines should be indented to avoid a floating image.
+ * Sets how many lines should be displayed at most
*/
@RemotableViewMethod
- public void setNumIndentLines(int numberLines) {
- mIndentLines = numberLines;
+ public void setMaxDisplayedLines(int numberLines) {
+ mMaxDisplayedLines = numberLines;
}
- /**
- * Set id of the child that's also visible in the contracted layout.
- */
- @RemotableViewMethod
- public void setContractedChildId(int contractedChildId) {
- mContractedChildId = contractedChildId;
+ public void setMessagingLayout(MessagingLayout layout) {
+ mMessagingLayout = layout;
}
- /**
- * Get id of the child that's also visible in the contracted layout.
- */
- public int getContractedChildId() {
- return mContractedChildId;
+ public MessagingLayout getMessagingLayout() {
+ return mMessagingLayout;
+ }
+
+ public interface MessagingChild {
+ int MEASURED_NORMAL = 0;
+ int MEASURED_SHORTENED = 1;
+ int MEASURED_TOO_SMALL = 2;
+
+ int getMeasuredType();
+ int getConsumedLines();
+ void setMaxDisplayedLines(int lines);
+ void hideAnimated();
+ boolean isHidingAnimated();
}
public static class LayoutParams extends MarginLayoutParams {
- boolean hide = false;
+ public boolean hide = false;
+ public boolean visibleBefore = false;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
diff --git a/core/java/com/android/internal/widget/MessagingMessage.java b/core/java/com/android/internal/widget/MessagingMessage.java
new file mode 100644
index 000000000000..f09621f544bc
--- /dev/null
+++ b/core/java/com/android/internal/widget/MessagingMessage.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.widget;
+
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
+import android.app.Notification;
+import android.content.Context;
+import android.text.Layout;
+import android.util.AttributeSet;
+import android.util.Pools;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.RemoteViews;
+
+import com.android.internal.R;
+
+import java.util.Objects;
+
+/**
+ * A message of a {@link MessagingLayout}.
+ */
+@RemoteViews.RemoteView
+public class MessagingMessage extends ImageFloatingTextView implements
+ MessagingLinearLayout.MessagingChild {
+
+ private static Pools.SimplePool<MessagingMessage> sInstancePool
+ = new Pools.SynchronizedPool<>(10);
+ private Notification.MessagingStyle.Message mMessage;
+ private MessagingGroup mGroup;
+ private boolean mIsHistoric;
+ private boolean mIsHidingAnimated;
+
+ public MessagingMessage(@NonNull Context context) {
+ super(context);
+ }
+
+ public MessagingMessage(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MessagingMessage(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public MessagingMessage(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ private void setMessage(Notification.MessagingStyle.Message message) {
+ mMessage = message;
+ setText(message.getText());
+ }
+
+ public Notification.MessagingStyle.Message getMessage() {
+ return mMessage;
+ }
+
+ boolean sameAs(Notification.MessagingStyle.Message message) {
+ if (!Objects.equals(message.getText(), mMessage.getText())) {
+ return false;
+ }
+ if (!Objects.equals(message.getSender(), mMessage.getSender())) {
+ return false;
+ }
+ if (!Objects.equals(message.getTimestamp(), mMessage.getTimestamp())) {
+ return false;
+ }
+ return true;
+ }
+
+ boolean sameAs(MessagingMessage message) {
+ return sameAs(message.getMessage());
+ }
+
+ static MessagingMessage createMessage(MessagingLayout layout,
+ Notification.MessagingStyle.Message m) {
+ MessagingLinearLayout messagingLinearLayout = layout.getMessagingLinearLayout();
+ MessagingMessage createdMessage = sInstancePool.acquire();
+ if (createdMessage == null) {
+ createdMessage = (MessagingMessage) LayoutInflater.from(layout.getContext()).inflate(
+ R.layout.notification_template_messaging_message, messagingLinearLayout,
+ false);
+ }
+ createdMessage.setMessage(m);
+ return createdMessage;
+ }
+
+ public void removeMessage() {
+ mGroup.removeMessage(this);
+ }
+
+ public void recycle() {
+ mGroup = null;
+ mMessage = null;
+ setAlpha(1.0f);
+ setTranslationY(0);
+ sInstancePool.release(this);
+ }
+
+ public void setMessagingGroup(MessagingGroup group) {
+ mGroup = group;
+ }
+
+ public static void dropCache() {
+ sInstancePool = new Pools.SynchronizedPool<>(10);
+ }
+
+ public void setIsHistoric(boolean isHistoric) {
+ mIsHistoric = isHistoric;
+ }
+
+ public MessagingGroup getGroup() {
+ return mGroup;
+ }
+
+ @Override
+ public int getMeasuredType() {
+ boolean measuredTooSmall = getMeasuredHeight()
+ < getLayoutHeight() + getPaddingTop() + getPaddingBottom();
+ if (measuredTooSmall) {
+ return MEASURED_TOO_SMALL;
+ } else {
+ Layout layout = getLayout();
+ if (layout == null) {
+ return MEASURED_TOO_SMALL;
+ }
+ if (layout.getEllipsisCount(layout.getLineCount() - 1) > 0) {
+ return MEASURED_SHORTENED;
+ } else {
+ return MEASURED_NORMAL;
+ }
+ }
+ }
+
+ @Override
+ public void hideAnimated() {
+ setIsHidingAnimated(true);
+ mGroup.performRemoveAnimation(this, () -> setIsHidingAnimated(false));
+ }
+
+ private void setIsHidingAnimated(boolean isHiding) {
+ ViewParent parent = getParent();
+ mIsHidingAnimated = isHiding;
+ invalidate();
+ if (parent instanceof ViewGroup) {
+ ((ViewGroup) parent).invalidate();
+ }
+ }
+
+ @Override
+ public boolean isHidingAnimated() {
+ return mIsHidingAnimated;
+ }
+
+ @Override
+ public void setMaxDisplayedLines(int lines) {
+ setMaxLines(lines);
+ }
+
+ @Override
+ public int getConsumedLines() {
+ return getLineCount();
+ }
+
+ public int getLayoutHeight() {
+ Layout layout = getLayout();
+ if (layout == null) {
+ return 0;
+ }
+ return layout.getHeight();
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+}
diff --git a/core/java/com/android/internal/widget/MessagingPropertyAnimator.java b/core/java/com/android/internal/widget/MessagingPropertyAnimator.java
new file mode 100644
index 000000000000..7c3ab7f9547f
--- /dev/null
+++ b/core/java/com/android/internal/widget/MessagingPropertyAnimator.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.internal.widget;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.util.IntProperty;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+
+import com.android.internal.R;
+
+/**
+ * A listener that automatically starts animations when the layout bounds change.
+ */
+public class MessagingPropertyAnimator implements View.OnLayoutChangeListener {
+ static final long APPEAR_ANIMATION_LENGTH = 210;
+ private static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
+ public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
+ private static final int TAG_LOCAL_TRANSLATION_ANIMATOR = R.id.tag_local_translation_y_animator;
+ private static final int TAG_LOCAL_TRANSLATION_Y = R.id.tag_local_translation_y;
+ private static final int TAG_LAYOUT_TOP = R.id.tag_layout_top;
+ private static final int TAG_ALPHA_ANIMATOR = R.id.tag_alpha_animator;
+ private static final ViewClippingUtil.ClippingParameters CLIPPING_PARAMETERS =
+ view -> view.getId() == com.android.internal.R.id.notification_messaging;
+ private static final IntProperty<View> LOCAL_TRANSLATION_Y =
+ new IntProperty<View>("localTranslationY") {
+ @Override
+ public void setValue(View object, int value) {
+ setLocalTranslationY(object, value);
+ }
+
+ @Override
+ public Integer get(View object) {
+ return getLocalTranslationY(object);
+ }
+ };
+
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ int oldHeight = oldBottom - oldTop;
+ Integer layoutTop = (Integer) v.getTag(TAG_LAYOUT_TOP);
+ if (layoutTop != null) {
+ oldTop = layoutTop;
+ }
+ int topChange = oldTop - top;
+ if (oldHeight == 0 || topChange == 0 || !v.isShown() || isGone(v)) {
+ // First layout
+ return;
+ }
+ if (layoutTop != null) {
+ v.setTagInternal(TAG_LAYOUT_TOP, top);
+ }
+ int newHeight = bottom - top;
+ int heightDifference = oldHeight - newHeight;
+ // Only add the difference if the height changes and it's getting smaller
+ heightDifference = Math.max(heightDifference, 0);
+ startLocalTranslationFrom(v, topChange + heightDifference + getLocalTranslationY(v));
+ }
+
+ private boolean isGone(View view) {
+ if (view.getVisibility() == View.GONE) {
+ return true;
+ }
+ final ViewGroup.LayoutParams lp = view.getLayoutParams();
+ if (lp instanceof MessagingLinearLayout.LayoutParams
+ && ((MessagingLinearLayout.LayoutParams) lp).hide) {
+ return true;
+ }
+ return false;
+ }
+
+ public static void startLocalTranslationFrom(View v, int startTranslation) {
+ startLocalTranslationFrom(v, startTranslation, MessagingLayout.FAST_OUT_SLOW_IN);
+ }
+
+ public static void startLocalTranslationFrom(View v, int startTranslation,
+ Interpolator interpolator) {
+ startLocalTranslation(v, startTranslation, 0, interpolator);
+ }
+
+ public static void startLocalTranslationTo(View v, int endTranslation,
+ Interpolator interpolator) {
+ startLocalTranslation(v, getLocalTranslationY(v), endTranslation, interpolator);
+ }
+
+ public static int getLocalTranslationY(View v) {
+ Integer tag = (Integer) v.getTag(TAG_LOCAL_TRANSLATION_Y);
+ if (tag == null) {
+ return 0;
+ }
+ return tag;
+ }
+
+ private static void setLocalTranslationY(View v, int value) {
+ v.setTagInternal(TAG_LOCAL_TRANSLATION_Y, value);
+ updateTopAndBottom(v);
+ }
+
+ private static void updateTopAndBottom(View v) {
+ int layoutTop = (int) v.getTag(TAG_LAYOUT_TOP);
+ int localTranslation = getLocalTranslationY(v);
+ int height = v.getHeight();
+ v.setTop(layoutTop + localTranslation);
+ v.setBottom(layoutTop + height + localTranslation);
+ }
+
+ private static void startLocalTranslation(final View v, int start, int end,
+ Interpolator interpolator) {
+ ObjectAnimator existing = (ObjectAnimator) v.getTag(TAG_LOCAL_TRANSLATION_ANIMATOR);
+ if (existing != null) {
+ existing.cancel();
+ }
+ ObjectAnimator animator = ObjectAnimator.ofInt(v, LOCAL_TRANSLATION_Y, start, end);
+ Integer layoutTop = (Integer) v.getTag(TAG_LAYOUT_TOP);
+ if (layoutTop == null) {
+ layoutTop = v.getTop();
+ v.setTagInternal(TAG_LAYOUT_TOP, layoutTop);
+ }
+ setLocalTranslationY(v, start);
+ animator.setInterpolator(interpolator);
+ animator.setDuration(APPEAR_ANIMATION_LENGTH);
+ animator.addListener(new AnimatorListenerAdapter() {
+ public boolean mCancelled;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ v.setTagInternal(TAG_LOCAL_TRANSLATION_ANIMATOR, null);
+ setClippingDeactivated(v, false);
+ if (!mCancelled) {
+ setLocalTranslationY(v, 0);
+ v.setTagInternal(TAG_LAYOUT_TOP, null);
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+ });
+ setClippingDeactivated(v, true);
+ v.setTagInternal(TAG_LOCAL_TRANSLATION_ANIMATOR, animator);
+ animator.start();
+ }
+
+ public static void fadeIn(final View v) {
+ ObjectAnimator existing = (ObjectAnimator) v.getTag(TAG_ALPHA_ANIMATOR);
+ if (existing != null) {
+ existing.cancel();
+ }
+ if (v.getVisibility() == View.INVISIBLE) {
+ v.setVisibility(View.VISIBLE);
+ }
+ ObjectAnimator animator = ObjectAnimator.ofFloat(v, View.ALPHA,
+ 0.0f, 1.0f);
+ v.setAlpha(0.0f);
+ animator.setInterpolator(ALPHA_IN);
+ animator.setDuration(APPEAR_ANIMATION_LENGTH);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ v.setTagInternal(TAG_ALPHA_ANIMATOR, null);
+ updateLayerType(v, false /* animating */);
+ }
+ });
+ updateLayerType(v, true /* animating */);
+ v.setTagInternal(TAG_ALPHA_ANIMATOR, animator);
+ animator.start();
+ }
+
+ private static void updateLayerType(View view, boolean animating) {
+ if (view.hasOverlappingRendering() && animating) {
+ view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ } else if (view.getLayerType() == View.LAYER_TYPE_HARDWARE) {
+ view.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+ }
+
+ public static void fadeOut(final View view, Runnable endAction) {
+ ObjectAnimator existing = (ObjectAnimator) view.getTag(TAG_ALPHA_ANIMATOR);
+ if (existing != null) {
+ existing.cancel();
+ }
+ ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.ALPHA,
+ view.getAlpha(), 0.0f);
+ animator.setInterpolator(ALPHA_OUT);
+ animator.setDuration(APPEAR_ANIMATION_LENGTH);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setTagInternal(TAG_ALPHA_ANIMATOR, null);
+ updateLayerType(view, false /* animating */);
+ if (endAction != null) {
+ endAction.run();
+ }
+ }
+ });
+ updateLayerType(view, true /* animating */);
+ view.setTagInternal(TAG_ALPHA_ANIMATOR, animator);
+ animator.start();
+ }
+
+ public static void setClippingDeactivated(final View transformedView, boolean deactivated) {
+ ViewClippingUtil.setClippingDeactivated(transformedView, deactivated,
+ CLIPPING_PARAMETERS);
+ }
+
+ public static boolean isAnimatingTranslation(View v) {
+ return v.getTag(TAG_LOCAL_TRANSLATION_ANIMATOR) != null;
+ }
+
+ public static boolean isAnimatingAlpha(View v) {
+ return v.getTag(TAG_ALPHA_ANIMATOR) != null;
+ }
+}
diff --git a/core/java/com/android/internal/widget/RemeasuringLinearLayout.java b/core/java/com/android/internal/widget/RemeasuringLinearLayout.java
new file mode 100644
index 000000000000..e352b45ef413
--- /dev/null
+++ b/core/java/com/android/internal/widget/RemeasuringLinearLayout.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.widget;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
+
+/**
+ * A LinearLayout that sets it's height again after the last measure pass. This is needed for
+ * MessagingLayouts where groups need to be able to snap it's height to.
+ */
+@RemoteViews.RemoteView
+public class RemeasuringLinearLayout extends LinearLayout {
+
+ public RemeasuringLinearLayout(Context context) {
+ super(context);
+ }
+
+ public RemeasuringLinearLayout(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public RemeasuringLinearLayout(Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public RemeasuringLinearLayout(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int count = getChildCount();
+ int height = 0;
+ for (int i = 0; i < count; ++i) {
+ final View child = getChildAt(i);
+ if (child == null || child.getVisibility() == View.GONE) {
+ continue;
+ }
+
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ height = Math.max(height, height + child.getMeasuredHeight() + lp.topMargin +
+ lp.bottomMargin);
+ }
+ setMeasuredDimension(getMeasuredWidth(), height);
+ }
+}
diff --git a/core/java/com/android/internal/widget/ViewClippingUtil.java b/core/java/com/android/internal/widget/ViewClippingUtil.java
new file mode 100644
index 000000000000..59bbed443193
--- /dev/null
+++ b/core/java/com/android/internal/widget/ViewClippingUtil.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.widget;
+
+import android.util.ArraySet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+
+import com.android.internal.R;
+
+/**
+ * A utility class that allows to clip views and their parents to allow for better transitions
+ */
+public class ViewClippingUtil {
+ private static final int CLIP_CLIPPING_SET = R.id.clip_children_set_tag;
+ private static final int CLIP_CHILDREN_TAG = R.id.clip_children_tag;
+ private static final int CLIP_TO_PADDING = R.id.clip_to_padding_tag;
+
+ public static void setClippingDeactivated(final View transformedView, boolean deactivated,
+ ClippingParameters clippingParameters) {
+ if (!deactivated && !clippingParameters.isClippingEnablingAllowed(transformedView)) {
+ return;
+ }
+ if (!(transformedView.getParent() instanceof ViewGroup)) {
+ return;
+ }
+ ViewGroup parent = (ViewGroup) transformedView.getParent();
+ while (true) {
+ if (!deactivated && !clippingParameters.isClippingEnablingAllowed(transformedView)) {
+ return;
+ }
+ ArraySet<View> clipSet = (ArraySet<View>) parent.getTag(CLIP_CLIPPING_SET);
+ if (clipSet == null) {
+ clipSet = new ArraySet<>();
+ parent.setTagInternal(CLIP_CLIPPING_SET, clipSet);
+ }
+ Boolean clipChildren = (Boolean) parent.getTag(CLIP_CHILDREN_TAG);
+ if (clipChildren == null) {
+ clipChildren = parent.getClipChildren();
+ parent.setTagInternal(CLIP_CHILDREN_TAG, clipChildren);
+ }
+ Boolean clipToPadding = (Boolean) parent.getTag(CLIP_TO_PADDING);
+ if (clipToPadding == null) {
+ clipToPadding = parent.getClipToPadding();
+ parent.setTagInternal(CLIP_TO_PADDING, clipToPadding);
+ }
+ if (!deactivated) {
+ clipSet.remove(transformedView);
+ if (clipSet.isEmpty()) {
+ parent.setClipChildren(clipChildren);
+ parent.setClipToPadding(clipToPadding);
+ parent.setTagInternal(CLIP_CLIPPING_SET, null);
+ clippingParameters.onClippingStateChanged(parent, true);
+ }
+ } else {
+ clipSet.add(transformedView);
+ parent.setClipChildren(false);
+ parent.setClipToPadding(false);
+ clippingParameters.onClippingStateChanged(parent, false);
+ }
+ if (clippingParameters.shouldFinish(parent)) {
+ return;
+ }
+ final ViewParent viewParent = parent.getParent();
+ if (viewParent instanceof ViewGroup) {
+ parent = (ViewGroup) viewParent;
+ } else {
+ return;
+ }
+ }
+ }
+
+ public interface ClippingParameters {
+ /**
+ * Should we stop clipping at this view? If true is returned, {@param view} is the last view
+ * where clipping is activated / deactivated.
+ */
+ boolean shouldFinish(View view);
+
+ /**
+ * Is it allowed to enable clipping on this view.
+ */
+ default boolean isClippingEnablingAllowed(View view) {
+ return !MessagingPropertyAnimator.isAnimatingTranslation(view);
+ }
+
+ /**
+ * A method that is called whenever the view starts clipping again / stops clipping to the
+ * children and padding.
+ */
+ default void onClippingStateChanged(View view, boolean isClipping) {};
+ }
+}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index fb8b9f75e031..3552e43b682a 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -28,10 +28,6 @@ cc_library_shared {
"-Wunused",
"-Wunreachable-code",
- // necessary for Clang as the GL bindings need to turn
- // off a GCC warning that Clang doesn't know.
- "-Wno-unknown-pragmas",
-
// TODO: Linear blending should be enabled by default, but we are
// TODO: making it an opt-in while it's a work in progress
//"-DANDROID_ENABLE_LINEAR_BLENDING",
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index 9e6985ca300e..1a19a4099e12 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -36,6 +36,7 @@
#include <hwui/Typeface.h>
#include <utils/FatVector.h>
#include <minikin/FontFamily.h>
+#include <minikin/LocaleList.h>
#include <memory>
@@ -43,9 +44,10 @@ namespace android {
struct NativeFamilyBuilder {
NativeFamilyBuilder(uint32_t langId, int variant)
- : langId(langId), variant(variant), allowUnsupportedFont(false) {}
+ : langId(langId), variant(static_cast<minikin::FontVariant>(variant)),
+ allowUnsupportedFont(false) {}
uint32_t langId;
- int variant;
+ minikin::FontVariant variant;
bool allowUnsupportedFont;
std::vector<minikin::Font> fonts;
std::vector<minikin::FontVariation> axes;
@@ -55,10 +57,9 @@ static jlong FontFamily_initBuilder(JNIEnv* env, jobject clazz, jstring langs, j
NativeFamilyBuilder* builder;
if (langs != nullptr) {
ScopedUtfChars str(env, langs);
- builder = new NativeFamilyBuilder(
- minikin::FontStyle::registerLocaleList(str.c_str()), variant);
+ builder = new NativeFamilyBuilder(minikin::registerLocaleList(str.c_str()), variant);
} else {
- builder = new NativeFamilyBuilder(minikin::FontStyle::registerLocaleList(""), variant);
+ builder = new NativeFamilyBuilder(minikin::registerLocaleList(""), variant);
}
return reinterpret_cast<jlong>(builder);
}
@@ -121,14 +122,14 @@ static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, in
std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize, ttcIndex,
builder->axes);
- int weight = givenWeight / 100;
+ int weight = givenWeight;
bool italic = givenItalic == 1;
if (givenWeight == RESOLVE_BY_FONT_TABLE || givenItalic == RESOLVE_BY_FONT_TABLE) {
int os2Weight;
bool os2Italic;
if (!minikin::FontFamily::analyzeStyle(minikinFont, &os2Weight, &os2Italic)) {
ALOGE("analyzeStyle failed. Using default style");
- os2Weight = 4;
+ os2Weight = 400;
os2Italic = false;
}
if (givenWeight == RESOLVE_BY_FONT_TABLE) {
@@ -139,7 +140,8 @@ static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, in
}
}
- builder->fonts.push_back(minikin::Font(minikinFont, minikin::FontStyle(weight, italic)));
+ builder->fonts.push_back(minikin::Font(minikinFont,
+ minikin::FontStyle(weight, static_cast<minikin::FontSlant>(italic))));
builder->axes.clear();
return true;
}
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index e8e3f57c718b..5f32d379af24 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -41,6 +41,7 @@
#include <hwui/Paint.h>
#include <hwui/Typeface.h>
#include <minikin/GraphemeBreak.h>
+#include <minikin/LocaleList.h>
#include <minikin/Measurement.h>
#include <unicode/utf16.h>
@@ -546,9 +547,9 @@ namespace PaintGlue {
static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
Paint* obj = reinterpret_cast<Paint*>(objHandle);
ScopedUtfChars localesChars(env, locales);
- jint minikinLangListId = minikin::FontStyle::registerLocaleList(localesChars.c_str());
- obj->setMinikinLangListId(minikinLangListId);
- return minikinLangListId;
+ jint minikinLocaleListId = minikin::registerLocaleList(localesChars.c_str());
+ obj->setMinikinLocaleListId(minikinLocaleListId);
+ return minikinLocaleListId;
}
static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) {
@@ -580,7 +581,7 @@ namespace PaintGlue {
// restore the original settings.
paint->setTextSkewX(saveSkewX);
paint->setFakeBoldText(savefakeBold);
- if (paint->getFontVariant() == minikin::VARIANT_ELEGANT) {
+ if (paint->getFontVariant() == minikin::FontVariant::ELEGANT) {
SkScalar size = paint->getTextSize();
metrics->fTop = -size * kElegantTop / 2048;
metrics->fBottom = -size * kElegantBottom / 2048;
@@ -871,20 +872,20 @@ namespace PaintGlue {
obj->setTextAlign(align);
}
- static void setTextLocalesByMinikinLangListId(jlong objHandle,
- jint minikinLangListId) {
+ static void setTextLocalesByMinikinLocaleListId(jlong objHandle,
+ jint minikinLocaleListId) {
Paint* obj = reinterpret_cast<Paint*>(objHandle);
- obj->setMinikinLangListId(minikinLangListId);
+ obj->setMinikinLocaleListId(minikinLocaleListId);
}
static jboolean isElegantTextHeight(jlong paintHandle) {
Paint* obj = reinterpret_cast<Paint*>(paintHandle);
- return obj->getFontVariant() == minikin::VARIANT_ELEGANT;
+ return obj->getFontVariant() == minikin::FontVariant::ELEGANT;
}
static void setElegantTextHeight(jlong paintHandle, jboolean aa) {
Paint* obj = reinterpret_cast<Paint*>(paintHandle);
- obj->setFontVariant(aa ? minikin::VARIANT_ELEGANT : minikin::VARIANT_DEFAULT);
+ obj->setFontVariant(aa ? minikin::FontVariant::ELEGANT : minikin::FontVariant::DEFAULT);
}
static jfloat getTextSize(jlong paintHandle) {
@@ -1080,8 +1081,8 @@ static const JNINativeMethod methods[] = {
{"nSetTypeface","(JJ)V", (void*) PaintGlue::setTypeface},
{"nGetTextAlign","(J)I", (void*) PaintGlue::getTextAlign},
{"nSetTextAlign","(JI)V", (void*) PaintGlue::setTextAlign},
- {"nSetTextLocalesByMinikinLangListId","(JI)V",
- (void*) PaintGlue::setTextLocalesByMinikinLangListId},
+ {"nSetTextLocalesByMinikinLocaleListId","(JI)V",
+ (void*) PaintGlue::setTextLocalesByMinikinLocaleListId},
{"nIsElegantTextHeight","(J)Z", (void*) PaintGlue::isElegantTextHeight},
{"nSetElegantTextHeight","(JZ)V", (void*) PaintGlue::setElegantTextHeight},
{"nGetTextSize","(J)F", (void*) PaintGlue::getTextSize},
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index d5f2a5c649a9..3e4073f6f215 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -83,7 +83,7 @@ static jint Typeface_getStyle(JNIEnv* env, jobject obj, jlong faceHandle) {
static jint Typeface_getWeight(JNIEnv* env, jobject obj, jlong faceHandle) {
Typeface* face = reinterpret_cast<Typeface*>(faceHandle);
- return face->fStyle.getWeight() * 100;
+ return face->fStyle.weight;
}
static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray,
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 616358866275..a9d75fd6aff7 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -17,7 +17,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
diff --git a/core/jni/android_opengl_EGLExt.cpp b/core/jni/android_opengl_EGLExt.cpp
index df1aa2025b98..75a25fe95e09 100644
--- a/core/jni/android_opengl_EGLExt.cpp
+++ b/core/jni/android_opengl_EGLExt.cpp
@@ -17,7 +17,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp
index 6d4f6eccfdba..ee5b5941202d 100644
--- a/core/jni/android_opengl_GLES10.cpp
+++ b/core/jni/android_opengl_GLES10.cpp
@@ -18,7 +18,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES/gl.h>
diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp
index e630cfca64c8..da7d0f01928f 100644
--- a/core/jni/android_opengl_GLES10Ext.cpp
+++ b/core/jni/android_opengl_GLES10Ext.cpp
@@ -18,7 +18,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES/gl.h>
diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp
index ab9cbb11a353..391ae5366a3b 100644
--- a/core/jni/android_opengl_GLES11.cpp
+++ b/core/jni/android_opengl_GLES11.cpp
@@ -18,7 +18,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES/gl.h>
diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp
index 8f71a6d7dc49..09dce32b9e56 100644
--- a/core/jni/android_opengl_GLES11Ext.cpp
+++ b/core/jni/android_opengl_GLES11Ext.cpp
@@ -18,7 +18,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES/gl.h>
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index f83d20467ea8..99922cfe401d 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -18,7 +18,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES2/gl2.h>
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index b649daf46607..adc635ed4eea 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -18,7 +18,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES3/gl3.h>
diff --git a/core/jni/android_opengl_GLES31.cpp b/core/jni/android_opengl_GLES31.cpp
index 07d920f87941..512f562062e6 100644
--- a/core/jni/android_opengl_GLES31.cpp
+++ b/core/jni/android_opengl_GLES31.cpp
@@ -17,7 +17,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <stdint.h>
diff --git a/core/jni/android_opengl_GLES31Ext.cpp b/core/jni/android_opengl_GLES31Ext.cpp
index 723dd4cd0b87..5543fcadaed0 100644
--- a/core/jni/android_opengl_GLES31Ext.cpp
+++ b/core/jni/android_opengl_GLES31Ext.cpp
@@ -17,7 +17,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <GLES3/gl31.h>
diff --git a/core/jni/android_opengl_GLES32.cpp b/core/jni/android_opengl_GLES32.cpp
index 62a6e6c61394..2f1e31e7fab9 100644
--- a/core/jni/android_opengl_GLES32.cpp
+++ b/core/jni/android_opengl_GLES32.cpp
@@ -17,7 +17,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include <stdint.h>
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index f6783e15e294..08d952791ef6 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -344,17 +344,6 @@ void JHwBinder_native_joinRpcThreadpool() {
IPCThreadState::self()->joinThreadPool();
}
-void JHwBinder_native_startRpcThreadPool(JNIEnv *, jclass,
- jlong maxThreads, jboolean callerWillJoin) {
- CHECK(maxThreads > 0);
- ProcessState::self()->setThreadPoolConfiguration(maxThreads,
- callerWillJoin /* callerJoinsPool */);
- ssize_t threadsNeeded = maxThreads - (callerWillJoin ? 0 : 1);
- for (ssize_t i = 0; i < threadsNeeded; ++i) {
- ProcessState::self()->spawnPooledThread(false /* isMain */);
- }
-}
-
static void JHwBinder_report_sysprop_change(JNIEnv * /*env*/, jclass /*clazz*/)
{
report_sysprop_change();
@@ -380,9 +369,6 @@ static JNINativeMethod gMethods[] = {
{ "joinRpcThreadpool", "()V",
(void *)JHwBinder_native_joinRpcThreadpool },
- { "startRpcThreadPool", "(JZ)V",
- (void *)JHwBinder_native_startRpcThreadPool },
-
{ "native_report_sysprop_change", "()V",
(void *)JHwBinder_report_sysprop_change },
};
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index f0ac79acd7de..d18c17269181 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -554,18 +554,6 @@ static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jclass clazz, job
}
}
-static void android_os_Parcel_clearFileDescriptor(JNIEnv* env, jclass clazz, jobject object)
-{
- if (object == NULL) {
- jniThrowNullPointerException(env, NULL);
- return;
- }
- int fd = jniGetFDFromFileDescriptor(env, object);
- if (fd >= 0) {
- jniSetFileDescriptorOfFD(env, object, -1);
- }
-}
-
static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
Parcel* parcel = new Parcel();
@@ -811,7 +799,6 @@ static const JNINativeMethod gParcelMethods[] = {
{"openFileDescriptor", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor},
{"dupFileDescriptor", "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_dupFileDescriptor},
{"closeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor},
- {"clearFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor},
{"nativeCreate", "()J", (void*)android_os_Parcel_create},
{"nativeFreeBuffer", "(J)J", (void*)android_os_Parcel_freeBuffer},
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index c1419ba6c7c6..4e88a83a92ea 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -67,6 +67,18 @@ class JNILineBreakerLineWidth : public minikin::LineBreaker::LineWidthDelegate {
return width - get(mIndents, lineNo);
}
+ float getMinLineWidth() override {
+ // A simpler algorithm would have been simply looping until the larger of
+ // mFirstLineCount and mIndents.size()-mOffset, but that does unnecessary calculations
+ // when mFirstLineCount is large. Instead, we measure the first line, all the lines that
+ // have an indent, and the first line after firstWidth ends and restWidth starts.
+ float minWidth = std::min(getLineWidth(0), getLineWidth(mFirstLineCount));
+ for (size_t lineNo = 1; lineNo + mOffset < mIndents.size(); lineNo++) {
+ minWidth = std::min(minWidth, getLineWidth(lineNo));
+ }
+ return minWidth;
+ }
+
float getLeftPadding(size_t lineNo) override {
return get(mLeftPaddings, lineNo);
}
@@ -108,14 +120,13 @@ static inline std::vector<float> jintArrayToFloatVector(JNIEnv* env, jintArray j
class Run {
public:
- Run(int32_t start, int32_t end) : mStart(start), mEnd(end) {}
+ Run(int32_t start, int32_t end) : mRange(start, end) {}
virtual ~Run() {}
virtual void addTo(minikin::LineBreaker* lineBreaker) = 0;
protected:
- const int32_t mStart;
- const int32_t mEnd;
+ minikin::Range mRange;
private:
// Forbid copy and assign.
@@ -126,19 +137,17 @@ class Run {
class StyleRun : public Run {
public:
StyleRun(int32_t start, int32_t end, minikin::MinikinPaint&& paint,
- std::shared_ptr<minikin::FontCollection>&& collection,
- minikin::FontStyle&& style, bool isRtl)
+ std::shared_ptr<minikin::FontCollection>&& collection, bool isRtl)
: Run(start, end), mPaint(std::move(paint)), mCollection(std::move(collection)),
- mStyle(std::move(style)), mIsRtl(isRtl) {}
+ mIsRtl(isRtl) {}
void addTo(minikin::LineBreaker* lineBreaker) override {
- lineBreaker->addStyleRun(&mPaint, mCollection, mStyle, mStart, mEnd, mIsRtl);
+ lineBreaker->addStyleRun(&mPaint, mCollection, mRange, mIsRtl);
}
private:
minikin::MinikinPaint mPaint;
std::shared_ptr<minikin::FontCollection> mCollection;
- minikin::FontStyle mStyle;
const bool mIsRtl;
};
@@ -148,7 +157,7 @@ class Replacement : public Run {
: Run(start, end), mWidth(width), mLocaleListId(localeListId) {}
void addTo(minikin::LineBreaker* lineBreaker) override {
- lineBreaker->addReplacement(mStart, mEnd, mWidth, mLocaleListId);
+ lineBreaker->addReplacement(mRange, mWidth, mLocaleListId);
}
private:
@@ -167,10 +176,9 @@ class StaticLayoutNative {
mRightPaddings(std::move(rightPaddings)) {}
void addStyleRun(int32_t start, int32_t end, minikin::MinikinPaint&& paint,
- std::shared_ptr<minikin::FontCollection> collection,
- minikin::FontStyle&& style, bool isRtl) {
+ std::shared_ptr<minikin::FontCollection> collection, bool isRtl) {
mRuns.emplace_back(std::make_unique<StyleRun>(
- start, end, std::move(paint), std::move(collection), std::move(style), isRtl));
+ start, end, std::move(paint), std::move(collection), isRtl));
}
void addReplacementRun(int32_t start, int32_t end, float width, uint32_t localeListId) {
@@ -264,7 +272,7 @@ static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
// Inputs
- jcharArray text,
+ jcharArray javaText,
jint length,
jfloat firstWidth,
jint firstWidthLineCount,
@@ -285,11 +293,10 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
StaticLayoutNative* builder = toNative(nativePtr);
+ ScopedCharArrayRO text(env, javaText);
+
// TODO: Reorganize minikin APIs.
- minikin::LineBreaker b;
- b.resize(length);
- env->GetCharArrayRegion(text, 0, length, b.buffer());
- b.setText();
+ minikin::LineBreaker b(minikin::U16StringPiece(text.get(), length));
if (variableTabStops == nullptr) {
b.setTabStops(nullptr, 0, defaultTabStop);
} else {
@@ -312,7 +319,6 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
env->SetFloatArrayRegion(charWidths, 0, b.size(), b.charWidths());
- b.finish();
builder->clearRuns();
return static_cast<jint>(nBreaks);
@@ -323,15 +329,9 @@ static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
static void nAddStyleRun(jlong nativePtr, jlong nativePaint, jint start, jint end, jboolean isRtl) {
StaticLayoutNative* builder = toNative(nativePtr);
Paint* paint = reinterpret_cast<Paint*>(nativePaint);
- const Typeface* typeface = paint->getAndroidTypeface();
- minikin::MinikinPaint minikinPaint;
- const Typeface* resolvedTypeface = Typeface::resolveDefault(typeface);
- minikin::FontStyle style = MinikinUtils::prepareMinikinPaint(&minikinPaint, paint,
- typeface);
-
- builder->addStyleRun(
- start, end, std::move(minikinPaint), resolvedTypeface->fFontCollection, std::move(style),
- isRtl);
+ 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
@@ -339,7 +339,7 @@ static void nAddReplacementRun(jlong nativePtr, jlong nativePaint, jint start, j
jfloat width) {
StaticLayoutNative* builder = toNative(nativePtr);
Paint* paint = reinterpret_cast<Paint*>(nativePaint);
- builder->addReplacementRun(start, end, width, paint->getMinikinLangListId());
+ builder->addReplacementRun(start, end, width, paint->getMinikinLocaleListId());
}
static const JNINativeMethod gMethods[] = {
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index dea38e81cd54..1350f3f46aca 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -171,6 +171,7 @@ static std::atomic<uint32_t> gCollectedAtRefs(0);
// Garbage collect if we've allocated at least GC_INTERVAL refs since the last time.
// TODO: Consider removing this completely. We should no longer be generating GlobalRefs
// that are reclaimed as a result of GC action.
+__attribute__((no_sanitize("unsigned-integer-overflow")))
static void gcIfManyNewRefs(JNIEnv* env)
{
uint32_t totalRefs = gNumLocalRefsCreated.load(std::memory_order_relaxed)
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 6e8c93132562..37ff8c8cefd2 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -174,6 +174,10 @@ static jboolean android_view_RenderNode_hasShadow(jlong renderNodePtr) {
return renderNode->stagingProperties().hasShadow();
}
+static jboolean android_view_RenderNode_setShadowColor(jlong renderNodePtr, jint shadowColor) {
+ return SET_AND_DIRTY(setShadowColor, static_cast<SkColor>(shadowColor), RenderNode::GENERIC);
+}
+
static jboolean android_view_RenderNode_setClipToOutline(jlong renderNodePtr,
jboolean clipToOutline) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
@@ -571,6 +575,7 @@ static const JNINativeMethod gMethods[] = {
{ "nSetOutlineEmpty", "(J)Z", (void*) android_view_RenderNode_setOutlineEmpty },
{ "nSetOutlineNone", "(J)Z", (void*) android_view_RenderNode_setOutlineNone },
{ "nHasShadow", "(J)Z", (void*) android_view_RenderNode_hasShadow },
+ { "nSetShadowColor", "(JI)Z", (void*) android_view_RenderNode_setShadowColor },
{ "nSetClipToOutline", "(JZ)Z", (void*) android_view_RenderNode_setClipToOutline },
{ "nSetRevealClip", "(JZFFF)Z", (void*) android_view_RenderNode_setRevealClip },
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 57263b1c80a8..870a0c2073d8 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -54,6 +54,7 @@
#include <renderthread/RenderProxy.h>
#include <renderthread/RenderTask.h>
#include <renderthread/RenderThread.h>
+#include <pipeline/skia/ShaderCache.h>
namespace android {
@@ -970,10 +971,14 @@ static void android_view_ThreadedRenderer_removeFrameMetricsObserver(JNIEnv* env
// ----------------------------------------------------------------------------
static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
- jstring diskCachePath) {
+ jstring diskCachePath, jstring skiaDiskCachePath) {
const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
android::egl_set_cache_filename(cacheArray);
env->ReleaseStringUTFChars(diskCachePath, cacheArray);
+
+ const char* skiaCacheArray = env->GetStringUTFChars(skiaDiskCachePath, NULL);
+ uirenderer::skiapipeline::ShaderCache::get().setFilename(skiaCacheArray);
+ env->ReleaseStringUTFChars(skiaDiskCachePath, skiaCacheArray);
}
// ----------------------------------------------------------------------------
@@ -1018,7 +1023,7 @@ static const JNINativeMethod gMethods[] = {
{ "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
{ "nSerializeDisplayListTree", "(J)V", (void*) android_view_ThreadedRenderer_serializeDisplayListTree },
{ "nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
- { "setupShadersDiskCache", "(Ljava/lang/String;)V",
+ { "setupShadersDiskCache", "(Ljava/lang/String;Ljava/lang/String;)V",
(void*) android_view_ThreadedRenderer_setupShadersDiskCache },
{ "nAddRenderNode", "(JJZ)V", (void*) android_view_ThreadedRenderer_addRenderNode},
{ "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode},
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index ac23eca93014..40ff7e4c5517 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -18,7 +18,6 @@
// This source file is automatically generated
#pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
#include "jni.h"
diff --git a/core/jni/hwbinder/EphemeralStorage.cpp b/core/jni/hwbinder/EphemeralStorage.cpp
index 4996bc86cade..3b18f2b36b9e 100644
--- a/core/jni/hwbinder/EphemeralStorage.cpp
+++ b/core/jni/hwbinder/EphemeralStorage.cpp
@@ -111,6 +111,7 @@ DEFINE_ALLOC_VECTOR_METHODS(Double,jdouble,Double)
break; \
}
+__attribute__((no_sanitize("unsigned-integer-overflow")))
void EphemeralStorage::release(JNIEnv *env) {
for (size_t i = mItems.size(); i--;) {
const Item &item = mItems[i];
diff --git a/core/proto/android/os/cpuinfo.proto b/core/proto/android/os/cpuinfo.proto
new file mode 100644
index 000000000000..a95fa57ac2b2
--- /dev/null
+++ b/core/proto/android/os/cpuinfo.proto
@@ -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.
+ */
+syntax = "proto2";
+
+option java_multiple_files = true;
+option java_outer_classname = "CpuInfoProto";
+
+import "frameworks/base/tools/streaming_proto/stream.proto";
+
+package android.os;
+
+/**
+ * Data structure of the linux command
+ * 'top -b -n 1 -H -s 6 -o pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name'
+ *
+ * Next Tag: 6
+ */
+message CpuInfo {
+
+ message TaskStats {
+ option (stream_proto.stream_msg).enable_fields_mapping = true;
+
+ optional int32 total = 1; // total number of cpu tasks
+ optional int32 running = 2; // number of running tasks
+ optional int32 sleeping = 3; // number of sleeping tasks
+ optional int32 stopped = 4; // number of stopped tasks
+ optional int32 zombie = 5; // number of zombie tasks
+ }
+ optional TaskStats task_stats = 1;
+
+ message MemStats { // unit in kB
+ option (stream_proto.stream_msg).enable_fields_mapping = true;
+
+ optional int32 total = 1;
+ optional int32 used = 2;
+ optional int32 free = 3;
+ optional int32 buffers = 4;
+ optional int32 cached = 5;
+ }
+ optional MemStats mem = 2;
+ optional MemStats swap = 3;
+
+ message CpuUsage { // unit is percentage %
+ option (stream_proto.stream_msg).enable_fields_mapping = true;
+
+ optional int32 cpu = 1; // 400% cpu indicates 4 cores
+ optional int32 user = 2;
+ optional int32 nice = 3;
+ optional int32 sys = 4;
+ optional int32 idle = 5;
+ optional int32 iow = 6;
+ optional int32 irq = 7;
+ optional int32 sirq = 8;
+ optional int32 host = 9;
+ }
+ optional CpuUsage cpu_usage = 4;
+
+ // Next Tag: 13
+ message Task {
+ option (stream_proto.stream_msg).enable_fields_mapping = true;
+
+ optional int32 pid = 1;
+ optional int32 tid = 2;
+ optional string user = 3;
+ optional string pr = 4; // priority of each task, using string type is because special value RT (real time)
+ optional sint32 ni = 5; // niceness value
+ optional float cpu = 6; // precentage of cpu usage of the task
+
+ enum Status {
+ option (stream_proto.stream_enum).enable_enums_mapping = true;
+
+ STATUS_UNKNOWN = 0;
+ STATUS_D = 1; // uninterruptible sleep
+ STATUS_R = 2; // running
+ STATUS_S = 3; // sleeping
+ STATUS_T = 4; // traced or stopped
+ STATUS_Z = 5; // zombie
+ }
+ optional Status s = 7; // process status
+ optional string virt = 8; // virtual memory size, i.e. 14.0G, 13.5M
+ optional string res = 9; // Resident size, i.e. 0, 3.1G
+
+ // How Android memory manager will treat the task
+ enum Policy {
+ option (stream_proto.stream_enum).enable_enums_mapping = true;
+
+ POLICY_UNKNOWN = 0;
+ POLICY_fg = 1; // foreground, the name is lower case for parsing the value
+ POLICY_bg = 2; // background, the name is lower case for parsing the value
+ POLICY_ta = 3; // TODO: figure out what is this value
+ }
+ optional Policy pcy = 10; // Policy of the task
+ optional string cmd = 11; // thread name
+ optional string name = 12; // program name
+ }
+ repeated Task tasks = 5;
+}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index e998b09d18ee..f68f3a4ad7a4 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -20,11 +20,13 @@ 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/providers/settings.proto";
+import "frameworks/base/core/proto/android/os/cpuinfo.proto";
import "frameworks/base/core/proto/android/os/incidentheader.proto";
import "frameworks/base/core/proto/android/os/kernelwake.proto";
import "frameworks/base/core/proto/android/os/pagetypeinfo.proto";
import "frameworks/base/core/proto/android/os/procrank.proto";
+import "frameworks/base/core/proto/android/os/system_properties.proto";
+import "frameworks/base/core/proto/android/providers/settings.proto";
import "frameworks/base/core/proto/android/server/activitymanagerservice.proto";
import "frameworks/base/core/proto/android/server/alarmmanagerservice.proto";
import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
@@ -50,7 +52,10 @@ message IncidentProto {
repeated IncidentHeaderProto header = 1;
// Device information
- //SystemProperties system_properties = 1000;
+ optional SystemPropertiesProto system_properties = 1000 [
+ (section).type = SECTION_COMMAND,
+ (section).args = "/system/bin/getprop"
+ ];
// Linux services
optional Procrank procrank = 2000 [
@@ -68,6 +73,11 @@ message IncidentProto {
(section).args = "/d/wakeup_sources"
];
+ optional CpuInfo cpu_info = 2003 [
+ (section).type = SECTION_COMMAND,
+ (section).args = "/system/bin/top -b -n 1 -H -s 6 -o pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"
+ ];
+
// System Services
optional com.android.server.fingerprint.FingerprintServiceDumpProto fingerprint = 3000 [
@@ -80,7 +90,11 @@ message IncidentProto {
(section).args = "netstats --proto"
];
- optional android.providers.settings.SettingsServiceDumpProto settings = 3002;
+ optional android.providers.settings.SettingsServiceDumpProto settings = 3002 [
+ (section).type = SECTION_DUMPSYS,
+ (section).args = "settings --proto"
+ ];
+
optional android.service.appwidget.AppWidgetServiceDumpProto appwidget = 3003;
optional android.service.notification.NotificationServiceDumpProto notification = 3004 [
(section).type = SECTION_DUMPSYS,
diff --git a/core/proto/android/os/kernelwake.proto b/core/proto/android/os/kernelwake.proto
index d032a452c14e..eaad37af2ebc 100644
--- a/core/proto/android/os/kernelwake.proto
+++ b/core/proto/android/os/kernelwake.proto
@@ -29,7 +29,7 @@ message KernelWakeSources {
// Next Tag: 11
message WakeupSourceProto {
- option (stream_proto.stream).enable_fields_mapping = true;
+ option (stream_proto.stream_msg).enable_fields_mapping = true;
// Name of the event which triggers application processor
optional string name = 1;
diff --git a/core/proto/android/os/pagetypeinfo.proto b/core/proto/android/os/pagetypeinfo.proto
index 22b3d730f1a1..b86ee01f31b7 100644
--- a/core/proto/android/os/pagetypeinfo.proto
+++ b/core/proto/android/os/pagetypeinfo.proto
@@ -63,7 +63,7 @@ message MigrateTypeProto {
// Next tag: 9
message BlockProto {
- option (stream_proto.stream).enable_fields_mapping = true;
+ option (stream_proto.stream_msg).enable_fields_mapping = true;
optional int32 node = 1;
diff --git a/core/proto/android/os/procrank.proto b/core/proto/android/os/procrank.proto
index 4d62a60c8345..9945f2e792a9 100644
--- a/core/proto/android/os/procrank.proto
+++ b/core/proto/android/os/procrank.proto
@@ -33,7 +33,7 @@ message Procrank {
// Next Tag: 11
message ProcessProto {
- option (stream_proto.stream).enable_fields_mapping = true;
+ option (stream_proto.stream_msg).enable_fields_mapping = true;
// ID of the process
optional int32 pid = 1;
diff --git a/core/proto/android/os/system_properties.proto b/core/proto/android/os/system_properties.proto
new file mode 100644
index 000000000000..921bb5a4b471
--- /dev/null
+++ b/core/proto/android/os/system_properties.proto
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 java_multiple_files = true;
+option java_outer_classname = "SystemPropertiesProtoMetadata";
+
+import "frameworks/base/tools/streaming_proto/stream.proto";
+
+package android.os;
+
+// System Properties from getprop
+message SystemPropertiesProto {
+ option (stream_proto.stream_msg).enable_fields_mapping = true;
+
+ // Properties that are not specified below are appended here.
+ message Property {
+ 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;
+ }
+ 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 bool keyguard_no_require_sim = 146;
+
+ optional string log_tag_WifiHAL = 147;
+
+ optional bool logd_logpersistd_enable = 148;
+
+ optional bool media_mediadrmservice_enable = 149;
+ optional bool media_recorder_show_manufacturer_and_model = 150;
+
+ 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;
+
+ optional bool nfc_initialized = 171;
+
+ 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;
+
+ 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 int32 persist_cne_feature = 183;
+
+ optional bool persist_data_iwlan_enable = 184;
+ optional string persist_data_mode = 185;
+
+ 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 int32 persist_rcs_supported = 210;
+
+ 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;
+
+ 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 string qcom_bluetooth_soc = 228;
+
+ optional int32 qdcm_diagonal_matrix_mode = 229;
+ optional int32 qdcm_only_pcc_for_trans = 230;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ optional string ro_bootimage_build_date = 276;
+ optional int64 ro_bootimage_build_date_utc = 277;
+ optional string ro_bootimage_build_fingerprint = 278;
+
+ optional string ro_bootloader = 279;
+ optional string ro_bootmode = 280;
+
+ 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;
+
+ optional string ro_bt_bdaddr_path = 382;
+
+ 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 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ optional string ro_frp_pst = 432;
+
+ optional string ro_hardware = 433;
+ optional string ro_hardware_power = 434;
+
+ 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;
+
+ 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 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;
+
+ 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 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;
+
+ optional int32 sdm_debug_disable_rotator_split = 506;
+
+ optional string selinux_restorecon_recursive = 507;
+
+ optional string sendbug_preferred_domain = 508;
+
+ optional string sensors_contexthub_lid_state = 509;
+
+ optional int32 service_bootanim_exit = 510;
+ optional int32 service_sf_present_timestamp = 511;
+
+ optional string setupwizard_theme = 512;
+
+ 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 int32 telephony_lteOnCdmaDevice = 539;
+
+ optional int32 tombstoned_max_tombstone_count = 540;
+
+ optional int32 vidc_debug_perf_mode = 541;
+
+ optional int32 vold_has_adoptable = 542;
+ optional int32 vold_has_quota = 543;
+ optional int32 vold_post_fs_data_done = 544;
+
+ 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 string wifi_interface = 552;
+ optional string wlan_driver_status = 553;
+
+ // Next Tag: 554
+}
+
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index 3411c6a6f1d4..764288c51b66 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -39,9 +39,10 @@ message UserSettingsProto {
optional SystemSettingsProto system_settings = 3;
}
+// Note: it's a conscious decision to add each setting as a separate field. This
+// allows annotating each setting with its own privacy tag.
message GlobalSettingsProto {
- // Historical operations
- repeated SettingsOperationProto historical_op = 1;
+ repeated SettingsOperationProto historical_operations = 1;
optional SettingProto add_users_when_locked = 2;
optional SettingProto enable_accessibility_global_gesture_enabled = 3;
@@ -54,6 +55,7 @@ message GlobalSettingsProto {
optional SettingProto radio_nfc = 10;
optional SettingProto airplane_mode_radios = 11;
optional SettingProto airplane_mode_toggleable_radios = 12;
+ optional SettingProto bluetooth_class_of_device = 293;
optional SettingProto bluetooth_disabled_profiles = 13;
optional SettingProto bluetooth_interoperability_list = 14;
optional SettingProto wifi_sleep_policy = 15;
@@ -86,6 +88,7 @@ message GlobalSettingsProto {
optional SettingProto data_roaming = 42;
optional SettingProto mdc_initial_max_retry = 43;
optional SettingProto force_allow_on_external = 44;
+ optional SettingProto euicc_provisioned = 294;
optional SettingProto development_force_resizable_activities = 45;
optional SettingProto development_enable_freeform_windows_support = 46;
optional SettingProto development_settings_enabled = 47;
@@ -99,6 +102,11 @@ message GlobalSettingsProto {
optional SettingProto hdmi_system_audio_control_enabled = 55;
optional SettingProto hdmi_control_auto_wakeup_enabled = 56;
optional SettingProto hdmi_control_auto_device_off_enabled = 57;
+ optional SettingProto location_background_throttle_interval_ms = 295;
+ optional SettingProto location_background_throttle_proximity_alert_interval_ms = 296;
+ optional SettingProto location_background_throttle_package_whitelist = 297;
+ optional SettingProto wifi_scan_background_throttle_interval_ms = 298;
+ optional SettingProto wifi_scan_background_throttle_package_whitelist = 299;
optional SettingProto mhl_input_switching_enabled = 58;
optional SettingProto mhl_power_charge_enabled = 59;
optional SettingProto mobile_data = 60;
@@ -109,6 +117,7 @@ message GlobalSettingsProto {
optional SettingProto netstats_time_cache_max_age = 65;
optional SettingProto netstats_global_alert_bytes = 66;
optional SettingProto netstats_sample_enabled = 67;
+ optional SettingProto netstats_augment_enabled = 300;
optional SettingProto netstats_dev_bucket_duration = 68;
optional SettingProto netstats_dev_persist_bytes = 69;
optional SettingProto netstats_dev_rotate_age = 70;
@@ -156,6 +165,7 @@ message GlobalSettingsProto {
optional SettingProto tether_supported = 113;
optional SettingProto tether_dun_required = 114;
optional SettingProto tether_dun_apn = 115;
+ optional SettingProto tether_offload_disabled = 301;
optional SettingProto carrier_app_whitelist = 116;
optional SettingProto usb_mass_storage_enabled = 117;
optional SettingProto use_google_mail = 118;
@@ -166,6 +176,9 @@ message GlobalSettingsProto {
optional SettingProto network_switch_notification_daily_limit = 123;
optional SettingProto network_switch_notification_rate_limit_millis = 124;
optional SettingProto network_avoid_bad_wifi = 125;
+ optional SettingProto network_metered_multipath_preference = 302;
+ optional SettingProto network_watchlist_last_report_time = 303;
+ optional SettingProto wifi_badging_thresholds = 304;
optional SettingProto wifi_display_on = 126;
optional SettingProto wifi_display_certification_on = 127;
optional SettingProto wifi_display_wps_config = 128;
@@ -179,7 +192,14 @@ message GlobalSettingsProto {
optional SettingProto wifi_on = 136;
optional SettingProto wifi_scan_always_available = 137;
optional SettingProto wifi_wakeup_enabled = 138;
+ optional SettingProto wifi_wakeup_available = 305;
+ optional SettingProto network_scoring_ui_enabled = 306;
+ optional SettingProto speed_label_cache_eviction_age_millis = 307;
+ optional SettingProto recommended_network_evaluator_cache_expiry_ms = 308;
optional SettingProto network_recommendations_enabled = 139;
+ optional SettingProto network_recommendations_package = 286;
+ optional SettingProto use_open_wifi_package = 309;
+ optional SettingProto network_recommendation_request_timeout_ms = 310;
optional SettingProto ble_scan_always_available = 140;
optional SettingProto wifi_saved_state = 141;
optional SettingProto wifi_supplicant_scan_interval_ms = 142;
@@ -219,15 +239,19 @@ message GlobalSettingsProto {
optional SettingProto sys_storage_threshold_percentage = 176;
optional SettingProto sys_storage_threshold_max_bytes = 177;
optional SettingProto sys_storage_full_threshold_bytes = 178;
+ optional SettingProto sys_storage_cache_percentage = 311;
+ optional SettingProto sys_storage_cache_max_bytes = 312;
optional SettingProto sync_max_retry_delay_in_seconds = 179;
optional SettingProto connectivity_change_delay = 180;
optional SettingProto connectivity_sampling_interval_in_seconds = 181;
optional SettingProto pac_change_delay = 182;
optional SettingProto captive_portal_mode = 183;
+ optional SettingProto captive_portal_detection_enabled = 313;
optional SettingProto captive_portal_server = 184;
optional SettingProto captive_portal_https_url = 185;
optional SettingProto captive_portal_http_url = 186;
optional SettingProto captive_portal_fallback_url = 187;
+ optional SettingProto captive_portal_other_fallback_urls = 314;
optional SettingProto captive_portal_use_https = 188;
optional SettingProto captive_portal_user_agent = 189;
optional SettingProto nsd_on = 190;
@@ -243,21 +267,33 @@ message GlobalSettingsProto {
optional SettingProto global_http_proxy_pac = 200;
optional SettingProto set_global_http_proxy = 201;
optional SettingProto default_dns_server = 202;
+ // The requested Private DNS mode and an accompanying specifier.
+ optional SettingProto private_dns_mode = 315;
+ optional SettingProto private_dns_specifier = 316;
optional SettingProto bluetooth_headset_priority_prefix = 203;
optional SettingProto bluetooth_a2dp_sink_priority_prefix = 204;
optional SettingProto bluetooth_a2dp_src_priority_prefix = 205;
+ optional SettingProto bluetooth_a2dp_supports_optional_codecs_prefix = 287;
+ optional SettingProto bluetooth_a2dp_optional_codecs_enabled_prefix = 288;
optional SettingProto bluetooth_input_device_priority_prefix = 206;
optional SettingProto bluetooth_map_priority_prefix = 207;
optional SettingProto bluetooth_map_client_priority_prefix = 208;
optional SettingProto bluetooth_pbap_client_priority_prefix = 209;
optional SettingProto bluetooth_sap_priority_prefix = 210;
optional SettingProto bluetooth_pan_priority_prefix = 211;
+ optional SettingProto activity_manager_constants = 317;
optional SettingProto device_idle_constants = 212;
optional SettingProto device_idle_constants_watch = 213;
+ optional SettingProto battery_saver_constants = 318;
+ optional SettingProto anomaly_detection_constants = 319;
+ optional SettingProto always_on_display_constants = 320;
optional SettingProto app_idle_constants = 214;
+ optional SettingProto power_manager_constants = 321;
optional SettingProto alarm_manager_constants = 215;
optional SettingProto job_scheduler_constants = 216;
optional SettingProto shortcut_manager_constants = 217;
+ optional SettingProto device_policy_constants = 322;
+ optional SettingProto text_classifier_constants = 323;
optional SettingProto window_animation_scale = 218;
optional SettingProto transition_animation_scale = 219;
optional SettingProto animator_duration_scale = 220;
@@ -287,6 +323,10 @@ message GlobalSettingsProto {
optional SettingProto cert_pin_update_metadata_url = 244;
optional SettingProto intent_firewall_update_content_url = 245;
optional SettingProto intent_firewall_update_metadata_url = 246;
+ optional SettingProto lang_id_update_content_url = 324;
+ optional SettingProto lang_id_update_metadata_url = 325;
+ optional SettingProto smart_selection_update_content_url = 326;
+ optional SettingProto smart_selection_update_metadata_url = 327;
optional SettingProto selinux_status = 247;
optional SettingProto development_force_rtl = 248;
optional SettingProto low_battery_sound_timeout = 249;
@@ -308,13 +348,24 @@ message GlobalSettingsProto {
optional SettingProto lte_service_forced = 265;
optional SettingProto ephemeral_cookie_max_size_bytes = 266;
optional SettingProto enable_ephemeral_feature = 267;
+ optional SettingProto instant_app_dexopt_enabled = 328;
optional SettingProto installed_instant_app_min_cache_period = 268;
+ optional SettingProto installed_instant_app_max_cache_period = 289;
+ optional SettingProto uninstalled_instant_app_min_cache_period = 290;
+ optional SettingProto uninstalled_instant_app_max_cache_period = 291;
+ optional SettingProto unused_static_shared_lib_min_cache_period = 292;
optional SettingProto allow_user_switching_when_system_user_locked = 269;
optional SettingProto boot_count = 270;
optional SettingProto safe_boot_disallowed = 271;
optional SettingProto device_demo_mode = 272;
+ optional SettingProto network_access_timeout_ms = 329;
optional SettingProto database_downgrade_reason = 274;
+ 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;
+ optional SettingProto euicc_factory_reset_timeout_millis = 333;
+ optional SettingProto storage_settings_clobber_threshold = 334;
optional SettingProto multi_sim_voice_call_subscription = 276;
optional SettingProto multi_sim_voice_prompt = 277;
optional SettingProto multi_sim_data_call_subscription = 278;
@@ -324,19 +375,20 @@ message GlobalSettingsProto {
optional SettingProto contact_metadata_sync_enabled = 282;
optional SettingProto enable_cellular_on_boot = 283;
optional SettingProto max_notification_enqueue_rate = 284;
+ optional SettingProto show_notification_channel_warnings = 335;
optional SettingProto cell_on = 285;
- optional SettingProto network_recommendations_package = 286;
- optional SettingProto bluetooth_a2dp_supports_optional_codecs_prefix = 287;
- optional SettingProto bluetooth_a2dp_optional_codecs_enabled_prefix = 288;
- optional SettingProto installed_instant_app_max_cache_period = 289;
- optional SettingProto uninstalled_instant_app_min_cache_period = 290;
- optional SettingProto uninstalled_instant_app_max_cache_period = 291;
- optional SettingProto unused_static_shared_lib_min_cache_period = 292;
+ optional SettingProto show_temperature_warning = 336;
+ optional SettingProto warning_temperature = 337;
+ optional SettingProto enable_diskstats_logging = 338;
+ optional SettingProto enable_cache_quota_calculation = 339;
+ optional SettingProto enable_deletion_helper_no_threshold_toggle = 340;
+ optional SettingProto notification_snooze_options = 341;
+
+ // Next tag = 342;
}
message SecureSettingsProto {
- // Historical operations
- repeated SettingsOperationProto historical_op = 1;
+ repeated SettingsOperationProto historical_operations = 1;
optional SettingProto android_id = 2;
optional SettingProto default_input_method = 3;
@@ -347,6 +399,10 @@ message SecureSettingsProto {
optional SettingProto autofill_service = 8;
optional SettingProto bluetooth_hci_log = 9;
optional SettingProto user_setup_complete = 10;
+ // Whether the current user has been set up via setup wizard (0 = false,
+ // 1 = true). This value differs from USER_SETUP_COMPLETE in that it can be
+ // reset back to 0 in case SetupWizard has been re-enabled on TV devices.
+ optional SettingProto tv_user_setup_complete = 170;
optional SettingProto completed_category_prefix = 11;
optional SettingProto enabled_input_methods = 12;
optional SettingProto disabled_system_input_methods = 13;
@@ -354,10 +410,12 @@ message SecureSettingsProto {
optional SettingProto always_on_vpn_app = 15;
optional SettingProto always_on_vpn_lockdown = 16;
optional SettingProto install_non_market_apps = 17;
+ optional SettingProto unknown_sources_default_reversed = 171;
optional SettingProto location_mode = 18;
optional SettingProto location_previous_mode = 19;
optional SettingProto lock_to_app_exit_locked = 20;
optional SettingProto lock_screen_lock_after_timeout = 21;
+ optional SettingProto lock_screen_allow_private_notifications = 172;
optional SettingProto lock_screen_allow_remote_input = 22;
optional SettingProto show_note_about_notification_hiding = 23;
optional SettingProto trust_agents_initialized = 24;
@@ -366,6 +424,11 @@ message SecureSettingsProto {
optional SettingProto parental_control_redirect_url = 27;
optional SettingProto settings_classname = 28;
optional SettingProto accessibility_enabled = 29;
+ optional SettingProto accessibility_shortcut_enabled = 173;
+ optional SettingProto accessibility_shortcut_on_lock_screen = 174;
+ optional SettingProto accessibility_shortcut_dialog_shown = 175;
+ optional SettingProto accessibility_shortcut_target_service = 176;
+ optional SettingProto accessibility_button_target_component = 177;
optional SettingProto touch_exploration_enabled = 30;
optional SettingProto enabled_accessibility_services = 31;
optional SettingProto touch_exploration_granted_accessibility_services = 32;
@@ -375,7 +438,9 @@ message SecureSettingsProto {
optional SettingProto accessibility_screen_reader_url = 36;
optional SettingProto accessibility_web_content_key_bindings = 37;
optional SettingProto accessibility_display_magnification_enabled = 38;
+ optional SettingProto accessibility_display_magnification_navbar_enabled = 178;
optional SettingProto accessibility_display_magnification_scale = 39;
+ optional SettingProto accessibility_display_magnification_auto_update = 179;
optional SettingProto accessibility_soft_keyboard_mode = 40;
optional SettingProto accessibility_captioning_enabled = 41;
optional SettingProto accessibility_captioning_locale = 42;
@@ -448,6 +513,7 @@ message SecureSettingsProto {
optional SettingProto doze_enabled = 109;
optional SettingProto doze_always_on = 110;
optional SettingProto doze_pulse_on_pick_up = 111;
+ optional SettingProto doze_pulse_on_long_press = 180;
optional SettingProto doze_pulse_on_double_tap = 112;
optional SettingProto ui_night_mode = 113;
optional SettingProto screensaver_enabled = 114;
@@ -470,6 +536,7 @@ message SecureSettingsProto {
optional SettingProto immersive_mode_confirmations = 131;
optional SettingProto print_service_search_uri = 132;
optional SettingProto payment_service_search_uri = 133;
+ optional SettingProto autofill_service_search_uri = 181;
optional SettingProto skip_first_use_hints = 134;
optional SettingProto unsafe_volume_music_active_ms = 135;
optional SettingProto lock_screen_show_notifications = 136;
@@ -482,10 +549,18 @@ message SecureSettingsProto {
optional SettingProto camera_gesture_disabled = 143;
optional SettingProto camera_double_tap_power_gesture_disabled = 144;
optional SettingProto camera_double_twist_to_flip_enabled = 145;
+ optional SettingProto camera_lift_trigger_enabled = 182;
+ optional SettingProto assist_gesture_enabled = 183;
+ optional SettingProto assist_gesture_sensitivity = 184;
+ optional SettingProto assist_gesture_silence_alerts_enabled = 185;
+ optional SettingProto assist_gesture_wake_enabled = 186;
+ optional SettingProto assist_gesture_setup_complete = 187;
optional SettingProto night_display_activated = 146;
optional SettingProto night_display_auto_mode = 147;
+ optional SettingProto night_display_color_temperature = 188;
optional SettingProto night_display_custom_start_time = 148;
optional SettingProto night_display_custom_end_time = 149;
+ optional SettingProto night_display_last_activated_time = 189;
optional SettingProto brightness_use_twilight = 150;
optional SettingProto enabled_vr_listeners = 151;
optional SettingProto vr_display_mode = 152;
@@ -495,6 +570,7 @@ message SecureSettingsProto {
optional SettingProto automatic_storage_manager_days_to_retain = 156;
optional SettingProto automatic_storage_manager_bytes_cleared = 157;
optional SettingProto automatic_storage_manager_last_run = 158;
+ optional SettingProto automatic_storage_manager_turned_off_by_policy = 190;
optional SettingProto system_navigation_keys_enabled = 159;
optional SettingProto downloads_backup_enabled = 160;
optional SettingProto downloads_backup_allow_metered = 161;
@@ -504,13 +580,18 @@ message SecureSettingsProto {
optional SettingProto demo_user_setup_complete = 165;
optional SettingProto instant_apps_enabled = 166;
optional SettingProto device_paired = 167;
+ optional SettingProto package_verifier_state = 191;
+ optional SettingProto cmas_additional_broadcast_pkg = 192;
optional SettingProto notification_badging = 168;
+ optional SettingProto qs_auto_added_tiles = 193;
+ optional SettingProto lockdown_in_power_menu = 194;
optional SettingProto backup_manager_constants = 169;
+
+ // Next tag = 195
}
message SystemSettingsProto {
- // Historical operations
- repeated SettingsOperationProto historical_op = 1;
+ repeated SettingsOperationProto historical_operations = 1;
optional SettingProto end_button_behavior = 2;
optional SettingProto advanced_settings = 3;
@@ -518,6 +599,7 @@ message SystemSettingsProto {
optional SettingProto bluetooth_discoverability_timeout = 5;
optional SettingProto font_scale = 6;
optional SettingProto system_locales = 7;
+ optional SettingProto display_color_mode = 67;
optional SettingProto screen_off_timeout = 8;
optional SettingProto screen_brightness = 9;
optional SettingProto screen_brightness_for_vr = 10;
@@ -534,8 +616,17 @@ message SystemSettingsProto {
optional SettingProto volume_alarm = 21;
optional SettingProto volume_notification = 22;
optional SettingProto volume_bluetooth_sco = 23;
+ optional SettingProto volume_accessibility = 68;
optional SettingProto volume_master = 24;
optional SettingProto master_mono = 25;
+ // Whether silent mode should allow vibration feedback. This is used
+ // internally in AudioService and the Sound settings activity to coordinate
+ // decoupling of vibrate and silent modes. This setting will likely be
+ // removed in a future release with support for audio/vibe feedback
+ // profiles.
+ // Not used anymore. On devices with vibrator, the user explicitly selects
+ // silent or vibrate mode. Kept for use by legacy database upgrade code in
+ // DatabaseHelper.
optional SettingProto vibrate_in_silent = 26;
optional SettingProto append_for_last_audible = 27;
optional SettingProto ringtone = 28;
@@ -566,6 +657,10 @@ message SystemSettingsProto {
optional SettingProto notification_light_pulse = 53;
optional SettingProto pointer_location = 54;
optional SettingProto show_touches = 55;
+ // Log raw orientation data from {@link
+ // com.android.server.policy.WindowOrientationListener} for use with the
+ // orientationplot.py tool.
+ // 0 = no, 1 = yes
optional SettingProto window_orientation_listener_log = 56;
optional SettingProto lockscreen_sounds_enabled = 57;
optional SettingProto lockscreen_disabled = 58;
@@ -576,7 +671,10 @@ message SystemSettingsProto {
optional SettingProto pointer_speed = 63;
optional SettingProto lock_to_app_enabled = 64;
optional SettingProto egg_mode = 65;
+ optional SettingProto show_battery_percent = 69;
optional SettingProto when_to_make_wifi_calls = 66;
+
+ // Next tag = 70;
}
message SettingProto {
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index d442acfd91be..d3b2cde01397 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -145,7 +145,7 @@ message PowerManagerServiceDumpProto {
optional bool is_holding_display_suspend_blocker = 39;
// Settings and configuration
optional PowerServiceSettingsAndConfigurationDumpProto settings_and_configuration = 40;
- // Sleep timeout in ms
+ // Sleep timeout in ms. This can be -1.
optional sint32 sleep_timeout_ms = 41;
// Screen off timeout in ms
optional int32 screen_off_timeout_ms = 42;
@@ -263,7 +263,7 @@ message PowerServiceSettingsAndConfigurationDumpProto {
optional float maximum_screen_dim_ratio_config = 24;
// The screen off timeout setting value in milliseconds.
optional int32 screen_off_timeout_setting_ms = 25;
- // The sleep timeout setting value in milliseconds.
+ // The sleep timeout setting value in milliseconds. Default value is -1.
optional sint32 sleep_timeout_setting_ms = 26;
// The maximum allowable screen off timeout according to the device administration policy.
optional int32 maximum_screen_off_timeout_from_device_admin_ms = 27;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 4d48a4299281..0228edb03a83 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -48,7 +48,6 @@ message RootWindowContainerProto {
/* represents PhoneWindowManager */
message WindowManagerPolicyProto {
- optional .android.graphics.RectProto stable_bounds = 1;
}
/* represents AppTransition */
@@ -101,8 +100,13 @@ message DisplayProto {
optional .android.view.DisplayInfoProto display_info = 10;
optional int32 rotation = 11;
optional ScreenRotationAnimationProto screen_rotation_animation = 12;
+ optional DisplayFramesProto display_frames = 13;
}
+/* represents DisplayFrames */
+message DisplayFramesProto {
+ optional .android.graphics.RectProto stable_bounds = 1;
+}
/* represents DockedStackDividerController */
message DockedStackDividerControllerProto {
diff --git a/core/res/Android.mk b/core/res/Android.mk
index b0669294dd9d..370a01ff3b93 100644
--- a/core/res/Android.mk
+++ b/core/res/Android.mk
@@ -29,6 +29,9 @@ 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)
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 77bfec345b1f..86103e4c8902 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -307,6 +307,8 @@
<protected-broadcast android:name="android.intent.action.DREAMING_STOPPED" />
<protected-broadcast android:name="android.intent.action.ANY_DATA_STATE" />
+ <protected-broadcast android:name="com.android.server.stats.action.TRIGGER_COLLECTION" />
+
<protected-broadcast android:name="com.android.server.WifiManager.action.START_SCAN" />
<protected-broadcast android:name="com.android.server.WifiManager.action.START_PNO" />
<protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" />
@@ -2776,8 +2778,9 @@
android:protectionLevel="signature|appop" />
<!-- Allows an application to request deleting packages. Apps
- targeting APIs greater than 25 must hold this permission in
- order to use {@link android.content.Intent#ACTION_UNINSTALL_PACKAGE}.
+ targeting APIs {@link android.os.Build.VERSION_CODES#P} or greater must hold this
+ permission in order to use {@link android.content.Intent#ACTION_UNINSTALL_PACKAGE} or
+ {@link android.content.pm.PackageInstaller#uninstall}.
<p>Protection level: normal
-->
<permission android:name="android.permission.REQUEST_DELETE_PACKAGES"
@@ -2907,6 +2910,13 @@
<permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_MODE"
android:protectionLevel="signature" />
+ <!-- Allows an application to collect usage infomation about brightness slider changes.
+ <p>Not for use by third-party applications.</p>
+ TODO: make a System API
+ @hide -->
+ <permission android:name="android.permission.BRIGHTNESS_SLIDER_USAGE"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows an application to control VPN.
<p>Not for use by third-party applications.</p>
@hide -->
@@ -3062,10 +3072,10 @@
android:protectionLevel="signature|privileged|development|appop" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
- <!-- @hide Allows an application to change the app idle state of an app.
+ <!-- @hide @SystemApi Allows an application to change the app idle state of an app.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.CHANGE_APP_IDLE_STATE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|privileged" />
<!-- @hide @SystemApi Allows an application to temporarily whitelist an inactive app to
access the network and acquire wakelocks.
@@ -3657,7 +3667,7 @@
</activity-alias>
<activity-alias android:name="com.android.internal.app.ForwardIntentToManagedProfile"
android:targetActivity="com.android.internal.app.IntentForwarderActivity"
- android:icon="@drawable/ic_corp_icon"
+ android:icon="@drawable/ic_corp_badge"
android:exported="true"
android:label="@string/managed_profile_label">
</activity-alias>
@@ -3840,14 +3850,6 @@
</intent-filter>
</receiver>
- <receiver android:name="com.android.server.updates.TzDataInstallReceiver"
- android:permission="android.permission.UPDATE_CONFIG">
- <intent-filter>
- <action android:name="android.intent.action.UPDATE_TZDATA" />
- <data android:scheme="content" android:host="*" android:mimeType="*/*" />
- </intent-filter>
- </receiver>
-
<receiver android:name="com.android.server.updates.CertificateTransparencyLogInstallReceiver"
android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
@@ -3952,6 +3954,10 @@
<service android:name="com.android.server.timezone.TimeZoneUpdateIdler"
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
+
+ <service android:name="com.android.server.net.watchlist.ReportWatchlistJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
</application>
</manifest>
diff --git a/core/res/res/anim/slide_out_micro.xml b/core/res/res/anim/slide_out_micro.xml
index 01df0dae6259..c6470935e5d2 100644
--- a/core/res/res/anim/slide_out_micro.xml
+++ b/core/res/res/anim/slide_out_micro.xml
@@ -19,7 +19,7 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:zAdjustment="normal">
+ android:zAdjustment="top">
<translate android:fromYDelta="0" android:toYDelta="5%p"
android:duration="250"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
diff --git a/core/res/res/drawable-hdpi/ic_print.png b/core/res/res/drawable-hdpi/ic_print.png
deleted file mode 100644
index aaff3ddb0e46..000000000000
--- a/core/res/res/drawable-hdpi/ic_print.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_print_error.png b/core/res/res/drawable-hdpi/ic_print_error.png
deleted file mode 100644
index 7846a78b5a20..000000000000
--- a/core/res/res/drawable-hdpi/ic_print_error.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_print.png b/core/res/res/drawable-mdpi/ic_print.png
deleted file mode 100644
index a3954b544e00..000000000000
--- a/core/res/res/drawable-mdpi/ic_print.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_print_error.png b/core/res/res/drawable-mdpi/ic_print_error.png
deleted file mode 100644
index 44109eb152cf..000000000000
--- a/core/res/res/drawable-mdpi/ic_print_error.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_print.png b/core/res/res/drawable-xhdpi/ic_print.png
deleted file mode 100644
index 6b55a14d142f..000000000000
--- a/core/res/res/drawable-xhdpi/ic_print.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_print_error.png b/core/res/res/drawable-xhdpi/ic_print_error.png
deleted file mode 100644
index c3faa4220be2..000000000000
--- a/core/res/res/drawable-xhdpi/ic_print_error.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/ic_print.xml b/core/res/res/drawable/ic_print.xml
new file mode 100644
index 000000000000..7aa251300448
--- /dev/null
+++ b/core/res/res/drawable/ic_print.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M19,8L5,8c-1.66,0 -3,1.34 -3,3v6h4v4h12v-4h4v-6c0,-1.66 -1.34,-3 -3,-3zM16,19L8,19v-5h8v5zM19,12c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM18,3L6,3v4h12L18,3z"
+ android:fillColor="#FFFFFF"/>
+</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_print_error.xml b/core/res/res/drawable/ic_print_error.xml
new file mode 100644
index 000000000000..37e51527e399
--- /dev/null
+++ b/core/res/res/drawable/ic_print_error.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M15.73,3L8.27,3L3,8.27v7.46L8.27,21h7.46L21,15.73L21,8.27L15.73,3zM12,17.3c-0.72,0 -1.3,-0.58 -1.3,-1.3 0,-0.72 0.58,-1.3 1.3,-1.3 0.72,0 1.3,0.58 1.3,1.3 0,0.72 -0.58,1.3 -1.3,1.3zM13,13h-2L11,7h2v6z"
+ android:fillColor="#FFFFFF"/>
+</vector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_reply_notification_large.xml b/core/res/res/drawable/ic_reply_notification_large.xml
new file mode 100644
index 000000000000..e75afddfead3
--- /dev/null
+++ b/core/res/res/drawable/ic_reply_notification_large.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:inset="8dp">
+ <vector android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M10.0,9.0L10.0,5.0l-7.0,7.0 7.0,7.0l0.0,-4.1c5.0,0.0 8.5,1.6 11.0,5.1 -1.0,-5.0 -4.0,-10.0 -11.0,-11.0z"/>
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0 0h24v24H0z"/>
+ </vector>
+</inset>
diff --git a/core/res/res/drawable/messaging_message_background.xml b/core/res/res/drawable/messaging_message_background.xml
new file mode 100644
index 000000000000..8a2096a62473
--- /dev/null
+++ b/core/res/res/drawable/messaging_message_background.xml
@@ -0,0 +1,26 @@
+<?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
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle"
+ android:tint="#14000000">
+ <corners android:radius="4dp" />
+ <padding android:bottom="6dp"
+ android:left="8dp"
+ android:right="8dp"
+ android:top="6dp" />
+</shape>
diff --git a/core/res/res/layout/chooser_row.xml b/core/res/res/layout/chooser_row.xml
index 6c1271d6d72b..cf812603fb89 100644
--- a/core/res/res/layout/chooser_row.xml
+++ b/core/res/res/layout/chooser_row.xml
@@ -22,8 +22,7 @@
android:layout_height="100dp"
android:gravity="start|top"
android:paddingStart="@dimen/chooser_grid_padding"
- android:paddingEnd="@dimen/chooser_grid_padding"
- android:weightSum="4">
+ android:paddingEnd="@dimen/chooser_grid_padding">
</LinearLayout>
diff --git a/core/res/res/layout/notification_material_action.xml b/core/res/res/layout/notification_material_action.xml
index 548ee0561698..3c9f6eecc7d6 100644
--- a/core/res/res/layout/notification_material_action.xml
+++ b/core/res/res/layout/notification_material_action.xml
@@ -25,6 +25,7 @@
android:layout_marginStart="4dp"
android:textColor="@color/notification_default_color"
android:singleLine="true"
+ android:textAlignment="viewStart"
android:ellipsize="end"
android:background="@drawable/notification_material_action_background"
/>
diff --git a/core/res/res/layout/notification_material_action_tombstone.xml b/core/res/res/layout/notification_material_action_tombstone.xml
index 1f59ea02025b..817f298f0c6f 100644
--- a/core/res/res/layout/notification_material_action_tombstone.xml
+++ b/core/res/res/layout/notification_material_action_tombstone.xml
@@ -26,6 +26,7 @@
android:textColor="#555555"
android:singleLine="true"
android:ellipsize="end"
+ android:textAlignment="viewStart"
android:alpha="0.5"
android:enabled="false"
android:background="@drawable/notification_material_action_background"
diff --git a/core/res/res/layout/notification_template_material_messaging.xml b/core/res/res/layout/notification_template_material_messaging.xml
index fd5154af3b0c..f72230be0833 100644
--- a/core/res/res/layout/notification_template_material_messaging.xml
+++ b/core/res/res/layout/notification_template_material_messaging.xml
@@ -14,13 +14,17 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.internal.widget.MessagingLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/status_bar_latest_event_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:tag="messaging"
>
- <include layout="@layout/notification_template_header" />
+ <include layout="@layout/notification_template_header"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/notification_header_height"
+ android:layout_marginEnd="56dp"/>
<LinearLayout
android:id="@+id/notification_action_list_margin_target"
android:layout_width="match_parent"
@@ -39,7 +43,6 @@
android:paddingEnd="@dimen/notification_content_margin_end"
android:minHeight="@dimen/notification_min_content_height"
android:layout_marginBottom="@dimen/notification_content_margin_bottom"
- android:clipToPadding="false"
android:orientation="vertical"
>
<include layout="@layout/notification_template_part_line1"
@@ -50,31 +53,14 @@
android:id="@+id/notification_messaging"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:spacing="@dimen/notification_messaging_spacing" >
- <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text0"
- style="@style/Widget.Material.Notification.MessagingText"
- />
- <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text1"
- style="@style/Widget.Material.Notification.MessagingText"
- />
- <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text2"
- style="@style/Widget.Material.Notification.MessagingText"
- />
- <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text3"
- style="@style/Widget.Material.Notification.MessagingText"
- />
- <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text4"
- style="@style/Widget.Material.Notification.MessagingText"
- />
- <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text5"
- style="@style/Widget.Material.Notification.MessagingText"
- />
- <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text6"
- style="@style/Widget.Material.Notification.MessagingText"
- />
- </com.android.internal.widget.MessagingLinearLayout>
+ android:layout_marginTop="8dp"
+ android:spacing="@dimen/notification_messaging_spacing" />
</LinearLayout>
</LinearLayout>
<include layout="@layout/notification_material_action_list" />
- <include layout="@layout/notification_template_right_icon" />
-</FrameLayout>
+ <include layout="@layout/notification_template_right_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="18dp"
+ android:layout_gravity="top|end"/>
+</com.android.internal.widget.MessagingLayout>
diff --git a/core/res/res/layout/notification_template_messaging_group.xml b/core/res/res/layout/notification_template_messaging_group.xml
new file mode 100644
index 000000000000..8973ceb5c3a1
--- /dev/null
+++ b/core/res/res/layout/notification_template_messaging_group.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+<com.android.internal.widget.MessagingGroup
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <ImageView
+ android:id="@+id/message_icon"
+ android:layout_width="@dimen/messaging_avatar_size"
+ android:layout_height="@dimen/messaging_avatar_size"
+ android:layout_marginEnd="8dp"
+ android:scaleType="centerCrop"
+ android:importantForAccessibility="no" />
+ <com.android.internal.widget.RemeasuringLinearLayout
+ android:id="@+id/message_group_and_sender_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <com.android.internal.widget.MessagingLinearLayout
+ android:id="@+id/group_message_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:spacing="2dp"
+ android:layout_weight="1"/>
+ <com.android.internal.widget.ImageFloatingTextView
+ android:id="@+id/message_name"
+ style="@style/Widget.Material.Notification.MessagingName"
+ android:layout_width="wrap_content"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:paddingTop="2dp"
+ />
+ </com.android.internal.widget.RemeasuringLinearLayout>
+</com.android.internal.widget.MessagingGroup>
diff --git a/core/res/res/layout/notification_template_messaging_message.xml b/core/res/res/layout/notification_template_messaging_message.xml
new file mode 100644
index 000000000000..ab6466cc7b3c
--- /dev/null
+++ b/core/res/res/layout/notification_template_messaging_message.xml
@@ -0,0 +1,21 @@
+<?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
+ -->
+<com.android.internal.widget.MessagingMessage
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/message_text"
+ style="@style/Widget.Material.Notification.MessagingText"
+/>
diff --git a/core/res/res/layout/notification_template_right_icon.xml b/core/res/res/layout/notification_template_right_icon.xml
index d379256f7753..8fb28877a81f 100644
--- a/core/res/res/layout/notification_template_right_icon.xml
+++ b/core/res/res/layout/notification_template_right_icon.xml
@@ -19,12 +19,12 @@
android:id="@+id/right_icon_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginTop="36dp"
android:layout_gravity="top|end">
<ImageView android:id="@+id/right_icon"
android:layout_width="@dimen/notification_right_icon_size"
android:layout_height="@dimen/notification_right_icon_size"
android:layout_gravity="top|end"
- android:layout_marginTop="36dp"
android:layout_marginEnd="@dimen/notification_content_margin_end"
android:scaleType="centerCrop"
android:importantForAccessibility="no" />
@@ -32,7 +32,7 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_gravity="top|end"
- android:layout_marginTop="64dp"
+ android:layout_marginTop="28dp"
android:layout_marginEnd="12dp"
android:background="@drawable/notification_reply_background"
android:src="@drawable/ic_reply_notification"
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 039b6ebfa41f..10ead459a239 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1676,7 +1676,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>
@@ -1852,14 +1851,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 8e1b5b421356..4ad3afbc8ac5 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1745,7 +1745,7 @@
<string name="app_category_image" msgid="4867854544519846048">"ফটো ও ছবিগুলি"</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_maps" msgid="5878491404538024367">"ম্যাপ ও নেভিগেশান"</string>
<string name="app_category_productivity" msgid="3742083261781538852">"উৎপাদনশীলতা"</string>
<string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"ডিভাইসের স্টোরেজ"</string>
<string name="adb_debugging_notification_channel_tv" msgid="5537766997350092316">"USB ডিবাগিং"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index bb793a57de9c..4e9ab0a0309f 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -838,8 +838,8 @@
<string name="permdesc_setAlarm" msgid="316392039157473848">"Permet que l\'aplicació defineixi una alarma en una aplicació de despertador instal·lada. És possible que algunes aplicacions de despertador no incorporin aquesta funció."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"afegeix bústia de veu"</string>
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"Permet que l\'aplicació afegeixi missatges a la safata d\'entrada de la bústia de veu."</string>
- <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Modifica els permisos d\'ubicació geogràfica del navegador"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permet que l\'aplicació modifiqui els permisos d\'ubicació geogràfica del navegador. Les aplicacions malicioses poden utilitzar-ho per enviar la informació d\'ubicació a llocs web arbitraris."</string>
+ <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Modifica els permisos d\'ubicació del navegador"</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permet que l\'aplicació modifiqui els permisos d\'ubicació del navegador. Les aplicacions malicioses poden utilitzar-ho per enviar la informació d\'ubicació a llocs web arbitraris."</string>
<string name="save_password_message" msgid="767344687139195790">"Voleu que el navegador recordi aquesta contrasenya?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ara no"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Recorda-ho"</string>
@@ -1203,7 +1203,7 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTEIX"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REBUTJA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Canvia el teclat"</string>
- <string name="show_ime" msgid="2506087537466597099">"Mantén-lo a la pantalla mentre el teclat físic està actiu"</string>
+ <string name="show_ime" msgid="2506087537466597099">"Mantén-lo en pantalla mentre el teclat físic està actiu"</string>
<string name="hardware" msgid="194658061510127999">"Mostra el teclat virtual"</string>
<string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura el teclat físic"</string>
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca per seleccionar l\'idioma i el disseny"</string>
@@ -1289,7 +1289,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fons de pantalla"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Canvia el fons de pantalla"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Oient de notificacions"</string>
- <string name="vr_listener_binding_label" msgid="4316591939343607306">"Processador d\'RV"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Processador de RV"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Proveïdor de condicions"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"Servei de classificació de notificacions"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 07450b2e1b61..e185683f2917 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -979,16 +979,11 @@
<string name="inputMethod" msgid="1653630062304567879">"Input method"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Text actions"</string>
<string name="email" msgid="4560673117055050403">"Email"</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">"Call"</string>
+ <string name="map" msgid="6521159124535543457">"Locate"</string>
+ <string name="browse" msgid="1245903488306147205">"Open"</string>
+ <string name="sms" msgid="4560537514610063430">"Message"</string>
+ <string name="add_contact" msgid="7867066569670597203">"Add"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -998,7 +993,6 @@
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancel"</string>
- <string name="close" msgid="2318214661230355730">"CLOSE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Loading…"</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1055,8 +1049,6 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scale"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Always show"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings &gt; Apps &gt; Downloaded."</string>
- <string name="top_app_killed_title" msgid="6814231368167994497">"App isn\'t responding"</string>
- <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> may be using too much memory."</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="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>
@@ -1634,7 +1626,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2nd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3rd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"To unpin this screen, touch &amp; hold Back and Overview buttons"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"This app can\'t be unpinned"</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">"Ask for PIN before unpinning"</string>
@@ -1790,18 +1781,14 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Emergency messages test"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Reply"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM not allowed"</string>
- <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM not provisioned"</string>
- <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM not allowed"</string>
- <string name="mmcc_illegal_me" msgid="4438696681169345015">"Phone not allowed"</string>
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM not allowed for voice"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM not provisioned for voice"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM not allowed for voice"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Phone not allowed for voice"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Pop-Up Window"</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">"This shortcut requires latest app"</string>
+ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Couldn’t restore shortcut because app doesn’t support backup and restore"</string>
+ <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Couldn’t restore shortcut because of app signature mismatch"</string>
+ <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Couldn’t restore shortcut"</string>
</resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 07450b2e1b61..e185683f2917 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -979,16 +979,11 @@
<string name="inputMethod" msgid="1653630062304567879">"Input method"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Text actions"</string>
<string name="email" msgid="4560673117055050403">"Email"</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">"Call"</string>
+ <string name="map" msgid="6521159124535543457">"Locate"</string>
+ <string name="browse" msgid="1245903488306147205">"Open"</string>
+ <string name="sms" msgid="4560537514610063430">"Message"</string>
+ <string name="add_contact" msgid="7867066569670597203">"Add"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -998,7 +993,6 @@
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancel"</string>
- <string name="close" msgid="2318214661230355730">"CLOSE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Loading…"</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1055,8 +1049,6 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scale"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Always show"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings &gt; Apps &gt; Downloaded."</string>
- <string name="top_app_killed_title" msgid="6814231368167994497">"App isn\'t responding"</string>
- <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> may be using too much memory."</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="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>
@@ -1634,7 +1626,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2nd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3rd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"To unpin this screen, touch &amp; hold Back and Overview buttons"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"This app can\'t be unpinned"</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">"Ask for PIN before unpinning"</string>
@@ -1790,18 +1781,14 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Emergency messages test"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Reply"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM not allowed"</string>
- <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM not provisioned"</string>
- <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM not allowed"</string>
- <string name="mmcc_illegal_me" msgid="4438696681169345015">"Phone not allowed"</string>
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM not allowed for voice"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM not provisioned for voice"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM not allowed for voice"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Phone not allowed for voice"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Pop-Up Window"</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">"This shortcut requires latest app"</string>
+ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Couldn’t restore shortcut because app doesn’t support backup and restore"</string>
+ <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Couldn’t restore shortcut because of app signature mismatch"</string>
+ <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Couldn’t restore shortcut"</string>
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 07450b2e1b61..e185683f2917 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -979,16 +979,11 @@
<string name="inputMethod" msgid="1653630062304567879">"Input method"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Text actions"</string>
<string name="email" msgid="4560673117055050403">"Email"</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">"Call"</string>
+ <string name="map" msgid="6521159124535543457">"Locate"</string>
+ <string name="browse" msgid="1245903488306147205">"Open"</string>
+ <string name="sms" msgid="4560537514610063430">"Message"</string>
+ <string name="add_contact" msgid="7867066569670597203">"Add"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -998,7 +993,6 @@
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancel"</string>
- <string name="close" msgid="2318214661230355730">"CLOSE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Loading…"</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1055,8 +1049,6 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scale"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Always show"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings &gt; Apps &gt; Downloaded."</string>
- <string name="top_app_killed_title" msgid="6814231368167994497">"App isn\'t responding"</string>
- <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> may be using too much memory."</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="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>
@@ -1634,7 +1626,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2nd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3rd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"To unpin this screen, touch &amp; hold Back and Overview buttons"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"This app can\'t be unpinned"</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">"Ask for PIN before unpinning"</string>
@@ -1790,18 +1781,14 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Emergency messages test"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Reply"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM not allowed"</string>
- <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM not provisioned"</string>
- <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM not allowed"</string>
- <string name="mmcc_illegal_me" msgid="4438696681169345015">"Phone not allowed"</string>
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM not allowed for voice"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM not provisioned for voice"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM not allowed for voice"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Phone not allowed for voice"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Pop-Up Window"</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">"This shortcut requires latest app"</string>
+ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Couldn’t restore shortcut because app doesn’t support backup and restore"</string>
+ <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Couldn’t restore shortcut because of app signature mismatch"</string>
+ <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Couldn’t restore shortcut"</string>
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 07450b2e1b61..e185683f2917 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -979,16 +979,11 @@
<string name="inputMethod" msgid="1653630062304567879">"Input method"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Text actions"</string>
<string name="email" msgid="4560673117055050403">"Email"</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">"Call"</string>
+ <string name="map" msgid="6521159124535543457">"Locate"</string>
+ <string name="browse" msgid="1245903488306147205">"Open"</string>
+ <string name="sms" msgid="4560537514610063430">"Message"</string>
+ <string name="add_contact" msgid="7867066569670597203">"Add"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Not enough storage for the system. Make sure that you have 250 MB of free space and restart."</string>
@@ -998,7 +993,6 @@
<string name="cancel" msgid="6442560571259935130">"Cancel"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Cancel"</string>
- <string name="close" msgid="2318214661230355730">"CLOSE"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attention"</string>
<string name="loading" msgid="7933681260296021180">"Loading…"</string>
<string name="capital_on" msgid="1544682755514494298">"ON"</string>
@@ -1055,8 +1049,6 @@
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scale"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Always show"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Re-enable this in System settings &gt; Apps &gt; Downloaded."</string>
- <string name="top_app_killed_title" msgid="6814231368167994497">"App isn\'t responding"</string>
- <string name="top_app_killed_message" msgid="3487519022191609844">"<xliff:g id="APP_NAME">%1$s</xliff:g> may be using too much memory."</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="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>
@@ -1634,7 +1626,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2nd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3rd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"To unpin this screen, touch &amp; hold Back and Overview buttons"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"This app can\'t be unpinned"</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">"Ask for PIN before unpinning"</string>
@@ -1790,18 +1781,14 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Emergency messages test"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Reply"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM not allowed"</string>
- <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM not provisioned"</string>
- <string name="mmcc_illegal_ms" msgid="2769452751852211112">"SIM not allowed"</string>
- <string name="mmcc_illegal_me" msgid="4438696681169345015">"Phone not allowed"</string>
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM not allowed for voice"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM not provisioned for voice"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM not allowed for voice"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Phone not allowed for voice"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Pop-Up Window"</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">"This shortcut requires latest app"</string>
+ <string name="shortcut_restore_not_supported" msgid="5028808567940014190">"Couldn’t restore shortcut because app doesn’t support backup and restore"</string>
+ <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"Couldn’t restore shortcut because of app signature mismatch"</string>
+ <string name="shortcut_restore_unknown_issue" msgid="8703738064603262597">"Couldn’t restore shortcut"</string>
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 9ec963b7c57b..878f9eb3347b 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -273,7 +273,7 @@
<string name="permgrouprequest_sms" msgid="605618939583628306">"Anna sovellukselle &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; lupa lähettää ja katsella tekstiviestejä."</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Tallennustila"</string>
<string name="permgroupdesc_storage" msgid="637758554581589203">"käyttää laitteellesi tallennettuja valokuvia, mediatiedostoja ja muita tiedostoja"</string>
- <string name="permgrouprequest_storage" msgid="7429669910547860218">"Anna &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; lupa käyttää laitteellasi olevia kuvia, mediaa ja tiedostoja."</string>
+ <string name="permgrouprequest_storage" msgid="7429669910547860218">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; tarvitsee sinulta luvan käyttää laitteellasi olevia kuvia, mediaa ja tiedostoja"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofoni"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"tallentaa ääntä"</string>
<string name="permgrouprequest_microphone" msgid="8065941268709600606">"Anna sovellukselle &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; lupa nauhoittaa ääntä."</string>
@@ -1626,7 +1626,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Toinen <xliff:g id="LABEL">%1$s</xliff:g>, työ"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Kolmas <xliff:g id="LABEL">%1$s</xliff:g>, työ"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Irrota näyttö koskettamalla pitkään Takaisin- ja Viimeisimmät-painikkeita"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Tätä sovellusta ei voi irrottaa"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Näyttö kiinnitetty"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Näyttö irrotettu"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pyydä PIN ennen irrotusta"</string>
@@ -1782,14 +1781,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Hätäilmoitustesti"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Vastaa"</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">"Äänipalvelujen käyttö ei sallittua SIM-kortilla"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM-kortti ei käyttäjien hallinnassa"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Äänipalvelujen käyttö ei sallittua SIM-kortilla"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Äänipalvelujen käyttö ei sallittua puhelimella"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Ponnahdusikkuna"</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">"Tämä pikakuvake edellyttää uusinta sovellusta."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 16283e71d1cb..05ab42d81569 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -217,7 +217,7 @@
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Rapport interactif"</string>
<string name="bugreport_option_interactive_summary" msgid="229299488536107968">"Utilisez cette option dans la plupart des circonstances. Elle vous permet de suivre la progression du rapport, d\'entrer plus d\'information sur le problème et d\'effectuer des saisies d\'écran. Certaines sections moins utilisées et dont le remplissage demande beaucoup de temps peuvent être omises."</string>
<string name="bugreport_option_full_title" msgid="6354382025840076439">"Rapport complet"</string>
- <string name="bugreport_option_full_summary" msgid="7210859858969115745">"Utilisez cette option pour qu\'il y ait le moins d\'interférences système possible lorsque votre appareil ne répond pas ou qu\'il est trop lent, ou lorsque vous avez besoin de toutes les sections du rapport de bogue. Aucune saisie d\'écran supplémentaire ne peut être capturée, et vous ne pouvez entrer aucune autre information."</string>
+ <string name="bugreport_option_full_summary" msgid="7210859858969115745">"Utilisez cette option pour qu\'il y ait le moins d\'interférences système possible lorsque votre appareil ne répond pas ou qu\'il est trop lent, ou lorsque vous avez besoin de toutes les sections du rapport de bogue. Aucune capture d\'écran supplémentaire ne peut être capturée, et vous ne pouvez entrer aucune autre information."</string>
<plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
<item quantity="one">Saisie d\'écran pour le rapport de bogue dans <xliff:g id="NUMBER_1">%d</xliff:g> seconde.</item>
<item quantity="other">Saisie d\'écran pour le rapport de bogue dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes.</item>
@@ -1626,7 +1626,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2e <xliff:g id="LABEL">%1$s</xliff:g> professionnel(le)"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3e <xliff:g id="LABEL">%1$s</xliff:g> professionnel(le)"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Pour annuler l\'épinglage de cet écran, maintenez enfoncés 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 NIP avant d\'annuler l\'épinglage"</string>
@@ -1782,14 +1781,10 @@
<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">"Cette carte SIM n\'est pas autorisée pour la voix"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"Cette carte SIM n\'est pas autorisée pour la voix"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Cette carte SIM n\'est pas autorisée pour la voix"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Ce téléphone n\'est pas autorisé pour la voix"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Fenêtre contextuelle"</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">"Ce raccourci nécessite la dernière version de l\'application"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index e3b93cb407d7..d0f100a0052b 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1626,7 +1626,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2.º <xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3.º <xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Para soltar a pantalla, mantén premidos os botóns Volver e Visión xeral."</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Esta aplicación non se pode soltar"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fixada"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Pantalla desactivada"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar un PIN antes de soltar a pantalla"</string>
@@ -1782,14 +1781,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Proba de mensaxes de urxencia"</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">"Non se permite a tarxeta SIM para as accións de voz"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"Non se introduciu ningunha tarxeta SIM para as accións de voz"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Non se permite a tarxeta SIM para as accións de voz"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Non se permite o teléfono para as accións de voz"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Ventá emerxente"</string>
<string name="slice_more_content" msgid="8504342889413274608">"<xliff:g id="NUMBER">%1$d</xliff:g> máis"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Para utilizar este atallo, necesítase a versión máis recente da aplicación"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index d1c37001d3e6..1e9b38c04ba8 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1626,7 +1626,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>
@@ -1782,14 +1781,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-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 11a882069908..f24ee7951568 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -525,7 +525,7 @@
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"नेटवर्क उपयोग हिसाब बदलें"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"ऐप्स को यह संशोधित करने देता है कि ऐप्स की तुलना में नेटवर्क उपयोग का मूल्यांकन कैसे किया जाता है. सामान्‍य ऐप्स द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_accessNotifications" msgid="7673416487873432268">"सूचना तक पहुंचें"</string>
- <string name="permdesc_accessNotifications" msgid="458457742683431387">"ऐप को सूचना पाने, जांच करने और साफ़ करने देता है, जिनमें अन्य ऐप के ज़रिए पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"ऐप को सूचना पाने, जाँच करने और साफ़ करने देता है, जिनमें अन्य ऐप के ज़रिए पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना श्रवणकर्ता सेवा से जुड़ें"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"उपयोगकर्ता को सूचना सुनने वाली सेवा के सबसे बेहतर इंटरफ़ेस से जुड़ने देती है. सामान्य ऐप के लिए कभी भी इसकी ज़रुरत नहीं होगी."</string>
<string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"किसी शर्तें लागू करने वाली (कंडीशन प्रोवाइडर) सेवा से जुड़ें"</string>
@@ -760,7 +760,7 @@
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"साइन इन करें"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"उपयोगकर्ता नाम या पासवर्ड गलत है."</string>
<string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"अपना उपयोगकर्ता नाम या पासवर्ड भूल गए?\n "<b>"google.com/accounts/recovery"</b>" पर जाएं."</string>
- <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"जांच रहा है…"</string>
+ <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"जाँच रहा है…"</string>
<string name="lockscreen_unlock_label" msgid="737440483220667054">"अनलॉक करें"</string>
<string name="lockscreen_sound_on_label" msgid="9068877576513425970">"ध्‍वनि चालू करें"</string>
<string name="lockscreen_sound_off_label" msgid="996822825154319026">"ध्वनि बंद"</string>
@@ -1215,7 +1215,7 @@
<string name="alert_windows_notification_message" msgid="8917232109522912560">"अगर आप नहीं चाहते कि <xliff:g id="NAME">%s</xliff:g> इस सुविधा का उपयोग करे, तो सेटिंग खोलने और उसे बंद करने के लिए टैप करें."</string>
<string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"बंद करें"</string>
<string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> को तैयार किया जा रहा है"</string>
- <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटियों की जांच कर रहा है"</string>
+ <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटियों की जाँच कर रहा है"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"नए <xliff:g id="NAME">%s</xliff:g> का पता लगा"</string>
<string name="ext_media_ready_notification_message" msgid="4083398150380114462">"फ़ोटो और मीडिया ट्रांसफर करने के लिए"</string>
<string name="ext_media_unmountable_notification_title" msgid="8295123366236989588">"दूषित <xliff:g id="NAME">%s</xliff:g>"</string>
@@ -1243,7 +1243,7 @@
<string name="ext_media_move_failure_message" msgid="1978096440816403360">"डेटा शुरुआती जगह पर छूट गया है"</string>
<string name="ext_media_status_removed" msgid="6576172423185918739">"निकाल दिया गया"</string>
<string name="ext_media_status_unmounted" msgid="2551560878416417752">"निकाला गया"</string>
- <string name="ext_media_status_checking" msgid="6193921557423194949">"जांच की जा रही है..."</string>
+ <string name="ext_media_status_checking" msgid="6193921557423194949">"जाँच की जा रही है..."</string>
<string name="ext_media_status_mounted" msgid="7253821726503179202">"तैयार"</string>
<string name="ext_media_status_mounted_ro" msgid="8020978752406021015">"केवल-पढ़ने के लिए"</string>
<string name="ext_media_status_bad_removal" msgid="8395398567890329422">"असुरक्षित रूप से निकाला गया"</string>
@@ -1475,7 +1475,7 @@
<string name="kg_login_submit_button" msgid="5355904582674054702">"साइन इन करें"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"उपयोगकर्ता नाम या पासवर्ड गलत है"</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"अपना उपयोगकर्ता नाम या पासवर्ड भूल गए?\n "<b>"google.com/accounts/recovery"</b>" पर जाएं."</string>
- <string name="kg_login_checking_password" msgid="1052685197710252395">"खाते की जांच की जा रही है…"</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"खाते की जाँच की जा रही है…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आप अपना PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आप अपना पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से आरेखित किया है. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
@@ -1789,6 +1789,6 @@
<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>
<string name="shortcut_restore_not_supported" msgid="5028808567940014190">"शॉर्टकट बहाल नहीं किया जा सका क्योंकि इस ऐप में बैकअप लेने और उसे बहाल करने की सुविधा नहीं है"</string>
- <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ऐप का हस्ताक्षर अलग होने के कारण शॉर्टकट बहाल नहीं किया जा सका"</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-in/strings.xml b/core/res/res/values-in/strings.xml
index 57312e7444e0..2389d4d829a8 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -146,7 +146,7 @@
<string name="httpErrorConnect" msgid="8714273236364640549">"Tidak dapat tersambung ke server."</string>
<string name="httpErrorIO" msgid="2340558197489302188">"Tidak dapat berkomunikasi dengan server. Coba lagi nanti."</string>
<string name="httpErrorTimeout" msgid="4743403703762883954">"Sambungan ke server terputus."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Laman ini berisi terlalu banyak pengalihan server."</string>
+ <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Halaman ini berisi terlalu banyak pengalihan server."</string>
<string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Protokol tidak didukung."</string>
<string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"Tidak dapat membuat sambungan aman."</string>
<string name="httpErrorBadUrl" msgid="3636929722728881972">"Tidak dapat membuka halaman karena URL tidak valid."</string>
@@ -295,7 +295,7 @@
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Mengontrol perbesaran layar"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Mengontrol tingkat zoom dan pemosisian layar."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Melakukan isyarat"</string>
- <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Dapat mengetuk, menggesek, mencubit, dan melakukan isyarat lainnya."</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Dapat mengetuk, menggeser, mencubit, dan melakukan isyarat lainnya."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestur sidik jari"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Dapat merekam gestur yang dilakukan di sensor sidik jari perangkat."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"nonaktifkan atau ubah bilah status"</string>
@@ -318,8 +318,8 @@
<string name="permdesc_receiveMms" msgid="533019437263212260">"Memungkinkan aplikasi menerima dan memproses pesan MMS. Ini artinya aplikasi dapat memantau atau menghapus pesan yang dikirim ke perangkat Anda tanpa menunjukkannya kepada Anda."</string>
<string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"membaca pesan siaran seluler"</string>
<string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Mengizinkan aplikasi membaca pesan siaran seluler yang diterima perangkat Anda. Notifikasi siaran seluler dikirimkan di beberapa lokasi untuk memperingatkan Anda tentang situasi darurat. Aplikasi berbahaya dapat mengganggu kinerja atau operasi perangkat Anda saat siaran seluler darurat diterima."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"baca umpan langganan"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Mengizinkan apl mendapatkan detail tentang umpan yang saat ini sedang disinkronkan."</string>
+ <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"baca feed langganan"</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Mengizinkan apl mendapatkan detail tentang feed yang saat ini sedang disinkronkan."</string>
<string name="permlab_sendSms" msgid="7544599214260982981">"mengirim dan melihat pesan SMS"</string>
<string name="permdesc_sendSms" msgid="7094729298204937667">"Memungkinkan aplikasi mengirim pesan SMS. Izin ini dapat mengakibatkan biaya tak terduga. Aplikasi berbahaya dapat membebankan biaya kepada Anda dengan mengirim pesan tanpa konfirmasi dari Anda."</string>
<string name="permlab_readSms" msgid="8745086572213270480">"membaca pesan teks (SMS atau MMS) Anda"</string>
@@ -802,11 +802,11 @@
<string name="factorytest_not_system" msgid="4435201656767276723">"Tindakan FACTORY_TEST hanya didukung untuk paket yang terpasang pada /system/app."</string>
<string name="factorytest_no_action" msgid="872991874799998561">"Tidak ada paket yang memberikan tindakan FACTORY_TEST."</string>
<string name="factorytest_reboot" msgid="6320168203050791643">"Mulai ulang"</string>
- <string name="js_dialog_title" msgid="1987483977834603872">"Laman pada \"<xliff:g id="TITLE">%s</xliff:g>\" menyatakan:"</string>
+ <string name="js_dialog_title" msgid="1987483977834603872">"Halaman pada \"<xliff:g id="TITLE">%s</xliff:g>\" menyatakan:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
<string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Konfirmasi Navigasi"</string>
- <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Keluar dari Laman ini"</string>
- <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Tetap di Laman ini"</string>
+ <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Keluar dari Halaman ini"</string>
+ <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Tetap di Halaman ini"</string>
<string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nYakin ingin beranjak dari halaman ini?"</string>
<string name="save_password_label" msgid="6860261758665825069">"Konfirmasi"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Kiat: Ketuk dua kali untuk memperbesar dan memperkecil."</string>
@@ -1042,7 +1042,7 @@
<string name="force_close" msgid="8346072094521265605">"Oke"</string>
<string name="report" msgid="4060218260984795706">"Laporkan"</string>
<string name="wait" msgid="7147118217226317732">"Tunggu"</string>
- <string name="webpage_unresponsive" msgid="3272758351138122503">"Laman ini tidak menanggapi.\n\nApakah Anda ingin menutupnya?"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Halaman ini tidak menanggapi.\n\nApakah Anda ingin menutupnya?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Apl dialihkan"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang berjalan."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> telah diluncurkan aslinya."</string>
@@ -1371,7 +1371,7 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Berbagi dengan"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Berbagi dengan <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Gagang geser. Sentuh &amp; tahan."</string>
- <string name="description_target_unlock_tablet" msgid="3833195335629795055">"Gesek untuk membuka kunci."</string>
+ <string name="description_target_unlock_tablet" msgid="3833195335629795055">"Geser untuk membuka kunci."</string>
<string name="action_bar_home_description" msgid="5293600496601490216">"Navigasi ke beranda"</string>
<string name="action_bar_up_description" msgid="2237496562952152589">"Navigasi naik"</string>
<string name="action_menu_overflow_description" msgid="2295659037509008453">"Opsi lainnya"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index f02a7bada1d3..609bef003d56 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1626,7 +1626,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>
@@ -1782,14 +1781,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-ml/strings.xml b/core/res/res/values-ml/strings.xml
index ae897b341b55..8fb570b22448 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1626,7 +1626,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>
@@ -1782,14 +1781,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-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 96a9eda75b29..af37300f379c 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -36,7 +36,7 @@
<string name="serviceDisabled" msgid="1937553226592516411">"सेवा अक्षम केली गेली आहे."</string>
<string name="serviceRegistered" msgid="6275019082598102493">"नोंदणी यशस्वी झाली."</string>
<string name="serviceErased" msgid="1288584695297200972">"मिटवणे यशस्वी झाले."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"अयोग्य संकेतशब्द."</string>
+ <string name="passwordIncorrect" msgid="7612208839450128715">"अयोग्य पासवर्ड."</string>
<string name="mmiComplete" msgid="8232527495411698359">"MMI पूर्ण."</string>
<string name="badPin" msgid="9015277645546710014">"आपण टाइप केलेला जुना पिन योग्य नाही."</string>
<string name="badPuk" msgid="5487257647081132201">"आपण टाइप केलेला PUK योग्य नाही."</string>
@@ -59,7 +59,7 @@
<string name="CfMmi" msgid="5123218989141573515">"कॉल फॉरवर्डिंग"</string>
<string name="CwMmi" msgid="9129678056795016867">"कॉल प्रतीक्षा"</string>
<string name="BaMmi" msgid="455193067926770581">"कॉल सोडून"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"संकेतशब्द बदल"</string>
+ <string name="PwdMmi" msgid="7043715687905254199">"पासवर्ड बदल"</string>
<string name="PinMmi" msgid="3113117780361190304">"पिन बदल"</string>
<string name="CnipMmi" msgid="3110534680557857162">"कॉल करण्‍याचा नंबर आहे"</string>
<string name="CnirMmi" msgid="3062102121430548731">"कॉल करणारे नंबर प्रतिबंधित"</string>
@@ -192,9 +192,9 @@
<string name="reboot_to_update_title" msgid="6212636802536823850">"Android सिस्टम अपडेट"</string>
<string name="reboot_to_update_prepare" msgid="6305853831955310890">"अपडेट करण्याची तयारी करत आहे…"</string>
<string name="reboot_to_update_package" msgid="3871302324500927291">"अपडेट पॅकेज प्रक्रिया करत आहे…"</string>
- <string name="reboot_to_update_reboot" msgid="6428441000951565185">"रीस्टार्ट करीत आहे..."</string>
+ <string name="reboot_to_update_reboot" msgid="6428441000951565185">"रीस्टार्ट करत आहे..."</string>
<string name="reboot_to_reset_title" msgid="4142355915340627490">"फॅक्‍टरी डेटा रीसेट"</string>
- <string name="reboot_to_reset_message" msgid="2432077491101416345">"रीस्टार्ट करीत आहे..."</string>
+ <string name="reboot_to_reset_message" msgid="2432077491101416345">"रीस्टार्ट करत आहे..."</string>
<string name="shutdown_progress" msgid="2281079257329981203">"बंद होत आहे…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"आपला टॅबलेट बंद होईल."</string>
<string name="shutdown_confirm" product="tv" msgid="476672373995075359">"आपला टीव्ही बंद होईल."</string>
@@ -215,7 +215,7 @@
<string name="bugreport_title" msgid="2667494803742548533">"बग रीपोर्ट घ्या"</string>
<string name="bugreport_message" msgid="398447048750350456">"ई-मेल संदेश म्हणून पाठविण्यासाठी, हे तुमच्या सद्य डिव्हाइस स्थितीविषयी माहिती संकलित करेल. बग रीपोर्ट सुरू करण्यापासून तो पाठविण्यापर्यंत थोडा वेळ लागेल; कृपया धीर धरा."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"परस्परसंवादी अहवाल"</string>
- <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"बहुतांश प्रसंगांमध्ये याचा वापर करा. ते आपल्याला अहवालाच्या प्रगतीचा मागोवा घेण्याची, समस्येविषयी आणखी तपाशील प्रविष्ट करण्याची आणि स्क्रीनशॉट घेण्याची अनुमती देते. ते कदाचित अहवाल देण्यासाठी बराच वेळ घेणारे कमी-वापरलेले विभाग वगळू शकते."</string>
+ <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"बहुतांश प्रसंगांमध्ये याचा वापर करा. ते आपल्याला अहवालाच्या प्रगतीचा मागोवा घेण्याची, समस्येविषयी आणखी तपाशील एंटर करण्याची आणि स्क्रीनशॉट घेण्याची अनुमती देते. ते कदाचित अहवाल देण्यासाठी बराच वेळ घेणारे कमी-वापरलेले विभाग वगळू शकते."</string>
<string name="bugreport_option_full_title" msgid="6354382025840076439">"संपूर्ण अहवाल"</string>
<string name="bugreport_option_full_summary" msgid="7210859858969115745">"तुमचे डिव्हाइस प्रतिसाद देत नाही किंवा खूप धीमे असते किंवा तुम्हाला सर्व अहवाल विभागांची आवश्यकता असते तेव्हा कमीतकमी सिस्टम हस्तक्षेपासाठी या पर्यायाचा वापर करा. तुम्हाला आणखी तपशील एंटर करण्याची किंवा अतिरिक्त स्क्रीनशॉट घेण्याची अनुमती देत नाही."</string>
<plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
@@ -461,13 +461,13 @@
<string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"WiMAX नेटवर्कवरून टीव्ही कनेक्ट करण्यासाठी आणि त्यावरून टीव्ही डिस्कनेक्ट करण्यासाठी अॅपला अनुमती देते."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"WiMAX नेटवर्कवर फोन कनेक्ट करण्यास आणि त्यावरून फोन डिस्कनेक्ट करण्यास अॅप ला अनुमती देते."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"ब्लूटूथ डीव्हाइससह जोडा"</string>
- <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"टॅबलेटवर ब्लूटूथ चे कॉंफिगरेशन पाहण्यासाठी आणि पेअर केलेल्या डीव्हाइससह कनेक्शन स्थापित करण्यासाठी आणि स्वीकारण्यासाठी, अॅप ला अनुमती देते."</string>
- <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"टीव्हीवर ब्लूटूथचे कॉंफिगरेशन पाहण्यासाठी आणि जोडलेल्या डीव्हाइससह कनेक्शन स्थापित करण्यासाठी आणि स्वीकारण्यासाठी अॅपला अनुमती देते."</string>
- <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"फोनवर ब्लूटूथ चे कॉंफिगरेशन पाहण्यासाठी आणि पेअर केलेल्या डीव्हाइससह कनेक्शन स्थापित करण्यासाठी आणि स्वीकारण्यासाठी, अॅप ला अनुमती देते."</string>
+ <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"टॅबलेटवर ब्लूटूथ चे कॉंफिगरेशन पाहण्यासाठी आणि पेअर केलेल्या डीव्हाइससह कनेक्शन इंस्टॉल करण्यासाठी आणि स्वीकारण्यासाठी, अॅप ला अनुमती देते."</string>
+ <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"टीव्हीवर ब्लूटूथचे कॉंफिगरेशन पाहण्यासाठी आणि जोडलेल्या डीव्हाइससह कनेक्शन इंस्टॉल करण्यासाठी आणि स्वीकारण्यासाठी अॅपला अनुमती देते."</string>
+ <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"फोनवर ब्लूटूथ चे कॉंफिगरेशन पाहण्यासाठी आणि पेअर केलेल्या डीव्हाइससह कनेक्शन इंस्टॉल करण्यासाठी आणि स्वीकारण्यासाठी, अॅप ला अनुमती देते."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"फील्ड जवळील कम्युनिकेशन नियंत्रित करा"</string>
<string name="permdesc_nfc" msgid="7120611819401789907">"फील्ड जवळील कम्युनिकेशन (NFC) टॅग, कार्डे आणि वाचक यांच्यासह संवाद करण्यासाठी अॅपला अनुमती देते."</string>
<string name="permlab_disableKeyguard" msgid="3598496301486439258">"आपले स्क्रीन लॉक अक्षम करा"</string>
- <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"कीलॉक आणि कोणतीही संबद्ध संकेतशब्द सुरक्षितता अक्षम करण्यासाठी अॅप ला अनुमती देते. उदाहरणार्थ, येणारा फोन कॉल प्राप्त करताना फोन कीलॉक अक्षम करतो, नंतर जेव्हा कॉल समाप्त होतो तेव्हा तो कीलॉक पुन्हा-सक्षम करतो."</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>
@@ -550,15 +550,15 @@
<string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"वाहक सेवांवर प्रतिबद्ध करण्यासाठी होल्डरला अनुमती देते. सामान्य अॅप्ससाठी कधीही आवश्यकता नसावी."</string>
<string name="permlab_access_notification_policy" msgid="4247510821662059671">"व्यत्यय आणू नका अॅक्सेस करा"</string>
<string name="permdesc_access_notification_policy" msgid="3296832375218749580">"व्यत्यय आणू नका कॉन्फिगरेशन वाचण्यासाठी आणि लिहिण्यासाठी अॅपला अनुमती देते."</string>
- <string name="policylab_limitPassword" msgid="4497420728857585791">"संकेतशब्द नियम सेट करा"</string>
+ <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करा"</string>
<string name="policydesc_limitPassword" msgid="2502021457917874968">"स्क्रीन लॉक पासवर्ड आणि पिन मध्ये अनुमती दिलेले लांबी आणि वर्ण नियंत्रित करा."</string>
<string name="policylab_watchLogin" msgid="5091404125971980158">"स्क्रीन अनलॉक प्रयत्नांचे परीक्षण करा"</string>
- <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"टाइप केलेल्या अयोग्य संकेतशब्दांच्या अंकांचे परीक्षण करा. स्क्रीन अनलॉक केली जाते, तेव्हा टॅबलेट लॉक करा किंवा बरेच संकेतशब्द टाइप केले असल्यास टॅबलेटचा सर्व डेटा मिटवा."</string>
- <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"स्क्रीन अनलॉक करताना टाइप केलेल्या चुकीच्या संकेतशब्दांच्या संख्येचे परीक्षण करा आणि टीव्ही लॉक करा किंवा अनेक चुकीचे संकेतशब्द टाइप केले असल्यास टीव्हीचा सर्व डेटा मिटवा."</string>
- <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"टाइप केलेल्या अयोग्य संकेतशब्दांच्या अंकांचे परीक्षण करा. स्क्रीन अनलॉक केली जाते, तेव्हा फोन लॉक करा किंवा बरेच संकेतशब्द टाइप केले असल्यास फोनचा सर्व डेटा मिटवा."</string>
- <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"स्क्रीन अनलॉक करताना टाइप केलेल्या चुकीच्या संकेतशब्दांच्या संख्येचे परीक्षण करा आणि टॅबलेट लॉक करा किंवा अनेक चुकीचे संकेतशब्द टाइप केले असल्यास या वापरकर्त्याचा सर्व डेटा मिटवा."</string>
- <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"स्क्रीन अनलॉक करताना टाइप केलेल्या चुकीच्या संकेतशब्दांच्या संख्येचे परीक्षण करा आणि टीव्ही लॉक करा किंवा अनेक चुकीचे संकेतशब्द टाइप केले असल्यास या वापरकर्त्याचा सर्व डेटा मिटवा."</string>
- <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"टाइप केलेल्या अयोग्य संकेतशब्दांच्या अंकांचे परीक्षण करा. स्क्रीन अनलॉक केली जाते, तेव्हा फोन लॉक करा किंवा बरेच संकेतशब्द टाइप केले असल्यास या वापरकर्त्याचा सर्व डेटा मिटवा."</string>
+ <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"टाइप केलेल्या अयोग्य पासवर्डांच्या अंकांचे परीक्षण करा. स्क्रीन अनलॉक केली जाते, तेव्हा टॅबलेट लॉक करा किंवा बरेच पासवर्ड टाइप केले असल्यास टॅबलेटचा सर्व डेटा मिटवा."</string>
+ <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"स्क्रीन अनलॉक करताना टाइप केलेल्या चुकीच्या पासवर्डांच्या संख्येचे परीक्षण करा आणि टीव्ही लॉक करा किंवा अनेक चुकीचे पासवर्ड टाइप केले असल्यास टीव्हीचा सर्व डेटा मिटवा."</string>
+ <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"टाइप केलेल्या अयोग्य पासवर्डांच्या अंकांचे परीक्षण करा. स्क्रीन अनलॉक केली जाते, तेव्हा फोन लॉक करा किंवा बरेच पासवर्ड टाइप केले असल्यास फोनचा सर्व डेटा मिटवा."</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"स्क्रीन अनलॉक करताना टाइप केलेल्या चुकीच्या पासवर्डांच्या संख्येचे परीक्षण करा आणि टॅबलेट लॉक करा किंवा अनेक चुकीचे पासवर्ड टाइप केले असल्यास या वापरकर्त्याचा सर्व डेटा मिटवा."</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"स्क्रीन अनलॉक करताना टाइप केलेल्या चुकीच्या पासवर्डांच्या संख्येचे परीक्षण करा आणि टीव्ही लॉक करा किंवा अनेक चुकीचे पासवर्ड टाइप केले असल्यास या वापरकर्त्याचा सर्व डेटा मिटवा."</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"टाइप केलेल्या अयोग्य पासवर्डांच्या अंकांचे परीक्षण करा. स्क्रीन अनलॉक केली जाते, तेव्हा फोन लॉक करा किंवा बरेच पासवर्ड टाइप केले असल्यास या वापरकर्त्याचा सर्व डेटा मिटवा."</string>
<string name="policylab_resetPassword" msgid="4934707632423915395">"स्क्रीन लॉक बदला"</string>
<string name="policydesc_resetPassword" msgid="1278323891710619128">"स्क्रीन लॉक बदला."</string>
<string name="policylab_forceLock" msgid="2274085384704248431">"स्क्रीन लॉक करा"</string>
@@ -573,8 +573,8 @@
<string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"कोणत्याही चेतावणी शिवाय या वापरकर्त्याचा या फोनवरील डेटा मिटवा."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"डिव्हाइस समग्र प्रॉक्सी सेट करा"</string>
<string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"धोरण सक्षम असताना वापरण्यासाठी डिव्हाइस समग्र प्रॉक्सी सेट करा. फक्त डिव्हाइस मालक समग्र प्रॉक्सी सेट करु शकतो."</string>
- <string name="policylab_expirePassword" msgid="5610055012328825874">"स्क्रीन लॉक संकेतशब्द कालबाह्यता सेट करा"</string>
- <string name="policydesc_expirePassword" msgid="5367525762204416046">"लॉक-स्क्रीन संकेतशब्द किती वारंवार बदलणे आवश्यक आहे ते बदला."</string>
+ <string name="policylab_expirePassword" msgid="5610055012328825874">"स्क्रीन लॉक पासवर्ड कालबाह्यता सेट करा"</string>
+ <string name="policydesc_expirePassword" msgid="5367525762204416046">"लॉक-स्क्रीन पासवर्ड किती वारंवार बदलणे आवश्यक आहे ते बदला."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"स्टोरेज एंक्रिप्शन सेट करा"</string>
<string name="policydesc_encryptedStorage" msgid="2637732115325316992">"स्टोअर केलेला अॅप डेटा एंक्रिप्ट केला जाणे आवश्यक आहे."</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"कॅमेरे अक्षम करा"</string>
@@ -699,8 +699,8 @@
<string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"PUK आणि नवीन पिन कोड टाइप करा"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK कोड"</string>
<string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"नवीन पिन कोड"</string>
- <string name="keyguard_password_entry_touch_hint" msgid="2644215452200037944"><font size="17">"संकेतशब्द टाइप करण्यासाठी टॅप करा"</font></string>
- <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"अनलॉक करण्यासाठी संकेतशब्द टाइप करा"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="2644215452200037944"><font size="17">"पासवर्ड टाइप करण्यासाठी टॅप करा"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"अनलॉक करण्यासाठी पासवर्ड टाइप करा"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"अनलॉक करण्यासाठी पिन टाइप करा"</string>
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"अयोग्य पिन कोड."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"अनलॉक करण्यासाठी, मेनू दाबा नंतर 0."</string>
@@ -739,7 +739,7 @@
<string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"सिम कार्ड लॉक केलेले आहे."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"सिम कार्ड अनलॉक करत आहे…"</string>
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"तुम्ही आपला अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने काढला. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
- <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"आपण आपला संकेतशब्द <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+ <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"आपण आपला पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"आपण आपला पिन <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"तुम्ही आपला अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीचा रेखांकित केला आहे. <xliff:g id="NUMBER_1">%2$d</xliff:g> अधिक अयशस्वी प्रयत्नांनंतर, तुमच्याला आपले Google साइन इन वापरून आपला टॅब्लेट अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"तुम्ही <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा आपला अनलॉक पॅटर्न अयोग्यरीत्या काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुमच्याला आपले Google साइन इन वापरून आपला टीव्ही अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांनी पुन्हा प्रयत्न करा."</string>
@@ -756,10 +756,10 @@
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"बरेच पॅटर्न प्रयत्न"</string>
<string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"अनलॉक करण्यासाठी, आपल्या Google खात्यासह साइन इन करा."</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"वापरकर्तानाव (ईमेल)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"संकेतशब्द"</string>
+ <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"पासवर्ड"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"साइन इन करा"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"अवैध वापरकर्तानाव किंवा पासवर्ड."</string>
- <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"आपले वापरकर्तानाव किंवा संकेतशब्द विसरलात?\n "<b>"google.com/accounts/recovery"</b>" ला भेट द्या."</string>
+ <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"आपले वापरकर्तानाव किंवा पासवर्ड विसरलात?\n "<b>"google.com/accounts/recovery"</b>" ला भेट द्या."</string>
<string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"तपासत आहे..."</string>
<string name="lockscreen_unlock_label" msgid="737440483220667054">"अनलॉक करा"</string>
<string name="lockscreen_sound_on_label" msgid="9068877576513425970">"ध्वनी सुरु"</string>
@@ -788,7 +788,7 @@
<string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"पॅटर्न अनलॉक."</string>
<string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"चेहरा अनलॉक."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"पिन अनलॉक."</string>
- <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"संकेतशब्द अनलॉक."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"पासवर्ड अनलॉक."</string>
<string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"पॅटर्न क्षेत्र."</string>
<string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"स्लाइड क्षेत्र."</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
@@ -840,7 +840,7 @@
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"आपल्या व्हॉइसमेल इनबॉक्समध्ये संदेश जोडण्यासाठी अॅप ला अनुमती देते."</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"ब्राउझर भौगोलिक स्थान परवानग्या सुधारित करा"</string>
<string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"ब्राउझरच्या भौगोलिक स्थान परवानग्या सुधारित करण्यासाठी अॅप ला अनुमती देते. दुर्भावनापूर्ण अॅप्स यादृच्छिक वेबसाइटवर स्थान माहिती पाठविण्यास अनुमती देण्यासाठी याचा वापर करू शकतात."</string>
- <string name="save_password_message" msgid="767344687139195790">"ब्राउझरने हा संकेतशब्द लक्षात ठेवावा असे आपण इच्छिता?"</string>
+ <string name="save_password_message" msgid="767344687139195790">"ब्राउझरने हा पासवर्ड लक्षात ठेवावा असे आपण इच्छिता?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"आत्ता नाही"</string>
<string name="save_password_remember" msgid="6491879678996749466">"लक्षात ठेवा"</string>
<string name="save_password_never" msgid="8274330296785855105">"कधीही नाही"</string>
@@ -994,7 +994,7 @@
<string name="yes" msgid="5362982303337969312">"ठीक"</string>
<string name="no" msgid="5141531044935541497">"रद्द करा"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"लक्ष द्या"</string>
- <string name="loading" msgid="7933681260296021180">"लोड करीत आहे..."</string>
+ <string name="loading" msgid="7933681260296021180">"लोड करत आहे..."</string>
<string name="capital_on" msgid="1544682755514494298">"चालू"</string>
<string name="capital_off" msgid="6815870386972805832">"बंद"</string>
<string name="whichApplication" msgid="4533185947064773386">"याचा वापर करून क्रिया पूर्ण करा"</string>
@@ -1058,9 +1058,9 @@
<string name="android_upgrading_fstrim" msgid="8036718871534640010">"संचयन ऑप्टिमाइझ करत आहे."</string>
<string name="android_upgrading_notification_title" msgid="8428357096969413169">"Android अपडेट संपवत आहे..."</string>
<string name="android_upgrading_notification_body" msgid="5761201379457064286">"श्रेणीसुधारणा पूर्ण होईपर्यंत काही अॅप्स योग्यरित्या कार्य करणार नाहीत"</string>
- <string name="app_upgrading_toast" msgid="3008139776215597053">"<xliff:g id="APPLICATION">%1$s</xliff:g> श्रेणीसुधारित करीत आहे…"</string>
+ <string name="app_upgrading_toast" msgid="3008139776215597053">"<xliff:g id="APPLICATION">%1$s</xliff:g> श्रेणीसुधारित करत आहे…"</string>
<string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> पैकी <xliff:g id="NUMBER_0">%1$d</xliff:g> अॅप ऑप्टिमाइझ करत आहे."</string>
- <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> तयार करीत आहे."</string>
+ <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> तयार करत आहे."</string>
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"अॅप्स प्रारंभ करत आहे."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"बूट समाप्त होत आहे."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> चालत आहे"</string>
@@ -1074,7 +1074,7 @@
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> ने मेमेरी मर्यादा वाढविली"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"हीप डंप संकलित केला गेला आहे; सामायिक करण्यासाठी टॅप करा"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"हीप डंप सामायिक करायचे?"</string>
- <string name="dump_heap_text" msgid="4809417337240334941">"<xliff:g id="PROC">%1$s</xliff:g> प्रक्रियेने त्याची <xliff:g id="SIZE">%2$s</xliff:g> ची प्रक्रिया मेमरी मर्यादा ओलांडली आहे. त्याच्या विकासकासह सामायिक करण्यासाठी आपल्याकरिता हीप डंप उपलब्ध आहे. सावधगिरी बाळगा: या हीप डंपमध्ये आपली कोणतीही वैयक्तिक माहिती असू शकते ज्यात अॅप्लिकेशन प्रवेश करू शकतो."</string>
+ <string name="dump_heap_text" msgid="4809417337240334941">"<xliff:g id="PROC">%1$s</xliff:g> प्रक्रियेने त्याची <xliff:g id="SIZE">%2$s</xliff:g> ची प्रक्रिया मेमरी मर्यादा ओलांडली आहे. त्याच्या विकासकासह सामायिक करण्यासाठी तुमच्यासाठी हीप डंप उपलब्ध आहे. सावधगिरी बाळगा: या हीप डंपमध्ये आपली कोणतीही वैयक्तिक माहिती असू शकते ज्यात अॅप्लिकेशन प्रवेश करू शकतो."</string>
<string name="sendText" msgid="5209874571959469142">"मजकुरासाठी क्रिया निवडा"</string>
<string name="volume_ringtone" msgid="6885421406845734650">"रिंगर व्हॉल्यूम"</string>
<string name="volume_music" msgid="5421651157138628171">"मीडिया व्हॉल्यूम"</string>
@@ -1185,7 +1185,7 @@
<string name="perm_costs_money" msgid="4902470324142151116">"यासाठी आपले पैसे खर्च होऊ शकतात"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ठीक"</string>
<string name="usb_charging_notification_title" msgid="6895185153353640787">"USB हे डिव्हाइस चार्ज करत आहे"</string>
- <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB संलग्न केलेल्या डिव्हाइसला पॉवरचा पुरवठा करीत आहे"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB संलग्न केलेल्या डिव्हाइसला पॉवरचा पुरवठा करत आहे"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"स्थानांतरणासाठी USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"फोटो स्थानांतरणासाठी USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI साठी USB"</string>
@@ -1210,11 +1210,11 @@
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="alert_windows_notification_channel_group_name" msgid="1463953341148606396">"इतर अ‍ॅप्सवर दाखवा"</string>
- <string name="alert_windows_notification_channel_name" msgid="3116610965549449803">"<xliff:g id="NAME">%s</xliff:g> इतर अॅप्सवर प्रदर्शित करीत आहे"</string>
- <string name="alert_windows_notification_title" msgid="3697657294867638947">"<xliff:g id="NAME">%s</xliff:g> अन्‍य अॅप्सवर प्रदर्शित करीत आहे"</string>
+ <string name="alert_windows_notification_channel_name" msgid="3116610965549449803">"<xliff:g id="NAME">%s</xliff:g> इतर अॅप्सवर प्रदर्शित करत आहे"</string>
+ <string name="alert_windows_notification_title" msgid="3697657294867638947">"<xliff:g id="NAME">%s</xliff:g> अन्‍य अॅप्सवर प्रदर्शित करत आहे"</string>
<string name="alert_windows_notification_message" msgid="8917232109522912560">"<xliff:g id="NAME">%s</xliff:g> ने हे वैशिष्ट्य वापरू नये असे आपण इच्छित असल्यास, सेटिंग्ज उघडण्यासाठी टॅप करा आणि ते बंद करा."</string>
<string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"बंद करा"</string>
- <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> तयार करीत आहे"</string>
+ <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> तयार करत आहे"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटींसाठी तपासत आहे"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"नवीन <xliff:g id="NAME">%s</xliff:g> आढळले"</string>
<string name="ext_media_ready_notification_message" msgid="4083398150380114462">"फोटो आणि मीडिया स्थानांतरित करण्‍यासाठी"</string>
@@ -1250,7 +1250,7 @@
<string name="ext_media_status_unmountable" msgid="805594039236667894">"दूषित झाले"</string>
<string name="ext_media_status_unsupported" msgid="4691436711745681828">"समर्थित नसलेले"</string>
<string name="ext_media_status_ejecting" msgid="5463887263101234174">"बाहेर काढत आहे…"</string>
- <string name="ext_media_status_formatting" msgid="1085079556538644861">"फॉर्मेट करीत आहे..."</string>
+ <string name="ext_media_status_formatting" msgid="1085079556538644861">"फॉर्मेट करत आहे..."</string>
<string name="ext_media_status_missing" msgid="5638633895221670766">"घातले नाही"</string>
<string name="activity_list_empty" msgid="1675388330786841066">"कोणत्याही जुळणाऱ्या अॅक्टिव्हिटी आढळल्या नाहीत."</string>
<string name="permlab_route_media_output" msgid="6243022988998972085">"मीडिया आउटपुट मार्गस्थ करा"</string>
@@ -1365,7 +1365,7 @@
<string name="keyboardview_keycode_done" msgid="1992571118466679775">"पूर्ण झाले"</string>
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"मोड बदल"</string>
<string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
- <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"प्रविष्ट करा"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"एंटर करा"</string>
<string name="activitychooserview_choose_application" msgid="2125168057199941199">"एक अ‍ॅप निवडा"</string>
<string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> लाँच करू शकलो नाही"</string>
<string name="shareactionprovider_share_with" msgid="806688056141131819">"यांच्यासह सामायिक करा"</string>
@@ -1438,7 +1438,7 @@
<string name="media_route_chooser_extended_settings" msgid="87015534236701604">"सेटिंग्ज"</string>
<string name="media_route_controller_disconnect" msgid="8966120286374158649">"‍डिस्कनेक्ट करा"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"स्कॅन करत आहे..."</string>
- <string name="media_route_status_connecting" msgid="6422571716007825440">"कनेक्ट करीत आहे..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"कनेक्ट करत आहे..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"उपलब्ध"</string>
<string name="media_route_status_not_available" msgid="6739899962681886401">"उपलब्ध नाही"</string>
<string name="media_route_status_in_use" msgid="4533786031090198063">"वापरात आहे"</string>
@@ -1449,18 +1449,18 @@
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", सुरक्षित"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"पॅटर्न विसरलात"</string>
<string name="kg_wrong_pattern" msgid="1850806070801358830">"चुकीचा पॅटर्न"</string>
- <string name="kg_wrong_password" msgid="2333281762128113157">"चुकीचा संकेतशब्द"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"चुकीचा पासवर्ड"</string>
<string name="kg_wrong_pin" msgid="1131306510833563801">"चुकीचा पिन"</string>
<plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="8790651267324125694">
<item quantity="one"><xliff:g id="NUMBER">%d</xliff:g> सेकंदात पुन्‍हा प्रयत्न करा.</item>
<item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> सेकंदांत पुन्‍हा प्रयत्न करा.</item>
</plurals>
<string name="kg_pattern_instructions" msgid="398978611683075868">"तुमचा पॅटर्न काढा"</string>
- <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"सिम पिन प्रविष्ट करा"</string>
- <string name="kg_pin_instructions" msgid="2377242233495111557">"पिन प्रविष्ट करा"</string>
- <string name="kg_password_instructions" msgid="5753646556186936819">"संकेतशब्द प्रविष्ट करा"</string>
- <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"सिम आता अक्षम केले आहे. सुरु ठेवण्यासाठी PUK कोड प्रविष्ट करा. तपशीलांसाठी वाहकाशी संपर्क साधा."</string>
- <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"इच्छित पिन कोड प्रविष्ट करा"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"सिम पिन एंटर करा"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"पिन एंटर करा"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"पासवर्ड एंटर करा"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"सिम आता अक्षम केले आहे. सुरु ठेवण्यासाठी PUK कोड एंटर करा. तपशीलांसाठी वाहकाशी संपर्क साधा."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"इच्छित पिन कोड एंटर करा"</string>
<string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"इच्छित पिन कोड ची पुष्टी करा"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"सिम कार्ड अनलॉक करत आहे…"</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"अयोग्य पिन कोड."</string>
@@ -1471,13 +1471,13 @@
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बरेच पॅटर्न प्रयत्न"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"अनलॉक करण्यासाठी, आपल्या Google खात्यासह साइन इन करा."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"वापरकर्तानाव (ईमेल)"</string>
- <string name="kg_login_password_hint" msgid="9057289103827298549">"संकेतशब्द"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"पासवर्ड"</string>
<string name="kg_login_submit_button" msgid="5355904582674054702">"साइन इन करा"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"अवैध वापरकर्तानाव किंवा पासवर्ड."</string>
- <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"आपले वापरकर्तानाव किंवा संकेतशब्द विसरलात?\n "<b>"google.com/accounts/recovery"</b>" ला भेट द्या."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"आपले वापरकर्तानाव किंवा पासवर्ड विसरलात?\n "<b>"google.com/accounts/recovery"</b>" ला भेट द्या."</string>
<string name="kg_login_checking_password" msgid="1052685197710252395">"खाते तपासत आहे…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आपण आपला पिन <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आपण आपला संकेतशब्द <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आपण आपला पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"तुम्ही आपला अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने काढला. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"आपण <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा टॅबलेट अनलॉक करण्याचा अयोग्यपणे प्रयत्न केला. <xliff:g id="NUMBER_1">%2$d</xliff:g> आणखी अयशस्वी प्रयत्नांनंतर, टॅबलेट फॅक्टरी डीफॉल्टवर रीसेट केला जाईल आणि वापरकर्ता डेटा गमावेल."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"आपण <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा टीव्ही अनलॉक करण्याचा अयोग्यरित्या प्रयत्न केला. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, टीव्ही फॅक्टरी डीफॉल्टवर रीसेट केला जाईल आणि सर्व वापरकर्ता डेटा गमावेल."</string>
@@ -1502,7 +1502,7 @@
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"मोठे करणे"</string>
<string name="user_switched" msgid="3768006783166984410">"वर्तमान वापरकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> वर स्विच करत आहे…"</string>
- <string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> लॉग आउट करीत आहे…"</string>
+ <string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> लॉग आउट करत आहे…"</string>
<string name="owner_name" msgid="2716755460376028154">"मालक"</string>
<string name="error_message_title" msgid="4510373083082500195">"एरर"</string>
<string name="error_message_change_not_allowed" msgid="1238035947357923497">"या बदलास आपल्या प्रशासकाद्वारे अनुमती नाही"</string>
@@ -1598,7 +1598,7 @@
<string name="print_service_installed_title" msgid="2246317169444081628">"<xliff:g id="NAME">%s</xliff:g> सेवा स्‍थापित केली"</string>
<string name="print_service_installed_message" msgid="5897362931070459152">"सक्षम करण्यासाठी टॅप करा"</string>
<string name="restr_pin_enter_admin_pin" msgid="8641662909467236832">"प्रशासक पिन एंटर करा"</string>
- <string name="restr_pin_enter_pin" msgid="3395953421368476103">"पिन प्रविष्ट करा"</string>
+ <string name="restr_pin_enter_pin" msgid="3395953421368476103">"पिन एंटर करा"</string>
<string name="restr_pin_incorrect" msgid="8571512003955077924">"चुकीचा"</string>
<string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"वर्तमान पिन"</string>
<string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"नवीन पिन"</string>
@@ -1626,7 +1626,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>
@@ -1771,7 +1770,7 @@
<string name="autofill_save_title_with_3types" msgid="6943161834231458441">"&lt;b&gt;<xliff:g id="LABEL">%4$s</xliff:g>&lt;/b&gt;मध्ये <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> आणि <xliff:g id="TYPE_2">%3$s</xliff:g> सेव्ह करायची?"</string>
<string name="autofill_save_yes" msgid="6398026094049005921">"सेव्ह करा"</string>
<string name="autofill_save_no" msgid="2625132258725581787">"नाही, नको"</string>
- <string name="autofill_save_type_password" msgid="5288448918465971568">"संकेतशब्द"</string>
+ <string name="autofill_save_type_password" msgid="5288448918465971568">"पासवर्ड"</string>
<string name="autofill_save_type_address" msgid="4936707762193009542">"पत्ता"</string>
<string name="autofill_save_type_credit_card" msgid="7127694776265563071">"क्रेडिट कार्ड"</string>
<string name="autofill_save_type_username" msgid="239040540379769562">"वापरकर्तानाव"</string>
@@ -1782,14 +1781,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-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 7de97b39cdb0..c41547b5b908 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1199,8 +1199,8 @@
<string name="usb_notification_message" msgid="3370903770828407960">"थप विकल्पहरूका लागि ट्याप गर्नुहोस्।"</string>
<string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"एनालग अडियोको सहायक उपकरण पत्ता लाग्यो"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"संलग्न गरिएको यन्त्र यो फोनसँग कम्प्याटिबल छैन। थप जान्न ट्याप गर्नुहोस्।"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"USB डिबग गर्ने जडित छ"</string>
- <string name="adb_active_notification_message" msgid="4948470599328424059">"USB डिबगिङलाई असक्षम गर्न ट्याप गर्नुहोस्।"</string>
+ <string name="adb_active_notification_title" msgid="6729044778949189918">"USB डिबग गर्ने सुविधा सुचारू छ"</string>
+ <string name="adb_active_notification_message" msgid="4948470599328424059">"USB डिबग गर्ने सुविधालाई असक्षम गर्न ट्याप गर्नुहोस्।"</string>
<string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB डिबगिङलाई असक्षम पार्न ट्याप गर्नुहोस्।"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"बग रिपोर्ट लिँदै..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग रिपोर्टलाई साझेदारी गर्ने हो?"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index d6233fb05497..d269fac8a9fc 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1626,7 +1626,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>
@@ -1782,14 +1781,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-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index d088cdd315b8..03c4536af96e 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1626,7 +1626,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Segundo <xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Terceiro <xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Para liberar esta tela, mantenha os botões Voltar e Visão geral pressionados"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Não é possível liberar este app"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Tela fixada"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Tela liberada"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de liberar"</string>
@@ -1782,14 +1781,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Teste de mensagens de emergência"</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">"SIM não autorizado para voz"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM não aprovisionado para voz"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM não autorizado para voz"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Smartphone não autorizado para voz"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Janela pop-up"</string>
<string name="slice_more_content" msgid="8504342889413274608">"Mais <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Esse atalho requer o app mais recente"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index d088cdd315b8..03c4536af96e 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1626,7 +1626,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"Segundo <xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"Terceiro <xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Para liberar esta tela, mantenha os botões Voltar e Visão geral pressionados"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Não é possível liberar este app"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Tela fixada"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Tela liberada"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de liberar"</string>
@@ -1782,14 +1781,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Teste de mensagens de emergência"</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">"SIM não autorizado para voz"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM não aprovisionado para voz"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM não autorizado para voz"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Smartphone não autorizado para voz"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Janela pop-up"</string>
<string name="slice_more_content" msgid="8504342889413274608">"Mais <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"Esse atalho requer o app mais recente"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 0afa41330959..d65eaa79ef46 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1651,7 +1651,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> pentru serviciu (2)"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> pentru serviciu (3)"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Pentru a anula fixarea acestui ecran, atingeți lung butoanele Înapoi și Recente"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Nu se poate anula fixarea acestei aplicații"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ecran fixat"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Fixarea ecranului anulată"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicită codul PIN înainte de a anula fixarea"</string>
@@ -1817,14 +1816,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Testarea mesajelor de urgență"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Răspundeț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">"Cardul SIM nu este permis pentru voce"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"Cardul SIM nu este activat pentru voce"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"Cardul SIM nu este permis pentru voce"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Telefonul nu este permis pentru voce"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Fereastră pop-up"</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">"Această comandă rapidă necesită cea mai recentă aplicație"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 0eaaf91cd6d5..cea220a7256c 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1624,7 +1624,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"<xliff:g id="LABEL">%1$s</xliff:g> ya 2 ya Kazini"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"<xliff:g id="LABEL">%1$s</xliff:g> ya 3 ya Kazini"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"Ili kubandua skrini hii, gusa na ushikilie vitufe vya Nyuma na Muhtasari"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"Huwezi kubandua programu hii"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Skrini imebandikwa"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"Skrini imebanduliwa"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Itisha PIN kabla hujabandua"</string>
@@ -1780,14 +1779,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Jaribio la ujumbe wa dharura"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"Jibu"</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 hairuhusiwi katika huduma ya sauti"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM haina mipangilio ya huduma ya sauti"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"SIM hairuhusiwi katika huduma ya sauti"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"Simu hairuhusiwi katika huduma ya sauti"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"Dirisha Ibukizi"</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">"Njia hii ya mkato inahitaji toleo jipya la programu"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 429ecf109bfd..e03824b11baf 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -282,7 +282,7 @@
<string name="permgrouprequest_camera" msgid="810824326507258410">"படங்களை எடுக்கவும் வீடியோவைப் பதிவுசெய்யவும், &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;க்கு அணுகல் வழங்கவும்"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"ஃபோன்"</string>
<string name="permgroupdesc_phone" msgid="6234224354060641055">"யாரையும் தொலைபேசியில் அழைக்கலாம்"</string>
- <string name="permgrouprequest_phone" msgid="7084161459732093690">"மொபைல் அழைப்புகளைச் செய்யவும், அவற்றை நிர்வகிக்கவும், &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;க்கு அனுமதி வழங்கவும்"</string>
+ <string name="permgrouprequest_phone" msgid="7084161459732093690">"மொபைல் அழைப்புகளைச் செய்யவும், அவற்றை நிர்வகிக்கவும், &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;க்கு அனுமதி வழங்கவா"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"உடல் சென்சார்கள்"</string>
<string name="permgroupdesc_sensors" msgid="7147968539346634043">"உங்கள் உடல் இயக்கம் பற்றி உணர்விகள் கூறும் தகவலைப் பார்க்கலாம்"</string>
<string name="permgrouprequest_sensors" msgid="8631146669524259656">"உடலியக்கக் குறிகள் பற்றிய உணர்வித் தரவை அணுக, &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;க்கு அனுமதி வழங்கவும்"</string>
@@ -1184,7 +1184,7 @@
<string name="no_permissions" msgid="7283357728219338112">"அனுமதிகள் தேவையில்லை"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"இதனால் நீங்கள் கட்டணம் செலுத்த வேண்டியிருக்கலாம்"</string>
<string name="dlg_ok" msgid="7376953167039865701">"சரி"</string>
- <string name="usb_charging_notification_title" msgid="6895185153353640787">"இந்தச் சாதனத்தை USB சார்ஜ் செய்கிறது"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"சாதனம் USB சார்ஜிங் செய்யப்படுகிறது"</string>
<string name="usb_supplying_notification_title" msgid="5310642257296510271">"இணைத்துள்ள சாதனத்திற்கு USB சக்தி அளிக்கிறது"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB, கோப்புப் பரிமாற்றத்துக்கு மட்டும்"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB, படப் பரிமாற்றத்துக்கு மட்டும்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 9b3b89b55574..8ae8401f8928 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1626,7 +1626,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">"ఈ స్క్రీన్‌ను అన్‌పిన్ చేయడానికి, వెనుకకు మరియు స్థూలదృష్టి బటన్‌లను నొక్కి &amp; పట్టుకోండి"</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>
@@ -1782,14 +1781,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 b89af42fc445..f009e08b32d1 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1626,7 +1626,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>
@@ -1782,18 +1781,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>
- <!-- 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>
<string name="shortcut_restore_not_supported" msgid="5028808567940014190">"شارٹ کٹ کو بحال نہیں کیا جا سکا، کیونکہ ایپ بیک اپ اور بحالی کو سپورٹ نہیں کرتی ہے"</string>
- <string name="shortcut_restore_signature_mismatch" msgid="2406209324521327518">"ایپ کی دستخط کے غیر مماثل ہونے کی وجہ سے شارٹ کٹ کو بحال نہیں کیا جا سکا"</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-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml
index fd881026ca6b..6cef47d4cbde 100644
--- a/core/res/res/values-watch/styles_material.xml
+++ b/core/res/res/values-watch/styles_material.xml
@@ -39,8 +39,8 @@ please see styles_device_defaults.xml.
<item name="taskOpenExitAnimation">@anim/slide_in_exit_micro</item>
<item name="taskCloseEnterAnimation">@null</item>
<item name="taskCloseExitAnimation">@anim/slide_out_micro</item>
- <item name="taskToFrontEnterAnimation">@anim/slide_in_enter_micro</item>
- <item name="taskToFrontExitAnimation">@anim/slide_in_exit_micro</item>
+ <item name="taskToFrontEnterAnimation">@null</item>
+ <item name="taskToFrontExitAnimation">@anim/slide_out_micro</item>
<item name="taskToBackEnterAnimation">@null</item>
<item name="taskToBackExitAnimation">@anim/slide_out_micro</item>
<item name="wallpaperOpenEnterAnimation">@null</item>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 5629df1796d5..6b95eda27a8a 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -979,10 +979,10 @@
<string name="inputMethod" msgid="1653630062304567879">"输入法"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"文字操作"</string>
<string name="email" msgid="4560673117055050403">"电子邮件"</string>
- <string name="dial" msgid="1253998302767701559">"通话"</string>
+ <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="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>
@@ -1626,7 +1626,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>
@@ -1782,14 +1781,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/config.xml b/core/res/res/values/config.xml
index 1c2e5a406772..edd793d89afa 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -123,6 +123,9 @@
be sent during a change to the audio output device. -->
<bool name="config_sendAudioBecomingNoisy">true</bool>
+ <!-- Flag to disable all transition animations -->
+ <bool name="config_disableTransitionAnimation">false</bool>
+
<!-- The duration (in milliseconds) of a short animation. -->
<integer name="config_shortAnimTime">200</integer>
@@ -876,7 +879,7 @@
<bool name="config_nightDisplayAvailable">@bool/config_setColorTransformAccelerated</bool>
<!-- Default mode to control how Night display is automatically activated.
- One of the following values (see NightDisplayController.java):
+ One of the following values (see ColorDisplayController.java):
0 - AUTO_MODE_DISABLED
1 - AUTO_MODE_CUSTOM
2 - AUTO_MODE_TWILIGHT
@@ -3161,4 +3164,6 @@
<!-- Corner radius of system dialogs -->
<dimen name="config_dialogCornerRadius">2dp</dimen>
+
+ <string translatable="false" name="config_batterySaverDeviceSpecificConfig"></string>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 947fcf127b9c..946216c06a01 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -605,6 +605,8 @@
<!-- The size of the right icon image when on low ram -->
<dimen name="notification_right_icon_size_low_ram">40dp</dimen>
+ <dimen name="messaging_avatar_size">24dp</dimen>
+
<!-- Max width/height of the autofill data set picker as a fraction of the screen width/height -->
<dimen name="autofill_dataset_picker_max_size">90%</dimen>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index cd3624db9afa..b40117e9e40b 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -139,6 +139,27 @@
<!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_MOVE_WINDOW}. -->
<item type="id" name="accessibilityActionMoveWindow" />
+ <!-- A tag used to save an animator in local y translation -->
+ <item type="id" name="tag_local_translation_y_animator" />
+
+ <!-- A tag used to save the local translation y -->
+ <item type="id" name="tag_local_translation_y" />
+
+ <!-- A tag used to save the original top of a view -->
+ <item type="id" name="tag_layout_top" />
+
+ <!-- A tag used to save an animator in alpha -->
+ <item type="id" name="tag_alpha_animator" />
+
+ <!-- A tag used to save the clip children in a tag -->
+ <item type="id" name="clip_children_tag" />
+
+ <!-- A tag used to save the set of deactivated children that clip -->
+ <item type="id" name="clip_children_set_tag" />
+
+ <!-- A tag used to save the clip to padding in a tag -->
+ <item type="id" name="clip_to_padding_tag" />
+
<!-- Action used to manually trigger an autofill request -->
<item type="id" name="autofill" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 78a8e2a3c748..9e0722bc0de0 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4744,4 +4744,7 @@
A toast message shown when an app shortcut that wasn't restored due to an unknown issue is clicked,
-->
<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>
</resources>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index cddf99a2df23..2cd4dcb84a5f 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -505,8 +505,17 @@ please see styles_device_defaults.xml.
<item name="layout_width">match_parent</item>
<item name="layout_height">wrap_content</item>
<item name="ellipsize">end</item>
- <item name="visibility">gone</item>
<item name="textAppearance">@style/TextAppearance.Material.Notification</item>
+ <item name="background">@drawable/messaging_message_background</item>
+ </style>
+
+ <style name="Widget.Material.Notification.MessagingName" parent="Widget.Material.Light.TextView">
+ <item name="layout_width">wrap_content</item>
+ <item name="layout_height">wrap_content</item>
+ <item name="ellipsize">end</item>
+ <item name="textAppearance">@style/TextAppearance.Material.Notification</item>
+ <item name="textColor">@color/notification_primary_text_color_light</item>
+ <item name="textSize">12sp</item>
</style>
<!-- Widget Styles -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 32758e83f9b7..54970851f3c1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -252,6 +252,7 @@
<java-symbol type="bool" name="config_bluetooth_hfp_inband_ringing_support" />
<java-symbol type="bool" name="config_cellBroadcastAppLinks" />
<java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
+ <java-symbol type="bool" name="config_disableTransitionAnimation" />
<java-symbol type="bool" name="config_enableAutoPowerModes" />
<java-symbol type="integer" name="config_autoPowerModeThresholdAngle" />
<java-symbol type="integer" name="config_autoPowerModeAnyMotionSensor" />
@@ -1324,6 +1325,7 @@
<java-symbol type="drawable" name="cling_button" />
<java-symbol type="drawable" name="cling_arrow_up" />
<java-symbol type="drawable" name="cling_bg" />
+ <java-symbol type="drawable" name="ic_corp_badge" />
<java-symbol type="drawable" name="ic_corp_badge_color" />
<java-symbol type="drawable" name="ic_corp_badge_case" />
<java-symbol type="drawable" name="ic_corp_icon" />
@@ -3105,6 +3107,22 @@
<java-symbol type="dimen" name="chooser_service_spacing" />
<java-symbol type="bool" name="config_showSysuiShutdown" />
+ <java-symbol type="layout" name="notification_template_messaging_message" />
+ <java-symbol type="layout" name="notification_template_messaging_group" />
+ <java-symbol type="id" name="message_text" />
+ <java-symbol type="id" name="message_name" />
+ <java-symbol type="id" name="message_icon" />
+ <java-symbol type="id" name="group_message_container" />
+ <java-symbol type="id" name="tag_local_translation_y_animator" />
+ <java-symbol type="id" name="tag_local_translation_y" />
+ <java-symbol type="id" name="tag_layout_top" />
+ <java-symbol type="id" name="tag_alpha_animator" />
+ <java-symbol type="id" name="clip_children_set_tag" />
+ <java-symbol type="id" name="clip_to_padding_tag" />
+ <java-symbol type="id" name="clip_children_tag" />
+ <java-symbol type="drawable" name="ic_reply_notification_large" />
+ <java-symbol type="dimen" name="messaging_avatar_size" />
+
<java-symbol type="integer" name="config_stableDeviceDisplayWidth" />
<java-symbol type="integer" name="config_stableDeviceDisplayHeight" />
<java-symbol type="bool" name="config_display_no_service_when_sim_unready" />
@@ -3128,7 +3146,9 @@
<java-symbol type="string" name="shortcut_restore_not_supported" />
<java-symbol type="string" name="shortcut_restore_signature_mismatch" />
<java-symbol type="string" name="shortcut_restore_unknown_issue" />
+ <java-symbol type="string" name="battery_saver_warning" />
<!-- From media projection -->
<java-symbol type="string" name="config_mediaProjectionPermissionDialogComponent" />
+ <java-symbol type="string" name="config_batterySaverDeviceSpecificConfig" />
</resources>
diff --git a/core/tests/coretests/res/font/samplexmlfont.xml b/core/tests/coretests/res/font/samplexmlfont.xml
index f1d14ff383fd..dc2319ea0a80 100644
--- a/core/tests/coretests/res/font/samplexmlfont.xml
+++ b/core/tests/coretests/res/font/samplexmlfont.xml
@@ -1,10 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
- <font android:fontStyle="normal" android:fontWeight="400" android:fontVariationSettings="'wdth' 0.8"
- android:font="@font/samplefont" android:ttcIndex="0"/>
- <font android:fontStyle="italic" android:fontWeight="400" android:fontVariationSettings="'contrast' 0.5"
- android:font="@font/samplefont2" android:ttcIndex="1" />
- <font android:fontStyle="normal" android:fontWeight="800" android:fontVariationSettings="'wdth' 500.0, 'wght' 300.0"
- android:font="@font/samplefont3" android:ttcIndex="2" />
+ <font android:fontStyle="normal" android:fontWeight="400" android:font="@font/samplefont" />
+ <font android:fontStyle="italic" android:fontWeight="400" android:font="@font/samplefont2" />
+ <font android:fontStyle="normal" android:fontWeight="800" android:font="@font/samplefont3" />
<font android:fontStyle="italic" android:fontWeight="800" android:font="@font/samplefont4" />
</font-family>
diff --git a/core/tests/coretests/res/font/samplexmlfontforparsing.xml b/core/tests/coretests/res/font/samplexmlfontforparsing.xml
new file mode 100644
index 000000000000..98e3213954aa
--- /dev/null
+++ b/core/tests/coretests/res/font/samplexmlfontforparsing.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:android="http://schemas.android.com/apk/res/android">
+ <font android:fontStyle="normal" android:fontWeight="400" android:fontVariationSettings="'wdth' 0.8"
+ android:font="@font/samplefont" android:ttcIndex="0" />
+ <font android:fontStyle="italic" android:fontWeight="400" android:fontVariationSettings="'cntr' 0.5"
+ android:font="@font/samplefont2" android:ttcIndex="1" />
+ <font android:fontStyle="normal" android:fontWeight="800" android:fontVariationSettings="'wdth' 500.0, 'wght' 300.0"
+ android:font="@font/samplefont3" android:ttcIndex="2" />
+ <font android:fontStyle="italic" android:fontWeight="800" android:font="@font/samplefont4" />
+</font-family>
diff --git a/core/tests/coretests/res/layout/add_column_in_table.xml b/core/tests/coretests/res/layout/add_column_in_table.xml
index 05f55a8b360e..d929b02f70af 100644
--- a/core/tests/coretests/res/layout/add_column_in_table.xml
+++ b/core/tests/coretests/res/layout/add_column_in_table.xml
@@ -18,6 +18,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
+ <requestFocus />
<TableLayout android:id="@+id/table"
android:layout_width="match_parent"
diff --git a/core/tests/coretests/res/layout/baseline_0width_and_weight.xml b/core/tests/coretests/res/layout/baseline_0width_and_weight.xml
index acbb10b7d7b2..eac9b9de2db1 100644
--- a/core/tests/coretests/res/layout/baseline_0width_and_weight.xml
+++ b/core/tests/coretests/res/layout/baseline_0width_and_weight.xml
@@ -21,6 +21,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
+ <requestFocus />
<LinearLayout android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/core/tests/coretests/res/layout/focus_after_removal.xml b/core/tests/coretests/res/layout/focus_after_removal.xml
index f4e388d695c9..84449d1a0062 100644
--- a/core/tests/coretests/res/layout/focus_after_removal.xml
+++ b/core/tests/coretests/res/layout/focus_after_removal.xml
@@ -22,6 +22,7 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
+ <requestFocus />
<LinearLayout android:id="@+id/leftLayout"
android:orientation="vertical"
diff --git a/core/tests/coretests/res/layout/linear_layout_edittext_then_button.xml b/core/tests/coretests/res/layout/linear_layout_edittext_then_button.xml
index ab76e29c5fa1..6b3b5a72c59c 100644
--- a/core/tests/coretests/res/layout/linear_layout_edittext_then_button.xml
+++ b/core/tests/coretests/res/layout/linear_layout_edittext_then_button.xml
@@ -22,6 +22,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
+ <requestFocus />
<EditText
android:id="@+id/editText"
diff --git a/core/tests/coretests/res/layout/visibility_callback.xml b/core/tests/coretests/res/layout/visibility_callback.xml
index 9034b3f2329b..ff918f541839 100644
--- a/core/tests/coretests/res/layout/visibility_callback.xml
+++ b/core/tests/coretests/res/layout/visibility_callback.xml
@@ -24,6 +24,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
+ <requestFocus />
<LinearLayout
android:orientation="vertical"
diff --git a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
index a12a0b8d125b..42ff2e94a24e 100644
--- a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
+++ b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
@@ -58,7 +58,7 @@ public class FontResourcesParserTest {
@Test
public void testParse() throws XmlPullParserException, IOException {
- XmlResourceParser parser = mResources.getXml(R.font.samplexmlfont);
+ XmlResourceParser parser = mResources.getXml(R.font.samplexmlfontforparsing);
FamilyResourceEntry result = FontResourcesParser.parse(parser, mResources);
@@ -76,7 +76,7 @@ public class FontResourcesParserTest {
assertEquals(400, font2.getWeight());
assertEquals(1, font2.getItalic());
assertEquals(1, font2.getTtcIndex());
- assertEquals("'contrast' 0.5", font2.getVariationSettings());
+ assertEquals("'cntr' 0.5", font2.getVariationSettings());
assertEquals("res/font/samplefont2.ttf", font2.getFileName());
FontFileResourceEntry font3 = fileEntries[2];
assertEquals(800, font3.getWeight());
diff --git a/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java b/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java
index 75eeb93f5b9a..9ed3f11b548f 100644
--- a/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java
+++ b/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java
@@ -16,6 +16,7 @@
package android.database;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -61,6 +62,10 @@ public class SQLiteOpenHelperTest {
super(context, name, null, 1);
}
+ TestHelper(Context context, String name, int version, SQLiteDatabase.OpenParams params) {
+ super(context, name, version, params);
+ }
+
@Override
public void onCreate(SQLiteDatabase db) {
}
@@ -168,4 +173,25 @@ public class SQLiteOpenHelperTest {
}
assertTrue("No dbstat found for " + dbName, dbStatFound);
}
+
+ @Test
+ public void testOpenParamsConstructor() {
+ SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder()
+ .setJournalMode("DELETE")
+ .setSynchronousMode("OFF")
+ .build();
+
+ TestHelper helper = new TestHelper(mContext, "openhelper_test_constructor", 1, params);
+ mHelpersToClose.add(helper);
+
+ String journalMode = DatabaseUtils
+ .stringForQuery(helper.getReadableDatabase(), "PRAGMA journal_mode", null);
+
+ assertEquals("DELETE", journalMode.toUpperCase());
+ String syncMode = DatabaseUtils
+ .stringForQuery(helper.getReadableDatabase(), "PRAGMA synchronous", null);
+
+ assertEquals("0", syncMode);
+ }
+
}
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index 6fa28b1ccdaa..27b7f9e185bb 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -187,6 +187,11 @@ public class UriTest extends TestCase {
uri = Uri.parse("http://localhost");
assertEquals("localhost", uri.getHost());
assertEquals(-1, uri.getPort());
+
+ uri = Uri.parse("http://a:a@example.com:a@example2.com/path");
+ assertEquals("a:a@example.com:a@example2.com", uri.getAuthority());
+ assertEquals("example2.com", uri.getHost());
+ assertEquals(-1, uri.getPort());
}
@SmallTest
diff --git a/core/tests/coretests/src/android/os/UserHandleTest.java b/core/tests/coretests/src/android/os/UserHandleTest.java
new file mode 100644
index 000000000000..af559fddd48a
--- /dev/null
+++ b/core/tests/coretests/src/android/os/UserHandleTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.UserHandle.ERR_GID;
+import static android.os.UserHandle.getAppId;
+import static android.os.UserHandle.getCacheAppGid;
+import static android.os.UserHandle.getSharedAppGid;
+import static android.os.UserHandle.getUid;
+import static android.os.UserHandle.getUserId;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class UserHandleTest {
+ // NOTE: keep logic in sync with system/core/libcutils/tests/multiuser_test.cpp
+
+ @Test
+ public void testMerge() throws Exception {
+ EXPECT_EQ(0, multiuser_get_uid(0, 0));
+ EXPECT_EQ(1000, multiuser_get_uid(0, 1000));
+ EXPECT_EQ(10000, multiuser_get_uid(0, 10000));
+ EXPECT_EQ(50000, multiuser_get_uid(0, 50000));
+ EXPECT_EQ(1000000, multiuser_get_uid(10, 0));
+ EXPECT_EQ(1001000, multiuser_get_uid(10, 1000));
+ EXPECT_EQ(1010000, multiuser_get_uid(10, 10000));
+ EXPECT_EQ(1050000, multiuser_get_uid(10, 50000));
+ }
+
+ @Test
+ public void testSplitUser() throws Exception {
+ EXPECT_EQ(0, multiuser_get_user_id(0));
+ EXPECT_EQ(0, multiuser_get_user_id(1000));
+ EXPECT_EQ(0, multiuser_get_user_id(10000));
+ EXPECT_EQ(0, multiuser_get_user_id(50000));
+ EXPECT_EQ(10, multiuser_get_user_id(1000000));
+ EXPECT_EQ(10, multiuser_get_user_id(1001000));
+ EXPECT_EQ(10, multiuser_get_user_id(1010000));
+ EXPECT_EQ(10, multiuser_get_user_id(1050000));
+ }
+
+ @Test
+ public void testSplitApp() throws Exception {
+ EXPECT_EQ(0, multiuser_get_app_id(0));
+ EXPECT_EQ(1000, multiuser_get_app_id(1000));
+ EXPECT_EQ(10000, multiuser_get_app_id(10000));
+ EXPECT_EQ(50000, multiuser_get_app_id(50000));
+ EXPECT_EQ(0, multiuser_get_app_id(1000000));
+ EXPECT_EQ(1000, multiuser_get_app_id(1001000));
+ EXPECT_EQ(10000, multiuser_get_app_id(1010000));
+ EXPECT_EQ(50000, multiuser_get_app_id(1050000));
+ }
+
+ @Test
+ public void testCache() throws Exception {
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 0));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 1000));
+ EXPECT_EQ(20000, multiuser_get_cache_gid(0, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 50000));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(10, 0));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(10, 1000));
+ EXPECT_EQ(1020000, multiuser_get_cache_gid(10, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(10, 50000));
+ }
+
+ @Test
+ public void testShared() throws Exception {
+ EXPECT_EQ(0, multiuser_get_shared_gid(0, 0));
+ EXPECT_EQ(1000, multiuser_get_shared_gid(0, 1000));
+ EXPECT_EQ(50000, multiuser_get_shared_gid(0, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(0, 50000));
+ EXPECT_EQ(0, multiuser_get_shared_gid(10, 0));
+ EXPECT_EQ(1000, multiuser_get_shared_gid(10, 1000));
+ EXPECT_EQ(50000, multiuser_get_shared_gid(10, 10000));
+ EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(10, 50000));
+ }
+
+ private static void EXPECT_EQ(int expected, int actual) {
+ assertEquals(expected, actual);
+ }
+
+ private static int multiuser_get_uid(int userId, int appId) {
+ return getUid(userId, appId);
+ }
+
+ private static int multiuser_get_cache_gid(int userId, int appId) {
+ return getCacheAppGid(userId, appId);
+ }
+
+ private static int multiuser_get_shared_gid(int userId, int appId) {
+ return getSharedAppGid(userId, appId);
+ }
+
+ private static int multiuser_get_user_id(int uid) {
+ return getUserId(uid);
+ }
+
+ private static int multiuser_get_app_id(int uid) {
+ return getAppId(uid);
+ }
+}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index ebe0527cbbec..d36ed639b4b9 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -26,7 +26,6 @@ import static java.lang.reflect.Modifier.isFinal;
import static java.lang.reflect.Modifier.isPublic;
import static java.lang.reflect.Modifier.isStatic;
-import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -180,7 +179,6 @@ public class SettingsBackupTest {
Settings.Global.DNS_RESOLVER_MIN_SAMPLES,
Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
- Settings.Global.DNS_TLS_DISABLED,
Settings.Global.DOCK_SOUNDS_ENABLED_WHEN_ACCESSIBILITY,
Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE,
Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE,
@@ -265,6 +263,7 @@ public class SettingsBackupTest {
Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE,
Settings.Global.NETWORK_AVOID_BAD_WIFI,
Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE,
+ Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME,
Settings.Global.NETWORK_PREFERENCE,
Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE,
Settings.Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS,
diff --git a/core/tests/coretests/src/android/util/ListScenario.java b/core/tests/coretests/src/android/util/ListScenario.java
index fa088a303507..129484af75de 100644
--- a/core/tests/coretests/src/android/util/ListScenario.java
+++ b/core/tests/coretests/src/android/util/ListScenario.java
@@ -28,6 +28,7 @@ import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
+
import com.google.android.collect.Maps;
import java.util.ArrayList;
@@ -60,18 +61,18 @@ public abstract class ListScenario extends Activity {
// separators
private Set<Integer> mUnselectableItems = new HashSet<Integer>();
-
+
private boolean mStackFromBottom;
private int mClickedPosition = -1;
-
+
private int mLongClickedPosition = -1;
-
+
private int mConvertMisses = 0;
-
+
private int mHeaderViewCount;
private boolean mHeadersFocusable;
-
+
private int mFooterViewCount;
private LinearLayout mLinearLayout;
@@ -193,7 +194,7 @@ public abstract class ListScenario extends Activity {
mIncludeHeader = includeHeader;
return this;
}
-
+
/**
* Sets the stacking direction
* @param stackFromBottom
@@ -203,7 +204,7 @@ public abstract class ListScenario extends Activity {
mStackFromBottom = stackFromBottom;
return this;
}
-
+
/**
* Sets whether the sum of the height of the list items must be at least the
* height of the list view.
@@ -220,7 +221,7 @@ public abstract class ListScenario extends Activity {
mFadingEdgeScreenSizeFactor = fadingEdgeScreenSizeFactor;
return this;
}
-
+
/**
* Set the number of header views to appear within the list
*/
@@ -246,7 +247,7 @@ public abstract class ListScenario extends Activity {
mFooterViewCount = footerViewCount;
return this;
}
-
+
/**
* Sets whether the {@link ListScenario} will automatically set the
* adapter on the list view. If this is false, the client MUST set it
@@ -278,7 +279,7 @@ public abstract class ListScenario extends Activity {
*/
protected void nothingSelected() {
}
-
+
/**
* Override this if you want to know when something has been clicked (perhaps
* more importantly, that {@link android.widget.AdapterView.OnItemClickListener} has
@@ -287,7 +288,7 @@ public abstract class ListScenario extends Activity {
protected void positionClicked(int position) {
setClickedPosition(position);
}
-
+
/**
* Override this if you want to know when something has been long clicked (perhaps
* more importantly, that {@link android.widget.AdapterView.OnItemLongClickListener} has
@@ -303,7 +304,7 @@ public abstract class ListScenario extends Activity {
// for test stability, turn off title bar
requestWindowFeature(Window.FEATURE_NO_TITLE);
-
+
mScreenHeight = getWindowManager().getDefaultDisplay().getHeight();
@@ -326,7 +327,7 @@ public abstract class ListScenario extends Activity {
header.setText("Header: " + i);
mListView.addHeaderView(header);
}
-
+
for (int i=0; i<mFooterViewCount; i++) {
TextView header = new TextView(this);
header.setText("Footer: " + i);
@@ -336,7 +337,7 @@ public abstract class ListScenario extends Activity {
if (params.mConnectAdapter) {
setAdapter(mListView);
}
-
+
mListView.setItemsCanFocus(mItemsFocusable);
if (mStartingSelectionPosition >= 0) {
mListView.setSelection(mStartingSelectionPosition);
@@ -360,11 +361,12 @@ public abstract class ListScenario extends Activity {
positionClicked(position);
}
});
-
+
// set the fading edge length porportionally to the screen
// height for test stability
if (params.mFadingEdgeScreenSizeFactor != null) {
- mListView.setFadingEdgeLength((int) (params.mFadingEdgeScreenSizeFactor * mScreenHeight));
+ mListView.setFadingEdgeLength(
+ (int) (params.mFadingEdgeScreenSizeFactor * mScreenHeight));
} else {
mListView.setFadingEdgeLength((int) ((64.0 / 480) * mScreenHeight));
}
@@ -403,6 +405,7 @@ public abstract class ListScenario extends Activity {
mLinearLayout.addView(mListView);
setContentView(mLinearLayout);
}
+ mLinearLayout.restoreDefaultFocus();
}
/**
@@ -426,7 +429,7 @@ public abstract class ListScenario extends Activity {
}
});
}
-
+
/**
* @return The newly created ListView widget.
*/
@@ -440,16 +443,16 @@ public abstract class ListScenario extends Activity {
protected Params createParams() {
return new Params();
}
-
+
/**
* Sets an adapter on a ListView.
- *
+ *
* @param listView The ListView to set the adapter on.
*/
protected void setAdapter(ListView listView) {
listView.setAdapter(new MyAdapter());
}
-
+
/**
* Read in and validate all of the params passed in by the scenario.
* @param params
@@ -525,7 +528,7 @@ public abstract class ListScenario extends Activity {
if (!mIncludeHeader) {
throw new IllegalArgumentException("no header above list");
}
- mHeaderTextView.setText(value);
+ mHeaderTextView.setText(value);
}
/**
@@ -543,12 +546,12 @@ public abstract class ListScenario extends Activity {
}
/**
- * Convert a non-null view.
+ * Convert a non-null view.
*/
public View convertView(int position, View convertView, ViewGroup parent) {
return ListItemFactory.convertText(convertView, getValueAtPosition(position), position);
}
-
+
public void setClickedPosition(int clickedPosition) {
mClickedPosition = clickedPosition;
}
@@ -580,7 +583,7 @@ public abstract class ListScenario extends Activity {
}
});
}
-
+
/**
* Return an item type for the specified position in the adapter. Override if your
* adapter creates more than one type.
@@ -596,7 +599,7 @@ public abstract class ListScenario extends Activity {
public int getViewTypeCount() {
return 1;
}
-
+
/**
* @return The number of times convertView failed
*/
@@ -647,7 +650,7 @@ public abstract class ListScenario extends Activity {
}
return result;
}
-
+
@Override
public int getItemViewType(int position) {
return ListScenario.this.getItemViewType(position);
diff --git a/core/tests/coretests/src/android/view/FocusFinderTest.java b/core/tests/coretests/src/android/view/FocusFinderTest.java
index 6f1dd7c40184..2732a04b44d5 100644
--- a/core/tests/coretests/src/android/view/FocusFinderTest.java
+++ b/core/tests/coretests/src/android/view/FocusFinderTest.java
@@ -117,8 +117,8 @@ public class FocusFinderTest extends AndroidTestCase {
// at edge
rect2.offset(0, 1);
- assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2);
- assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2);
+ assertBeamsDontOverlap(View.FOCUS_LEFT, rect1, rect2);
+ assertBeamsDontOverlap(View.FOCUS_RIGHT, rect1, rect2);
// just beyond
rect2.offset(0, 1);
@@ -133,8 +133,8 @@ public class FocusFinderTest extends AndroidTestCase {
// at top edge
rect2.offset(0, -1);
- assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2);
- assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2);
+ assertBeamsDontOverlap(View.FOCUS_LEFT, rect1, rect2);
+ assertBeamsDontOverlap(View.FOCUS_RIGHT, rect1, rect2);
// just beyond top edge
rect2.offset(0, -1);
@@ -154,8 +154,8 @@ public class FocusFinderTest extends AndroidTestCase {
// at edge
rect2.offset(1, 0);
- assertBeamsOverlap(View.FOCUS_UP, rect1, rect2);
- assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2);
+ assertBeamsDontOverlap(View.FOCUS_UP, rect1, rect2);
+ assertBeamsDontOverlap(View.FOCUS_DOWN, rect1, rect2);
// just beyond
rect2.offset(1, 0);
@@ -170,8 +170,8 @@ public class FocusFinderTest extends AndroidTestCase {
// at edge
rect2.offset(-1, 0);
- assertBeamsOverlap(View.FOCUS_UP, rect1, rect2);
- assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2);
+ assertBeamsDontOverlap(View.FOCUS_UP, rect1, rect2);
+ assertBeamsDontOverlap(View.FOCUS_DOWN, rect1, rect2);
// just beyond edge
rect2.offset(-1, 0);
@@ -445,7 +445,7 @@ public class FocusFinderTest extends AndroidTestCase {
assertBetterCandidate(View.FOCUS_LEFT,
// L T R B
new Rect(150, 0, 200, 50), // src
- new Rect(0, 50, 50, 50), // better, (way further, but in beam)
+ new Rect(0, 0, 50, 50), // better, (way further, but in beam)
new Rect(49, 99, 149, 101)); // worse, even though it is closer
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 2a6c22e21487..41686fa135e0 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -18,6 +18,8 @@ package android.view.textclassifier;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import android.os.LocaleList;
@@ -32,6 +34,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Collection;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TextClassificationManagerTest {
@@ -174,6 +178,23 @@ public class TextClassificationManagerTest {
}
@Test
+ public void testGenerateLinks() {
+ if (isTextClassifierDisabled()) return;
+
+ checkGenerateLinksFindsLink(
+ "The number is +12122537077. See you tonight!",
+ "+12122537077",
+ TextClassifier.TYPE_PHONE);
+
+ checkGenerateLinksFindsLink(
+ "The address is 1600 Amphitheater Parkway, Mountain View, CA. See you tonight!",
+ "1600 Amphitheater Parkway, Mountain View, CA",
+ TextClassifier.TYPE_ADDRESS);
+
+ // TODO: Add more entity types when the model supports them.
+ }
+
+ @Test
public void testSetTextClassifier() {
TextClassifier classifier = mock(TextClassifier.class);
mTcm.setTextClassifier(classifier);
@@ -184,6 +205,24 @@ public class TextClassificationManagerTest {
return mClassifier == TextClassifier.NO_OP;
}
+ private void checkGenerateLinksFindsLink(String text, String classifiedText, String type) {
+ assertTrue(text.contains(classifiedText));
+ int startIndex = text.indexOf(classifiedText);
+ int endIndex = startIndex + classifiedText.length();
+
+ Collection<TextLinks.TextLink> links = mClassifier.generateLinks(text, null).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);
+ return;
+ }
+ }
+ fail(); // Subsequence was not identified.
+ }
+
private static Matcher<TextSelection> isTextSelection(
final int startIndex, final int endIndex, final String type) {
return new BaseMatcher<TextSelection>() {
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index bbdbdb13b3f7..0e460b9ed2b2 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -49,6 +49,11 @@ import static junit.framework.Assert.assertTrue;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.is;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.Activity;
import android.app.Instrumentation;
@@ -632,16 +637,57 @@ public class TextViewActivityTest {
}
@Test
- public void testSetSelectionAndActionMode() throws Throwable {
- final String text = "abc def";
+ public void testSelectionHandles_visibleEvenWithEmptyMenu() {
+ ((TextView) mActivity.findViewById(R.id.textview)).setCustomSelectionActionModeCallback(
+ new ActionMode.Callback() {
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ menu.clear();
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ menu.clear();
+ return true;
+ }
+
+ @Override
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ return false;
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {}
+ });
+ final String text = "abcd efg hijk lmn";
onView(withId(R.id.textview)).perform(replaceText(text));
+ onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('f')));
+
+ onHandleView(com.android.internal.R.id.selection_start_handle)
+ .check(matches(isDisplayed()));
+ onHandleView(com.android.internal.R.id.selection_end_handle)
+ .check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void testSetSelectionAndActionMode() throws Throwable {
final TextView textView = mActivity.findViewById(R.id.textview);
+ final ActionMode.Callback amCallback = mock(ActionMode.Callback.class);
+ when(amCallback.onCreateActionMode(any(ActionMode.class), any(Menu.class)))
+ .thenReturn(true);
+ when(amCallback.onPrepareActionMode(any(ActionMode.class), any(Menu.class)))
+ .thenReturn(true);
+ textView.setCustomSelectionActionModeCallback(amCallback);
+
+ final String text = "abc def";
+ onView(withId(R.id.textview)).perform(replaceText(text));
mActivityRule.runOnUiThread(
() -> Selection.setSelection((Spannable) textView.getText(), 0, 3));
mInstrumentation.waitForIdleSync();
// Don't automatically start action mode.
- // TODO: Implement assertActionModeNotStarted()
+ verify(amCallback, never()).onCreateActionMode(any(ActionMode.class), any(Menu.class));
// Make sure that "Select All" is included in the selection action mode when the entire text
// is not selected.
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('e')));
diff --git a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
index b6986d5c5a68..0355f82506d7 100644
--- a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
@@ -48,6 +48,7 @@ import org.hamcrest.TypeSafeMatcher;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Predicate;
/**
* Espresso utility methods for the floating toolbar.
@@ -175,31 +176,10 @@ public class FloatingToolbarEspressoUtils {
* @throws AssertionError if the assertion fails
*/
public static void assertFloatingToolbarDoesNotContainItem(String itemLabel) {
- onFloatingToolBar().check(matches(new TypeSafeMatcher<View>() {
- @Override
- public boolean matchesSafely(View view) {
- return doesNotContainItem(view);
- }
-
- @Override
- public void describeTo(Description description) {}
-
- private boolean doesNotContainItem(View view) {
- if (view.getTag() instanceof MenuItem) {
- if (itemLabel.equals(((MenuItem) view.getTag()).getTitle().toString())) {
- return false;
- }
- } else if (view instanceof ViewGroup) {
- ViewGroup viewGroup = (ViewGroup) view;
- for (int i = 0; i < viewGroup.getChildCount(); i++) {
- if (doesNotContainItem(viewGroup.getChildAt(i))) {
- return false;
- }
- }
- }
- return true;
- }
- }));
+ final Predicate<View> hasMenuItemLabel = view ->
+ view.getTag() instanceof MenuItem
+ && itemLabel.equals(((MenuItem) view.getTag()).getTitle().toString());
+ assertFloatingToolbarMenuItem(hasMenuItemLabel, false);
}
/**
@@ -209,23 +189,30 @@ public class FloatingToolbarEspressoUtils {
* @throws AssertionError if the assertion fails
*/
public static void assertFloatingToolbarDoesNotContainItem(final int menuItemId) {
+ final Predicate<View> hasMenuItemId = view ->
+ view.getTag() instanceof MenuItem
+ && ((MenuItem) view.getTag()).getItemId() == menuItemId;
+ assertFloatingToolbarMenuItem(hasMenuItemId, false);
+ }
+
+ private static void assertFloatingToolbarMenuItem(
+ final Predicate<View> predicate, final boolean positiveAssertion) {
onFloatingToolBar().check(matches(new TypeSafeMatcher<View>() {
@Override
public boolean matchesSafely(View view) {
- return !hasMenuItemWithSpecifiedId(view);
+ return positiveAssertion == containsItem(view);
}
@Override
public void describeTo(Description description) {}
- private boolean hasMenuItemWithSpecifiedId(View view) {
- if (view.getTag() instanceof MenuItem
- && ((MenuItem) view.getTag()).getItemId() == menuItemId) {
+ private boolean containsItem(View view) {
+ if (predicate.test(view)) {
return true;
} else if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
- if (hasMenuItemWithSpecifiedId(viewGroup.getChildAt(i))) {
+ if (containsItem(viewGroup.getChildAt(i))) {
return true;
}
}
diff --git a/core/tests/coretests/src/android/widget/layout/linear/LLOfTwoFocusableInTouchMode.java b/core/tests/coretests/src/android/widget/layout/linear/LLOfTwoFocusableInTouchMode.java
index 1ba56ba99717..0d8d834fd48b 100644
--- a/core/tests/coretests/src/android/widget/layout/linear/LLOfTwoFocusableInTouchMode.java
+++ b/core/tests/coretests/src/android/widget/layout/linear/LLOfTwoFocusableInTouchMode.java
@@ -16,12 +16,12 @@
package android.widget.layout.linear;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
+import com.android.frameworks.coretests.R;
+
public class LLOfTwoFocusableInTouchMode extends Activity {
private View mButton1;
@@ -63,6 +63,7 @@ public class LLOfTwoFocusableInTouchMode extends Activity {
mB3Fired = true;
}
});
+ getWindow().getDecorView().restoreDefaultFocus();
}
public View getButton1() {
diff --git a/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java b/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
index 98fbed31eabf..9e49719c6527 100644
--- a/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
+++ b/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
@@ -16,10 +16,9 @@
package android.widget.listview;
-import android.util.InternalSelectionView;
-
import android.app.Activity;
import android.os.Bundle;
+import android.util.InternalSelectionView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
@@ -80,6 +79,7 @@ public class AdjacentListsWithAdjacentISVsInside extends Activity {
setContentView(combineAdjacent(mLeftListView, mRightListView));
+ getWindow().getDecorView().restoreDefaultFocus();
}
private static View combineAdjacent(View... views) {
diff --git a/core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java b/core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java
index 8f971bb4d972..edc60b58e9d0 100644
--- a/core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java
+++ b/core/tests/coretests/src/android/widget/listview/focus/ListHorizontalFocusWithinItemWinsTest.java
@@ -16,15 +16,12 @@
package android.widget.listview.focus;
-import android.widget.listview.ListHorizontalFocusWithinItemWins;
-
import android.test.ActivityInstrumentationTestCase;
import android.test.suitebuilder.annotation.MediumTest;
-import android.view.FocusFinder;
import android.view.KeyEvent;
-import android.view.View;
import android.widget.Button;
import android.widget.ListView;
+import android.widget.listview.ListHorizontalFocusWithinItemWins;
public class ListHorizontalFocusWithinItemWinsTest extends ActivityInstrumentationTestCase<ListHorizontalFocusWithinItemWins> {
@@ -51,12 +48,6 @@ public class ListHorizontalFocusWithinItemWinsTest extends ActivityInstrumentati
public void testPreconditions() {
assertEquals("list position", 0, mListView.getSelectedItemPosition());
assertTrue("mTopLeftButton.isFocused()", mTopLeftButton.isFocused());
- assertEquals("global focus search to right from top left is bottom middle",
- mBottomMiddleButton,
- FocusFinder.getInstance().findNextFocus(mListView, mTopLeftButton, View.FOCUS_RIGHT));
- assertEquals("global focus search to left from top right is bottom middle",
- mBottomMiddleButton,
- FocusFinder.getInstance().findNextFocus(mListView, mTopRightButton, View.FOCUS_LEFT));
}
@MediumTest
diff --git a/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java b/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java
index bd6977efed0f..5a6110c08116 100644
--- a/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java
+++ b/core/tests/coretests/src/android/widget/touchmode/TouchModeFocusChangeTest.java
@@ -16,7 +16,6 @@
package android.widget.touchmode;
-import android.widget.layout.linear.LLOfButtons1;
import static android.util.TouchModeFlexibleAsserts.assertInTouchModeAfterClick;
import static android.util.TouchModeFlexibleAsserts.assertInTouchModeAfterTap;
import static android.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
@@ -25,6 +24,8 @@ import android.test.ActivityInstrumentationTestCase;
import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
import android.widget.Button;
+import android.widget.layout.linear.LLOfButtons1;
+
/**
* Make sure focus isn't kept by buttons when entering touch mode.
@@ -52,7 +53,6 @@ public class TouchModeFocusChangeTest extends ActivityInstrumentationTestCase<LL
@MediumTest
public void testPreconditions() {
assertFalse("we should not be in touch mode", mActivity.isInTouchMode());
- assertTrue("top button should have focus", mFirstButton.isFocused());
}
@MediumTest
diff --git a/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
index dfe851104e1c..3919fdd7082f 100644
--- a/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
@@ -23,11 +23,11 @@ import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
+import android.text.Layout;
import android.view.LayoutInflater;
import android.view.View.MeasureSpec;
import com.android.frameworks.coretests.R;
-import com.google.common.base.Function;
import org.junit.Before;
import org.junit.Test;
@@ -52,33 +52,28 @@ public class MessagingLinearLayoutTest {
@Test
public void testSingleChild() {
- FakeImageFloatingTextView child = fakeChild((i) -> 3);
+ FakeImageFloatingTextView child = fakeChild(3);
- mView.setNumIndentLines(2);
mView.addView(child);
mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
- assertEquals(3, child.getNumIndentLines());
assertFalse(child.isHidden());
assertEquals(150, mView.getMeasuredHeight());
}
@Test
public void testLargeSmall() {
- FakeImageFloatingTextView child1 = fakeChild((i) -> 3);
- FakeImageFloatingTextView child2 = fakeChild((i) -> 1);
+ FakeImageFloatingTextView child1 = fakeChild(3);
+ FakeImageFloatingTextView child2 = fakeChild(1);
- mView.setNumIndentLines(2);
mView.addView(child1);
mView.addView(child2);
mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
- assertEquals(3, child1.getNumIndentLines());
- assertEquals(0, child2.getNumIndentLines());
assertFalse("child1 should not be hidden", child1.isHidden());
assertFalse("child2 should not be hidden", child2.isHidden());
assertEquals(205, mView.getMeasuredHeight());
@@ -86,18 +81,15 @@ public class MessagingLinearLayoutTest {
@Test
public void testSmallSmall() {
- FakeImageFloatingTextView child1 = fakeChild((i) -> 1);
- FakeImageFloatingTextView child2 = fakeChild((i) -> 1);
+ FakeImageFloatingTextView child1 = fakeChild(1);
+ FakeImageFloatingTextView child2 = fakeChild(1);
- mView.setNumIndentLines(2);
mView.addView(child1);
mView.addView(child2);
mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
- assertEquals(2, child1.getNumIndentLines());
- assertEquals(1, child2.getNumIndentLines());
assertFalse("child1 should not be hidden", child1.isHidden());
assertFalse("child2 should not be hidden", child2.isHidden());
assertEquals(105, mView.getMeasuredHeight());
@@ -105,17 +97,15 @@ public class MessagingLinearLayoutTest {
@Test
public void testLargeLarge() {
- FakeImageFloatingTextView child1 = fakeChild((i) -> 7);
- FakeImageFloatingTextView child2 = fakeChild((i) -> 7);
+ FakeImageFloatingTextView child1 = fakeChild(7);
+ FakeImageFloatingTextView child2 = fakeChild(7);
- mView.setNumIndentLines(2);
mView.addView(child1);
mView.addView(child2);
mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
- assertEquals(3, child2.getNumIndentLines());
assertTrue("child1 should be hidden", child1.isHidden());
assertFalse("child2 should not be hidden", child2.isHidden());
assertEquals(350, mView.getMeasuredHeight());
@@ -123,10 +113,9 @@ public class MessagingLinearLayoutTest {
@Test
public void testLargeSmall_largeWrapsWith3indentbutNotFullHeight_andHitsMax() {
- FakeImageFloatingTextView child1 = fakeChild((i) -> i > 2 ? 7 : 6);
- FakeImageFloatingTextView child2 = fakeChild((i) -> 1);
+ FakeImageFloatingTextView child1 = fakeChild(7);
+ FakeImageFloatingTextView child2 = fakeChild(1);
- mView.setNumIndentLines(2);
mView.addView(child1);
mView.addView(child2);
@@ -135,51 +124,18 @@ public class MessagingLinearLayoutTest {
assertFalse("child1 should not be hidden", child1.isHidden());
assertFalse("child2 should not be hidden", child2.isHidden());
- assertEquals(355, mView.getMeasuredHeight());
- assertEquals(3, child1.getNumIndentLines());
- assertEquals(0, child2.getNumIndentLines());
+ assertEquals(355, mView.getMeasuredHeight());;
}
- @Test
- public void testLargeSmall_largeWrapsWith3indentbutnot3() {
- FakeImageFloatingTextView child1 = fakeChild((i) -> i > 2 ? 4 : 3);
- FakeImageFloatingTextView child2 = fakeChild((i) -> 1);
-
- mView.setNumIndentLines(2);
- mView.addView(child1);
- mView.addView(child2);
-
- mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
- mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
-
- assertFalse("child1 should not be hidden", child1.isHidden());
- assertFalse("child2 should not be hidden", child2.isHidden());
- assertEquals(255, mView.getMeasuredHeight());
- assertEquals(3, child1.getNumIndentLines());
- assertEquals(0, child2.getNumIndentLines());
- }
-
- private class FakeImageFloatingTextView extends ImageFloatingTextView {
+ private class FakeImageFloatingTextView extends MessagingMessage {
public static final int LINE_HEIGHT = 50;
- private final Function<Integer, Integer> mLinesForIndent;
- private int mNumIndentLines;
+ private final int mNumLines;
public FakeImageFloatingTextView(Context context,
- Function<Integer, Integer> linesForIndent) {
+ int linesForIndent) {
super(context, null, 0, 0);
- mLinesForIndent = linesForIndent;
- }
-
- @Override
- public boolean setNumIndentLines(int lines) {
- boolean changed = (mNumIndentLines != lines);
- mNumIndentLines = lines;
- return changed;
- }
-
- public int getNumIndentLines() {
- return mNumIndentLines;
+ mNumLines = linesForIndent;
}
@Override
@@ -195,6 +151,20 @@ public class MessagingLinearLayoutTest {
heightMeasureSpec)));
}
+ public int getMeasuredType() {
+ boolean measuredTooSmall = getMeasuredHeight()
+ < getLayoutHeight() + getPaddingTop() + getPaddingBottom();
+ if (measuredTooSmall) {
+ return MEASURED_TOO_SMALL;
+ } else {
+ if (getMeasuredHeight() == getDesiredHeight()) {
+ return MEASURED_NORMAL;
+ } else {
+ return MEASURED_SHORTENED;
+ }
+ }
+ }
+
private int clampToMultiplesOfLineHeight(int size) {
if (size <= LINE_HEIGHT) {
return size;
@@ -204,7 +174,7 @@ public class MessagingLinearLayoutTest {
@Override
public int getLineCount() {
- return mLinesForIndent.apply(mNumIndentLines);
+ return mNumLines;
}
public int getDesiredHeight() {
@@ -229,7 +199,7 @@ public class MessagingLinearLayoutTest {
}
}
- private FakeImageFloatingTextView fakeChild(Function<Integer,Integer> linesForIndent) {
- return new FakeImageFloatingTextView(mContext, linesForIndent);
+ private FakeImageFloatingTextView fakeChild(int numLines) {
+ return new FakeImageFloatingTextView(mContext, numLines);
}
}
diff --git a/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java b/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java
index ebfa45c9bbc6..c5d175b4245f 100644
--- a/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java
+++ b/core/tests/featureflagtests/src/android/util/FeatureFlagUtilsTest.java
@@ -20,7 +20,9 @@ import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import android.content.Context;
import android.os.SystemProperties;
+import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
@@ -35,8 +37,11 @@ public class FeatureFlagUtilsTest {
private static final String TEST_FEATURE_NAME = "feature_foobar";
+ private Context mContext;
+
@Before
public void setUp() {
+ mContext = InstrumentationRegistry.getTargetContext();
cleanup();
}
@@ -54,7 +59,7 @@ public class FeatureFlagUtilsTest {
public void testGetFlag_enabled_shouldReturnTrue() {
SystemProperties.set(FeatureFlagUtils.FFLAG_PREFIX + TEST_FEATURE_NAME, "true");
- assertTrue(FeatureFlagUtils.isEnabled(TEST_FEATURE_NAME));
+ assertTrue(FeatureFlagUtils.isEnabled(mContext, TEST_FEATURE_NAME));
}
@Test
@@ -62,12 +67,12 @@ public class FeatureFlagUtilsTest {
SystemProperties.set(FeatureFlagUtils.FFLAG_PREFIX + TEST_FEATURE_NAME, "false");
SystemProperties.set(FeatureFlagUtils.FFLAG_OVERRIDE_PREFIX + TEST_FEATURE_NAME, "true");
- assertTrue(FeatureFlagUtils.isEnabled(TEST_FEATURE_NAME));
+ assertTrue(FeatureFlagUtils.isEnabled(mContext, TEST_FEATURE_NAME));
}
@Test
public void testSetEnabled_shouldSetOverrideFlag() {
- assertFalse(FeatureFlagUtils.isEnabled(TEST_FEATURE_NAME));
+ assertFalse(FeatureFlagUtils.isEnabled(mContext, TEST_FEATURE_NAME));
FeatureFlagUtils.setEnabled(TEST_FEATURE_NAME, true);
@@ -79,7 +84,7 @@ public class FeatureFlagUtilsTest {
@Test
public void testGetFlag_notSet_shouldReturnFalse() {
- assertFalse(FeatureFlagUtils.isEnabled(TEST_FEATURE_NAME));
+ assertFalse(FeatureFlagUtils.isEnabled(mContext, TEST_FEATURE_NAME));
}
}
diff --git a/core/tests/webkit/apk_with_native_libs/Android.mk b/core/tests/webkit/apk_with_native_libs/Android.mk
index 7c6c36e0a6a2..c51de6a7897e 100644
--- a/core/tests/webkit/apk_with_native_libs/Android.mk
+++ b/core/tests/webkit/apk_with_native_libs/Android.mk
@@ -20,6 +20,7 @@ MY_MODULE_TAGS := optional
MY_JNI_SHARED_LIBRARIES := libwebviewtest_jni
MY_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
MY_SRC_FILES := $(call all-java-files-under, src)
+MY_CFLAGS := -Wall -Werror
MY_SDK_VERSION := system_current
MY_PROGUARD_ENABLED := disabled
MY_MULTILIB := both
@@ -40,6 +41,7 @@ LOCAL_MODULE_TAGS := $(MY_MODULE_TAGS)
LOCAL_JNI_SHARED_LIBRARIES := $(MY_JNI_SHARED_LIBRARIES)
LOCAL_MODULE_PATH := $(MY_MODULE_PATH)
LOCAL_SRC_FILES := $(MY_SRC_FILES)
+LOCAL_CFLAGS := $(MY_CFLAGS)
LOCAL_SDK_VERSION := $(MY_SDK_VERSION)
LOCAL_PROGUARD_ENABLED := $(MY_PROGUARD_ENABLED)
LOCAL_MULTILIB := $(MY_MULTILIB)
@@ -59,6 +61,7 @@ LOCAL_MODULE_TAGS := $(MY_MODULE_TAGS)
LOCAL_JNI_SHARED_LIBRARIES := $(MY_JNI_SHARED_LIBRARIES)
LOCAL_MODULE_PATH := $(MY_MODULE_PATH)
LOCAL_SRC_FILES := $(MY_SRC_FILES)
+LOCAL_CFLAGS := $(MY_CFLAGS)
LOCAL_SDK_VERSION := $(MY_SDK_VERSION)
LOCAL_PROGUARD_ENABLED := $(MY_PROGUARD_ENABLED)
LOCAL_MULTILIB := $(MY_MULTILIB)
diff --git a/core/tests/webkit/apk_with_native_libs/jni/WebViewTestJniOnLoad.cpp b/core/tests/webkit/apk_with_native_libs/jni/WebViewTestJniOnLoad.cpp
index 9b0502fc286d..0ced4ee12ac5 100644
--- a/core/tests/webkit/apk_with_native_libs/jni/WebViewTestJniOnLoad.cpp
+++ b/core/tests/webkit/apk_with_native_libs/jni/WebViewTestJniOnLoad.cpp
@@ -16,6 +16,6 @@
#include <jni.h>
-jint JNI_OnLoad(JavaVM *vm, void *reserved) {
+jint JNI_OnLoad(JavaVM * /*vm*/, void * /*reserved*/) {
return JNI_VERSION_1_4;
}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 2f9ae578ade1..161a0c2997e0 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -232,6 +232,7 @@ applications that come with the platform
<permission name="android.permission.BACKUP"/>
<permission name="android.permission.BATTERY_STATS"/>
<permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
+ <permission name="android.permission.CHANGE_APP_IDLE_STATE"/>
<permission name="android.permission.CHANGE_CONFIGURATION"/>
<permission name="android.permission.DELETE_PACKAGES"/>
<permission name="android.permission.FORCE_STOP_PACKAGES"/>
@@ -257,6 +258,11 @@ applications that come with the platform
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
</privapp-permissions>
+ <privapp-permissions package="com.android.settings.intelligence">
+ <permission name="android.permission.READ_SEARCH_INDEXABLES"/>
+ <permission name="android.permission.MODIFY_PHONE_STATE"/>
+ </privapp-permissions>
+
<privapp-permissions package="com.android.sharedstoragebackup">
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
</privapp-permissions>
@@ -266,6 +272,7 @@ applications that come with the platform
<permission name="android.permission.BACKUP"/>
<permission name="android.permission.BATTERY_STATS"/>
<permission name="android.permission.BIND_APPWIDGET"/>
+ <permission name="android.permission.CHANGE_APP_IDLE_STATE"/>
<permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
<permission name="android.permission.CHANGE_CONFIGURATION"/>
<permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
@@ -326,6 +333,7 @@ applications that come with the platform
<privapp-permissions package="com.android.systemui">
<permission name="android.permission.BATTERY_STATS"/>
<permission name="android.permission.BIND_APPWIDGET"/>
+ <permission name="android.permission.BIND_SLICE" />
<permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
<permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
<permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/>
diff --git a/data/keyboards/Vendor_045e_Product_02e0.kl b/data/keyboards/Vendor_045e_Product_02e0.kl
new file mode 100644
index 000000000000..1012fb1eb28d
--- /dev/null
+++ b/data/keyboards/Vendor_045e_Product_02e0.kl
@@ -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.
+
+#
+# Xbox Wireless Controller
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 0x132 BUTTON_X
+key 0x130 BUTTON_A
+key 0x131 BUTTON_B
+key 0x133 BUTTON_Y
+
+key 0x134 BUTTON_L1
+key 0x135 BUTTON_R1
+
+# LT axis
+axis 0x02 LTRIGGER
+# RT axis
+axis 0x05 RTRIGGER
+
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+# Right Analog Stick
+axis 0x03 Z
+axis 0x04 RZ
+
+# Left stick click
+key 0x138 BUTTON_THUMBL
+# Right stick click
+key 0x139 BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 0x136 BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 0x137 BUTTON_START
+
+# Xbox key
+key 0x8b HOME \ No newline at end of file
diff --git a/docs/html/reference/images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png b/docs/html/reference/images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png
new file mode 100644
index 000000000000..7578b48770fb
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png
new file mode 100644
index 000000000000..7b10f6b7c812
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png
new file mode 100644
index 000000000000..41972cfd71b9
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png
new file mode 100644
index 000000000000..d26600b37aca
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png
new file mode 100644
index 000000000000..1e7208ed79a2
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png
new file mode 100644
index 000000000000..ecef3ae7998e
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png
new file mode 100644
index 000000000000..a02fd893b286
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png
new file mode 100644
index 000000000000..c309ac5ea887
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png
new file mode 100644
index 000000000000..414fad49a919
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png
new file mode 100644
index 000000000000..c147a8729f17
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png
Binary files differ
diff --git a/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png
new file mode 100644
index 000000000000..4ce2125f3c91
--- /dev/null
+++ b/docs/html/reference/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png
Binary files differ
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 1a06a5683cd3..317144a21d32 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -88,7 +88,7 @@ public class Paint {
* A map from a string representation of the LocaleList to Minikin's language list ID.
*/
@GuardedBy("sCacheLock")
- private static final HashMap<String, Integer> sMinikinLangListIdCache = new HashMap<>();
+ private static final HashMap<String, Integer> sMinikinLocaleListIdCache = new HashMap<>();
/**
* @hide
@@ -1445,16 +1445,16 @@ public class Paint {
private void syncTextLocalesWithMinikin() {
final String languageTags = mLocales.toLanguageTags();
- final Integer minikinLangListId;
+ final Integer minikinLocaleListId;
synchronized (sCacheLock) {
- minikinLangListId = sMinikinLangListIdCache.get(languageTags);
- if (minikinLangListId == null) {
+ minikinLocaleListId = sMinikinLocaleListIdCache.get(languageTags);
+ if (minikinLocaleListId == null) {
final int newID = nSetTextLocales(mNativePaint, languageTags);
- sMinikinLangListIdCache.put(languageTags, newID);
+ sMinikinLocaleListIdCache.put(languageTags, newID);
return;
}
}
- nSetTextLocalesByMinikinLangListId(mNativePaint, minikinLangListId.intValue());
+ nSetTextLocalesByMinikinLocaleListId(mNativePaint, minikinLocaleListId.intValue());
}
/**
@@ -2918,8 +2918,8 @@ public class Paint {
@CriticalNative
private static native void nSetTextAlign(long paintPtr, int align);
@CriticalNative
- private static native void nSetTextLocalesByMinikinLangListId(long paintPtr,
- int mMinikinLangListId);
+ private static native void nSetTextLocalesByMinikinLocaleListId(long paintPtr,
+ int mMinikinLocaleListId);
@CriticalNative
private static native void nSetShadowLayer(long paintPtr,
float radius, float dx, float dy, int color);
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 3dc928de60df..aff942da78d1 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -475,6 +475,19 @@ public final class Rect implements Parcelable {
}
/**
+ * If the specified rectangle intersects this rectangle, set this rectangle to that
+ * intersection, otherwise set this rectangle to the empty rectangle.
+ * @see #inset(int, int, int, int) but without checking if the rects overlap.
+ * @hide
+ */
+ public void intersectUnchecked(Rect other) {
+ left = Math.max(left, other.left);
+ top = Math.max(top, other.top);
+ right = Math.min(right, other.right);
+ bottom = Math.min(bottom, other.bottom);
+ }
+
+ /**
* If rectangles a and b intersect, return true and set this rectangle to
* that intersection, otherwise return false and do not change this
* rectangle. No check is performed to see if either rectangle is empty.
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index c4bb72c71d17..635432da7942 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -28,6 +28,8 @@ interface IKeyChainService {
String requestPrivateKey(String alias);
byte[] getCertificate(String alias);
byte[] getCaCertificates(String alias);
+ boolean isUserSelectable(String alias);
+ void setUserSelectable(String alias, boolean isUserSelectable);
// APIs used by CertInstaller and DevicePolicyManager
String installCaCertificate(in byte[] caCertificate);
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 7e959a87da5d..399dddd71a2a 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -20,6 +20,7 @@ import android.app.ActivityThread;
import android.app.Application;
import android.app.KeyguardManager;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Binder;
import android.os.IBinder;
@@ -53,7 +54,7 @@ import java.util.Locale;
public class KeyStore {
private static final String TAG = "KeyStore";
- // ResponseCodes
+ // ResponseCodes - see system/security/keystore/include/keystore/keystore.h
public static final int NO_ERROR = 1;
public static final int LOCKED = 2;
public static final int UNINITIALIZED = 3;
@@ -167,10 +168,14 @@ public class KeyStore {
public byte[] get(String key, int uid) {
try {
+ key = key != null ? key : "";
return mBinder.get(key, uid);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
+ } catch (android.os.ServiceSpecificException e) {
+ Log.w(TAG, "KeyStore exception", e);
+ return null;
}
}
@@ -184,6 +189,9 @@ public class KeyStore {
public int insert(String key, byte[] value, int uid, int flags) {
try {
+ if (value == null) {
+ value = new byte[0];
+ }
return mBinder.insert(key, value, uid, flags);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
@@ -227,6 +235,9 @@ public class KeyStore {
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
+ } catch (android.os.ServiceSpecificException e) {
+ Log.w(TAG, "KeyStore exception", e);
+ return null;
}
}
@@ -275,6 +286,7 @@ public class KeyStore {
*/
public boolean unlock(int userId, String password) {
try {
+ password = password != null ? password : "";
mError = mBinder.unlock(userId, password);
return mError == NO_ERROR;
} catch (RemoteException e) {
@@ -329,16 +341,25 @@ public class KeyStore {
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
+ } catch (android.os.ServiceSpecificException e) {
+ Log.w(TAG, "KeyStore exception", e);
+ return null;
}
+
}
public boolean verify(String key, byte[] data, byte[] signature) {
try {
+ signature = signature != null ? signature : new byte[0];
return mBinder.verify(key, data, signature) == NO_ERROR;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return false;
+ } catch (android.os.ServiceSpecificException e) {
+ Log.w(TAG, "KeyStore exception", e);
+ return false;
}
+
}
public String grant(String key, int uid) {
@@ -431,6 +452,8 @@ public class KeyStore {
public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
int flags, KeyCharacteristics outCharacteristics) {
try {
+ entropy = entropy != null ? entropy : new byte[0];
+ args = args != null ? args : new KeymasterArguments();
return mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
@@ -446,6 +469,8 @@ public class KeyStore {
public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
int uid, KeyCharacteristics outCharacteristics) {
try {
+ clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
+ appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
return mBinder.getKeyCharacteristics(alias, clientId, appId, uid, outCharacteristics);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
@@ -477,6 +502,8 @@ public class KeyStore {
public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
KeymasterBlob appId, int uid) {
try {
+ clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
+ appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
return mBinder.exportKey(alias, format, clientId, appId, uid);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
@@ -491,6 +518,8 @@ public class KeyStore {
public OperationResult begin(String alias, int purpose, boolean pruneable,
KeymasterArguments args, byte[] entropy, int uid) {
try {
+ args = args != null ? args : new KeymasterArguments();
+ entropy = entropy != null ? entropy : new byte[0];
return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
@@ -500,11 +529,15 @@ public class KeyStore {
public OperationResult begin(String alias, int purpose, boolean pruneable,
KeymasterArguments args, byte[] entropy) {
+ entropy = entropy != null ? entropy : new byte[0];
+ args = args != null ? args : new KeymasterArguments();
return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
}
public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
try {
+ arguments = arguments != null ? arguments : new KeymasterArguments();
+ input = input != null ? input : new byte[0];
return mBinder.update(token, arguments, input);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
@@ -515,6 +548,9 @@ public class KeyStore {
public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature,
byte[] entropy) {
try {
+ arguments = arguments != null ? arguments : new KeymasterArguments();
+ entropy = entropy != null ? entropy : new byte[0];
+ signature = signature != null ? signature : new byte[0];
return mBinder.finish(token, arguments, signature, entropy);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
@@ -631,6 +667,12 @@ public class KeyStore {
public int attestKey(
String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
try {
+ if (params == null) {
+ params = new KeymasterArguments();
+ }
+ if (outChain == null) {
+ outChain = new KeymasterCertificateChain();
+ }
return mBinder.attestKey(alias, params, outChain);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
@@ -640,6 +682,12 @@ public class KeyStore {
public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) {
try {
+ if (params == null) {
+ params = new KeymasterArguments();
+ }
+ if (outChain == null) {
+ outChain = new KeymasterCertificateChain();
+ }
return mBinder.attestDeviceIds(params, outChain);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
@@ -762,6 +810,10 @@ public class KeyStore {
}
private long getFingerprintOnlySid() {
+ final PackageManager packageManager = mContext.getPackageManager();
+ if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+ return 0;
+ }
FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
if (fingerprintManager == null) {
return 0;
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
index bec22c934fc6..4c150c8f8a23 100644
--- a/legacy-test/Android.mk
+++ b/legacy-test/Android.mk
@@ -146,6 +146,7 @@ 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
diff --git a/legacy-test/src/com/android/internal/util/Predicate.java b/legacy-test/src/com/android/internal/util/Predicate.java
index 1b5eaff67b87..e87f489f4670 100644
--- a/legacy-test/src/com/android/internal/util/Predicate.java
+++ b/legacy-test/src/com/android/internal/util/Predicate.java
@@ -27,6 +27,7 @@ package com.android.internal.util;
* strongly encouraged to state this fact clearly in their API documentation.
*
* @deprecated Use {@code java.util.function.Predicate} instead.
+ * This must not be used outside frameworks/base/test-runner.
*/
@Deprecated
public interface Predicate<T> {
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 5484cf048468..251b2e773cfb 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -98,6 +98,9 @@ cc_library {
enabled: true,
},
},
+ sanitize: {
+ blacklist: "libandroidfw_blacklist.txt",
+ },
}
common_test_libs = [
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 17de8fa1e7a5..3fe75cffaa71 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -812,7 +812,13 @@ const char* ResStringPool::string8At(size_t idx, size_t* outLen) const
*outLen = encLen;
if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
- return (const char*)str;
+ // Reject malformed (non null-terminated) strings
+ if (str[encLen] != 0x00) {
+ ALOGW("Bad string block: string #%d is not null-terminated",
+ (int)idx);
+ return NULL;
+ }
+ return (const char*)str;
} else {
ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
(int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
@@ -1868,10 +1874,7 @@ void ResTable_config::swapHtoD() {
/* static */ inline int compareLocales(const ResTable_config &l, const ResTable_config &r) {
if (l.locale != r.locale) {
- // NOTE: This is the old behaviour with respect to comparison orders.
- // The diff value here doesn't make much sense (given our bit packing scheme)
- // but it's stable, and that's all we need.
- return l.locale - r.locale;
+ return (l.locale > r.locale) ? 1 : -1;
}
// The language & region are equal, so compare the scripts and variants.
@@ -1890,30 +1893,49 @@ void ResTable_config::swapHtoD() {
}
int ResTable_config::compare(const ResTable_config& o) const {
- int32_t diff = (int32_t)(imsi - o.imsi);
- if (diff != 0) return diff;
- diff = compareLocales(*this, o);
- if (diff != 0) return diff;
- diff = (int32_t)(screenType - o.screenType);
- if (diff != 0) return diff;
- diff = (int32_t)(input - o.input);
- if (diff != 0) return diff;
- diff = (int32_t)(screenSize - o.screenSize);
- if (diff != 0) return diff;
- diff = (int32_t)(version - o.version);
- if (diff != 0) return diff;
- diff = (int32_t)(screenLayout - o.screenLayout);
- if (diff != 0) return diff;
- diff = (int32_t)(screenLayout2 - o.screenLayout2);
- if (diff != 0) return diff;
- diff = (int32_t)(colorMode - o.colorMode);
- if (diff != 0) return diff;
- diff = (int32_t)(uiMode - o.uiMode);
- if (diff != 0) return diff;
- diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp);
- if (diff != 0) return diff;
- diff = (int32_t)(screenSizeDp - o.screenSizeDp);
- return (int)diff;
+ if (imsi != o.imsi) {
+ return (imsi > o.imsi) ? 1 : -1;
+ }
+
+ int32_t diff = compareLocales(*this, o);
+ if (diff < 0) {
+ return -1;
+ }
+ if (diff > 0) {
+ return 1;
+ }
+
+ if (screenType != o.screenType) {
+ return (screenType > o.screenType) ? 1 : -1;
+ }
+ if (input != o.input) {
+ return (input > o.input) ? 1 : -1;
+ }
+ if (screenSize != o.screenSize) {
+ return (screenSize > o.screenSize) ? 1 : -1;
+ }
+ if (version != o.version) {
+ return (version > o.version) ? 1 : -1;
+ }
+ if (screenLayout != o.screenLayout) {
+ return (screenLayout > o.screenLayout) ? 1 : -1;
+ }
+ if (screenLayout2 != o.screenLayout2) {
+ return (screenLayout2 > o.screenLayout2) ? 1 : -1;
+ }
+ if (colorMode != o.colorMode) {
+ return (colorMode > o.colorMode) ? 1 : -1;
+ }
+ if (uiMode != o.uiMode) {
+ return (uiMode > o.uiMode) ? 1 : -1;
+ }
+ if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
+ return (smallestScreenWidthDp > o.smallestScreenWidthDp) ? 1 : -1;
+ }
+ if (screenSizeDp != o.screenSizeDp) {
+ return (screenSizeDp > o.screenSizeDp) ? 1 : -1;
+ }
+ return 0;
}
int ResTable_config::compareLogical(const ResTable_config& o) const {
diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp
index 5abfc8ee917e..5d243da2097c 100644
--- a/libs/androidfw/ZipUtils.cpp
+++ b/libs/androidfw/ZipUtils.cpp
@@ -20,10 +20,11 @@
#define LOG_TAG "ziputil"
+#include "android-base/file.h"
#include <androidfw/ZipUtils.h>
-#include <androidfw/ZipFileRO.h>
#include <utils/Log.h>
#include <utils/Compat.h>
+#include <ziparchive/zip_archive.h>
#include <stdlib.h>
#include <string.h>
@@ -33,211 +34,121 @@
using namespace android;
-static inline unsigned long get4LE(const unsigned char* buf) {
- return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
-}
-
-
-static const unsigned long kReadBufSize = 32768;
-
-/*
- * Utility function that expands zip/gzip "deflate" compressed data
- * into a buffer.
- *
- * (This is a clone of the previous function, but it takes a FILE* instead
- * of an fd. We could pass fileno(fd) to the above, but we can run into
- * trouble when "fp" has a different notion of what fd's file position is.)
- *
- * "fp" is an open file positioned at the start of the "deflate" data
- * "buf" must hold at least "uncompressedLen" bytes.
- */
-/*static*/ template<typename T> bool inflateToBuffer(T& reader, void* buf,
- long uncompressedLen, long compressedLen)
-{
- bool result = false;
-
- z_stream zstream;
- int zerr;
- unsigned long compRemaining;
-
- assert(uncompressedLen >= 0);
- assert(compressedLen >= 0);
-
- compRemaining = compressedLen;
-
- /*
- * Initialize the zlib stream.
- */
- memset(&zstream, 0, sizeof(zstream));
- zstream.zalloc = Z_NULL;
- zstream.zfree = Z_NULL;
- zstream.opaque = Z_NULL;
- zstream.next_in = NULL;
- zstream.avail_in = 0;
- zstream.next_out = (Bytef*) buf;
- zstream.avail_out = uncompressedLen;
- zstream.data_type = Z_UNKNOWN;
-
- /*
- * Use the undocumented "negative window bits" feature to tell zlib
- * that there's no zlib header waiting for it.
- */
- zerr = inflateInit2(&zstream, -MAX_WBITS);
- if (zerr != Z_OK) {
- if (zerr == Z_VERSION_ERROR) {
- ALOGE("Installed zlib is not compatible with linked version (%s)\n",
- ZLIB_VERSION);
- } else {
- ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
- }
- goto bail;
+// TODO: This can go away once the only remaining usage in aapt goes away.
+class FileReader : public zip_archive::Reader {
+ public:
+ FileReader(FILE* fp) : Reader(), mFp(fp), mCurrentOffset(0) {
}
- /*
- * Loop while we have data.
- */
- do {
- unsigned long getSize;
-
- /* read as much as we can */
- if (zstream.avail_in == 0) {
- getSize = (compRemaining > kReadBufSize) ?
- kReadBufSize : compRemaining;
- ALOGV("+++ reading %ld bytes (%ld left)\n",
- getSize, compRemaining);
-
- unsigned char* nextBuffer = NULL;
- const unsigned long nextSize = reader.read(&nextBuffer, getSize);
-
- if (nextSize < getSize || nextBuffer == NULL) {
- ALOGD("inflate read failed (%ld vs %ld)\n", nextSize, getSize);
- goto z_bail;
+ bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
+ // Data is usually requested sequentially, so this helps avoid pointless
+ // fseeks every time we perform a read. There's an impedence mismatch
+ // here because the original API was designed around pread and pwrite.
+ if (offset != mCurrentOffset) {
+ if (fseek(mFp, offset, SEEK_SET) != 0) {
+ return false;
}
- compRemaining -= nextSize;
-
- zstream.next_in = nextBuffer;
- zstream.avail_in = nextSize;
+ mCurrentOffset = offset;
}
- /* uncompress the data */
- zerr = inflate(&zstream, Z_NO_FLUSH);
- if (zerr != Z_OK && zerr != Z_STREAM_END) {
- ALOGD("zlib inflate call failed (zerr=%d)\n", zerr);
- goto z_bail;
+ size_t read = fread(buf, 1, len, mFp);
+ if (read != len) {
+ return false;
}
- /* output buffer holds all, so no need to write the output */
- } while (zerr == Z_OK);
-
- assert(zerr == Z_STREAM_END); /* other errors should've been caught */
-
- if ((long) zstream.total_out != uncompressedLen) {
- ALOGW("Size mismatch on inflated file (%ld vs %ld)\n",
- zstream.total_out, uncompressedLen);
- goto z_bail;
+ mCurrentOffset += read;
+ return true;
}
- // success!
- result = true;
-
-z_bail:
- inflateEnd(&zstream); /* free up any allocated structures */
-
-bail:
- return result;
-}
-
-class FileReader {
-public:
- explicit FileReader(FILE* fp) :
- mFp(fp), mReadBuf(new unsigned char[kReadBufSize])
- {
- }
+ private:
+ FILE* mFp;
+ mutable uint32_t mCurrentOffset;
+};
- ~FileReader() {
- delete[] mReadBuf;
- }
+class FdReader : public zip_archive::Reader {
+ public:
+ explicit FdReader(int fd) : mFd(fd) {
+ }
- long read(unsigned char** nextBuffer, long readSize) const {
- *nextBuffer = mReadBuf;
- return fread(mReadBuf, 1, readSize, mFp);
- }
+ bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
+ return android::base::ReadFullyAtOffset(mFd, buf, len, static_cast<off_t>(offset));
+ }
- FILE* mFp;
- unsigned char* mReadBuf;
+ private:
+ const int mFd;
};
-class FdReader {
-public:
- explicit FdReader(int fd) :
- mFd(fd), mReadBuf(new unsigned char[kReadBufSize])
- {
- }
+class BufferReader : public zip_archive::Reader {
+ public:
+ BufferReader(const void* input, size_t inputSize) : Reader(),
+ mInput(reinterpret_cast<const uint8_t*>(input)),
+ mInputSize(inputSize) {
+ }
- ~FdReader() {
- delete[] mReadBuf;
- }
+ bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
+ if (offset + len > mInputSize) {
+ return false;
+ }
- long read(unsigned char** nextBuffer, long readSize) const {
- *nextBuffer = mReadBuf;
- return TEMP_FAILURE_RETRY(::read(mFd, mReadBuf, readSize));
- }
+ memcpy(buf, mInput + offset, len);
+ return true;
+ }
- int mFd;
- unsigned char* mReadBuf;
+ private:
+ const uint8_t* mInput;
+ const size_t mInputSize;
};
-class BufferReader {
-public:
- BufferReader(void* input, size_t inputSize) :
- mInput(reinterpret_cast<unsigned char*>(input)),
- mInputSize(inputSize),
- mBufferReturned(false)
- {
+class BufferWriter : public zip_archive::Writer {
+ public:
+ BufferWriter(void* output, size_t outputSize) : Writer(),
+ mOutput(reinterpret_cast<uint8_t*>(output)), mOutputSize(outputSize), mBytesWritten(0) {
}
- long read(unsigned char** nextBuffer, long /*readSize*/) {
- if (!mBufferReturned) {
- mBufferReturned = true;
- *nextBuffer = mInput;
- return mInputSize;
+ bool Append(uint8_t* buf, size_t bufSize) override {
+ if (mBytesWritten + bufSize > mOutputSize) {
+ return false;
}
- *nextBuffer = NULL;
- return 0;
+ memcpy(mOutput + mBytesWritten, buf, bufSize);
+ mBytesWritten += bufSize;
+ return true;
}
- unsigned char* mInput;
- const size_t mInputSize;
- bool mBufferReturned;
+ private:
+ uint8_t* const mOutput;
+ const size_t mOutputSize;
+ size_t mBytesWritten;
};
/*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf,
long uncompressedLen, long compressedLen)
{
FileReader reader(fp);
- return ::inflateToBuffer<FileReader>(reader, buf,
- uncompressedLen, compressedLen);
+ BufferWriter writer(buf, uncompressedLen);
+ return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0);
}
/*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf,
long uncompressedLen, long compressedLen)
{
FdReader reader(fd);
- return ::inflateToBuffer<FdReader>(reader, buf,
- uncompressedLen, compressedLen);
+ BufferWriter writer(buf, uncompressedLen);
+ return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0);
}
-/*static*/ bool ZipUtils::inflateToBuffer(void* in, void* buf,
+/*static*/ bool ZipUtils::inflateToBuffer(const void* in, void* buf,
long uncompressedLen, long compressedLen)
{
BufferReader reader(in, compressedLen);
- return ::inflateToBuffer<BufferReader>(reader, buf,
- uncompressedLen, compressedLen);
+ BufferWriter writer(buf, uncompressedLen);
+ return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0);
}
-
+static inline unsigned long get4LE(const unsigned char* buf) {
+ return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+}
/*
* Look at the contents of a gzip archive. We want to know where the
@@ -275,7 +186,7 @@ public:
/* quick sanity checks */
if (method == EOF || flags == EOF)
return false;
- if (method != ZipFileRO::kCompressDeflated)
+ if (method != kCompressDeflated)
return false;
/* skip over 4 bytes of mod time, 1 byte XFL, 1 byte OS */
diff --git a/libs/androidfw/include/androidfw/ZipUtils.h b/libs/androidfw/include/androidfw/ZipUtils.h
index 55575d774522..4d35e992cc89 100644
--- a/libs/androidfw/include/androidfw/ZipUtils.h
+++ b/libs/androidfw/include/androidfw/ZipUtils.h
@@ -40,7 +40,7 @@ public:
long compressedLen);
static bool inflateToBuffer(int fd, void* buf, long uncompressedLen,
long compressedLen);
- static bool inflateToBuffer(void *in, void* buf, long uncompressedLen,
+ static bool inflateToBuffer(const void *in, void* buf, long uncompressedLen,
long compressedLen);
/*
diff --git a/libs/androidfw/libandroidfw_blacklist.txt b/libs/androidfw/libandroidfw_blacklist.txt
new file mode 100644
index 000000000000..dd17e4d5b1e8
--- /dev/null
+++ b/libs/androidfw/libandroidfw_blacklist.txt
@@ -0,0 +1 @@
+src:*/ResourceTypes.cpp
diff --git a/libs/hwui/.clang-format b/libs/hwui/.clang-format
new file mode 100644
index 000000000000..5e9bba8377cb
--- /dev/null
+++ b/libs/hwui/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: Google
+DerivePointerAlignment: false
+IndentWidth: 4
+ConstructorInitializerIndentWidth: 8
+ContinuationIndentWidth: 8
+ColumnLimit: 100
+AllowShortFunctionsOnASingleLine: Inline
+AccessModifierOffset: -4
+#BreakConstructorInitializers: BeforeComma
+BreakConstructorInitializersBeforeComma: true
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp
index 3982fa0938bf..aa96698c1e53 100644
--- a/libs/hwui/AmbientShadow.cpp
+++ b/libs/hwui/AmbientShadow.cpp
@@ -25,7 +25,7 @@
// For the whole polygon, the sum of all the deltas b/t normals is 2 * M_PI,
// therefore, the maximum number of extra vertices will be twice bigger.
-#define MAX_EXTRA_CORNER_VERTEX_NUMBER (2 * EXTRA_CORNER_VERTEX_PER_PI)
+#define MAX_EXTRA_CORNER_VERTEX_NUMBER (2 * EXTRA_CORNER_VERTEX_PER_PI)
// For each RADIANS_DIVISOR, we would allocate one more vertex b/t the normals.
#define CORNER_RADIANS_DIVISOR (M_PI / EXTRA_CORNER_VERTEX_PER_PI)
@@ -36,9 +36,9 @@
*/
#define EXTRA_EDGE_VERTEX_PER_PI 50
-#define MAX_EXTRA_EDGE_VERTEX_NUMBER (2 * EXTRA_EDGE_VERTEX_PER_PI)
+#define MAX_EXTRA_EDGE_VERTEX_NUMBER (2 * EXTRA_EDGE_VERTEX_PER_PI)
-#define EDGE_RADIANS_DIVISOR (M_PI / EXTRA_EDGE_VERTEX_PER_PI)
+#define EDGE_RADIANS_DIVISOR (M_PI / EXTRA_EDGE_VERTEX_PER_PI)
/**
* Other constants:
@@ -56,8 +56,8 @@
#include "Vertex.h"
#include "VertexBuffer.h"
-#include <algorithm>
#include <utils/Log.h>
+#include <algorithm>
namespace android {
namespace uirenderer {
@@ -67,8 +67,8 @@ namespace uirenderer {
*/
inline Vector2 getNormalFromVertices(const Vector3* vertices, int current, int next) {
// Convert from Vector3 to Vector2 first.
- Vector2 currentVertex = { vertices[current].x, vertices[current].y };
- Vector2 nextVertex = { vertices[next].x, vertices[next].y };
+ Vector2 currentVertex = {vertices[current].x, vertices[current].y};
+ Vector2 nextVertex = {vertices[next].x, vertices[next].y};
return ShadowTessellator::calculateNormal(currentVertex, nextVertex);
}
@@ -79,24 +79,24 @@ inline float getAlphaFromFactoredZ(float factoredZ) {
return 1.0 / (1 + std::max(factoredZ, 0.0f));
}
-inline int getEdgeExtraAndUpdateSpike(Vector2* currentSpike,
- const Vector3& secondVertex, const Vector3& centroid) {
- Vector2 secondSpike = {secondVertex.x - centroid.x, secondVertex.y - centroid.y};
+inline int getEdgeExtraAndUpdateSpike(Vector2* currentSpike, const Vector3& secondVertex,
+ const Vector3& centroid) {
+ Vector2 secondSpike = {secondVertex.x - centroid.x, secondVertex.y - centroid.y};
secondSpike.normalize();
int result = ShadowTessellator::getExtraVertexNumber(secondSpike, *currentSpike,
- EDGE_RADIANS_DIVISOR);
+ EDGE_RADIANS_DIVISOR);
*currentSpike = secondSpike;
return result;
}
// Given the caster's vertex count, compute all the buffers size depending on
// whether or not the caster is opaque.
-inline void computeBufferSize(int* totalVertexCount, int* totalIndexCount,
- int* totalUmbraCount, int casterVertexCount, bool isCasterOpaque) {
+inline void computeBufferSize(int* totalVertexCount, int* totalIndexCount, int* totalUmbraCount,
+ int casterVertexCount, bool isCasterOpaque) {
// Compute the size of the vertex buffer.
- int outerVertexCount = casterVertexCount * 2 + MAX_EXTRA_CORNER_VERTEX_NUMBER +
- MAX_EXTRA_EDGE_VERTEX_NUMBER;
+ int outerVertexCount =
+ casterVertexCount * 2 + MAX_EXTRA_CORNER_VERTEX_NUMBER + MAX_EXTRA_EDGE_VERTEX_NUMBER;
int innerVertexCount = casterVertexCount + MAX_EXTRA_EDGE_VERTEX_NUMBER;
*totalVertexCount = outerVertexCount + innerVertexCount;
@@ -163,44 +163,42 @@ inline bool needsExtraForEdge(float firstAlpha, float secondAlpha) {
* | |
* (V3)-----------------------------------(V2)
*/
-void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
- const Vector3* casterVertices, int casterVertexCount, const Vector3& centroid3d,
- float heightFactor, float geomFactor, VertexBuffer& shadowVertexBuffer) {
+void AmbientShadow::createAmbientShadow(bool isCasterOpaque, const Vector3* casterVertices,
+ int casterVertexCount, const Vector3& centroid3d,
+ float heightFactor, float geomFactor,
+ VertexBuffer& shadowVertexBuffer) {
shadowVertexBuffer.setMeshFeatureFlags(VertexBuffer::kAlpha | VertexBuffer::kIndices);
// In order to computer the outer vertices in one loop, we need pre-compute
// the normal by the vertex (n - 1) to vertex 0, and the spike and alpha value
// for vertex 0.
- Vector2 previousNormal = getNormalFromVertices(casterVertices,
- casterVertexCount - 1 , 0);
- Vector2 currentSpike = {casterVertices[0].x - centroid3d.x,
- casterVertices[0].y - centroid3d.y};
+ Vector2 previousNormal = getNormalFromVertices(casterVertices, casterVertexCount - 1, 0);
+ Vector2 currentSpike = {casterVertices[0].x - centroid3d.x, casterVertices[0].y - centroid3d.y};
currentSpike.normalize();
float currentAlpha = getAlphaFromFactoredZ(casterVertices[0].z * heightFactor);
// Preparing all the output data.
int totalVertexCount, totalIndexCount, totalUmbraCount;
- computeBufferSize(&totalVertexCount, &totalIndexCount, &totalUmbraCount,
- casterVertexCount, isCasterOpaque);
- AlphaVertex* shadowVertices =
- shadowVertexBuffer.alloc<AlphaVertex>(totalVertexCount);
+ computeBufferSize(&totalVertexCount, &totalIndexCount, &totalUmbraCount, casterVertexCount,
+ isCasterOpaque);
+ AlphaVertex* shadowVertices = shadowVertexBuffer.alloc<AlphaVertex>(totalVertexCount);
int vertexBufferIndex = 0;
uint16_t* indexBuffer = shadowVertexBuffer.allocIndices<uint16_t>(totalIndexCount);
int indexBufferIndex = 0;
uint16_t umbraVertices[totalUmbraCount];
int umbraIndex = 0;
- for (int i = 0; i < casterVertexCount; i++) {
+ for (int i = 0; i < casterVertexCount; i++) {
// Corner: first figure out the extra vertices we need for the corner.
const Vector3& innerVertex = casterVertices[i];
- Vector2 currentNormal = getNormalFromVertices(casterVertices, i,
- (i + 1) % casterVertexCount);
+ Vector2 currentNormal =
+ getNormalFromVertices(casterVertices, i, (i + 1) % casterVertexCount);
- int extraVerticesNumber = ShadowTessellator::getExtraVertexNumber(currentNormal,
- previousNormal, CORNER_RADIANS_DIVISOR);
+ int extraVerticesNumber = ShadowTessellator::getExtraVertexNumber(
+ currentNormal, previousNormal, CORNER_RADIANS_DIVISOR);
float expansionDist = innerVertex.z * heightFactor * geomFactor;
- const int cornerSlicesNumber = extraVerticesNumber + 1; // Minimal as 1.
+ const int cornerSlicesNumber = extraVerticesNumber + 1; // Minimal as 1.
#if DEBUG_SHADOW
ALOGD("cornerSlicesNumber is %d", cornerSlicesNumber);
#endif
@@ -212,9 +210,8 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
if (!isCasterOpaque) {
umbraVertices[umbraIndex++] = vertexBufferIndex;
}
- AlphaVertex::set(&shadowVertices[vertexBufferIndex++],
- casterVertices[i].x, casterVertices[i].y,
- currentAlpha);
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], casterVertices[i].x,
+ casterVertices[i].y, currentAlpha);
const Vector3& innerStart = casterVertices[i];
@@ -225,8 +222,7 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
// This will create vertices from [0, cornerSlicesNumber] inclusively,
// which means minimally 2 vertices even without the extra ones.
for (int j = 0; j <= cornerSlicesNumber; j++) {
- Vector2 averageNormal =
- previousNormal * (cornerSlicesNumber - j) + currentNormal * j;
+ Vector2 averageNormal = previousNormal * (cornerSlicesNumber - j) + currentNormal * j;
averageNormal /= cornerSlicesNumber;
averageNormal.normalize();
Vector2 outerVertex;
@@ -235,8 +231,8 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
indexBuffer[indexBufferIndex++] = vertexBufferIndex;
indexBuffer[indexBufferIndex++] = currentInnerVertexIndex;
- AlphaVertex::set(&shadowVertices[vertexBufferIndex++], outerVertex.x,
- outerVertex.y, OUTER_ALPHA);
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], outerVertex.x, outerVertex.y,
+ OUTER_ALPHA);
if (j == 0) {
outerStart = outerVertex;
@@ -257,8 +253,8 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
outerNext.y = innerNext.y + currentNormal.y * expansionDist;
// Compute the angle and see how many extra points we need.
- int extraVerticesNumber = getEdgeExtraAndUpdateSpike(&currentSpike,
- innerNext, centroid3d);
+ int extraVerticesNumber =
+ getEdgeExtraAndUpdateSpike(&currentSpike, innerNext, centroid3d);
#if DEBUG_SHADOW
ALOGD("extraVerticesNumber %d for edge %d", extraVerticesNumber, i);
#endif
@@ -269,20 +265,20 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
for (int k = 1; k < extraVerticesNumber; k++) {
int startWeight = extraVerticesNumber - k;
Vector2 currentOuter =
- (outerLast * startWeight + outerNext * k) / extraVerticesNumber;
+ (outerLast * startWeight + outerNext * k) / extraVerticesNumber;
indexBuffer[indexBufferIndex++] = vertexBufferIndex;
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], currentOuter.x,
- currentOuter.y, OUTER_ALPHA);
+ currentOuter.y, OUTER_ALPHA);
if (!isCasterOpaque) {
umbraVertices[umbraIndex++] = vertexBufferIndex;
}
Vector3 currentInner =
- (innerStart * startWeight + innerNext * k) / extraVerticesNumber;
+ (innerStart * startWeight + innerNext * k) / extraVerticesNumber;
indexBuffer[indexBufferIndex++] = vertexBufferIndex;
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], currentInner.x,
- currentInner.y,
- getAlphaFromFactoredZ(currentInner.z * heightFactor));
+ currentInner.y,
+ getAlphaFromFactoredZ(currentInner.z * heightFactor));
}
}
currentAlpha = nextAlpha;
@@ -293,11 +289,10 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
if (!isCasterOpaque) {
// Add the centroid as the last one in the vertex buffer.
- float centroidOpacity =
- getAlphaFromFactoredZ(centroid3d.z * heightFactor);
+ float centroidOpacity = getAlphaFromFactoredZ(centroid3d.z * heightFactor);
int centroidIndex = vertexBufferIndex;
- AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid3d.x,
- centroid3d.y, centroidOpacity);
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid3d.x, centroid3d.y,
+ centroidOpacity);
for (int i = 0; i < umbraIndex; i++) {
// Note that umbraVertices[0] is always 0.
@@ -322,7 +317,7 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
#if DEBUG_SHADOW
for (int i = 0; i < vertexBufferIndex; i++) {
ALOGD("vertexBuffer i %d, (%f, %f %f)", i, shadowVertices[i].x, shadowVertices[i].y,
- shadowVertices[i].alpha);
+ shadowVertices[i].alpha);
}
for (int i = 0; i < indexBufferIndex; i++) {
ALOGD("indexBuffer i %d, indexBuffer[i] %d", i, indexBuffer[i]);
@@ -330,5 +325,5 @@ void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
#endif
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/AmbientShadow.h b/libs/hwui/AmbientShadow.h
index 8eb1048f4d1c..cb1d915f2540 100644
--- a/libs/hwui/AmbientShadow.h
+++ b/libs/hwui/AmbientShadow.h
@@ -31,12 +31,12 @@ class VertexBuffer;
*/
class AmbientShadow {
public:
- static void createAmbientShadow(bool isCasterOpaque, const Vector3* poly,
- int polyLength, const Vector3& centroid3d, float heightFactor,
- float geomFactor, VertexBuffer& shadowVertexBuffer);
-}; // AmbientShadow
+ static void createAmbientShadow(bool isCasterOpaque, const Vector3* poly, int polyLength,
+ const Vector3& centroid3d, float heightFactor, float geomFactor,
+ VertexBuffer& shadowVertexBuffer);
+}; // AmbientShadow
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_AMBIENT_SHADOW_H
+#endif // ANDROID_HWUI_AMBIENT_SHADOW_H
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 26442927a60e..24ce1e4c23d0 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -68,6 +68,7 @@ cc_defaults {
],
static_libs: [
"libplatformprotos",
+ "libEGL_blobCache",
],
}
@@ -131,6 +132,7 @@ cc_defaults {
"pipeline/skia/LayerDrawable.cpp",
"pipeline/skia/RenderNodeDrawable.cpp",
"pipeline/skia/ReorderBarrierDrawables.cpp",
+ "pipeline/skia/ShaderCache.cpp",
"pipeline/skia/SkiaDisplayList.cpp",
"pipeline/skia/SkiaOpenGLPipeline.cpp",
"pipeline/skia/SkiaOpenGLReadback.cpp",
@@ -346,6 +348,7 @@ cc_test {
"tests/unit/RecordingCanvasTests.cpp",
"tests/unit/RenderNodeTests.cpp",
"tests/unit/RenderPropertiesTests.cpp",
+ "tests/unit/ShaderCacheTests.cpp",
"tests/unit/SkiaBehaviorTests.cpp",
"tests/unit/SkiaDisplayListTests.cpp",
"tests/unit/SkiaPipelineTests.cpp",
diff --git a/libs/hwui/AnimationContext.cpp b/libs/hwui/AnimationContext.cpp
index 5759ccd85464..46c9da2ac6b8 100644
--- a/libs/hwui/AnimationContext.cpp
+++ b/libs/hwui/AnimationContext.cpp
@@ -26,11 +26,9 @@ AnimationContext::AnimationContext(renderthread::TimeLord& clock)
: mClock(clock)
, mCurrentFrameAnimations(*this)
, mNextFrameAnimations(*this)
- , mFrameTimeMs(0) {
-}
+ , mFrameTimeMs(0) {}
-AnimationContext::~AnimationContext() {
-}
+AnimationContext::~AnimationContext() {}
void AnimationContext::destroy() {
startFrame(TreeInfo::MODE_RT_ONLY);
@@ -39,7 +37,7 @@ void AnimationContext::destroy() {
AnimatorManager& animators = current->mRenderNode->animators();
animators.endAllActiveAnimators();
LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle == current,
- "endAllAnimators failed to remove from current frame list!");
+ "endAllAnimators failed to remove from current frame list!");
}
}
@@ -56,7 +54,7 @@ void AnimationContext::addAnimationHandle(AnimationHandle* handle) {
void AnimationContext::startFrame(TreeInfo::TraversalMode mode) {
LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle,
- "Missed running animations last frame!");
+ "Missed running animations last frame!");
AnimationHandle* head = mNextFrameAnimations.mNextHandle;
if (head) {
mNextFrameAnimations.mNextHandle = nullptr;
@@ -73,20 +71,17 @@ void AnimationContext::runRemainingAnimations(TreeInfo& info) {
animators.pushStaging();
animators.animateNoDamage(info);
LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle == current,
- "Animate failed to remove from current frame list!");
+ "Animate failed to remove from current frame list!");
}
}
void AnimationContext::callOnFinished(BaseRenderNodeAnimator* animator,
- AnimationListener* listener) {
+ AnimationListener* listener) {
listener->onAnimationFinished(animator);
}
AnimationHandle::AnimationHandle(AnimationContext& context)
- : mContext(context)
- , mPreviousHandle(nullptr)
- , mNextHandle(nullptr) {
-}
+ : mContext(context), mPreviousHandle(nullptr), mNextHandle(nullptr) {}
AnimationHandle::AnimationHandle(RenderNode& animatingNode, AnimationContext& context)
: mRenderNode(&animatingNode)
@@ -98,7 +93,7 @@ AnimationHandle::AnimationHandle(RenderNode& animatingNode, AnimationContext& co
AnimationHandle::~AnimationHandle() {
LOG_ALWAYS_FATAL_IF(mPreviousHandle || mNextHandle,
- "AnimationHandle destroyed while still animating!");
+ "AnimationHandle destroyed while still animating!");
}
void AnimationHandle::notifyAnimationsRan() {
@@ -112,7 +107,7 @@ void AnimationHandle::notifyAnimationsRan() {
void AnimationHandle::release() {
LOG_ALWAYS_FATAL_IF(mRenderNode->animators().hasAnimators(),
- "Releasing the handle for an RenderNode with outstanding animators!");
+ "Releasing the handle for an RenderNode with outstanding animators!");
removeFromList();
mRenderNode->animators().setAnimationHandle(nullptr);
delete this;
diff --git a/libs/hwui/AnimationContext.h b/libs/hwui/AnimationContext.h
index 71ee8602a29f..74d5e79c0b77 100644
--- a/libs/hwui/AnimationContext.h
+++ b/libs/hwui/AnimationContext.h
@@ -43,6 +43,7 @@ class RenderNode;
*/
class AnimationHandle {
PREVENT_COPY_AND_ASSIGN(AnimationHandle);
+
public:
AnimationContext& context() { return mContext; }
@@ -74,14 +75,14 @@ private:
class AnimationContext {
PREVENT_COPY_AND_ASSIGN(AnimationContext);
+
public:
ANDROID_API explicit AnimationContext(renderthread::TimeLord& clock);
ANDROID_API virtual ~AnimationContext();
nsecs_t frameTimeMs() { return mFrameTimeMs; }
bool hasAnimations() {
- return mCurrentFrameAnimations.mNextHandle
- || mNextFrameAnimations.mNextHandle;
+ return mCurrentFrameAnimations.mNextHandle || mNextFrameAnimations.mNextHandle;
}
// Will always add to the next frame list, which is swapped when
@@ -96,7 +97,8 @@ public:
// as part of the standard RenderNode:prepareTree pass.
ANDROID_API virtual void runRemainingAnimations(TreeInfo& info);
- ANDROID_API virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener);
+ ANDROID_API virtual void callOnFinished(BaseRenderNodeAnimator* animator,
+ AnimationListener* listener);
ANDROID_API virtual void destroy();
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index b6fbf891f84d..74cf1fda1b75 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -44,16 +44,14 @@ BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
, mDuration(300)
, mStartDelay(0)
, mMayRunAsync(true)
- , mPlayTime(0) {
-}
+ , mPlayTime(0) {}
-BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
-}
+BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {}
void BaseRenderNodeAnimator::checkMutable() {
// Should be impossible to hit as the Java-side also has guards for this
LOG_ALWAYS_FATAL_IF(mStagingPlayState != PlayState::NotStarted,
- "Animator has already been started!");
+ "Animator has already been started!");
}
void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
@@ -119,34 +117,36 @@ void BaseRenderNodeAnimator::end() {
void BaseRenderNodeAnimator::resolveStagingRequest(Request request) {
switch (request) {
- case Request::Start:
- mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
- mPlayTime : 0;
- mPlayState = PlayState::Running;
- mPendingActionUponFinish = Action::None;
- break;
- case Request::Reverse:
- mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
- mPlayTime : mDuration;
- mPlayState = PlayState::Reversing;
- mPendingActionUponFinish = Action::None;
- break;
- case Request::Reset:
- mPlayTime = 0;
- mPlayState = PlayState::Finished;
- mPendingActionUponFinish = Action::Reset;
- break;
- case Request::Cancel:
- mPlayState = PlayState::Finished;
- mPendingActionUponFinish = Action::None;
- break;
- case Request::End:
- mPlayTime = mPlayState == PlayState::Reversing ? 0 : mDuration;
- mPlayState = PlayState::Finished;
- mPendingActionUponFinish = Action::End;
- break;
- default:
- LOG_ALWAYS_FATAL("Invalid staging request: %d", static_cast<int>(request));
+ case Request::Start:
+ mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing)
+ ? mPlayTime
+ : 0;
+ mPlayState = PlayState::Running;
+ mPendingActionUponFinish = Action::None;
+ break;
+ case Request::Reverse:
+ mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing)
+ ? mPlayTime
+ : mDuration;
+ mPlayState = PlayState::Reversing;
+ mPendingActionUponFinish = Action::None;
+ break;
+ case Request::Reset:
+ mPlayTime = 0;
+ mPlayState = PlayState::Finished;
+ mPendingActionUponFinish = Action::Reset;
+ break;
+ case Request::Cancel:
+ mPlayState = PlayState::Finished;
+ mPendingActionUponFinish = Action::None;
+ break;
+ case Request::End:
+ mPlayTime = mPlayState == PlayState::Reversing ? 0 : mDuration;
+ mPlayState = PlayState::Finished;
+ mPendingActionUponFinish = Action::End;
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Invalid staging request: %d", static_cast<int>(request));
};
}
@@ -182,8 +182,8 @@ void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) {
if (mStagingPlayState == PlayState::Finished) {
callOnFinishedListener(context);
- } else if (mStagingPlayState == PlayState::Running
- || mStagingPlayState == PlayState::Reversing) {
+ } else if (mStagingPlayState == PlayState::Running ||
+ mStagingPlayState == PlayState::Reversing) {
bool changed = currentPlayTime != mPlayTime || prevFramePlayState != mStagingPlayState;
if (prevFramePlayState != mStagingPlayState) {
transitionToRunning(context);
@@ -197,7 +197,7 @@ void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) {
if (mPlayState == PlayState::Reversing) {
// Reverse is not supported for animations with a start delay, so here we
// assume no start delay.
- mStartTime = currentFrameTime - (mDuration - mPlayTime);
+ mStartTime = currentFrameTime - (mDuration - mPlayTime);
} else {
// Animation should play forward
if (mPlayTime == 0) {
@@ -223,9 +223,9 @@ void BaseRenderNodeAnimator::transitionToRunning(AnimationContext& context) {
}
mStartTime = frameTimeMs + mStartDelay;
if (mStartTime < 0) {
- ALOGW("Ended up with a really weird start time of %" PRId64
- " with frame time %" PRId64 " and start delay %" PRId64,
- mStartTime, frameTimeMs, mStartDelay);
+ ALOGW("Ended up with a really weird start time of %" PRId64 " with frame time %" PRId64
+ " and start delay %" PRId64,
+ mStartTime, frameTimeMs, mStartDelay);
// Set to 0 so that the animate() basically instantly finishes
mStartTime = 0;
}
@@ -247,7 +247,7 @@ bool BaseRenderNodeAnimator::animate(AnimationContext& context) {
updatePlayTime(mDuration);
}
// Reset pending action.
- mPendingActionUponFinish = Action ::None;
+ mPendingActionUponFinish = Action::None;
return true;
}
@@ -276,7 +276,7 @@ bool BaseRenderNodeAnimator::updatePlayTime(nsecs_t playTime) {
float fraction = 1.0f;
if ((mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) && mDuration > 0) {
- fraction = mPlayTime / (float) mDuration;
+ fraction = mPlayTime / (float)mDuration;
}
fraction = MathUtils::clamp(fraction, 0.0f, 1.0f);
@@ -308,35 +308,35 @@ void BaseRenderNodeAnimator::callOnFinishedListener(AnimationContext& context) {
************************************************************/
struct RenderPropertyAnimator::PropertyAccessors {
- RenderNode::DirtyPropertyMask dirtyMask;
- GetFloatProperty getter;
- SetFloatProperty setter;
+ RenderNode::DirtyPropertyMask dirtyMask;
+ GetFloatProperty getter;
+ SetFloatProperty setter;
};
// Maps RenderProperty enum to accessors
const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = {
- {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
- {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
- {RenderNode::TRANSLATION_Z, &RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
- {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX },
- {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY },
- {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation },
- {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX },
- {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY },
- {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX },
- {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY },
- {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ },
- {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha },
+ {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX,
+ &RenderProperties::setTranslationX},
+ {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY,
+ &RenderProperties::setTranslationY},
+ {RenderNode::TRANSLATION_Z, &RenderProperties::getTranslationZ,
+ &RenderProperties::setTranslationZ},
+ {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX},
+ {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY},
+ {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation},
+ {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX},
+ {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY},
+ {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX},
+ {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY},
+ {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ},
+ {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha},
};
RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue)
- : BaseRenderNodeAnimator(finalValue)
- , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {
-}
+ : BaseRenderNodeAnimator(finalValue), mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {}
void RenderPropertyAnimator::onAttached() {
- if (!mHasStartValue
- && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
+ if (!mHasStartValue && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
setStartValue((mStagingTarget->stagingProperties().*mPropertyAccess->getter)());
}
}
@@ -385,11 +385,9 @@ void RenderPropertyAnimator::setValue(RenderNode* target, float value) {
* CanvasPropertyPrimitiveAnimator
************************************************************/
-CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(
- CanvasPropertyPrimitive* property, float finalValue)
- : BaseRenderNodeAnimator(finalValue)
- , mProperty(property) {
-}
+CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
+ float finalValue)
+ : BaseRenderNodeAnimator(finalValue), mProperty(property) {}
float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const {
return mProperty->value;
@@ -407,50 +405,44 @@ uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() {
* CanvasPropertySkPaintAnimator
************************************************************/
-CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
- CanvasPropertyPaint* property, PaintField field, float finalValue)
- : BaseRenderNodeAnimator(finalValue)
- , mProperty(property)
- , mField(field) {
-}
+CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(CanvasPropertyPaint* property,
+ PaintField field, float finalValue)
+ : BaseRenderNodeAnimator(finalValue), mProperty(property), mField(field) {}
float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const {
switch (mField) {
- case STROKE_WIDTH:
- return mProperty->value.getStrokeWidth();
- case ALPHA:
- return mProperty->value.getAlpha();
+ case STROKE_WIDTH:
+ return mProperty->value.getStrokeWidth();
+ case ALPHA:
+ return mProperty->value.getAlpha();
}
- LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
+ LOG_ALWAYS_FATAL("Unknown field %d", (int)mField);
return -1;
}
static uint8_t to_uint8(float value) {
- int c = (int) (value + .5f);
- return static_cast<uint8_t>( c < 0 ? 0 : c > 255 ? 255 : c );
+ int c = (int)(value + .5f);
+ return static_cast<uint8_t>(c < 0 ? 0 : c > 255 ? 255 : c);
}
void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) {
switch (mField) {
- case STROKE_WIDTH:
- mProperty->value.setStrokeWidth(value);
- return;
- case ALPHA:
- mProperty->value.setAlpha(to_uint8(value));
- return;
+ case STROKE_WIDTH:
+ mProperty->value.setStrokeWidth(value);
+ return;
+ case ALPHA:
+ mProperty->value.setAlpha(to_uint8(value));
+ return;
}
- LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
+ LOG_ALWAYS_FATAL("Unknown field %d", (int)mField);
}
uint32_t CanvasPropertyPaintAnimator::dirtyMask() {
return RenderNode::DISPLAY_LIST;
}
-RevealAnimator::RevealAnimator(int centerX, int centerY,
- float startValue, float finalValue)
- : BaseRenderNodeAnimator(finalValue)
- , mCenterX(centerX)
- , mCenterY(centerY) {
+RevealAnimator::RevealAnimator(int centerX, int centerY, float startValue, float finalValue)
+ : BaseRenderNodeAnimator(finalValue), mCenterX(centerX), mCenterY(centerY) {
setStartValue(startValue);
}
@@ -459,8 +451,7 @@ float RevealAnimator::getValue(RenderNode* target) const {
}
void RevealAnimator::setValue(RenderNode* target, float value) {
- target->animatorProperties().mutableRevealClip().set(true,
- mCenterX, mCenterY, value);
+ target->animatorProperties().mutableRevealClip().set(true, mCenterX, mCenterY, value);
}
uint32_t RevealAnimator::dirtyMask() {
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index aac355c11ac9..42f4cf8828bd 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -16,11 +16,11 @@
#ifndef ANIMATOR_H
#define ANIMATOR_H
-#include <memory>
#include <cutils/compiler.h>
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
+#include <memory>
#include "utils/Macros.h"
@@ -40,6 +40,7 @@ class RenderProperties;
class AnimationListener : public VirtualLightRefBase {
public:
ANDROID_API virtual void onAnimationFinished(BaseRenderNodeAnimator*) = 0;
+
protected:
ANDROID_API virtual ~AnimationListener() {}
};
@@ -52,6 +53,7 @@ enum class RepeatMode {
class BaseRenderNodeAnimator : public VirtualLightRefBase {
PREVENT_COPY_AND_ASSIGN(BaseRenderNodeAnimator);
+
public:
ANDROID_API void setStartValue(float value);
ANDROID_API void setInterpolator(Interpolator* interpolator);
@@ -59,13 +61,9 @@ public:
ANDROID_API nsecs_t duration() { return mDuration; }
ANDROID_API void setStartDelay(nsecs_t startDelayInMs);
ANDROID_API nsecs_t startDelay() { return mStartDelay; }
- ANDROID_API void setListener(AnimationListener* listener) {
- mListener = listener;
- }
+ ANDROID_API void setListener(AnimationListener* listener) { mListener = listener; }
AnimationListener* listener() { return mListener.get(); }
- ANDROID_API void setAllowRunningAsync(bool mayRunAsync) {
- mMayRunAsync = mayRunAsync;
- }
+ ANDROID_API void setAllowRunningAsync(bool mayRunAsync) { mMayRunAsync = mayRunAsync; }
bool mayRunAsync() { return mMayRunAsync; }
ANDROID_API void start();
ANDROID_API virtual void reset();
@@ -86,8 +84,9 @@ public:
// an animation on RenderThread.
ANDROID_API nsecs_t getRemainingPlayTime();
- bool isRunning() { return mPlayState == PlayState::Running
- || mPlayState == PlayState::Reversing; }
+ bool isRunning() {
+ return mPlayState == PlayState::Running || mPlayState == PlayState::Reversing;
+ }
bool isFinished() { return mPlayState == PlayState::Finished; }
float finalValue() { return mFinalValue; }
@@ -158,13 +157,7 @@ protected:
sp<AnimationListener> mListener;
private:
- enum class Request {
- Start,
- Reverse,
- Reset,
- Cancel,
- End
- };
+ enum class Request { Start, Reverse, Reset, Cancel, End };
// Defines different actions upon finish.
enum class Action {
@@ -229,13 +222,14 @@ private:
class CanvasPropertyPrimitiveAnimator : public BaseRenderNodeAnimator {
public:
ANDROID_API CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
- float finalValue);
+ float finalValue);
ANDROID_API virtual uint32_t dirtyMask();
protected:
virtual float getValue(RenderNode* target) const override;
virtual void setValue(RenderNode* target, float value) override;
+
private:
sp<CanvasPropertyPrimitive> mProperty;
};
@@ -247,14 +241,15 @@ public:
ALPHA,
};
- ANDROID_API CanvasPropertyPaintAnimator(CanvasPropertyPaint* property,
- PaintField field, float finalValue);
+ ANDROID_API CanvasPropertyPaintAnimator(CanvasPropertyPaint* property, PaintField field,
+ float finalValue);
ANDROID_API virtual uint32_t dirtyMask();
protected:
virtual float getValue(RenderNode* target) const override;
virtual void setValue(RenderNode* target, float value) override;
+
private:
sp<CanvasPropertyPaint> mProperty;
PaintField mField;
@@ -262,8 +257,7 @@ private:
class RevealAnimator : public BaseRenderNodeAnimator {
public:
- ANDROID_API RevealAnimator(int centerX, int centerY,
- float startValue, float finalValue);
+ ANDROID_API RevealAnimator(int centerX, int centerY, float startValue, float finalValue);
ANDROID_API virtual uint32_t dirtyMask();
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
index 69ead5890566..4826d5a0c8da 100644
--- a/libs/hwui/AnimatorManager.cpp
+++ b/libs/hwui/AnimatorManager.cpp
@@ -17,8 +17,8 @@
#include <algorithm>
-#include "Animator.h"
#include "AnimationContext.h"
+#include "Animator.h"
#include "DamageAccumulator.h"
#include "RenderNode.h"
@@ -31,10 +31,7 @@ static void detach(sp<BaseRenderNodeAnimator>& animator) {
animator->detach();
}
-AnimatorManager::AnimatorManager(RenderNode& parent)
- : mParent(parent)
- , mAnimationHandle(nullptr) {
-}
+AnimatorManager::AnimatorManager(RenderNode& parent) : mParent(parent), mAnimationHandle(nullptr) {}
AnimatorManager::~AnimatorManager() {
for_each(mNewAnimators.begin(), mNewAnimators.end(), detach);
@@ -58,22 +55,22 @@ void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
void AnimatorManager::removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
mNewAnimators.erase(std::remove(mNewAnimators.begin(), mNewAnimators.end(), animator),
- mNewAnimators.end());
+ mNewAnimators.end());
}
void AnimatorManager::setAnimationHandle(AnimationHandle* handle) {
LOG_ALWAYS_FATAL_IF(mAnimationHandle && handle, "Already have an AnimationHandle!");
mAnimationHandle = handle;
LOG_ALWAYS_FATAL_IF(!mAnimationHandle && mAnimators.size(),
- "Lost animation handle on %p (%s) with outstanding animators!",
- &mParent, mParent.getName());
+ "Lost animation handle on %p (%s) with outstanding animators!", &mParent,
+ mParent.getName());
}
void AnimatorManager::pushStaging() {
if (mNewAnimators.size()) {
if (CC_UNLIKELY(!mAnimationHandle)) {
- ALOGW("Trying to start new animators on %p (%s) without an animation handle!",
- &mParent, mParent.getName());
+ ALOGW("Trying to start new animators on %p (%s) without an animation handle!", &mParent,
+ mParent.getName());
return;
}
@@ -100,7 +97,7 @@ public:
AnimateFunctor(TreeInfo& info, AnimationContext& context, uint32_t* outDirtyMask)
: mInfo(info), mContext(context), mDirtyMask(outDirtyMask) {}
- bool operator() (sp<BaseRenderNodeAnimator>& animator) {
+ bool operator()(sp<BaseRenderNodeAnimator>& animator) {
*mDirtyMask |= animator->dirtyMask();
bool remove = animator->animate(mContext);
if (remove) {
@@ -172,17 +169,15 @@ class EndActiveAnimatorsFunctor {
public:
explicit EndActiveAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
- void operator() (sp<BaseRenderNodeAnimator>& animator) {
- animator->forceEndNow(mContext);
- }
+ void operator()(sp<BaseRenderNodeAnimator>& animator) { animator->forceEndNow(mContext); }
private:
AnimationContext& mContext;
};
void AnimatorManager::endAllActiveAnimators() {
- ALOGD("endAllActiveAnimators on %p (%s) with handle %p",
- &mParent, mParent.getName(), mAnimationHandle);
+ ALOGD("endAllActiveAnimators on %p (%s) with handle %p", &mParent, mParent.getName(),
+ mAnimationHandle);
EndActiveAnimatorsFunctor functor(mAnimationHandle->context());
for_each(mAnimators.begin(), mAnimators.end(), functor);
mAnimators.clear();
diff --git a/libs/hwui/AnimatorManager.h b/libs/hwui/AnimatorManager.h
index 8e6f820608b5..9575391a8b3f 100644
--- a/libs/hwui/AnimatorManager.h
+++ b/libs/hwui/AnimatorManager.h
@@ -34,6 +34,7 @@ class TreeInfo;
// Responsible for managing the animators for a single RenderNode
class AnimatorManager {
PREVENT_COPY_AND_ASSIGN(AnimatorManager);
+
public:
explicit AnimatorManager(RenderNode& parent);
~AnimatorManager();
@@ -68,8 +69,8 @@ private:
AnimationHandle* mAnimationHandle;
// To improve the efficiency of resizing & removing from the vector
- std::vector< sp<BaseRenderNodeAnimator> > mNewAnimators;
- std::vector< sp<BaseRenderNodeAnimator> > mAnimators;
+ std::vector<sp<BaseRenderNodeAnimator> > mNewAnimators;
+ std::vector<sp<BaseRenderNodeAnimator> > mAnimators;
};
} /* namespace uirenderer */
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 03a397c1084d..f78cb418c5cd 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -23,29 +23,28 @@
#include "GlopBuilder.h"
#include "Patch.h"
#include "PathTessellator.h"
+#include "VertexBuffer.h"
#include "renderstate/OffscreenBufferPool.h"
#include "renderstate/RenderState.h"
#include "utils/GLUtils.h"
-#include "VertexBuffer.h"
-#include <algorithm>
-#include <math.h>
#include <SkPaintDefaults.h>
#include <SkPathOps.h>
+#include <math.h>
+#include <algorithm>
namespace android {
namespace uirenderer {
static void storeTexturedRect(TextureVertex* vertices, const Rect& bounds) {
- vertices[0] = { bounds.left, bounds.top, 0, 0 };
- vertices[1] = { bounds.right, bounds.top, 1, 0 };
- vertices[2] = { bounds.left, bounds.bottom, 0, 1 };
- vertices[3] = { bounds.right, bounds.bottom, 1, 1 };
+ vertices[0] = {bounds.left, bounds.top, 0, 0};
+ vertices[1] = {bounds.right, bounds.top, 1, 0};
+ vertices[2] = {bounds.left, bounds.bottom, 0, 1};
+ vertices[3] = {bounds.right, bounds.bottom, 1, 1};
}
void BakedOpDispatcher::onMergedBitmapOps(BakedOpRenderer& renderer,
- const MergedBakedOpList& opList) {
-
+ const MergedBakedOpList& opList) {
const BakedOpState& firstState = *(opList.states[0]);
Bitmap* bitmap = (static_cast<const BitmapOp*>(opList.states[0]->op))->bitmap;
@@ -70,7 +69,8 @@ void BakedOpDispatcher::onMergedBitmapOps(BakedOpRenderer& renderer,
}
const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType)
- ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
+ ? TextureFillFlags::IsAlphaMaskTexture
+ : TextureFillFlags::None;
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(firstState.roundRectClipState)
@@ -85,7 +85,7 @@ void BakedOpDispatcher::onMergedBitmapOps(BakedOpRenderer& renderer,
}
void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
- const MergedBakedOpList& opList) {
+ const MergedBakedOpList& opList) {
const PatchOp& firstOp = *(static_cast<const PatchOp*>(opList.states[0]->op));
const BakedOpState& firstState = *(opList.states[0]);
@@ -99,8 +99,8 @@ void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
// TODO: cache mesh lookups
const Patch* opMesh = renderer.caches().patchCache.get(
- op.bitmap->width(), op.bitmap->height(),
- op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
+ op.bitmap->width(), op.bitmap->height(), op.unmappedBounds.getWidth(),
+ op.unmappedBounds.getHeight(), op.patch);
totalVertices += opMesh->verticesCount;
}
@@ -120,9 +120,8 @@ void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
// TODO: cache mesh lookups
const Patch* opMesh = renderer.caches().patchCache.get(
- op.bitmap->width(), op.bitmap->height(),
- op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
-
+ op.bitmap->width(), op.bitmap->height(), op.unmappedBounds.getWidth(),
+ op.unmappedBounds.getHeight(), op.patch);
uint32_t vertexCount = opMesh->verticesCount;
if (vertexCount == 0) continue;
@@ -130,17 +129,16 @@ void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
// We use the bounds to know where to translate our vertices
// Using patchOp->state.mBounds wouldn't work because these
// bounds are clipped
- const float tx = floorf(state.computedState.transform.getTranslateX()
- + op.unmappedBounds.left + 0.5f);
- const float ty = floorf(state.computedState.transform.getTranslateY()
- + op.unmappedBounds.top + 0.5f);
+ const float tx = floorf(state.computedState.transform.getTranslateX() +
+ op.unmappedBounds.left + 0.5f);
+ const float ty = floorf(state.computedState.transform.getTranslateY() +
+ op.unmappedBounds.top + 0.5f);
// Copy & transform all the vertices for the current operation
TextureVertex* opVertices = opMesh->vertices.get();
for (uint32_t j = 0; j < vertexCount; j++, opVertices++) {
- TextureVertex::set(vertex++,
- opVertices->x + tx, opVertices->y + ty,
- opVertices->u, opVertices->v);
+ TextureVertex::set(vertex++, opVertices->x + tx, opVertices->y + ty, opVertices->u,
+ opVertices->v);
}
// Dirty the current layer if possible. When the 9-patch does not
@@ -148,16 +146,16 @@ void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
// dirty rect to the object's bounds.
if (dirtyRenderTarget) {
if (!opMesh->hasEmptyQuads) {
- renderer.dirtyRenderTarget(Rect(tx, ty,
- tx + op.unmappedBounds.getWidth(), ty + op.unmappedBounds.getHeight()));
+ renderer.dirtyRenderTarget(Rect(tx, ty, tx + op.unmappedBounds.getWidth(),
+ ty + op.unmappedBounds.getHeight()));
} else {
const size_t count = opMesh->quads.size();
for (size_t i = 0; i < count; i++) {
const Rect& quadBounds = opMesh->quads[i];
const float x = tx + quadBounds.left;
const float y = ty + quadBounds.top;
- renderer.dirtyRenderTarget(Rect(x, y,
- x + quadBounds.getWidth(), y + quadBounds.getHeight()));
+ renderer.dirtyRenderTarget(
+ Rect(x, y, x + quadBounds.getWidth(), y + quadBounds.getHeight()));
}
}
}
@@ -165,7 +163,6 @@ void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
indexCount += opMesh->indexCount;
}
-
Texture* texture = renderer.caches().textureCache.get(firstOp.bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -188,8 +185,8 @@ void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
renderer.renderGlop(nullptr, clip, glop);
}
-static void renderTextShadow(BakedOpRenderer& renderer,
- const TextOp& op, const BakedOpState& textOpState) {
+static void renderTextShadow(BakedOpRenderer& renderer, const TextOp& op,
+ const BakedOpState& textOpState) {
if (CC_LIKELY(!PaintUtils::hasTextShadow(op.paint))) return;
FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer();
@@ -225,7 +222,7 @@ static void renderTextShadow(BakedOpRenderer& renderer,
// Bounds should be same as text op, but with dx/dy offset and radius outset
// applied in local space.
auto& transform = textOpState.computedState.transform;
- Rect shadowBounds = op.unmappedBounds; // STROKE
+ Rect shadowBounds = op.unmappedBounds; // STROKE
const bool expandForStroke = op.paint->getStyle() != SkPaint::kFill_Style;
if (expandForStroke) {
shadowBounds.outset(op.paint->getStrokeWidth() * 0.5f);
@@ -234,13 +231,12 @@ static void renderTextShadow(BakedOpRenderer& renderer,
shadowBounds.outset(textShadow.radius, textShadow.radius);
transform.mapRect(shadowBounds);
if (CC_UNLIKELY(expandForStroke &&
- (!transform.isPureTranslate() || op.paint->getStrokeWidth() < 1.0f))) {
+ (!transform.isPureTranslate() || op.paint->getStrokeWidth() < 1.0f))) {
shadowBounds.outset(0.5f);
}
auto clipState = textOpState.computedState.clipState;
- if (clipState->mode != ClipMode::Rectangle
- || !clipState->rect.contains(shadowBounds)) {
+ if (clipState->mode != ClipMode::Rectangle || !clipState->rect.contains(shadowBounds)) {
// need clip, so pass it and clip bounds
shadowBounds.doIntersect(clipState->rect);
} else {
@@ -251,13 +247,10 @@ static void renderTextShadow(BakedOpRenderer& renderer,
renderer.renderGlop(&shadowBounds, clipState, glop);
}
-enum class TextRenderType {
- Defer,
- Flush
-};
+enum class TextRenderType { Defer, Flush };
static void renderText(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state,
- const ClipBase* renderClip, TextRenderType renderType) {
+ const ClipBase* renderClip, TextRenderType renderType) {
FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer();
float x = op.x;
float y = op.y;
@@ -285,23 +278,23 @@ static void renderText(BakedOpRenderer& renderer, const TextOp& op, const BakedO
// font renderer which greatly simplifies the code, clipping in particular.
float sx, sy;
transform.decomposeScale(sx, sy);
- fontRenderer.setFont(op.paint, SkMatrix::MakeScale(
- roundf(std::max(1.0f, sx)),
- roundf(std::max(1.0f, sy))));
+ fontRenderer.setFont(op.paint, SkMatrix::MakeScale(roundf(std::max(1.0f, sx)),
+ roundf(std::max(1.0f, sy))));
fontRenderer.setTextureFiltering(true);
}
Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
int alpha = PaintUtils::getAlphaDirect(op.paint) * state.alpha;
SkBlendMode mode = PaintUtils::getBlendModeDirect(op.paint);
- TextDrawFunctor functor(&renderer, &state, renderClip,
- x, y, pureTranslate, alpha, mode, op.paint);
+ TextDrawFunctor functor(&renderer, &state, renderClip, x, y, pureTranslate, alpha, mode,
+ op.paint);
bool forceFinish = (renderType == TextRenderType::Flush);
bool mustDirtyRenderTarget = renderer.offscreenRenderTarget();
const Rect* localOpClip = pureTranslate ? &state.computedState.clipRect() : nullptr;
- fontRenderer.renderPosText(op.paint, localOpClip, op.glyphs, op.glyphCount, x, y,
- op.positions, mustDirtyRenderTarget ? &layerBounds : nullptr, &functor, forceFinish);
+ fontRenderer.renderPosText(op.paint, localOpClip, op.glyphs, op.glyphCount, x, y, op.positions,
+ mustDirtyRenderTarget ? &layerBounds : nullptr, &functor,
+ forceFinish);
if (mustDirtyRenderTarget) {
if (!pureTranslate) {
@@ -312,7 +305,7 @@ static void renderText(BakedOpRenderer& renderer, const TextOp& op, const BakedO
}
void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer,
- const MergedBakedOpList& opList) {
+ const MergedBakedOpList& opList) {
for (size_t i = 0; i < opList.count; i++) {
const BakedOpState& state = *(opList.states[i]);
const TextOp& op = *(static_cast<const TextOp*>(state.op));
@@ -324,26 +317,27 @@ void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer,
for (size_t i = 0; i < opList.count; i++) {
const BakedOpState& state = *(opList.states[i]);
const TextOp& op = *(static_cast<const TextOp*>(state.op));
- TextRenderType renderType = (i + 1 == opList.count)
- ? TextRenderType::Flush : TextRenderType::Defer;
+ TextRenderType renderType =
+ (i + 1 == opList.count) ? TextRenderType::Flush : TextRenderType::Defer;
renderText(renderer, op, state, clip, renderType);
}
}
namespace VertexBufferRenderFlags {
- enum {
- Offset = 0x1,
- ShadowInterp = 0x2,
- };
+enum {
+ Offset = 0x1,
+ ShadowInterp = 0x2,
+};
}
static void renderVertexBuffer(BakedOpRenderer& renderer, const BakedOpState& state,
- const VertexBuffer& vertexBuffer, float translateX, float translateY,
- const SkPaint& paint, int vertexBufferRenderFlags) {
+ const VertexBuffer& vertexBuffer, float translateX, float translateY,
+ const SkPaint& paint, int vertexBufferRenderFlags) {
if (CC_LIKELY(vertexBuffer.getVertexCount())) {
bool shadowInterp = vertexBufferRenderFlags & VertexBufferRenderFlags::ShadowInterp;
const int transformFlags = vertexBufferRenderFlags & VertexBufferRenderFlags::Offset
- ? TransformFlags::OffsetByFudgeFactor : 0;
+ ? TransformFlags::OffsetByFudgeFactor
+ : 0;
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
@@ -358,24 +352,23 @@ static void renderVertexBuffer(BakedOpRenderer& renderer, const BakedOpState& st
}
static void renderConvexPath(BakedOpRenderer& renderer, const BakedOpState& state,
- const SkPath& path, const SkPaint& paint) {
+ const SkPath& path, const SkPaint& paint) {
VertexBuffer vertexBuffer;
// TODO: try clipping large paths to viewport
PathTessellator::tessellatePath(path, &paint, state.computedState.transform, vertexBuffer);
renderVertexBuffer(renderer, state, vertexBuffer, 0.0f, 0.0f, paint, 0);
}
-static void renderPathTexture(BakedOpRenderer& renderer, const BakedOpState& state,
- float xOffset, float yOffset, PathTexture& texture, const SkPaint& paint) {
+static void renderPathTexture(BakedOpRenderer& renderer, const BakedOpState& state, float xOffset,
+ float yOffset, PathTexture& texture, const SkPaint& paint) {
Rect dest(texture.width(), texture.height());
- dest.translate(xOffset + texture.left - texture.offset,
- yOffset + texture.top - texture.offset);
+ dest.translate(xOffset + texture.left - texture.offset, yOffset + texture.top - texture.offset);
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(state.roundRectClipState)
.setMeshTexturedUnitQuad(nullptr)
.setFillPathTexturePaint(texture, paint, state.alpha)
- .setTransform(state.computedState.transform, TransformFlags::None)
+ .setTransform(state.computedState.transform, TransformFlags::None)
.setModelViewMapUnitToRect(dest)
.build();
renderer.renderGlop(state, glop);
@@ -390,18 +383,18 @@ SkRect getBoundsOfFill(const RecordedOp& op) {
return bounds;
}
-void BakedOpDispatcher::onArcOp(BakedOpRenderer& renderer, const ArcOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onArcOp(BakedOpRenderer& renderer, const ArcOp& op,
+ const BakedOpState& state) {
// TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
- if (op.paint->getStyle() != SkPaint::kStroke_Style
- || op.paint->getPathEffect() != nullptr
- || op.useCenter) {
+ if (op.paint->getStyle() != SkPaint::kStroke_Style || op.paint->getPathEffect() != nullptr ||
+ op.useCenter) {
PathTexture* texture = renderer.caches().pathCache.getArc(
- op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(),
- op.startAngle, op.sweepAngle, op.useCenter, op.paint);
+ op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.startAngle,
+ op.sweepAngle, op.useCenter, op.paint);
const AutoTexture holder(texture);
if (CC_LIKELY(holder.texture)) {
renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
- *texture, *(op.paint));
+ *texture, *(op.paint));
}
} else {
SkRect rect = getBoundsOfFill(op);
@@ -417,13 +410,15 @@ void BakedOpDispatcher::onArcOp(BakedOpRenderer& renderer, const ArcOp& op, cons
}
}
-void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op,
+ const BakedOpState& state) {
Texture* texture = renderer.getTexture(op.bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
- ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
+ ? TextureFillFlags::IsAlphaMaskTexture
+ : TextureFillFlags::None;
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(state.roundRectClipState)
@@ -435,7 +430,8 @@ void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op
renderer.renderGlop(state, glop);
}
-void BakedOpDispatcher::onBitmapMeshOp(BakedOpRenderer& renderer, const BitmapMeshOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onBitmapMeshOp(BakedOpRenderer& renderer, const BitmapMeshOp& op,
+ const BakedOpState& state) {
Texture* texture = renderer.caches().textureCache.get(op.bitmap);
if (!texture) {
return;
@@ -495,13 +491,14 @@ void BakedOpDispatcher::onBitmapMeshOp(BakedOpRenderer& renderer, const BitmapMe
.setRoundRectClipState(state.roundRectClipState)
.setMeshColoredTexturedMesh(mesh.get(), elementCount)
.setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
- .setTransform(state.computedState.transform, TransformFlags::None)
+ .setTransform(state.computedState.transform, TransformFlags::None)
.setModelViewOffsetRect(0, 0, op.unmappedBounds)
.build();
renderer.renderGlop(state, glop);
}
-void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRectOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRectOp& op,
+ const BakedOpState& state) {
Texture* texture = renderer.getTexture(op.bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -512,9 +509,10 @@ void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRe
std::min(1.0f, op.src.bottom / texture->height()));
const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
- ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
- const bool tryToSnap = MathUtils::areEqual(op.src.getWidth(), op.unmappedBounds.getWidth())
- && MathUtils::areEqual(op.src.getHeight(), op.unmappedBounds.getHeight());
+ ? TextureFillFlags::IsAlphaMaskTexture
+ : TextureFillFlags::None;
+ const bool tryToSnap = MathUtils::areEqual(op.src.getWidth(), op.unmappedBounds.getWidth()) &&
+ MathUtils::areEqual(op.src.getHeight(), op.unmappedBounds.getHeight());
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(state.roundRectClipState)
@@ -526,7 +524,8 @@ void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRe
renderer.renderGlop(state, glop);
}
-void BakedOpDispatcher::onColorOp(BakedOpRenderer& renderer, const ColorOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onColorOp(BakedOpRenderer& renderer, const ColorOp& op,
+ const BakedOpState& state) {
SkPaint paint;
paint.setColor(op.color);
paint.setBlendMode(op.mode);
@@ -542,26 +541,29 @@ void BakedOpDispatcher::onColorOp(BakedOpRenderer& renderer, const ColorOp& op,
renderer.renderGlop(state, glop);
}
-void BakedOpDispatcher::onFunctorOp(BakedOpRenderer& renderer, const FunctorOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onFunctorOp(BakedOpRenderer& renderer, const FunctorOp& op,
+ const BakedOpState& state) {
renderer.renderFunctor(op, state);
}
-void BakedOpDispatcher::onLinesOp(BakedOpRenderer& renderer, const LinesOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onLinesOp(BakedOpRenderer& renderer, const LinesOp& op,
+ const BakedOpState& state) {
VertexBuffer buffer;
PathTessellator::tessellateLines(op.points, op.floatCount, op.paint,
- state.computedState.transform, buffer);
+ state.computedState.transform, buffer);
int displayFlags = op.paint->isAntiAlias() ? 0 : VertexBufferRenderFlags::Offset;
renderVertexBuffer(renderer, state, buffer, 0, 0, *(op.paint), displayFlags);
}
-void BakedOpDispatcher::onOvalOp(BakedOpRenderer& renderer, const OvalOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onOvalOp(BakedOpRenderer& renderer, const OvalOp& op,
+ const BakedOpState& state) {
if (op.paint->getPathEffect() != nullptr) {
PathTexture* texture = renderer.caches().pathCache.getOval(
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint);
const AutoTexture holder(texture);
if (CC_LIKELY(holder.texture)) {
renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
- *texture, *(op.paint));
+ *texture, *(op.paint));
}
} else {
SkPath path;
@@ -577,7 +579,8 @@ void BakedOpDispatcher::onOvalOp(BakedOpRenderer& renderer, const OvalOp& op, co
}
}
-void BakedOpDispatcher::onPatchOp(BakedOpRenderer& renderer, const PatchOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onPatchOp(BakedOpRenderer& renderer, const PatchOp& op,
+ const BakedOpState& state) {
// 9 patches are built for stretching - always filter
int textureFillFlags = TextureFillFlags::ForceFilter;
if (op.bitmap->colorType() == kAlpha_8_SkColorType) {
@@ -585,9 +588,9 @@ void BakedOpDispatcher::onPatchOp(BakedOpRenderer& renderer, const PatchOp& op,
}
// TODO: avoid redoing the below work each frame:
- const Patch* mesh = renderer.caches().patchCache.get(
- op.bitmap->width(), op.bitmap->height(),
- op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
+ const Patch* mesh = renderer.caches().patchCache.get(op.bitmap->width(), op.bitmap->height(),
+ op.unmappedBounds.getWidth(),
+ op.unmappedBounds.getHeight(), op.patch);
Texture* texture = renderer.caches().textureCache.get(op.bitmap);
if (CC_LIKELY(texture)) {
@@ -598,14 +601,16 @@ void BakedOpDispatcher::onPatchOp(BakedOpRenderer& renderer, const PatchOp& op,
.setMeshPatchQuads(*mesh)
.setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
.setTransform(state.computedState.transform, TransformFlags::None)
- .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
+ .setModelViewOffsetRectSnap(
+ op.unmappedBounds.left, op.unmappedBounds.top,
Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
.build();
renderer.renderGlop(state, glop);
}
}
-void BakedOpDispatcher::onPathOp(BakedOpRenderer& renderer, const PathOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onPathOp(BakedOpRenderer& renderer, const PathOp& op,
+ const BakedOpState& state) {
PathTexture* texture = renderer.caches().pathCache.get(op.path, op.paint);
const AutoTexture holder(texture);
if (CC_LIKELY(holder.texture)) {
@@ -615,10 +620,11 @@ void BakedOpDispatcher::onPathOp(BakedOpRenderer& renderer, const PathOp& op, co
}
}
-void BakedOpDispatcher::onPointsOp(BakedOpRenderer& renderer, const PointsOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onPointsOp(BakedOpRenderer& renderer, const PointsOp& op,
+ const BakedOpState& state) {
VertexBuffer buffer;
PathTessellator::tessellatePoints(op.points, op.floatCount, op.paint,
- state.computedState.transform, buffer);
+ state.computedState.transform, buffer);
int displayFlags = op.paint->isAntiAlias() ? 0 : VertexBufferRenderFlags::Offset;
renderVertexBuffer(renderer, state, buffer, 0, 0, *(op.paint), displayFlags);
}
@@ -626,20 +632,21 @@ void BakedOpDispatcher::onPointsOp(BakedOpRenderer& renderer, const PointsOp& op
// See SkPaintDefaults.h
#define SkPaintDefaults_MiterLimit SkIntToScalar(4)
-void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op,
+ const BakedOpState& state) {
if (op.paint->getStyle() != SkPaint::kFill_Style) {
// only fill + default miter is supported by drawConvexPath, since others must handle joins
static_assert(SkPaintDefaults_MiterLimit == 4.0f, "Miter limit has changed");
- if (CC_UNLIKELY(op.paint->getPathEffect() != nullptr
- || op.paint->getStrokeJoin() != SkPaint::kMiter_Join
- || op.paint->getStrokeMiter() != SkPaintDefaults_MiterLimit)) {
- PathTexture* texture = renderer.caches().pathCache.getRect(
- op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint);
- const AutoTexture holder(texture);
- if (CC_LIKELY(holder.texture)) {
- renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
- *texture, *(op.paint));
- }
+ if (CC_UNLIKELY(op.paint->getPathEffect() != nullptr ||
+ op.paint->getStrokeJoin() != SkPaint::kMiter_Join ||
+ op.paint->getStrokeMiter() != SkPaintDefaults_MiterLimit)) {
+ PathTexture* texture = renderer.caches().pathCache.getRect(
+ op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint);
+ const AutoTexture holder(texture);
+ if (CC_LIKELY(holder.texture)) {
+ renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
+ *texture, *(op.paint));
+ }
} else {
SkPath path;
path.addRect(getBoundsOfFill(op));
@@ -665,29 +672,31 @@ void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, co
}
}
-void BakedOpDispatcher::onRoundRectOp(BakedOpRenderer& renderer, const RoundRectOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onRoundRectOp(BakedOpRenderer& renderer, const RoundRectOp& op,
+ const BakedOpState& state) {
if (op.paint->getPathEffect() != nullptr) {
PathTexture* texture = renderer.caches().pathCache.getRoundRect(
- op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(),
- op.rx, op.ry, op.paint);
+ op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.rx, op.ry,
+ op.paint);
const AutoTexture holder(texture);
if (CC_LIKELY(holder.texture)) {
renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
- *texture, *(op.paint));
+ *texture, *(op.paint));
}
} else {
const VertexBuffer* buffer = renderer.caches().tessellationCache.getRoundRect(
- state.computedState.transform, *(op.paint),
- op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.rx, op.ry);
- renderVertexBuffer(renderer, state, *buffer,
- op.unmappedBounds.left, op.unmappedBounds.top, *(op.paint), 0);
+ state.computedState.transform, *(op.paint), op.unmappedBounds.getWidth(),
+ op.unmappedBounds.getHeight(), op.rx, op.ry);
+ renderVertexBuffer(renderer, state, *buffer, op.unmappedBounds.left, op.unmappedBounds.top,
+ *(op.paint), 0);
}
}
static void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, float casterAlpha,
- const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
+ const VertexBuffer* ambientShadowVertexBuffer,
+ const VertexBuffer* spotShadowVertexBuffer) {
SkPaint paint;
- paint.setAntiAlias(true); // want to use AlphaVertex
+ paint.setAntiAlias(true); // want to use AlphaVertex
// The caller has made sure casterAlpha > 0.
uint8_t ambientShadowAlpha = renderer.getLightInfo().ambientShadowAlpha;
@@ -696,8 +705,8 @@ static void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, f
}
if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) {
paint.setAlpha((uint8_t)(casterAlpha * ambientShadowAlpha));
- renderVertexBuffer(renderer, state, *ambientShadowVertexBuffer, 0, 0,
- paint, VertexBufferRenderFlags::ShadowInterp);
+ renderVertexBuffer(renderer, state, *ambientShadowVertexBuffer, 0, 0, paint,
+ VertexBufferRenderFlags::ShadowInterp);
}
uint8_t spotShadowAlpha = renderer.getLightInfo().spotShadowAlpha;
@@ -706,17 +715,19 @@ static void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, f
}
if (spotShadowVertexBuffer && spotShadowAlpha > 0) {
paint.setAlpha((uint8_t)(casterAlpha * spotShadowAlpha));
- renderVertexBuffer(renderer, state, *spotShadowVertexBuffer, 0, 0,
- paint, VertexBufferRenderFlags::ShadowInterp);
+ renderVertexBuffer(renderer, state, *spotShadowVertexBuffer, 0, 0, paint,
+ VertexBufferRenderFlags::ShadowInterp);
}
}
-void BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op,
+ const BakedOpState& state) {
TessellationCache::vertexBuffer_pair_t buffers = op.shadowTask->getResult();
renderShadow(renderer, state, op.casterAlpha, buffers.first, buffers.second);
}
-void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op,
+ const BakedOpState& state) {
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(state.roundRectClipState)
@@ -728,12 +739,14 @@ void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleR
renderer.renderGlop(state, glop);
}
-void BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op,
+ const BakedOpState& state) {
renderTextShadow(renderer, op, state);
renderText(renderer, op, state, state.computedState.getClipIfNeeded(), TextRenderType::Flush);
}
-void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPathOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPathOp& op,
+ const BakedOpState& state) {
// Note: can't trust clipSideFlags since we record with unmappedBounds == clip.
// TODO: respect clipSideFlags, once we record with bounds
auto renderTargetClip = state.computedState.clipState;
@@ -746,14 +759,14 @@ void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPa
int alpha = PaintUtils::getAlphaDirect(op.paint) * state.alpha;
SkBlendMode mode = PaintUtils::getBlendModeDirect(op.paint);
- TextDrawFunctor functor(&renderer, &state, renderTargetClip,
- 0.0f, 0.0f, false, alpha, mode, op.paint);
+ TextDrawFunctor functor(&renderer, &state, renderTargetClip, 0.0f, 0.0f, false, alpha, mode,
+ op.paint);
bool mustDirtyRenderTarget = renderer.offscreenRenderTarget();
const Rect localSpaceClip = state.computedState.computeLocalSpaceClip();
- if (fontRenderer.renderTextOnPath(op.paint, &localSpaceClip, op.glyphs, op.glyphCount,
- op.path, op.hOffset, op.vOffset,
- mustDirtyRenderTarget ? &layerBounds : nullptr, &functor)) {
+ if (fontRenderer.renderTextOnPath(op.paint, &localSpaceClip, op.glyphs, op.glyphCount, op.path,
+ op.hOffset, op.vOffset,
+ mustDirtyRenderTarget ? &layerBounds : nullptr, &functor)) {
if (mustDirtyRenderTarget) {
// manually dirty render target, since TextDrawFunctor won't
state.computedState.transform.mapRect(layerBounds);
@@ -762,7 +775,8 @@ void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPa
}
}
-void BakedOpDispatcher::onTextureLayerOp(BakedOpRenderer& renderer, const TextureLayerOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onTextureLayerOp(BakedOpRenderer& renderer, const TextureLayerOp& op,
+ const BakedOpState& state) {
GlLayer* layer = static_cast<GlLayer*>(op.layerHandle->backingLayer());
if (!layer) {
return;
@@ -772,16 +786,17 @@ void BakedOpDispatcher::onTextureLayerOp(BakedOpRenderer& renderer, const Textur
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(state.roundRectClipState)
- .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
+ .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
.setFillTextureLayer(*(layer), alpha)
.setTransform(state.computedState.transform, TransformFlags::None)
- .setModelViewMapUnitToRectOptionalSnap(tryToSnap, Rect(layer->getWidth(), layer->getHeight()))
+ .setModelViewMapUnitToRectOptionalSnap(tryToSnap,
+ Rect(layer->getWidth(), layer->getHeight()))
.build();
renderer.renderGlop(state, glop);
}
void renderRectForLayer(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state,
- int color, SkBlendMode mode, SkColorFilter* colorFilter) {
+ int color, SkBlendMode mode, SkColorFilter* colorFilter) {
SkPaint paint;
paint.setColor(color);
paint.setBlendMode(mode);
@@ -790,7 +805,8 @@ void renderRectForLayer(BakedOpRenderer& renderer, const LayerOp& op, const Bake
BakedOpDispatcher::onRectOp(renderer, rectOp, state);
}
-void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op,
+ const BakedOpState& state) {
// Note that we don't use op->paint in this function - it's never set on a LayerOp
OffscreenBuffer* buffer = *op.layerHandle;
@@ -801,9 +817,11 @@ void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op,
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(state.roundRectClipState)
.setMeshTexturedIndexedVbo(buffer->vbo, buffer->elementCount)
- .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode, Blend::ModeOrderSwap::NoSwap)
+ .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode,
+ Blend::ModeOrderSwap::NoSwap)
.setTransform(state.computedState.transform, TransformFlags::None)
- .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
+ .setModelViewOffsetRectSnap(
+ op.unmappedBounds.left, op.unmappedBounds.top,
Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
.build();
renderer.renderGlop(state, glop);
@@ -812,23 +830,24 @@ void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op,
buffer->hasRenderedSinceRepaint = true;
if (CC_UNLIKELY(Properties::debugLayersUpdates)) {
// render debug layer highlight
- renderRectForLayer(renderer, op, state,
- 0x7f00ff00, SkBlendMode::kSrcOver, nullptr);
+ renderRectForLayer(renderer, op, state, 0x7f00ff00, SkBlendMode::kSrcOver, nullptr);
} else if (CC_UNLIKELY(Properties::debugOverdraw)) {
// render transparent to increment overdraw for repaint area
- renderRectForLayer(renderer, op, state,
- SK_ColorTRANSPARENT, SkBlendMode::kSrcOver, nullptr);
+ renderRectForLayer(renderer, op, state, SK_ColorTRANSPARENT, SkBlendMode::kSrcOver,
+ nullptr);
}
}
}
-void BakedOpDispatcher::onCopyToLayerOp(BakedOpRenderer& renderer, const CopyToLayerOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onCopyToLayerOp(BakedOpRenderer& renderer, const CopyToLayerOp& op,
+ const BakedOpState& state) {
LOG_ALWAYS_FATAL_IF(*(op.layerHandle) != nullptr, "layer already exists!");
*(op.layerHandle) = renderer.copyToLayer(state.computedState.clippedBounds);
LOG_ALWAYS_FATAL_IF(*op.layerHandle == nullptr, "layer copy failed");
}
-void BakedOpDispatcher::onCopyFromLayerOp(BakedOpRenderer& renderer, const CopyFromLayerOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onCopyFromLayerOp(BakedOpRenderer& renderer, const CopyFromLayerOp& op,
+ const BakedOpState& state) {
LOG_ALWAYS_FATAL_IF(*op.layerHandle == nullptr, "no layer to draw underneath!");
if (!state.computedState.clippedBounds.isEmpty()) {
if (op.paint && op.paint->getAlpha() < 255) {
@@ -836,7 +855,8 @@ void BakedOpDispatcher::onCopyFromLayerOp(BakedOpRenderer& renderer, const CopyF
layerPaint.setAlpha(op.paint->getAlpha());
layerPaint.setBlendMode(SkBlendMode::kDstIn);
layerPaint.setColorFilter(sk_ref_sp(op.paint->getColorFilter()));
- RectOp rectOp(state.computedState.clippedBounds, Matrix4::identity(), nullptr, &layerPaint);
+ RectOp rectOp(state.computedState.clippedBounds, Matrix4::identity(), nullptr,
+ &layerPaint);
BakedOpDispatcher::onRectOp(renderer, rectOp, state);
}
@@ -855,5 +875,5 @@ void BakedOpDispatcher::onCopyFromLayerOp(BakedOpRenderer& renderer, const CopyF
renderer.renderState().layerPool().putOrDelete(*op.layerHandle);
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/BakedOpDispatcher.h b/libs/hwui/BakedOpDispatcher.h
index 4dfdd3ff619a..e3708685afc9 100644
--- a/libs/hwui/BakedOpDispatcher.h
+++ b/libs/hwui/BakedOpDispatcher.h
@@ -33,21 +33,20 @@ namespace uirenderer {
*/
class BakedOpDispatcher {
public:
- // Declares all "onMergedBitmapOps(...)" style methods for mergeable op types
+// Declares all "onMergedBitmapOps(...)" style methods for mergeable op types
#define X(Type) \
- static void onMerged##Type##s(BakedOpRenderer& renderer, const MergedBakedOpList& opList);
+ static void onMerged##Type##s(BakedOpRenderer& renderer, const MergedBakedOpList& opList);
MAP_MERGEABLE_OPS(X)
#undef X
- // Declares all "onBitmapOp(...)" style methods for every op type
+// Declares all "onBitmapOp(...)" style methods for every op type
#define X(Type) \
- static void on##Type(BakedOpRenderer& renderer, const Type& op, const BakedOpState& state);
+ static void on##Type(BakedOpRenderer& renderer, const Type& op, const BakedOpState& state);
MAP_RENDERABLE_OPS(X)
#undef X
-
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_BAKED_OP_DISPATCHER_H
+#endif // ANDROID_HWUI_BAKED_OP_DISPATCHER_H
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index 3c3b3177159b..6b64b94d291e 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -19,10 +19,10 @@
#include "Caches.h"
#include "Glop.h"
#include "GlopBuilder.h"
+#include "VertexBuffer.h"
#include "renderstate/OffscreenBufferPool.h"
#include "renderstate/RenderState.h"
#include "utils/GLUtils.h"
-#include "VertexBuffer.h"
#include <algorithm>
@@ -32,8 +32,8 @@ namespace uirenderer {
OffscreenBuffer* BakedOpRenderer::startTemporaryLayer(uint32_t width, uint32_t height) {
LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
- OffscreenBuffer* buffer = mRenderState.layerPool().get(
- mRenderState, width, height, mWideColorGamut);
+ OffscreenBuffer* buffer =
+ mRenderState.layerPool().get(mRenderState, width, height, mWideColorGamut);
startRepaintLayer(buffer, Rect(width, height));
return buffer;
}
@@ -46,13 +46,13 @@ void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const
LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
// subtract repaintRect from region, since it will be regenerated
- if (repaintRect.contains(0, 0,
- offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight)) {
+ if (repaintRect.contains(0, 0, offscreenBuffer->viewportWidth,
+ offscreenBuffer->viewportHeight)) {
// repaint full layer, so throw away entire region
offscreenBuffer->region.clear();
} else {
offscreenBuffer->region.subtractSelf(android::Rect(repaintRect.left, repaintRect.top,
- repaintRect.right, repaintRect.bottom));
+ repaintRect.right, repaintRect.bottom));
}
mRenderTarget.offscreenBuffer = offscreenBuffer;
@@ -64,16 +64,14 @@ void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const
// attach the texture to the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- offscreenBuffer->texture.id(), 0);
+ offscreenBuffer->texture.id(), 0);
GL_CHECKPOINT(LOW);
int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
LOG_ALWAYS_FATAL_IF(status != GL_FRAMEBUFFER_COMPLETE,
- "framebuffer incomplete, status %d, textureId %d, size %dx%d",
- status,
- offscreenBuffer->texture.id(),
- offscreenBuffer->texture.width(),
- offscreenBuffer->texture.height());
+ "framebuffer incomplete, status %d, textureId %d, size %dx%d", status,
+ offscreenBuffer->texture.id(), offscreenBuffer->texture.width(),
+ offscreenBuffer->texture.height());
// Change the viewport & ortho projection
setViewport(offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight);
@@ -92,7 +90,7 @@ void BakedOpRenderer::endLayer() {
mRenderTarget.lastStencilClip = nullptr;
mRenderTarget.offscreenBuffer->updateMeshFromRegion();
- mRenderTarget.offscreenBuffer = nullptr; // It's in drawLayerOp's hands now.
+ mRenderTarget.offscreenBuffer = nullptr; // It's in drawLayerOp's hands now.
// Detach the texture from the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
@@ -104,14 +102,14 @@ void BakedOpRenderer::endLayer() {
OffscreenBuffer* BakedOpRenderer::copyToLayer(const Rect& area) {
const uint32_t width = area.getWidth();
const uint32_t height = area.getHeight();
- OffscreenBuffer* buffer = mRenderState.layerPool().get(
- mRenderState, width, height, mWideColorGamut);
+ OffscreenBuffer* buffer =
+ mRenderState.layerPool().get(mRenderState, width, height, mWideColorGamut);
if (!area.isEmpty() && width != 0 && height != 0) {
mCaches.textureState().activateTexture(0);
mCaches.textureState().bindTexture(buffer->texture.id());
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
- area.left, mRenderTarget.viewportHeight - area.bottom, width, height);
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, area.left,
+ mRenderTarget.viewportHeight - area.bottom, width, height);
}
return buffer;
}
@@ -177,7 +175,7 @@ void BakedOpRenderer::clearColorBuffer(const Rect& rect) {
// Requested rect is subset of viewport - scissor to it to avoid over-clearing
mRenderState.scissor().setEnabled(true);
mRenderState.scissor().set(rect.left, mRenderTarget.viewportHeight - rect.bottom,
- rect.getWidth(), rect.getHeight());
+ rect.getWidth(), rect.getHeight());
}
glClear(GL_COLOR_BUFFER_BIT);
if (!mRenderTarget.frameBufferId) mHasDrawn = true;
@@ -222,8 +220,7 @@ void BakedOpRenderer::drawRects(const float* rects, int count, const SkPaint* pa
// clears and re-fills stencil with provided rendertarget space quads,
// and then put stencil into test mode
-void BakedOpRenderer::setupStencilQuads(std::vector<Vertex>& quadVertices,
- int incrementThreshold) {
+void BakedOpRenderer::setupStencilQuads(std::vector<Vertex>& quadVertices, int incrementThreshold) {
mRenderState.stencil().enableWrite(incrementThreshold);
mRenderState.stencil().clear();
Glop glop;
@@ -239,7 +236,8 @@ void BakedOpRenderer::setupStencilQuads(std::vector<Vertex>& quadVertices,
}
void BakedOpRenderer::setupStencilRectList(const ClipBase* clip) {
- LOG_ALWAYS_FATAL_IF(clip->mode != ClipMode::RectangleList, "can't rectlist clip without rectlist");
+ LOG_ALWAYS_FATAL_IF(clip->mode != ClipMode::RectangleList,
+ "can't rectlist clip without rectlist");
auto&& rectList = reinterpret_cast<const ClipRectList*>(clip)->rectList;
int quadCount = rectList.getTransformedRectanglesCount();
std::vector<Vertex> rectangleVertices;
@@ -253,7 +251,7 @@ void BakedOpRenderer::setupStencilRectList(const ClipBase* clip) {
transform.mapRect(bounds);
bounds.doIntersect(clip->rect);
if (bounds.isEmpty()) {
- continue; // will be outside of scissor, skip
+ continue; // will be outside of scissor, skip
}
}
@@ -309,11 +307,11 @@ void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* cli
if (mRenderTarget.frameBufferId != 0 && !mRenderTarget.stencil) {
OffscreenBuffer* layer = mRenderTarget.offscreenBuffer;
mRenderTarget.stencil = mCaches.renderBufferCache.get(
- Stencil::getLayerStencilFormat(),
- layer->texture.width(), layer->texture.height());
+ Stencil::getLayerStencilFormat(), layer->texture.width(),
+ layer->texture.height());
// stencil is bound + allocated - associate it with current FBO
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER, mRenderTarget.stencil->getName());
+ GL_RENDERBUFFER, mRenderTarget.stencil->getName());
}
if (clip->mode == ClipMode::RectangleList) {
@@ -344,17 +342,15 @@ void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* cli
}
void BakedOpRenderer::renderGlopImpl(const Rect* dirtyBounds, const ClipBase* clip,
- const Glop& glop) {
+ const Glop& glop) {
prepareRender(dirtyBounds, clip);
// Disable blending if this is the first draw to the main framebuffer, in case app has defined
// transparency where it doesn't make sense - as first draw in opaque window. Note that we only
// apply this improvement when the blend mode is SRC_OVER - other modes (e.g. CLEAR) can be
// valid draws that affect other content (e.g. draw CLEAR, then draw DST_OVER)
- bool overrideDisableBlending = !mHasDrawn
- && mOpaque
- && !mRenderTarget.frameBufferId
- && glop.blend.src == GL_ONE
- && glop.blend.dst == GL_ONE_MINUS_SRC_ALPHA;
+ bool overrideDisableBlending = !mHasDrawn && mOpaque && !mRenderTarget.frameBufferId &&
+ glop.blend.src == GL_ONE &&
+ glop.blend.dst == GL_ONE_MINUS_SRC_ALPHA;
mRenderState.render(glop, mRenderTarget.orthoMatrix, overrideDisableBlending);
if (!mRenderTarget.frameBufferId) mHasDrawn = true;
}
@@ -383,5 +379,5 @@ void BakedOpRenderer::dirtyRenderTarget(const Rect& uiDirty) {
}
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h
index 01ca36742d24..7c0590d7ab48 100644
--- a/libs/hwui/BakedOpRenderer.h
+++ b/libs/hwui/BakedOpRenderer.h
@@ -46,23 +46,20 @@ public:
*/
struct LightInfo {
LightInfo() : LightInfo(0, 0) {}
- LightInfo(uint8_t ambientShadowAlpha,
- uint8_t spotShadowAlpha)
- : ambientShadowAlpha(ambientShadowAlpha)
- , spotShadowAlpha(spotShadowAlpha) {}
+ LightInfo(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha)
+ : ambientShadowAlpha(ambientShadowAlpha), spotShadowAlpha(spotShadowAlpha) {}
uint8_t ambientShadowAlpha;
uint8_t spotShadowAlpha;
};
BakedOpRenderer(Caches& caches, RenderState& renderState, bool opaque, bool wideColorGamut,
- const LightInfo& lightInfo)
+ const LightInfo& lightInfo)
: mGlopReceiver(DefaultGlopReceiver)
, mRenderState(renderState)
, mCaches(caches)
, mOpaque(opaque)
, mWideColorGamut(wideColorGamut)
- , mLightInfo(lightInfo) {
- }
+ , mLightInfo(lightInfo) {}
RenderState& renderState() { return mRenderState; }
Caches& caches() { return mCaches; }
@@ -79,9 +76,7 @@ public:
const LightInfo& getLightInfo() const { return mLightInfo; }
void renderGlop(const BakedOpState& state, const Glop& glop) {
- renderGlop(&state.computedState.clippedBounds,
- state.computedState.getClipIfNeeded(),
- glop);
+ renderGlop(&state.computedState.clippedBounds, state.computedState.getClipIfNeeded(), glop);
}
void renderFunctor(const FunctorOp& op, const BakedOpState& state);
@@ -97,15 +92,17 @@ public:
// simple draw methods, to be used for end frame decoration
void drawRect(float left, float top, float right, float bottom, const SkPaint* paint) {
- float ltrb[4] = { left, top, right, bottom };
+ float ltrb[4] = {left, top, right, bottom};
drawRects(ltrb, 4, paint);
}
void drawRects(const float* rects, int count, const SkPaint* paint);
+
protected:
GlopReceiver mGlopReceiver;
+
private:
static void DefaultGlopReceiver(BakedOpRenderer& renderer, const Rect* dirtyBounds,
- const ClipBase* clip, const Glop& glop) {
+ const ClipBase* clip, const Glop& glop) {
renderer.renderGlopImpl(dirtyBounds, clip, glop);
}
void renderGlopImpl(const Rect* dirtyBounds, const ClipBase* clip, const Glop& glop);
@@ -148,5 +145,5 @@ private:
const LightInfo mLightInfo;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp
index 9823a02dc847..63edf77279e3 100644
--- a/libs/hwui/BakedOpState.cpp
+++ b/libs/hwui/BakedOpState.cpp
@@ -31,7 +31,8 @@ static int computeClipSideFlags(const Rect& clip, const Rect& bounds) {
}
ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
- const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture) {
+ const RecordedOp& recordedOp, bool expandForStroke,
+ bool expandForPathTexture) {
// resolvedMatrix = parentMatrix * localMatrix
transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix);
@@ -44,16 +45,16 @@ ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& s
clippedBounds.outset(1);
}
transform.mapRect(clippedBounds);
- if (CC_UNLIKELY(expandForStroke
- && (!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) {
+ if (CC_UNLIKELY(expandForStroke &&
+ (!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) {
// account for hairline stroke when stroke may be < 1 scaled pixel
// Non translate || strokeWidth < 1 is conservative, but will cover all cases
clippedBounds.outset(0.5f);
}
// resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
- clipState = snapshot.serializeIntersectedClip(allocator,
- recordedOp.localClip, *(snapshot.transform));
+ clipState = snapshot.serializeIntersectedClip(allocator, recordedOp.localClip,
+ *(snapshot.transform));
LOG_ALWAYS_FATAL_IF(!clipState, "must clip!");
const Rect& clipRect = clipState->rect;
@@ -85,7 +86,7 @@ ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& s
}
ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
- const Matrix4& localTransform, const ClipBase* localClip) {
+ const Matrix4& localTransform, const ClipBase* localClip) {
transform.loadMultiply(*snapshot.transform, localTransform);
clipState = snapshot.serializeIntersectedClip(allocator, localClip, *(snapshot.transform));
clippedBounds = clipState->rect;
@@ -109,11 +110,11 @@ ResolvedRenderState::ResolvedRenderState(const ClipRect* clipRect, const Rect& d
clippedBounds.doIntersect(clipRect->rect);
}
-BakedOpState* BakedOpState::tryConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp) {
+BakedOpState* BakedOpState::tryConstruct(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp) {
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
- BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
- allocator, snapshot, recordedOp, false, false);
+ BakedOpState* bakedState =
+ allocator.create_trivial<BakedOpState>(allocator, snapshot, recordedOp, false, false);
if (bakedState->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
allocator.rewindIfLastAlloc(bakedState);
@@ -122,21 +123,23 @@ BakedOpState* BakedOpState::tryConstruct(LinearAllocator& allocator,
return bakedState;
}
-BakedOpState* BakedOpState::tryConstructUnbounded(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp) {
+BakedOpState* BakedOpState::tryConstructUnbounded(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp) {
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
return allocator.create_trivial<BakedOpState>(allocator, snapshot, recordedOp);
}
-BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior,
- bool expandForPathTexture) {
+BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp,
+ StrokeBehavior strokeBehavior,
+ bool expandForPathTexture) {
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
- bool expandForStroke = (strokeBehavior == StrokeBehavior::Forced
- || (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style));
+ bool expandForStroke =
+ (strokeBehavior == StrokeBehavior::Forced ||
+ (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style));
BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
- allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture);
+ allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture);
if (bakedState->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
// NOTE: this won't succeed if a clip was allocated
@@ -146,26 +149,25 @@ BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator,
return bakedState;
}
-BakedOpState* BakedOpState::tryShadowOpConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
+BakedOpState* BakedOpState::tryShadowOpConstruct(LinearAllocator& allocator, Snapshot& snapshot,
+ const ShadowOp* shadowOpPtr) {
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
// clip isn't empty, so construct the op
return allocator.create_trivial<BakedOpState>(allocator, snapshot, shadowOpPtr);
}
-BakedOpState* BakedOpState::directConstruct(LinearAllocator& allocator,
- const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) {
+BakedOpState* BakedOpState::directConstruct(LinearAllocator& allocator, const ClipRect* clip,
+ const Rect& dstRect, const RecordedOp& recordedOp) {
return allocator.create_trivial<BakedOpState>(clip, dstRect, recordedOp);
}
void BakedOpState::setupOpacity(const SkPaint* paint) {
- computedState.opaqueOverClippedBounds = computedState.transform.isSimple()
- && computedState.clipState->mode == ClipMode::Rectangle
- && MathUtils::areEqual(alpha, 1.0f)
- && !roundRectClipState
- && PaintUtils::isOpaquePaint(paint);
+ computedState.opaqueOverClippedBounds = computedState.transform.isSimple() &&
+ computedState.clipState->mode == ClipMode::Rectangle &&
+ MathUtils::areEqual(alpha, 1.0f) &&
+ !roundRectClipState && PaintUtils::isOpaquePaint(paint);
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index 7b0b34f3d9c0..c74475516cdc 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -26,22 +26,22 @@ namespace android {
namespace uirenderer {
namespace OpClipSideFlags {
- enum {
- None = 0x0,
- Left = 0x1,
- Top = 0x2,
- Right = 0x4,
- Bottom = 0x8,
- Full = 0xF,
- // ConservativeFull = 0x1F needed?
- };
+enum {
+ None = 0x0,
+ Left = 0x1,
+ Top = 0x2,
+ Right = 0x4,
+ Bottom = 0x8,
+ Full = 0xF,
+ // ConservativeFull = 0x1F needed?
+};
}
/**
* Holds a list of BakedOpStates of ops that can be drawn together
*/
struct MergedBakedOpList {
- const BakedOpState*const* states;
+ const BakedOpState* const* states;
size_t count;
int clipSideFlags;
Rect clip;
@@ -53,11 +53,12 @@ struct MergedBakedOpList {
class ResolvedRenderState {
public:
ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
- const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture);
+ const RecordedOp& recordedOp, bool expandForStroke,
+ bool expandForPathTexture);
// Constructor for unbounded ops *with* transform/clip
ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
- const Matrix4& localTransform, const ClipBase* localClip);
+ const Matrix4& localTransform, const ClipBase* localClip);
// Constructor for unbounded ops without transform/clip (namely shadows)
ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot);
@@ -74,19 +75,15 @@ public:
return outClip;
}
- const Rect& clipRect() const {
- return clipState->rect;
- }
+ const Rect& clipRect() const { return clipState->rect; }
bool requiresClip() const {
- return clipSideFlags != OpClipSideFlags::None
- || CC_UNLIKELY(clipState->mode != ClipMode::Rectangle);
+ return clipSideFlags != OpClipSideFlags::None ||
+ CC_UNLIKELY(clipState->mode != ClipMode::Rectangle);
}
// returns the clip if it's needed to draw the operation, otherwise nullptr
- const ClipBase* getClipIfNeeded() const {
- return requiresClip() ? clipState : nullptr;
- }
+ const ClipBase* getClipIfNeeded() const { return requiresClip() ? clipState : nullptr; }
Matrix4 transform;
const ClipBase* clipState = nullptr;
@@ -103,11 +100,11 @@ public:
*/
class BakedOpState {
public:
- static BakedOpState* tryConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp);
+ static BakedOpState* tryConstruct(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp);
- static BakedOpState* tryConstructUnbounded(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp);
+ static BakedOpState* tryConstructUnbounded(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp);
enum class StrokeBehavior {
// stroking is forced, regardless of style on paint (such as for lines)
@@ -116,15 +113,16 @@ public:
StyleDefined,
};
- static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior,
- bool expandForPathTexture);
+ static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp,
+ StrokeBehavior strokeBehavior,
+ bool expandForPathTexture);
- static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const ShadowOp* shadowOpPtr);
+ static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator, Snapshot& snapshot,
+ const ShadowOp* shadowOpPtr);
- static BakedOpState* directConstruct(LinearAllocator& allocator,
- const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp);
+ static BakedOpState* directConstruct(LinearAllocator& allocator, const ClipRect* clip,
+ const Rect& dstRect, const RecordedOp& recordedOp);
// Set opaqueOverClippedBounds. If this method isn't called, the op is assumed translucent.
void setupOpacity(const SkPaint* paint);
@@ -140,8 +138,8 @@ public:
private:
friend class LinearAllocator;
- BakedOpState(LinearAllocator& allocator, Snapshot& snapshot,
- const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture)
+ BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp,
+ bool expandForStroke, bool expandForPathTexture)
: computedState(allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture)
, alpha(snapshot.alpha)
, roundRectClipState(snapshot.roundRectClipState)
@@ -167,7 +165,7 @@ private:
, op(&recordedOp) {}
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_BAKED_OP_STATE_H
+#endif // ANDROID_HWUI_BAKED_OP_STATE_H
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 0700d1fb9f70..3c774a3313d2 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -19,8 +19,8 @@
#include "GammaFontRenderer.h"
#include "GlLayer.h"
#include "Properties.h"
-#include "renderstate/RenderState.h"
#include "ShadowTessellator.h"
+#include "renderstate/RenderState.h"
#ifdef BUGREPORT_FONT_CACHE_USAGE
#include "font/FontCacheHistoryTracker.h"
#endif
@@ -40,9 +40,9 @@ Caches* Caches::sInstance = nullptr;
///////////////////////////////////////////////////////////////////////////////
#if DEBUG_CACHE_FLUSH
- #define FLUSH_LOGD(...) ALOGD(__VA_ARGS__)
+#define FLUSH_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define FLUSH_LOGD(...)
+#define FLUSH_LOGD(...)
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -98,8 +98,8 @@ void Caches::initConstraints() {
void Caches::initStaticProperties() {
// OpenGL ES 3.0+ specific features
- gpuPixelBuffersEnabled = extensions().hasPixelBufferObjects()
- && property_get_bool(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, true);
+ gpuPixelBuffersEnabled = extensions().hasPixelBufferObjects() &&
+ property_get_bool(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, true);
}
void Caches::terminate() {
@@ -143,10 +143,8 @@ void Caches::setProgram(Program* program) {
///////////////////////////////////////////////////////////////////////////////
uint32_t Caches::getOverdrawColor(uint32_t amount) const {
- static uint32_t sOverdrawColors[2][4] = {
- { 0x2f0000ff, 0x2f00ff00, 0x3fff0000, 0x7fff0000 },
- { 0x2f0000ff, 0x4fffff00, 0x5fff8ad8, 0x7fff0000 }
- };
+ static uint32_t sOverdrawColors[2][4] = {{0x2f0000ff, 0x2f00ff00, 0x3fff0000, 0x7fff0000},
+ {0x2f0000ff, 0x4fffff00, 0x5fff8ad8, 0x7fff0000}};
if (amount < 1) amount = 1;
if (amount > 4) amount = 4;
@@ -160,46 +158,44 @@ void Caches::dumpMemoryUsage() {
ALOGD("%s", stringLog.string());
}
-void Caches::dumpMemoryUsage(String8 &log) {
+void Caches::dumpMemoryUsage(String8& log) {
uint32_t total = 0;
log.appendFormat("Current memory usage / total memory usage (bytes):\n");
- log.appendFormat(" TextureCache %8d / %8d\n",
- textureCache.getSize(), textureCache.getMaxSize());
+ log.appendFormat(" TextureCache %8d / %8d\n", textureCache.getSize(),
+ textureCache.getMaxSize());
if (mRenderState) {
int memused = 0;
for (std::set<Layer*>::iterator it = mRenderState->mActiveLayers.begin();
- it != mRenderState->mActiveLayers.end(); it++) {
+ it != mRenderState->mActiveLayers.end(); it++) {
const Layer* layer = *it;
LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::OpenGL);
const GlLayer* glLayer = static_cast<const GlLayer*>(layer);
- log.appendFormat(" GlLayer size %dx%d; texid=%u refs=%d\n",
- layer->getWidth(), layer->getHeight(),
- glLayer->getTextureId(),
- layer->getStrongCount());
+ log.appendFormat(" GlLayer size %dx%d; texid=%u refs=%d\n", layer->getWidth(),
+ layer->getHeight(), glLayer->getTextureId(), layer->getStrongCount());
memused += layer->getWidth() * layer->getHeight() * 4;
}
- log.appendFormat(" Layers total %8d (numLayers = %zu)\n",
- memused, mRenderState->mActiveLayers.size());
+ log.appendFormat(" Layers total %8d (numLayers = %zu)\n", memused,
+ mRenderState->mActiveLayers.size());
total += memused;
}
- log.appendFormat(" RenderBufferCache %8d / %8d\n",
- renderBufferCache.getSize(), renderBufferCache.getMaxSize());
- log.appendFormat(" GradientCache %8d / %8d\n",
- gradientCache.getSize(), gradientCache.getMaxSize());
- log.appendFormat(" PathCache %8d / %8d\n",
- pathCache.getSize(), pathCache.getMaxSize());
- log.appendFormat(" TessellationCache %8d / %8d\n",
- tessellationCache.getSize(), tessellationCache.getMaxSize());
+ log.appendFormat(" RenderBufferCache %8d / %8d\n", renderBufferCache.getSize(),
+ renderBufferCache.getMaxSize());
+ log.appendFormat(" GradientCache %8d / %8d\n", gradientCache.getSize(),
+ gradientCache.getMaxSize());
+ log.appendFormat(" PathCache %8d / %8d\n", pathCache.getSize(),
+ pathCache.getMaxSize());
+ log.appendFormat(" TessellationCache %8d / %8d\n", tessellationCache.getSize(),
+ tessellationCache.getMaxSize());
log.appendFormat(" TextDropShadowCache %8d / %8d\n", dropShadowCache.getSize(),
- dropShadowCache.getMaxSize());
- log.appendFormat(" PatchCache %8d / %8d\n",
- patchCache.getSize(), patchCache.getMaxSize());
+ dropShadowCache.getMaxSize());
+ log.appendFormat(" PatchCache %8d / %8d\n", patchCache.getSize(),
+ patchCache.getMaxSize());
fontRenderer.dumpMemoryUsage(log);
log.appendFormat("Other:\n");
- log.appendFormat(" FboCache %8d / %8d\n",
- fboCache.getSize(), fboCache.getMaxSize());
+ log.appendFormat(" FboCache %8d / %8d\n", fboCache.getSize(),
+ fboCache.getMaxSize());
total += textureCache.getSize();
total += renderBufferCache.getSize();
@@ -238,13 +234,13 @@ void Caches::flush(FlushMode mode) {
gradientCache.clear();
fontRenderer.clear();
fboCache.clear();
- // fall through
+ // fall through
case FlushMode::Moderate:
fontRenderer.flush();
textureCache.flush();
pathCache.clear();
tessellationCache.clear();
- // fall through
+ // fall through
case FlushMode::Layers:
renderBufferCache.clear();
break;
@@ -274,5 +270,5 @@ TextureVertex* Caches::getRegionMesh() {
// Temporary Properties
///////////////////////////////////////////////////////////////////////////////
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 29eddde1e42b..97328324df04 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -22,20 +22,20 @@
#include "GammaFontRenderer.h"
#include "GradientCache.h"
#include "PatchCache.h"
-#include "ProgramCache.h"
#include "PathCache.h"
+#include "ProgramCache.h"
#include "RenderBufferCache.h"
-#include "renderstate/PixelBufferState.h"
-#include "renderstate/TextureState.h"
#include "ResourceCache.h"
#include "TessellationCache.h"
#include "TextDropShadowCache.h"
#include "TextureCache.h"
-#include "thread/TaskProcessor.h"
+#include "renderstate/PixelBufferState.h"
+#include "renderstate/TextureState.h"
#include "thread/TaskManager.h"
+#include "thread/TaskProcessor.h"
-#include <vector>
#include <memory>
+#include <vector>
#include <GLES3/gl3.h>
@@ -70,19 +70,14 @@ public:
return *sInstance;
}
- static bool hasInstance() {
- return sInstance != nullptr;
- }
+ static bool hasInstance() { return sInstance != nullptr; }
+
private:
explicit Caches(RenderState& renderState);
static Caches* sInstance;
public:
- enum class FlushMode {
- Layers = 0,
- Moderate,
- Full
- };
+ enum class FlushMode { Layers = 0, Moderate, Full };
/**
* Initialize caches.
@@ -181,9 +176,9 @@ private:
void initConstraints();
void initStaticProperties();
- static void eventMarkNull(GLsizei length, const GLchar* marker) { }
- static void startMarkNull(GLsizei length, const GLchar* marker) { }
- static void endMarkNull() { }
+ static void eventMarkNull(GLsizei length, const GLchar* marker) {}
+ static void startMarkNull(GLsizei length, const GLchar* marker) {}
+ static void endMarkNull() {}
RenderState* mRenderState;
@@ -198,9 +193,9 @@ private:
// TODO: move below to RenderState
PixelBufferState* mPixelBufferState = nullptr;
TextureState* mTextureState = nullptr;
- Program* mProgram = nullptr; // note: object owned by ProgramCache
+ Program* mProgram = nullptr; // note: object owned by ProgramCache
-}; // class Caches
+}; // class Caches
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/CanvasProperty.h b/libs/hwui/CanvasProperty.h
index 56671bba654b..fc76e8b68af8 100644
--- a/libs/hwui/CanvasProperty.h
+++ b/libs/hwui/CanvasProperty.h
@@ -27,6 +27,7 @@ namespace uirenderer {
class CanvasPropertyPrimitive : public VirtualLightRefBase {
PREVENT_COPY_AND_ASSIGN(CanvasPropertyPrimitive);
+
public:
explicit CanvasPropertyPrimitive(float initialValue) : value(initialValue) {}
@@ -35,6 +36,7 @@ public:
class CanvasPropertyPaint : public VirtualLightRefBase {
PREVENT_COPY_AND_ASSIGN(CanvasPropertyPaint);
+
public:
explicit CanvasPropertyPaint(const SkPaint& initialValue) : value(initialValue) {}
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index 9c068b080d45..d18c4abde7f2 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -21,14 +21,8 @@
namespace android {
namespace uirenderer {
-
CanvasState::CanvasState(CanvasStateClient& renderer)
- : mWidth(-1)
- , mHeight(-1)
- , mSaveCount(1)
- , mCanvas(renderer)
- , mSnapshot(&mFirstSnapshot) {
-}
+ : mWidth(-1), mHeight(-1), mSaveCount(1), mCanvas(renderer), mSnapshot(&mFirstSnapshot) {}
CanvasState::~CanvasState() {
// First call freeSnapshot on all but mFirstSnapshot
@@ -57,10 +51,9 @@ void CanvasState::initializeRecordingSaveStack(int viewportWidth, int viewportHe
mSaveCount = 1;
}
-void CanvasState::initializeSaveStack(
- int viewportWidth, int viewportHeight,
- float clipLeft, float clipTop,
- float clipRight, float clipBottom, const Vector3& lightCenter) {
+void CanvasState::initializeSaveStack(int viewportWidth, int viewportHeight, float clipLeft,
+ float clipTop, float clipRight, float clipBottom,
+ const Vector3& lightCenter) {
if (mWidth != viewportWidth || mHeight != viewportHeight) {
mWidth = viewportWidth;
mHeight = viewportHeight;
@@ -92,7 +85,7 @@ void CanvasState::freeSnapshot(Snapshot* snapshot) {
snapshot->~Snapshot();
// Arbitrary number, just don't let this grown unbounded
if (mSnapshotPoolCount > 10) {
- free((void*) snapshot);
+ free((void*)snapshot);
} else {
snapshot->previous = mSnapshotPool;
mSnapshotPool = snapshot;
@@ -215,7 +208,7 @@ bool CanvasState::clipPath(const SkPath* path, SkClipOp op) {
void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
Rect bounds;
float radius;
- if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
+ if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
bool outlineIsRounded = MathUtils::isPositive(radius);
if (!outlineIsRounded || currentTransform()->isSimple()) {
@@ -241,10 +234,9 @@ void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline*
* @param snapOut if set, the geometry will be treated as having an AA ramp.
* See Rect::snapGeometryToPixelBoundaries()
*/
-bool CanvasState::calculateQuickRejectForScissor(float left, float top,
- float right, float bottom,
- bool* clipRequired, bool* roundRectClipRequired,
- bool snapOut) const {
+bool CanvasState::calculateQuickRejectForScissor(float left, float top, float right, float bottom,
+ bool* clipRequired, bool* roundRectClipRequired,
+ bool snapOut) const {
if (bottom <= top || right <= left) {
return true;
}
@@ -265,21 +257,20 @@ bool CanvasState::calculateQuickRejectForScissor(float left, float top,
// round rect clip is required if RR clip exists, and geometry intersects its corners
if (roundRectClipRequired) {
- *roundRectClipRequired = mSnapshot->roundRectClipState != nullptr
- && mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r);
+ *roundRectClipRequired = mSnapshot->roundRectClipState != nullptr &&
+ mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r);
}
return false;
}
-bool CanvasState::quickRejectConservative(float left, float top,
- float right, float bottom) const {
+bool CanvasState::quickRejectConservative(float left, float top, float right, float bottom) const {
if (bottom <= top || right <= left) {
return true;
}
Rect r(left, top, right, bottom);
currentTransform()->mapRect(r);
- r.roundOut(); // rounded out to be conservative
+ r.roundOut(); // rounded out to be conservative
Rect clipRect(currentRenderTargetClip());
clipRect.snapToPixelBoundaries();
@@ -289,5 +280,5 @@ bool CanvasState::quickRejectConservative(float left, float top,
return false;
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
index b1fe09eb1aec..9ac35ff47dab 100644
--- a/libs/hwui/CanvasState.h
+++ b/libs/hwui/CanvasState.h
@@ -32,8 +32,8 @@ namespace uirenderer {
*/
class CanvasStateClient {
public:
- CanvasStateClient() { }
- virtual ~CanvasStateClient() { }
+ CanvasStateClient() {}
+ virtual ~CanvasStateClient() {}
/**
* Callback allowing embedder to take actions in the middle of a
@@ -53,7 +53,7 @@ public:
*/
virtual GLuint getTargetFbo() const = 0;
-}; // class CanvasStateClient
+}; // class CanvasStateClient
/**
* Implements Canvas state methods on behalf of Renderers.
@@ -86,13 +86,10 @@ public:
* Initializes the first snapshot, computing the projection matrix,
* and stores the dimensions of the render target.
*/
- void initializeSaveStack(int viewportWidth, int viewportHeight,
- float clipLeft, float clipTop, float clipRight, float clipBottom,
- const Vector3& lightCenter);
+ void initializeSaveStack(int viewportWidth, int viewportHeight, float clipLeft, float clipTop,
+ float clipRight, float clipBottom, const Vector3& lightCenter);
- bool hasRectToRectTransform() const {
- return CC_LIKELY(currentTransform()->rectToRect());
- }
+ bool hasRectToRectTransform() const { return CC_LIKELY(currentTransform()->rectToRect()); }
// Save (layer)
int getSaveCount() const { return mSaveCount; }
@@ -112,9 +109,9 @@ public:
void skew(float sx, float sy);
void setMatrix(const SkMatrix& matrix);
- void setMatrix(const Matrix4& matrix); // internal only convenience method
+ void setMatrix(const Matrix4& matrix); // internal only convenience method
void concatMatrix(const SkMatrix& matrix);
- void concatMatrix(const Matrix4& matrix); // internal only convenience method
+ void concatMatrix(const Matrix4& matrix); // internal only convenience method
// Clip
const Rect& getLocalClipBounds() const { return mSnapshot->getLocalClip(); }
@@ -132,13 +129,11 @@ public:
* outline.
*/
void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
- void setClippingRoundRect(LinearAllocator& allocator,
- const Rect& rect, float radius, bool highPriority = true) {
+ void setClippingRoundRect(LinearAllocator& allocator, const Rect& rect, float radius,
+ bool highPriority = true) {
mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority);
}
- void setProjectionPathMask(const SkPath* path) {
- mSnapshot->setProjectionPathMask(path);
- }
+ void setProjectionPathMask(const SkPath* path) { mSnapshot->setProjectionPathMask(path); }
/**
* Returns true if drawing in the rectangle (left, top, right, bottom)
@@ -146,14 +141,19 @@ public:
* perfect tests would return true.
*/
bool calculateQuickRejectForScissor(float left, float top, float right, float bottom,
- bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const;
+ bool* clipRequired, bool* roundRectClipRequired,
+ bool snapOut) const;
void scaleAlpha(float alpha) { mSnapshot->alpha *= alpha; }
inline const mat4* currentTransform() const { return currentSnapshot()->transform; }
- inline const Rect& currentRenderTargetClip() const { return currentSnapshot()->getRenderTargetClip(); }
+ inline const Rect& currentRenderTargetClip() const {
+ return currentSnapshot()->getRenderTargetClip();
+ }
inline int currentFlags() const { return currentSnapshot()->flags; }
- const Vector3& currentLightCenter() const { return currentSnapshot()->getRelativeLightCenter(); }
+ const Vector3& currentLightCenter() const {
+ return currentSnapshot()->getRelativeLightCenter();
+ }
int getViewportWidth() const { return currentSnapshot()->getViewportWidth(); }
int getViewportHeight() const { return currentSnapshot()->getViewportHeight(); }
int getWidth() const { return mWidth; }
@@ -189,7 +189,7 @@ private:
Snapshot* mSnapshotPool = nullptr;
int mSnapshotPoolCount = 0;
-}; // class CanvasState
+}; // class CanvasState
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index 84451bacbc09..27d93cfa0391 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -33,7 +33,7 @@ static void handlePoint(Rect& transformedBounds, const Matrix4& transform, float
Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform) {
const float kMinFloat = std::numeric_limits<float>::lowest();
const float kMaxFloat = std::numeric_limits<float>::max();
- Rect transformedBounds = { kMaxFloat, kMaxFloat, kMinFloat, kMinFloat };
+ Rect transformedBounds = {kMaxFloat, kMaxFloat, kMinFloat, kMinFloat};
handlePoint(transformedBounds, transform, r.left, r.top);
handlePoint(transformedBounds, transform, r.right, r.top);
handlePoint(transformedBounds, transform, r.left, r.bottom);
@@ -49,18 +49,12 @@ void ClipBase::dump() const {
* TransformedRectangle
*/
-TransformedRectangle::TransformedRectangle() {
-}
-
-TransformedRectangle::TransformedRectangle(const Rect& bounds,
- const Matrix4& transform)
- : mBounds(bounds)
- , mTransform(transform) {
-}
+TransformedRectangle::TransformedRectangle() {}
-bool TransformedRectangle::canSimplyIntersectWith(
- const TransformedRectangle& other) const {
+TransformedRectangle::TransformedRectangle(const Rect& bounds, const Matrix4& transform)
+ : mBounds(bounds), mTransform(transform) {}
+bool TransformedRectangle::canSimplyIntersectWith(const TransformedRectangle& other) const {
return mTransform == other.mTransform;
}
@@ -76,9 +70,7 @@ bool TransformedRectangle::isEmpty() const {
* RectangleList
*/
-RectangleList::RectangleList()
- : mTransformedRectanglesCount(0) {
-}
+RectangleList::RectangleList() : mTransformedRectanglesCount(0) {}
bool RectangleList::isEmpty() const {
if (mTransformedRectanglesCount < 1) {
@@ -110,8 +102,7 @@ void RectangleList::set(const Rect& bounds, const Matrix4& transform) {
mTransformedRectangles[0] = TransformedRectangle(bounds, transform);
}
-bool RectangleList::intersectWith(const Rect& bounds,
- const Matrix4& transform) {
+bool RectangleList::intersectWith(const Rect& bounds, const Matrix4& transform) {
TransformedRectangle newRectangle(bounds, transform);
// Try to find a rectangle with a compatible transformation
@@ -148,8 +139,7 @@ Rect RectangleList::calculateBounds() const {
return bounds;
}
-static SkPath pathFromTransformedRectangle(const Rect& bounds,
- const Matrix4& transform) {
+static SkPath pathFromTransformedRectangle(const Rect& bounds, const Matrix4& transform) {
SkPath rectPath;
SkPath rectPathTransformed;
rectPath.addRect(bounds.left, bounds.top, bounds.right, bounds.bottom);
@@ -163,8 +153,8 @@ SkRegion RectangleList::convertToRegion(const SkRegion& clip) const {
SkRegion rectangleListAsRegion;
for (int index = 0; index < mTransformedRectanglesCount; index++) {
const TransformedRectangle& tr(mTransformedRectangles[index]);
- SkPath rectPathTransformed = pathFromTransformedRectangle(
- tr.getBounds(), tr.getTransform());
+ SkPath rectPathTransformed =
+ pathFromTransformedRectangle(tr.getBounds(), tr.getTransform());
if (index == 0) {
rectangleListAsRegion.setPath(rectPathTransformed, clip);
} else {
@@ -186,9 +176,7 @@ void RectangleList::transform(const Matrix4& transform) {
* ClipArea
*/
-ClipArea::ClipArea()
- : mMode(ClipMode::Rectangle) {
-}
+ClipArea::ClipArea() : mMode(ClipMode::Rectangle) {}
/*
* Interface
@@ -215,21 +203,20 @@ void ClipArea::setClip(float left, float top, float right, float bottom) {
mClipRegion.setEmpty();
}
-void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
- SkRegion::Op op) {
+void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op) {
if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true;
if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
onClipUpdated();
switch (mMode) {
- case ClipMode::Rectangle:
- rectangleModeClipRectWithTransform(r, transform, op);
- break;
- case ClipMode::RectangleList:
- rectangleListModeClipRectWithTransform(r, transform, op);
- break;
- case ClipMode::Region:
- regionModeClipRectWithTransform(r, transform, op);
- break;
+ case ClipMode::Rectangle:
+ rectangleModeClipRectWithTransform(r, transform, op);
+ break;
+ case ClipMode::RectangleList:
+ rectangleListModeClipRectWithTransform(r, transform, op);
+ break;
+ case ClipMode::Region:
+ regionModeClipRectWithTransform(r, transform, op);
+ break;
}
}
@@ -242,8 +229,7 @@ void ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
onClipRegionUpdated();
}
-void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
- SkRegion::Op op) {
+void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform, SkRegion::Op op) {
if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true;
if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
onClipUpdated();
@@ -269,9 +255,8 @@ void ClipArea::enterRectangleMode() {
mMode = ClipMode::Rectangle;
}
-void ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
- const mat4* transform, SkRegion::Op op) {
-
+void ClipArea::rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform,
+ SkRegion::Op op) {
if (op == SkRegion::kReplace_Op && transform->rectToRect()) {
mClipRect = r;
transform->mapRect(mClipRect);
@@ -306,10 +291,9 @@ void ClipArea::enterRectangleListMode() {
mRectangleList.set(mClipRect, Matrix4::identity());
}
-void ClipArea::rectangleListModeClipRectWithTransform(const Rect& r,
- const mat4* transform, SkRegion::Op op) {
- if (op != SkRegion::kIntersect_Op
- || !mRectangleList.intersectWith(r, *transform)) {
+void ClipArea::rectangleListModeClipRectWithTransform(const Rect& r, const mat4* transform,
+ SkRegion::Op op) {
+ if (op != SkRegion::kIntersect_Op || !mRectangleList.intersectWith(r, *transform)) {
enterRegionMode();
regionModeClipRectWithTransform(r, transform, op);
}
@@ -332,8 +316,8 @@ void ClipArea::enterRegionMode() {
}
}
-void ClipArea::regionModeClipRectWithTransform(const Rect& r,
- const mat4* transform, SkRegion::Op op) {
+void ClipArea::regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
+ SkRegion::Op op) {
SkPath transformedRect = pathFromTransformedRectangle(r, *transform);
SkRegion transformedRectRegion;
regionFromPath(transformedRect, transformedRectRegion);
@@ -365,24 +349,24 @@ const ClipBase* ClipArea::serializeClip(LinearAllocator& allocator) {
}
static_assert(std::is_trivially_destructible<Rect>::value,
- "expect Rect to be trivially destructible");
+ "expect Rect to be trivially destructible");
static_assert(std::is_trivially_destructible<RectangleList>::value,
- "expect RectangleList to be trivially destructible");
+ "expect RectangleList to be trivially destructible");
if (mLastSerialization == nullptr) {
ClipBase* serialization = nullptr;
switch (mMode) {
- case ClipMode::Rectangle:
- serialization = allocator.create<ClipRect>(mClipRect);
- break;
- case ClipMode::RectangleList:
- serialization = allocator.create<ClipRectList>(mRectangleList);
- serialization->rect = mRectangleList.calculateBounds();
- break;
- case ClipMode::Region:
- serialization = allocator.create<ClipRegion>(mClipRegion);
- serialization->rect.set(mClipRegion.getBounds());
- break;
+ case ClipMode::Rectangle:
+ serialization = allocator.create<ClipRect>(mClipRect);
+ break;
+ case ClipMode::RectangleList:
+ serialization = allocator.create<ClipRectList>(mRectangleList);
+ serialization->rect = mRectangleList.calculateBounds();
+ break;
+ case ClipMode::Region:
+ serialization = allocator.create<ClipRegion>(mClipRegion);
+ serialization->rect.set(mClipRegion.getBounds());
+ break;
}
serialization->intersectWithRoot = mReplaceOpObserved;
// TODO: this is only done for draw time, should eventually avoid for record time
@@ -404,81 +388,79 @@ inline static const SkRegion& getRegion(const ClipBase* scb) {
// For simplicity, doesn't account for rect merging
static bool cannotFitInRectangleList(const ClipArea& clipArea, const ClipBase* scb) {
int currentRectCount = clipArea.isRectangleList()
- ? clipArea.getRectangleList().getTransformedRectanglesCount()
- : 1;
+ ? clipArea.getRectangleList().getTransformedRectanglesCount()
+ : 1;
int recordedRectCount = (scb->mode == ClipMode::RectangleList)
- ? getRectList(scb).getTransformedRectanglesCount()
- : 1;
+ ? getRectList(scb).getTransformedRectanglesCount()
+ : 1;
return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles;
}
static const ClipRect sEmptyClipRect(Rect(0, 0));
const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
- const ClipBase* recordedClip, const Matrix4& recordedClipTransform) {
-
+ const ClipBase* recordedClip,
+ const Matrix4& recordedClipTransform) {
// if no recordedClip passed, just serialize current state
if (!recordedClip) return serializeClip(allocator);
// if either is empty, clip is empty
- if (CC_UNLIKELY(recordedClip->rect.isEmpty())|| mClipRect.isEmpty()) return &sEmptyClipRect;
+ if (CC_UNLIKELY(recordedClip->rect.isEmpty()) || mClipRect.isEmpty()) return &sEmptyClipRect;
- if (!mLastResolutionResult
- || recordedClip != mLastResolutionClip
- || recordedClipTransform != mLastResolutionTransform) {
+ if (!mLastResolutionResult || recordedClip != mLastResolutionClip ||
+ recordedClipTransform != mLastResolutionTransform) {
mLastResolutionClip = recordedClip;
mLastResolutionTransform = recordedClipTransform;
- if (CC_LIKELY(mMode == ClipMode::Rectangle
- && recordedClip->mode == ClipMode::Rectangle
- && recordedClipTransform.rectToRect())) {
+ if (CC_LIKELY(mMode == ClipMode::Rectangle && recordedClip->mode == ClipMode::Rectangle &&
+ recordedClipTransform.rectToRect())) {
// common case - result is a single rectangle
auto rectClip = allocator.create<ClipRect>(recordedClip->rect);
recordedClipTransform.mapRect(rectClip->rect);
rectClip->rect.doIntersect(mClipRect);
rectClip->rect.snapToPixelBoundaries();
mLastResolutionResult = rectClip;
- } else if (CC_UNLIKELY(mMode == ClipMode::Region
- || recordedClip->mode == ClipMode::Region
- || cannotFitInRectangleList(*this, recordedClip))) {
+ } else if (CC_UNLIKELY(mMode == ClipMode::Region ||
+ recordedClip->mode == ClipMode::Region ||
+ cannotFitInRectangleList(*this, recordedClip))) {
// region case
SkRegion other;
switch (recordedClip->mode) {
- case ClipMode::Rectangle:
- if (CC_LIKELY(recordedClipTransform.rectToRect())) {
- // simple transform, skip creating SkPath
- Rect resultClip(recordedClip->rect);
- recordedClipTransform.mapRect(resultClip);
- other.setRect(resultClip.toSkIRect());
- } else {
- SkPath transformedRect = pathFromTransformedRectangle(recordedClip->rect,
- recordedClipTransform);
- other.setPath(transformedRect, createViewportRegion());
+ case ClipMode::Rectangle:
+ if (CC_LIKELY(recordedClipTransform.rectToRect())) {
+ // simple transform, skip creating SkPath
+ Rect resultClip(recordedClip->rect);
+ recordedClipTransform.mapRect(resultClip);
+ other.setRect(resultClip.toSkIRect());
+ } else {
+ SkPath transformedRect = pathFromTransformedRectangle(
+ recordedClip->rect, recordedClipTransform);
+ other.setPath(transformedRect, createViewportRegion());
+ }
+ break;
+ case ClipMode::RectangleList: {
+ RectangleList transformedList(getRectList(recordedClip));
+ transformedList.transform(recordedClipTransform);
+ other = transformedList.convertToRegion(createViewportRegion());
+ break;
}
- break;
- case ClipMode::RectangleList: {
- RectangleList transformedList(getRectList(recordedClip));
- transformedList.transform(recordedClipTransform);
- other = transformedList.convertToRegion(createViewportRegion());
- break;
- }
- case ClipMode::Region:
- other = getRegion(recordedClip);
- applyTransformToRegion(recordedClipTransform, &other);
+ case ClipMode::Region:
+ other = getRegion(recordedClip);
+ applyTransformToRegion(recordedClipTransform, &other);
}
ClipRegion* regionClip = allocator.create<ClipRegion>();
switch (mMode) {
- case ClipMode::Rectangle:
- regionClip->region.op(mClipRect.toSkIRect(), other, SkRegion::kIntersect_Op);
- break;
- case ClipMode::RectangleList:
- regionClip->region.op(mRectangleList.convertToRegion(createViewportRegion()),
- other, SkRegion::kIntersect_Op);
- break;
- case ClipMode::Region:
- regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
- break;
+ case ClipMode::Rectangle:
+ regionClip->region.op(mClipRect.toSkIRect(), other, SkRegion::kIntersect_Op);
+ break;
+ case ClipMode::RectangleList:
+ regionClip->region.op(mRectangleList.convertToRegion(createViewportRegion()),
+ other, SkRegion::kIntersect_Op);
+ break;
+ case ClipMode::Region:
+ regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
+ break;
}
// Don't need to snap, since region's in int bounds
regionClip->rect.set(regionClip->region.getBounds());
@@ -510,7 +492,7 @@ const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
}
void ClipArea::applyClip(const ClipBase* clip, const Matrix4& transform) {
- if (!clip) return; // nothing to do
+ if (!clip) return; // nothing to do
if (CC_LIKELY(clip->mode == ClipMode::Rectangle)) {
clipRectWithTransform(clip->rect, &transform, SkRegion::kIntersect_Op);
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
index cf5751606d12..a7a11801cfe2 100644
--- a/libs/hwui/ClipArea.h
+++ b/libs/hwui/ClipArea.h
@@ -39,18 +39,14 @@ public:
bool isEmpty() const;
- const Rect& getBounds() const {
- return mBounds;
- }
+ const Rect& getBounds() const { return mBounds; }
Rect transformedBounds() const {
Rect transformedBounds(transformAndCalculateBounds(mBounds, mTransform));
return transformedBounds;
}
- const Matrix4& getTransform() const {
- return mTransform;
- }
+ const Matrix4& getTransform() const { return mTransform; }
void transform(const Matrix4& transform) {
Matrix4 t;
@@ -79,9 +75,7 @@ public:
SkRegion convertToRegion(const SkRegion& clip) const;
Rect calculateBounds() const;
- enum {
- kMaxTransformedRectangles = 5
- };
+ enum { kMaxTransformedRectangles = 5 };
private:
int mTransformedRectanglesCount;
@@ -97,11 +91,8 @@ enum class ClipMode {
};
struct ClipBase {
- explicit ClipBase(ClipMode mode)
- : mode(mode) {}
- explicit ClipBase(const Rect& rect)
- : mode(ClipMode::Rectangle)
- , rect(rect) {}
+ explicit ClipBase(ClipMode mode) : mode(mode) {}
+ explicit ClipBase(const Rect& rect) : mode(ClipMode::Rectangle), rect(rect) {}
const ClipMode mode;
bool intersectWithRoot = false;
// Bounds of the clipping area, used to define the scissor, and define which
@@ -112,23 +103,18 @@ struct ClipBase {
};
struct ClipRect : ClipBase {
- explicit ClipRect(const Rect& rect)
- : ClipBase(rect) {}
+ explicit ClipRect(const Rect& rect) : ClipBase(rect) {}
};
struct ClipRectList : ClipBase {
explicit ClipRectList(const RectangleList& rectList)
- : ClipBase(ClipMode::RectangleList)
- , rectList(rectList) {}
+ : ClipBase(ClipMode::RectangleList), rectList(rectList) {}
RectangleList rectList;
};
struct ClipRegion : ClipBase {
- explicit ClipRegion(const SkRegion& region)
- : ClipBase(ClipMode::Region)
- , region(region) {}
- ClipRegion()
- : ClipBase(ClipMode::Region) {}
+ explicit ClipRegion(const SkRegion& region) : ClipBase(ClipMode::Region), region(region) {}
+ ClipRegion() : ClipBase(ClipMode::Region) {}
SkRegion region;
};
@@ -138,44 +124,29 @@ public:
void setViewportDimensions(int width, int height);
- bool isEmpty() const {
- return mClipRect.isEmpty();
- }
+ bool isEmpty() const { return mClipRect.isEmpty(); }
void setEmpty();
void setClip(float left, float top, float right, float bottom);
- void clipRectWithTransform(const Rect& r, const mat4* transform,
- SkRegion::Op op);
- void clipPathWithTransform(const SkPath& path, const mat4* transform,
- SkRegion::Op op);
+ void clipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
+ void clipPathWithTransform(const SkPath& path, const mat4* transform, SkRegion::Op op);
- const Rect& getClipRect() const {
- return mClipRect;
- }
+ const Rect& getClipRect() const { return mClipRect; }
- const SkRegion& getClipRegion() const {
- return mClipRegion;
- }
+ const SkRegion& getClipRegion() const { return mClipRegion; }
- const RectangleList& getRectangleList() const {
- return mRectangleList;
- }
+ const RectangleList& getRectangleList() const { return mRectangleList; }
- bool isRegion() const {
- return ClipMode::Region == mMode;
- }
+ bool isRegion() const { return ClipMode::Region == mMode; }
- bool isSimple() const {
- return mMode == ClipMode::Rectangle;
- }
+ bool isSimple() const { return mMode == ClipMode::Rectangle; }
- bool isRectangleList() const {
- return mMode == ClipMode::RectangleList;
- }
+ bool isRectangleList() const { return mMode == ClipMode::RectangleList; }
WARN_UNUSED_RESULT const ClipBase* serializeClip(LinearAllocator& allocator);
- WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip(LinearAllocator& allocator,
- const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
+ WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip(
+ LinearAllocator& allocator, const ClipBase* recordedClip,
+ const Matrix4& recordedClipTransform);
void applyClip(const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
static void applyTransformToRegion(const Matrix4& transform, SkRegion* region);
@@ -185,14 +156,13 @@ private:
void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
void enterRectangleListMode();
- void rectangleListModeClipRectWithTransform(const Rect& r,
- const mat4* transform, SkRegion::Op op);
+ void rectangleListModeClipRectWithTransform(const Rect& r, const mat4* transform,
+ SkRegion::Op op);
void enterRegionModeFromRectangleMode();
void enterRegionModeFromRectangleListMode();
void enterRegionMode();
- void regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
- SkRegion::Op op);
+ void regionModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
void clipRegion(const SkRegion& region, SkRegion::Op op);
void ensureClipRegion();
@@ -205,9 +175,7 @@ private:
mLastResolutionResult = nullptr;
}
- SkRegion createViewportRegion() {
- return SkRegion(mViewportBounds.toSkIRect());
- }
+ SkRegion createViewportRegion() { return SkRegion(mViewportBounds.toSkIRect()); }
void regionFromPath(const SkPath& path, SkRegion& pathAsRegion) {
// TODO: this should not mask every path to the viewport - this makes it impossible to use
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index 2b4fe17d424d..cca0032b230e 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -57,17 +57,18 @@ static void computeTransformImpl(const DirtyStack* currentFrame, Matrix4* outMat
computeTransformImpl(currentFrame->prev, outMatrix);
}
switch (currentFrame->type) {
- case TransformRenderNode:
- currentFrame->renderNode->applyViewPropertyTransforms(*outMatrix);
- break;
- case TransformMatrix4:
- outMatrix->multiply(*currentFrame->matrix4);
- break;
- case TransformNone:
- // nothing to be done
- break;
- default:
- LOG_ALWAYS_FATAL("Tried to compute transform with an invalid type: %d", currentFrame->type);
+ case TransformRenderNode:
+ currentFrame->renderNode->applyViewPropertyTransforms(*outMatrix);
+ break;
+ case TransformMatrix4:
+ outMatrix->multiply(*currentFrame->matrix4);
+ break;
+ case TransformNone:
+ // nothing to be done
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Tried to compute transform with an invalid type: %d",
+ currentFrame->type);
}
}
@@ -104,17 +105,17 @@ void DamageAccumulator::popTransform() {
DirtyStack* dirtyFrame = mHead;
mHead = mHead->prev;
switch (dirtyFrame->type) {
- case TransformRenderNode:
- applyRenderNodeTransform(dirtyFrame);
- break;
- case TransformMatrix4:
- applyMatrix4Transform(dirtyFrame);
- break;
- case TransformNone:
- mHead->pendingDirty.join(dirtyFrame->pendingDirty);
- break;
- default:
- LOG_ALWAYS_FATAL("Tried to pop an invalid type: %d", dirtyFrame->type);
+ case TransformRenderNode:
+ applyRenderNodeTransform(dirtyFrame);
+ break;
+ case TransformMatrix4:
+ applyMatrix4Transform(dirtyFrame);
+ break;
+ case TransformNone:
+ mHead->pendingDirty.join(dirtyFrame->pendingDirty);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Tried to pop an invalid type: %d", dirtyFrame->type);
}
}
@@ -168,8 +169,7 @@ static DirtyStack* findProjectionReceiver(DirtyStack* frame) {
if (frame) {
while (frame->prev != frame) {
frame = frame->prev;
- if (frame->type == TransformRenderNode
- && frame->renderNode->hasProjectionReceiver()) {
+ if (frame->type == TransformRenderNode && frame->renderNode->hasProjectionReceiver()) {
return frame;
}
}
@@ -233,7 +233,8 @@ void DamageAccumulator::peekAtDirty(SkRect* dest) const {
}
void DamageAccumulator::finish(SkRect* totalDirty) {
- LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p", mHead->prev, mHead);
+ LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p",
+ mHead->prev, mHead);
// Root node never has a transform, so this is the fully mapped dirty rect
*totalDirty = mHead->pendingDirty;
totalDirty->roundOut(totalDirty);
diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h
index 250296ecc89f..7d0b6877a71a 100644
--- a/libs/hwui/DamageAccumulator.h
+++ b/libs/hwui/DamageAccumulator.h
@@ -26,7 +26,7 @@
// Smaller than INT_MIN/INT_MAX because we offset these values
// and thus don't want to be adding offsets to INT_MAX, that's bad
-#define DIRTY_MIN (-0x7ffffff-1)
+#define DIRTY_MIN (-0x7ffffff - 1)
#define DIRTY_MAX (0x7ffffff)
namespace android {
@@ -38,6 +38,7 @@ class Matrix4;
class DamageAccumulator {
PREVENT_COPY_AND_ASSIGN(DamageAccumulator);
+
public:
DamageAccumulator();
// mAllocator will clean everything up for us, no need for a dtor
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index e29699d0faf4..9b1ba69a5377 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -102,9 +102,9 @@
#define DEBUG_VECTOR_DRAWABLE 0
#if DEBUG_INIT
- #define INIT_LOGD(...) ALOGD(__VA_ARGS__)
+#define INIT_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define INIT_LOGD(...)
+#define INIT_LOGD(...)
#endif
-#endif // ANDROID_HWUI_DEBUG_H
+#endif // ANDROID_HWUI_DEBUG_H
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index ff90160b8855..be7d663b412f 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -26,7 +26,7 @@ namespace android {
namespace uirenderer {
DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn,
- Layer::Api layerApi)
+ Layer::Api layerApi)
: mRenderState(renderState)
, mBlend(false)
, mSurfaceTexture(nullptr)
@@ -110,8 +110,8 @@ void DeferredLayerUpdater::apply() {
void DeferredLayerUpdater::doUpdateTexImage() {
LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL,
- "doUpdateTexImage non GL backend %x, GL %x, VK %x",
- mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
+ "doUpdateTexImage non GL backend %x, GL %x, VK %x", mLayer->getApi(),
+ Layer::Api::OpenGL, Layer::Api::Vulkan);
if (mSurfaceTexture->updateTexImage() == NO_ERROR) {
float transform[16];
@@ -132,15 +132,15 @@ void DeferredLayerUpdater::doUpdateTexImage() {
sp<GraphicBuffer> buffer = mSurfaceTexture->getCurrentBuffer();
if (buffer != nullptr) {
// force filtration if buffer size != layer size
- forceFilter = mWidth != static_cast<int>(buffer->getWidth())
- || mHeight != static_cast<int>(buffer->getHeight());
+ forceFilter = mWidth != static_cast<int>(buffer->getWidth()) ||
+ mHeight != static_cast<int>(buffer->getHeight());
}
- #if DEBUG_RENDERER
+#if DEBUG_RENDERER
if (dropCounter > 0) {
RENDERER_LOGD("Dropped %d frames on texture layer update", dropCounter);
}
- #endif
+#endif
mSurfaceTexture->getTransformMatrix(transform);
updateLayer(forceFilter, transform);
@@ -149,8 +149,8 @@ void DeferredLayerUpdater::doUpdateTexImage() {
void DeferredLayerUpdater::doUpdateVkTexImage() {
LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::Vulkan,
- "updateLayer non Vulkan backend %x, GL %x, VK %x",
- mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
+ "updateLayer non Vulkan backend %x, GL %x, VK %x", mLayer->getApi(),
+ Layer::Api::OpenGL, Layer::Api::Vulkan);
static const mat4 identityMatrix;
updateLayer(false, identityMatrix.data);
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 6164e4744da5..9dc029fd3852 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -16,10 +16,10 @@
#pragma once
-#include <cutils/compiler.h>
-#include <gui/GLConsumer.h>
#include <SkColorFilter.h>
#include <SkMatrix.h>
+#include <cutils/compiler.h>
+#include <gui/GLConsumer.h>
#include <utils/StrongPointer.h>
#include <GLES2/gl2.h>
@@ -41,10 +41,11 @@ public:
// Note that DeferredLayerUpdater assumes it is taking ownership of the layer
// and will not call incrementRef on it as a result.
typedef std::function<Layer*(RenderState& renderState, uint32_t layerWidth,
- uint32_t layerHeight, SkColorFilter* colorFilter, int alpha,
- SkBlendMode mode, bool blend)> CreateLayerFn;
- ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState,
- CreateLayerFn createLayerFn, Layer::Api layerApi);
+ uint32_t layerHeight, SkColorFilter* colorFilter, int alpha,
+ SkBlendMode mode, bool blend)>
+ CreateLayerFn;
+ ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn,
+ Layer::Api layerApi);
ANDROID_API ~DeferredLayerUpdater();
@@ -74,30 +75,24 @@ public:
GLenum target = texture->getCurrentTextureTarget();
LOG_ALWAYS_FATAL_IF(target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES,
- "set unsupported GLConsumer with target %x", target);
+ "set unsupported GLConsumer with target %x", target);
}
}
- ANDROID_API void updateTexImage() {
- mUpdateTexImage = true;
- }
+ ANDROID_API void updateTexImage() { mUpdateTexImage = true; }
ANDROID_API void setTransform(const SkMatrix* matrix) {
delete mTransform;
mTransform = matrix ? new SkMatrix(*matrix) : nullptr;
}
- SkMatrix* getTransform() {
- return mTransform;
- }
+ SkMatrix* getTransform() { return mTransform; }
ANDROID_API void setPaint(const SkPaint* paint);
void apply();
- Layer* backingLayer() {
- return mLayer;
- }
+ Layer* backingLayer() { return mLayer; }
void detachSurfaceTexture();
@@ -105,9 +100,7 @@ public:
void destroyLayer();
- Layer::Api getBackingLayerApi() {
- return mLayerApi;
- }
+ Layer::Api getBackingLayerApi() { return mLayerApi; }
private:
RenderState& mRenderState;
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index 37965daf9a8d..e4162875279c 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -19,8 +19,8 @@
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
-#include <thread>
#include <mutex>
+#include <thread>
#include <log/log.h>
@@ -58,8 +58,7 @@ void DeviceInfo::load() {
}
void DeviceInfo::loadDisplayInfo() {
- sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain));
+ sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo);
LOG_ALWAYS_FATAL_IF(status, "Failed to get display info, error %d", status);
}
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index 5bd7b14b156d..a0b2f06d8f4a 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -18,14 +18,15 @@
#include <ui/DisplayInfo.h>
-#include "utils/Macros.h"
#include "Extensions.h"
+#include "utils/Macros.h"
namespace android {
namespace uirenderer {
class DeviceInfo {
PREVENT_COPY_AND_ASSIGN(DeviceInfo);
+
public:
// returns nullptr if DeviceInfo is not initialized yet
// Note this does not have a memory fence so it's up to the caller
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 0ff101c6b2b4..aa87aea8b374 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -44,8 +44,7 @@ DisplayList::DisplayList()
, regions(stdAllocator)
, referenceHolders(stdAllocator)
, functors(stdAllocator)
- , vectorDrawables(stdAllocator) {
-}
+ , vectorDrawables(stdAllocator) {}
DisplayList::~DisplayList() {
cleanupResources();
@@ -105,14 +104,16 @@ void DisplayList::updateChildren(std::function<void(RenderNode*)> updateFn) {
}
}
-bool DisplayList::prepareListAndChildren(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
+bool DisplayList::prepareListAndChildren(
+ TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) {
info.prepareTextures = info.canvasContext.pinImages(bitmapResources);
for (auto&& op : children) {
RenderNode* childNode = op->renderNode;
info.damageAccumulator->pushTransform(&op->localMatrix);
- bool childFunctorsNeedLayer = functorsNeedLayer; // TODO! || op->mRecordedWithPotentialStencilClip;
+ bool childFunctorsNeedLayer =
+ functorsNeedLayer; // TODO! || op->mRecordedWithPotentialStencilClip;
childFn(childNode, observer, info, childFunctorsNeedLayer);
info.damageAccumulator->popTransform();
}
@@ -140,5 +141,5 @@ void DisplayList::output(std::ostream& output, uint32_t level) {
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index d22a764c0ea5..0cfc3b701aff 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -32,8 +32,8 @@
#include <androidfw/ResourceTypes.h>
-#include "Debug.h"
#include "CanvasProperty.h"
+#include "Debug.h"
#include "GlFunctorLifecycleListener.h"
#include "Matrix.h"
#include "RenderProperties.h"
@@ -74,6 +74,7 @@ struct FunctorContainer {
*/
class DisplayList {
friend class RecordingCanvas;
+
public:
struct Chunk {
// range of included ops in DisplayList::ops()
@@ -106,14 +107,9 @@ public:
size_t addChild(NodeOpType* childOp);
+ void ref(VirtualLightRefBase* prop) { referenceHolders.push_back(prop); }
- void ref(VirtualLightRefBase* prop) {
- referenceHolders.push_back(prop);
- }
-
- size_t getUsedSize() {
- return allocator.usedSize();
- }
+ size_t getUsedSize() { return allocator.usedSize(); }
virtual bool isEmpty() const { return ops.empty(); }
virtual bool hasFunctor() const { return !functors.empty(); }
@@ -125,7 +121,8 @@ public:
virtual void syncContents();
virtual void updateChildren(std::function<void(RenderNode*)> updateFn);
- virtual bool prepareListAndChildren(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
+ virtual bool prepareListAndChildren(
+ TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn);
virtual void output(std::ostream& output, uint32_t level);
@@ -148,12 +145,13 @@ private:
LsaVector<const Res_png_9patch*> patchResources;
LsaVector<std::unique_ptr<const SkPaint>> paints;
LsaVector<std::unique_ptr<const SkRegion>> regions;
- LsaVector< sp<VirtualLightRefBase> > referenceHolders;
+ LsaVector<sp<VirtualLightRefBase>> referenceHolders;
// List of functors
LsaVector<FunctorContainer> functors;
- // List of VectorDrawables that need to be notified of pushStaging. Note that this list gets nothing
+ // List of VectorDrawables that need to be notified of pushStaging. Note that this list gets
+ // nothing
// but a callback during sync DisplayList, unlike the list of functors defined above, which
// gets special treatment exclusive for webview.
LsaVector<VectorDrawableRoot*> vectorDrawables;
@@ -161,5 +159,5 @@ private:
void cleanupResources();
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index 0919e82a003b..530e82e65a28 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -31,14 +31,10 @@ namespace android {
namespace uirenderer {
Extensions::Extensions() {
- if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
- //Extensions class is used only by OpenGL and SkiaGL pipelines
- //The code below will crash for SkiaVulkan, because OpenGL is not initialized
- //TODO: instantiate Extensions class only for OpenGL pipeline
- //TODO: remove the only usage of Extensions by SkiaGL in SkiaOpenGLReadback::copyImageInto
+ if (Properties::isSkiaEnabled()) {
return;
}
- const char* version = (const char*) glGetString(GL_VERSION);
+ const char* version = (const char*)glGetString(GL_VERSION);
// Section 6.1.5 of the OpenGL ES specification indicates the GL version
// string strictly follows this format:
@@ -58,7 +54,7 @@ Extensions::Extensions() {
mVersionMinor = 0;
}
- auto extensions = StringUtils::split((const char*) glGetString(GL_EXTENSIONS));
+ auto extensions = StringUtils::split((const char*)glGetString(GL_EXTENSIONS));
mHasNPot = extensions.has("GL_OES_texture_npot");
mHasFramebufferFetch = extensions.has("GL_NV_shader_framebuffer_fetch");
mHasDiscardFramebuffer = extensions.has("GL_EXT_discard_framebuffer");
@@ -83,5 +79,5 @@ Extensions::Extensions() {
#endif
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 7af7f7944ac9..214ee0bbeefd 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -63,9 +63,9 @@ private:
int mVersionMajor;
int mVersionMinor;
-}; // class Extensions
+}; // class Extensions
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_EXTENSIONS_H
+#endif // ANDROID_HWUI_EXTENSIONS_H
diff --git a/libs/hwui/FboCache.cpp b/libs/hwui/FboCache.cpp
index a39e49f82eb0..88302cc52c2b 100644
--- a/libs/hwui/FboCache.cpp
+++ b/libs/hwui/FboCache.cpp
@@ -27,8 +27,7 @@ namespace uirenderer {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-FboCache::FboCache()
- : mMaxSize(0) {}
+FboCache::FboCache() : mMaxSize(0) {}
FboCache::~FboCache() {
clear();
@@ -79,5 +78,5 @@ bool FboCache::put(GLuint fbo) {
return false;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/FboCache.h b/libs/hwui/FboCache.h
index ad6cc3ea96c9..5e8bb0c7a7a7 100644
--- a/libs/hwui/FboCache.h
+++ b/libs/hwui/FboCache.h
@@ -71,9 +71,9 @@ public:
private:
SortedVector<GLuint> mCache;
uint32_t mMaxSize;
-}; // class FboCache
+}; // class FboCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_FBO_CACHE_H
+#endif // ANDROID_HWUI_FBO_CACHE_H
diff --git a/libs/hwui/FloatColor.h b/libs/hwui/FloatColor.h
index a738ba4fe97e..b424f97a5004 100644
--- a/libs/hwui/FloatColor.h
+++ b/libs/hwui/FloatColor.h
@@ -33,8 +33,8 @@ struct FloatColor {
void set(uint32_t color) {
a = ((color >> 24) & 0xff) / 255.0f;
r = a * EOCF(((color >> 16) & 0xff) / 255.0f);
- g = a * EOCF(((color >> 8) & 0xff) / 255.0f);
- b = a * EOCF(((color ) & 0xff) / 255.0f);
+ g = a * EOCF(((color >> 8) & 0xff) / 255.0f);
+ b = a * EOCF(((color)&0xff) / 255.0f);
}
// "color" is a gamma-encoded sRGB color
@@ -44,27 +44,18 @@ struct FloatColor {
void setUnPreMultiplied(uint32_t color) {
a = ((color >> 24) & 0xff) / 255.0f;
r = EOCF(((color >> 16) & 0xff) / 255.0f);
- g = EOCF(((color >> 8) & 0xff) / 255.0f);
- b = EOCF(((color ) & 0xff) / 255.0f);
+ g = EOCF(((color >> 8) & 0xff) / 255.0f);
+ b = EOCF(((color)&0xff) / 255.0f);
}
- bool isNotBlack() {
- return a < 1.0f
- || r > 0.0f
- || g > 0.0f
- || b > 0.0f;
- }
+ bool isNotBlack() { return a < 1.0f || r > 0.0f || g > 0.0f || b > 0.0f; }
bool operator==(const FloatColor& other) const {
- return MathUtils::areEqual(r, other.r)
- && MathUtils::areEqual(g, other.g)
- && MathUtils::areEqual(b, other.b)
- && MathUtils::areEqual(a, other.a);
+ return MathUtils::areEqual(r, other.r) && MathUtils::areEqual(g, other.g) &&
+ MathUtils::areEqual(b, other.b) && MathUtils::areEqual(a, other.a);
}
- bool operator!=(const FloatColor& other) const {
- return !(*this == other);
- }
+ bool operator!=(const FloatColor& other) const { return !(*this == other); }
float r;
float g;
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 8b0346867cbc..bbcedb15335d 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -22,20 +22,20 @@
#include "Caches.h"
#include "Debug.h"
#include "Extensions.h"
-#include "font/Font.h"
#include "Glop.h"
#include "GlopBuilder.h"
#include "PixelBuffer.h"
#include "Rect.h"
+#include "font/Font.h"
#include "renderstate/RenderState.h"
#include "utils/Blur.h"
#include "utils/Timing.h"
-#include <algorithm>
#include <RenderScript.h>
#include <SkGlyph.h>
#include <SkUtils.h>
#include <utils/Log.h>
+#include <algorithm>
namespace android {
namespace uirenderer {
@@ -55,8 +55,8 @@ void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) {
if (linearFiltering) {
textureFillFlags |= TextureFillFlags::ForceFilter;
}
- int transformFlags = pureTranslate
- ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
+ int transformFlags =
+ pureTranslate ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
#ifdef ANDROID_ENABLE_LINEAR_BLENDING
bool gammaCorrection = true;
#else
@@ -93,7 +93,6 @@ FontRenderer::FontRenderer(const uint8_t* gammaTable)
, mDrawn(false)
, mInitialized(false)
, mLinearFiltering(false) {
-
if (sLogFontRendererCreate) {
INIT_LOGD("Creating FontRenderer");
}
@@ -118,10 +117,8 @@ FontRenderer::FontRenderer(const uint8_t* gammaTable)
if (sLogFontRendererCreate) {
INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
- mSmallCacheWidth, mSmallCacheHeight,
- mLargeCacheWidth, mLargeCacheHeight >> 1,
- mLargeCacheWidth, mLargeCacheHeight >> 1,
- mLargeCacheWidth, mLargeCacheHeight);
+ mSmallCacheWidth, mSmallCacheHeight, mLargeCacheWidth, mLargeCacheHeight >> 1,
+ mLargeCacheWidth, mLargeCacheHeight >> 1, mLargeCacheWidth, mLargeCacheHeight);
}
sLogFontRendererCreate = false;
@@ -195,7 +192,8 @@ void FontRenderer::flushLargeCaches() {
}
CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
- const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
+ const SkGlyph& glyph, uint32_t* startX,
+ uint32_t* startY) {
for (uint32_t i = 0; i < cacheTextures.size(); i++) {
if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
return cacheTextures[i];
@@ -206,7 +204,7 @@ CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cac
}
void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
- uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
+ uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
checkInit();
// If the glyph bitmap is empty let's assum the glyph is valid
@@ -234,14 +232,14 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
#if DEBUG_FONT_RENDERER
ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
#endif
- return;
+ return;
}
// If the glyph is too tall, don't cache it
if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
- (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
- ALOGE("Font size too large to fit in cache. width, height = %i, %i",
- (int) glyph.fWidth, (int) glyph.fHeight);
+ (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
+ ALOGE("Font size too large to fit in cache. width, height = %i, %i", (int)glyph.fWidth,
+ (int)glyph.fHeight);
return;
}
@@ -285,14 +283,14 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
}
uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
- uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
+ uint8_t* bitmapBuffer = (uint8_t*)glyph.fImage;
int srcStride = glyph.rowBytes();
// Copy the glyph image, taking the mask format into account
switch (format) {
case SkMask::kA8_Format: {
- uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
- - TEXTURE_BORDER_SIZE;
+ uint32_t row =
+ (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
// write leading border line
memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
// write glyph data
@@ -337,9 +335,9 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
memset(dstL, 0, rowSize + 2 * borderSize);
// write glyph data
while (dst < dstEnd) {
- memset(dstL += dstStride, 0, borderSize); // leading border column
- memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
- memset(dstR += dstStride, 0, borderSize); // trailing border column
+ memset(dstL += dstStride, 0, borderSize); // leading border column
+ memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
+ memset(dstR += dstStride, 0, borderSize); // trailing border column
}
// write trailing border line
memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
@@ -347,9 +345,9 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
}
case SkMask::kBW_Format: {
uint32_t cacheX = 0, cacheY = 0;
- uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
- - TEXTURE_BORDER_SIZE;
- static const uint8_t COLORS[2] = { 0, 255 };
+ uint32_t row =
+ (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
+ static const uint8_t COLORS[2] = {0, 255};
// write leading border line
memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
// write glyph data
@@ -388,7 +386,7 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
}
CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
- bool allocate) {
+ bool allocate) {
CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
if (allocate) {
@@ -405,18 +403,18 @@ void FontRenderer::initTextTexture() {
clearCacheTextures(mRGBACacheTextures);
mUploadTexture = false;
- mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
- GL_ALPHA, true));
- mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
- GL_ALPHA, false));
- mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
- GL_ALPHA, false));
- mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
- GL_ALPHA, false));
- mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
- GL_RGBA, false));
- mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
- GL_RGBA, false));
+ mACacheTextures.push_back(
+ createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, GL_ALPHA, true));
+ mACacheTextures.push_back(
+ createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, GL_ALPHA, false));
+ mACacheTextures.push_back(
+ createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, GL_ALPHA, false));
+ mACacheTextures.push_back(
+ createCacheTexture(mLargeCacheWidth, mLargeCacheHeight, GL_ALPHA, false));
+ mRGBACacheTextures.push_back(
+ createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, GL_RGBA, false));
+ mRGBACacheTextures.push_back(
+ createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, GL_RGBA, false));
mCurrentCacheTexture = mACacheTextures[0];
}
@@ -432,7 +430,7 @@ void FontRenderer::checkInit() {
}
void checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
- bool& resetPixelStore, GLuint& lastTextureId) {
+ bool& resetPixelStore, GLuint& lastTextureId) {
for (uint32_t i = 0; i < cacheTextures.size(); i++) {
CacheTexture* cacheTexture = cacheTextures[i];
if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
@@ -500,24 +498,22 @@ void FontRenderer::issueDrawCommand() {
issueDrawCommand(mRGBACacheTextures);
}
-void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
- float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
- float x4, float y4, float u4, float v4, CacheTexture* texture) {
+void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1, float x2, float y2,
+ float u2, float v2, float x3, float y3, float u3, float v3,
+ float x4, float y4, float u4, float v4,
+ CacheTexture* texture) {
if (texture != mCurrentCacheTexture) {
// Now use the new texture id
mCurrentCacheTexture = texture;
}
- mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
- x3, y3, u3, v3, x4, y4, u4, v4);
+ mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4);
}
-void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
- float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
- float x4, float y4, float u4, float v4, CacheTexture* texture) {
-
- if (mClip &&
- (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
+void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1, float x2, float y2,
+ float u2, float v2, float x3, float y3, float u3, float v3,
+ float x4, float y4, float u4, float v4, CacheTexture* texture) {
+ if (mClip && (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
return;
}
@@ -535,10 +531,10 @@ void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
}
}
-void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
- float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
- float x4, float y4, float u4, float v4, CacheTexture* texture) {
-
+void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1, float x2, float y2,
+ float u2, float v2, float x3, float y3, float u3, float v3,
+ float x4, float y4, float u4, float v4,
+ CacheTexture* texture) {
appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
if (mBounds) {
@@ -557,8 +553,9 @@ void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
mCurrentFont = Font::create(this, paint, matrix);
}
-FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const glyph_t *glyphs,
- int numGlyphs, float radius, const float* positions) {
+FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const glyph_t* glyphs,
+ int numGlyphs, float radius,
+ const float* positions) {
checkInit();
DropShadow image;
@@ -580,8 +577,8 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
mCurrentFont->measure(paint, glyphs, numGlyphs, &bounds, positions);
uint32_t intRadius = Blur::convertRadiusToInt(radius);
- uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
- uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
+ uint32_t paddedWidth = (uint32_t)(bounds.right - bounds.left) + 2 * intRadius;
+ uint32_t paddedHeight = (uint32_t)(bounds.top - bounds.bottom) + 2 * intRadius;
uint32_t maxSize = Caches::getInstance().maxTextureSize;
if (paddedWidth > maxSize || paddedHeight > maxSize) {
@@ -593,7 +590,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
}
int size = paddedWidth * paddedHeight;
- uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
+ uint8_t* dataBuffer = (uint8_t*)memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
memset(dataBuffer, 0, size);
@@ -604,8 +601,8 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
// text has non-whitespace, so draw and blur to create the shadow
// NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
// TODO: don't draw pure whitespace in the first place, and avoid needing this check
- mCurrentFont->render(paint, glyphs, numGlyphs, penX, penY,
- Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
+ mCurrentFont->render(paint, glyphs, numGlyphs, penX, penY, Font::BITMAP, dataBuffer,
+ paddedWidth, paddedHeight, nullptr, positions);
// Unbind any PBO we might have used
Caches::getInstance().pixelBufferState().unbind();
@@ -639,7 +636,7 @@ void FontRenderer::finishRender() {
}
void FontRenderer::precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
- const SkMatrix& matrix) {
+ const SkMatrix& matrix) {
Font* font = Font::create(this, paint, matrix);
font->precache(paint, glyphs, numGlyphs);
}
@@ -649,8 +646,8 @@ void FontRenderer::endPrecaching() {
}
bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
- int numGlyphs, int x, int y, const float* positions,
- Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
+ int numGlyphs, int x, int y, const float* positions, Rect* bounds,
+ TextDrawFunctor* functor, bool forceFinish) {
if (!mCurrentFont) {
ALOGE("No font set");
return false;
@@ -667,8 +664,8 @@ bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const g
}
bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
- int numGlyphs, const SkPath* path, float hOffset, float vOffset,
- Rect* bounds, TextDrawFunctor* functor) {
+ int numGlyphs, const SkPath* path, float hOffset, float vOffset,
+ Rect* bounds, TextDrawFunctor* functor) {
if (!mCurrentFont) {
ALOGE("No font set");
return false;
@@ -684,7 +681,7 @@ bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, cons
void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
uint32_t intRadius = Blur::convertRadiusToInt(radius);
if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF && radius <= 25.0f) {
- uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
+ uint8_t* outImage = (uint8_t*)memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
if (mRs == nullptr) {
mRs = new RSC::RS();
@@ -700,14 +697,12 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, flo
}
if (mRs != nullptr) {
RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
- RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
- RS_ALLOCATION_MIPMAP_NONE,
- RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
- *image);
- RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
- RS_ALLOCATION_MIPMAP_NONE,
- RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
- outImage);
+ RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(
+ mRs, t, RS_ALLOCATION_MIPMAP_NONE,
+ RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, *image);
+ RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(
+ mRs, t, RS_ALLOCATION_MIPMAP_NONE,
+ RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, outImage);
mRsScript->setRadius(radius);
mRsScript->setInput(ain);
@@ -768,7 +763,7 @@ const std::vector<CacheTexture*>& FontRenderer::cacheTexturesForFormat(GLenum fo
}
static void dumpTextures(String8& log, const char* tag,
- const std::vector<CacheTexture*>& cacheTextures) {
+ const std::vector<CacheTexture*>& cacheTextures) {
for (uint32_t i = 0; i < cacheTextures.size(); i++) {
CacheTexture* cacheTexture = cacheTextures[i];
if (cacheTexture && cacheTexture->getPixelBuffer()) {
@@ -803,5 +798,5 @@ uint32_t FontRenderer::getSize() const {
return getCacheSize(GL_ALPHA) + getCacheSize(GL_RGBA);
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 329309c1cd5c..6b9dec4719cb 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -16,10 +16,10 @@
#pragma once
-#include "font/FontUtil.h"
#include "font/CacheTexture.h"
#include "font/CachedGlyphInfo.h"
#include "font/Font.h"
+#include "font/FontUtil.h"
#ifdef BUGREPORT_FONT_CACHE_USAGE
#include "font/FontCacheHistoryTracker.h"
#endif
@@ -36,10 +36,10 @@
#include "RenderScript.h"
namespace RSC {
- class Element;
- class RS;
- class ScriptIntrinsicBlur;
- class sp;
+class Element;
+class RS;
+class ScriptIntrinsicBlur;
+class sp;
}
namespace android {
@@ -51,22 +51,18 @@ struct ClipBase;
class TextDrawFunctor {
public:
- TextDrawFunctor(
- BakedOpRenderer* renderer,
- const BakedOpState* bakedState,
- const ClipBase* clip,
- float x, float y, bool pureTranslate,
- int alpha, SkBlendMode mode, const SkPaint* paint)
- : renderer(renderer)
- , bakedState(bakedState)
- , clip(clip)
- , x(x)
- , y(y)
- , pureTranslate(pureTranslate)
- , alpha(alpha)
- , mode(mode)
- , paint(paint) {
- }
+ TextDrawFunctor(BakedOpRenderer* renderer, const BakedOpState* bakedState, const ClipBase* clip,
+ float x, float y, bool pureTranslate, int alpha, SkBlendMode mode,
+ const SkPaint* paint)
+ : renderer(renderer)
+ , bakedState(bakedState)
+ , clip(clip)
+ , x(x)
+ , y(y)
+ , pureTranslate(pureTranslate)
+ , alpha(alpha)
+ , mode(mode)
+ , paint(paint) {}
void draw(CacheTexture& texture, bool linearFiltering);
@@ -91,16 +87,17 @@ public:
void setFont(const SkPaint* paint, const SkMatrix& matrix);
- void precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, const SkMatrix& matrix);
+ void precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
+ const SkMatrix& matrix);
void endPrecaching();
- bool renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
- int numGlyphs, int x, int y, const float* positions,
- Rect* outBounds, TextDrawFunctor* functor, bool forceFinish = true);
+ bool renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs, int numGlyphs,
+ int x, int y, const float* positions, Rect* outBounds,
+ TextDrawFunctor* functor, bool forceFinish = true);
bool renderTextOnPath(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
- int numGlyphs, const SkPath* path,
- float hOffset, float vOffset, Rect* outBounds, TextDrawFunctor* functor);
+ int numGlyphs, const SkPath* path, float hOffset, float vOffset,
+ Rect* outBounds, TextDrawFunctor* functor);
struct DropShadow {
uint32_t width;
@@ -112,12 +109,10 @@ public:
// After renderDropShadow returns, the called owns the memory in DropShadow.image
// and is responsible for releasing it when it's done with it
- DropShadow renderDropShadow(const SkPaint* paint, const glyph_t *glyphs, int numGlyphs,
- float radius, const float* positions);
+ DropShadow renderDropShadow(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
+ float radius, const float* positions);
- void setTextureFiltering(bool linearFiltering) {
- mLinearFiltering = linearFiltering;
- }
+ void setTextureFiltering(bool linearFiltering) { mLinearFiltering = linearFiltering; }
uint32_t getSize() const;
void dumpMemoryUsage(String8& log) const;
@@ -135,10 +130,10 @@ private:
void deallocateTextureMemory(CacheTexture* cacheTexture);
void initTextTexture();
CacheTexture* createCacheTexture(int width, int height, GLenum format, bool allocate);
- void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
- uint32_t *retOriginX, uint32_t *retOriginY, bool precaching);
- CacheTexture* cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures, const SkGlyph& glyph,
- uint32_t* startX, uint32_t* startY);
+ void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, uint32_t* retOriginX,
+ uint32_t* retOriginY, bool precaching);
+ CacheTexture* cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
+ const SkGlyph& glyph, uint32_t* startX, uint32_t* startY);
void flushAllAndInvalidate();
@@ -148,24 +143,19 @@ private:
void issueDrawCommand(std::vector<CacheTexture*>& cacheTextures);
void issueDrawCommand();
- void appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
- float x2, float y2, float u2, float v2,
- float x3, float y3, float u3, float v3,
- float x4, float y4, float u4, float v4, CacheTexture* texture);
- void appendMeshQuad(float x1, float y1, float u1, float v1,
- float x2, float y2, float u2, float v2,
- float x3, float y3, float u3, float v3,
- float x4, float y4, float u4, float v4, CacheTexture* texture);
- void appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
- float x2, float y2, float u2, float v2,
- float x3, float y3, float u3, float v3,
- float x4, float y4, float u4, float v4, CacheTexture* texture);
+ void appendMeshQuadNoClip(float x1, float y1, float u1, float v1, float x2, float y2, float u2,
+ float v2, float x3, float y3, float u3, float v3, float x4, float y4,
+ float u4, float v4, CacheTexture* texture);
+ void appendMeshQuad(float x1, float y1, float u1, float v1, float x2, float y2, float u2,
+ float v2, float x3, float y3, float u3, float v3, float x4, float y4,
+ float u4, float v4, CacheTexture* texture);
+ void appendRotatedMeshQuad(float x1, float y1, float u1, float v1, float x2, float y2, float u2,
+ float v2, float x3, float y3, float u3, float v3, float x4, float y4,
+ float u4, float v4, CacheTexture* texture);
void checkTextureUpdate();
- void setTextureDirty() {
- mUploadTexture = true;
- }
+ void setTextureDirty() { mUploadTexture = true; }
const std::vector<CacheTexture*>& cacheTexturesForFormat(GLenum format) const;
uint32_t getCacheSize(GLenum format) const;
@@ -205,14 +195,14 @@ private:
RSC::sp<RSC::ScriptIntrinsicBlur> mRsScript;
static void computeGaussianWeights(float* weights, int32_t radius);
- static void horizontalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
- int32_t width, int32_t height);
- static void verticalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
- int32_t width, int32_t height);
+ static void horizontalBlur(float* weights, int32_t radius, const uint8_t* source, uint8_t* dest,
+ int32_t width, int32_t height);
+ static void verticalBlur(float* weights, int32_t radius, const uint8_t* source, uint8_t* dest,
+ int32_t width, int32_t height);
// the input image handle may have its pointer replaced (to avoid copies)
void blurImage(uint8_t** image, int32_t width, int32_t height, float radius);
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 86f9a5d73fd1..ced37ede0746 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -20,8 +20,8 @@
#include "LayerUpdateQueue.h"
#include "RenderNode.h"
#include "VectorDrawable.h"
-#include "renderstate/OffscreenBufferPool.h"
#include "hwui/Canvas.h"
+#include "renderstate/OffscreenBufferPool.h"
#include "utils/FatVector.h"
#include "utils/PaintUtils.h"
#include "utils/TraceUtils.h"
@@ -32,9 +32,8 @@
namespace android {
namespace uirenderer {
-FrameBuilder::FrameBuilder(const SkRect& clip,
- uint32_t viewportWidth, uint32_t viewportHeight,
- const LightGeometry& lightGeometry, Caches& caches)
+FrameBuilder::FrameBuilder(const SkRect& clip, uint32_t viewportWidth, uint32_t viewportHeight,
+ const LightGeometry& lightGeometry, Caches& caches)
: mStdAllocator(mAllocator)
, mLayerBuilders(mStdAllocator)
, mLayerStack(mStdAllocator)
@@ -42,18 +41,16 @@ FrameBuilder::FrameBuilder(const SkRect& clip,
, mCaches(caches)
, mLightRadius(lightGeometry.radius)
, mDrawFbo0(true) {
-
// Prepare to defer Fbo0
auto fbo0 = mAllocator.create<LayerBuilder>(viewportWidth, viewportHeight, Rect(clip));
mLayerBuilders.push_back(fbo0);
mLayerStack.push_back(0);
- mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
- clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
- lightGeometry.center);
+ mCanvasState.initializeSaveStack(viewportWidth, viewportHeight, clip.fLeft, clip.fTop,
+ clip.fRight, clip.fBottom, lightGeometry.center);
}
-FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers,
- const LightGeometry& lightGeometry, Caches& caches)
+FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const LightGeometry& lightGeometry,
+ Caches& caches)
: mStdAllocator(mAllocator)
, mLayerBuilders(mStdAllocator)
, mLayerStack(mStdAllocator)
@@ -67,9 +64,7 @@ FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers,
auto fbo0 = mAllocator.create<LayerBuilder>(1, 1, Rect(1, 1));
mLayerBuilders.push_back(fbo0);
mLayerStack.push_back(0);
- mCanvasState.initializeSaveStack(1, 1,
- 0, 0, 1, 1,
- lightGeometry.center);
+ mCanvasState.initializeSaveStack(1, 1, 0, 0, 1, 1, lightGeometry.center);
deferLayers(layers);
}
@@ -84,8 +79,8 @@ void FrameBuilder::deferLayers(const LayerUpdateQueue& layers) {
// as not to lose info on what portion is damaged
OffscreenBuffer* layer = layerNode->getLayer();
if (CC_LIKELY(layer)) {
- ATRACE_FORMAT("Optimize HW Layer DisplayList %s %ux%u",
- layerNode->getName(), layerNode->getWidth(), layerNode->getHeight());
+ ATRACE_FORMAT("Optimize HW Layer DisplayList %s %ux%u", layerNode->getName(),
+ layerNode->getWidth(), layerNode->getHeight());
Rect layerDamage = layers.entries()[i].damage;
// TODO: ensure layer damage can't be larger than layer
@@ -96,8 +91,8 @@ void FrameBuilder::deferLayers(const LayerUpdateQueue& layers) {
Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter();
layer->inverseTransformInWindow.mapPoint3d(lightCenter);
- saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0,
- layerDamage, lightCenter, nullptr, layerNode);
+ saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0, layerDamage,
+ lightCenter, nullptr, layerNode);
if (layerNode->getDisplayList()) {
deferNodeOps(*layerNode);
@@ -121,19 +116,18 @@ void FrameBuilder::deferRenderNode(float tx, float ty, Rect clipRect, RenderNode
mCanvasState.save(SaveFlags::MatrixClip);
mCanvasState.translate(tx, ty);
mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
- SkClipOp::kIntersect);
+ SkClipOp::kIntersect);
deferNodePropsAndOps(renderNode);
mCanvasState.restore();
}
static Rect nodeBounds(RenderNode& node) {
auto& props = node.properties();
- return Rect(props.getLeft(), props.getTop(),
- props.getRight(), props.getBottom());
+ return Rect(props.getLeft(), props.getTop(), props.getRight(), props.getBottom());
}
-void FrameBuilder::deferRenderNodeScene(const std::vector< sp<RenderNode> >& nodes,
- const Rect& contentDrawBounds) {
+void FrameBuilder::deferRenderNodeScene(const std::vector<sp<RenderNode> >& nodes,
+ const Rect& contentDrawBounds) {
if (nodes.size() < 1) return;
if (nodes.size() == 1) {
if (!nodes[0]->nothingToDraw()) {
@@ -170,14 +164,16 @@ void FrameBuilder::deferRenderNodeScene(const std::vector< sp<RenderNode> >& nod
// the backdrop, so this isn't necessary.
if (content.right < backdrop.right) {
// draw backdrop to right side of content
- deferRenderNode(0, 0, Rect(content.right, backdrop.top,
- backdrop.right, backdrop.bottom), *nodes[0]);
+ deferRenderNode(0, 0,
+ Rect(content.right, backdrop.top, backdrop.right, backdrop.bottom),
+ *nodes[0]);
}
if (content.bottom < backdrop.bottom) {
// draw backdrop to bottom of content
// Note: bottom fill uses content left/right, to avoid overdrawing left/right fill
- deferRenderNode(0, 0, Rect(content.left, content.bottom,
- content.right, backdrop.bottom), *nodes[0]);
+ deferRenderNode(0, 0,
+ Rect(content.left, content.bottom, content.right, backdrop.bottom),
+ *nodes[0]);
}
}
@@ -210,11 +206,9 @@ void FrameBuilder::onSnapshotRestored(const Snapshot& removed, const Snapshot& r
void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
const RenderProperties& properties = node.properties();
const Outline& outline = properties.getOutline();
- if (properties.getAlpha() <= 0
- || (outline.getShouldClip() && outline.isEmpty())
- || properties.getScaleX() == 0
- || properties.getScaleY() == 0) {
- return; // rejected
+ if (properties.getAlpha() <= 0 || (outline.getShouldClip() && outline.isEmpty()) ||
+ properties.getScaleX() == 0 || properties.getScaleY() == 0) {
+ return; // rejected
}
if (properties.getLeft() != 0 || properties.getTop() != 0) {
@@ -236,12 +230,12 @@ void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
const int width = properties.getWidth();
const int height = properties.getHeight();
- Rect saveLayerBounds; // will be set to non-empty if saveLayer needed
+ Rect saveLayerBounds; // will be set to non-empty if saveLayer needed
const bool isLayer = properties.effectiveLayerType() != LayerType::None;
int clipFlags = properties.getClippingFlags();
if (properties.getAlpha() < 1) {
if (isLayer) {
- clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
+ clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
}
if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering())) {
// simply scale rendering content's alpha
@@ -251,7 +245,7 @@ void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
saveLayerBounds.set(0, 0, width, height);
if (clipFlags) {
properties.getClippingRectForFlags(clipFlags, &saveLayerBounds);
- clipFlags = 0; // all clipping done by savelayer
+ clipFlags = 0; // all clipping done by savelayer
}
}
@@ -265,21 +259,21 @@ void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
Rect clipRect;
properties.getClippingRectForFlags(clipFlags, &clipRect);
mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
- SkClipOp::kIntersect);
+ SkClipOp::kIntersect);
}
if (properties.getRevealClip().willClip()) {
Rect bounds;
properties.getRevealClip().getBounds(&bounds);
- mCanvasState.setClippingRoundRect(mAllocator,
- bounds, properties.getRevealClip().getRadius());
+ mCanvasState.setClippingRoundRect(mAllocator, bounds,
+ properties.getRevealClip().getRadius());
} else if (properties.getOutline().willClip()) {
mCanvasState.setClippingOutline(mAllocator, &(properties.getOutline()));
}
- bool quickRejected = mCanvasState.currentSnapshot()->getRenderTargetClip().isEmpty()
- || (properties.getClipToBounds()
- && mCanvasState.quickRejectConservative(0, 0, width, height));
+ bool quickRejected = mCanvasState.currentSnapshot()->getRenderTargetClip().isEmpty() ||
+ (properties.getClipToBounds() &&
+ mCanvasState.quickRejectConservative(0, 0, width, height));
if (!quickRejected) {
// not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer)
if (node.getLayer()) {
@@ -296,9 +290,8 @@ void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
SkPaint saveLayerPaint;
saveLayerPaint.setAlpha(properties.getAlpha());
deferBeginLayerOp(*mAllocator.create_trivial<BeginLayerOp>(
- saveLayerBounds,
- Matrix4::identity(),
- nullptr, // no record-time clip - need only respect defer-time one
+ saveLayerBounds, Matrix4::identity(),
+ nullptr, // no record-time clip - need only respect defer-time one
&saveLayerPaint));
deferNodeOps(node);
deferEndLayerOp(*mAllocator.create_trivial<EndLayerOp>());
@@ -311,8 +304,8 @@ void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
typedef key_value_pair_t<float, const RenderNodeOp*> ZRenderNodeOpPair;
template <typename V>
-static void buildZSortedChildList(V* zTranslatedNodes,
- const DisplayList& displayList, const DisplayList::Chunk& chunk) {
+static void buildZSortedChildList(V* zTranslatedNodes, const DisplayList& displayList,
+ const DisplayList::Chunk& chunk) {
if (chunk.beginChildIndex == chunk.endChildIndex) return;
for (size_t i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) {
@@ -343,11 +336,10 @@ static size_t findNonNegativeIndex(const V& zTranslatedNodes) {
template <typename V>
void FrameBuilder::defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMode mode,
- const V& zTranslatedNodes) {
+ const V& zTranslatedNodes) {
const int size = zTranslatedNodes.size();
- if (size == 0
- || (mode == ChildrenSelectMode::Negative&& zTranslatedNodes[0].key > 0.0f)
- || (mode == ChildrenSelectMode::Positive && zTranslatedNodes[size - 1].key < 0.0f)) {
+ if (size == 0 || (mode == ChildrenSelectMode::Negative && zTranslatedNodes[0].key > 0.0f) ||
+ (mode == ChildrenSelectMode::Positive && zTranslatedNodes[size - 1].key < 0.0f)) {
// no 3d children to draw
return;
}
@@ -364,11 +356,11 @@ void FrameBuilder::defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMo
if (mode == ChildrenSelectMode::Negative) {
drawIndex = 0;
endIndex = nonNegativeIndex;
- shadowIndex = endIndex; // draw no shadows
+ shadowIndex = endIndex; // draw no shadows
} else {
drawIndex = nonNegativeIndex;
endIndex = size;
- shadowIndex = drawIndex; // potentially draw shadow for each pos Z child
+ shadowIndex = drawIndex; // potentially draw shadow for each pos Z child
}
float lastCasterZ = 0.0f;
@@ -381,7 +373,7 @@ void FrameBuilder::defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMo
if (shadowIndex == drawIndex || casterZ - lastCasterZ < 0.1f) {
deferShadow(reorderClip, *casterNodeOp);
- lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
+ lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
shadowIndex++;
continue;
}
@@ -397,11 +389,9 @@ void FrameBuilder::deferShadow(const ClipBase* reorderClip, const RenderNodeOp&
auto& node = *casterNodeOp.renderNode;
auto& properties = node.properties();
- if (properties.getAlpha() <= 0.0f
- || properties.getOutline().getAlpha() <= 0.0f
- || !properties.getOutline().getPath()
- || properties.getScaleX() == 0
- || properties.getScaleY() == 0) {
+ if (properties.getAlpha() <= 0.0f || properties.getOutline().getAlpha() <= 0.0f ||
+ !properties.getOutline().getPath() || properties.getScaleX() == 0 ||
+ properties.getScaleY() == 0) {
// no shadow to draw
return;
}
@@ -432,8 +422,8 @@ void FrameBuilder::deferShadow(const ClipBase* reorderClip, const RenderNodeOp&
Rect clipBounds;
properties.getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds);
SkPath clipBoundsPath;
- clipBoundsPath.addRect(clipBounds.left, clipBounds.top,
- clipBounds.right, clipBounds.bottom);
+ clipBoundsPath.addRect(clipBounds.left, clipBounds.top, clipBounds.right,
+ clipBounds.bottom);
Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, frameAllocatedPath);
casterPath = frameAllocatedPath;
@@ -442,7 +432,7 @@ void FrameBuilder::deferShadow(const ClipBase* reorderClip, const RenderNodeOp&
// apply reorder clip to shadow, so it respects clip at beginning of reorderable chunk
int restoreTo = mCanvasState.save(SaveFlags::MatrixClip);
mCanvasState.writableSnapshot()->applyClip(reorderClip,
- *mCanvasState.currentSnapshot()->transform);
+ *mCanvasState.currentSnapshot()->transform);
if (CC_LIKELY(!mCanvasState.getRenderTargetClipBounds().isEmpty())) {
Matrix4 shadowMatrixXY(casterNodeOp.localMatrix);
Matrix4 shadowMatrixZ(casterNodeOp.localMatrix);
@@ -450,13 +440,9 @@ void FrameBuilder::deferShadow(const ClipBase* reorderClip, const RenderNodeOp&
node.applyViewPropertyTransforms(shadowMatrixZ, true);
sp<TessellationCache::ShadowTask> task = mCaches.tessellationCache.getShadowTask(
- mCanvasState.currentTransform(),
- mCanvasState.getLocalClipBounds(),
- casterAlpha >= 1.0f,
- casterPath,
- &shadowMatrixXY, &shadowMatrixZ,
- mCanvasState.currentSnapshot()->getRelativeLightCenter(),
- mLightRadius);
+ mCanvasState.currentTransform(), mCanvasState.getLocalClipBounds(),
+ casterAlpha >= 1.0f, casterPath, &shadowMatrixXY, &shadowMatrixZ,
+ mCanvasState.currentSnapshot()->getRelativeLightCenter(), mLightRadius);
ShadowOp* shadowOp = mAllocator.create<ShadowOp>(task, casterAlpha);
BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct(
mAllocator, *mCanvasState.writableSnapshot(), shadowOp);
@@ -471,15 +457,13 @@ void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) {
int count = mCanvasState.save(SaveFlags::MatrixClip);
const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath();
- SkPath transformedMaskPath; // on stack, since BakedOpState makes a deep copy
+ SkPath transformedMaskPath; // on stack, since BakedOpState makes a deep copy
if (projectionReceiverOutline) {
// transform the mask for this projector into render target space
// TODO: consider combining both transforms by stashing transform instead of applying
SkMatrix skCurrentTransform;
mCanvasState.currentTransform()->copyTo(skCurrentTransform);
- projectionReceiverOutline->transform(
- skCurrentTransform,
- &transformedMaskPath);
+ projectionReceiverOutline->transform(skCurrentTransform, &transformedMaskPath);
mCanvasState.setProjectionPathMask(&transformedMaskPath);
}
@@ -509,10 +493,12 @@ void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) {
* This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas.
* E.g. a BitmapOp op then would be dispatched to FrameBuilder::onBitmapOp(const BitmapOp&)
*/
-#define OP_RECEIVER(Type) \
- [](FrameBuilder& frameBuilder, const RecordedOp& op) { frameBuilder.defer##Type(static_cast<const Type&>(op)); },
+#define OP_RECEIVER(Type) \
+ [](FrameBuilder& frameBuilder, const RecordedOp& op) { \
+ frameBuilder.defer##Type(static_cast<const Type&>(op)); \
+ },
void FrameBuilder::deferNodeOps(const RenderNode& renderNode) {
- typedef void (*OpDispatcher) (FrameBuilder& frameBuilder, const RecordedOp& op);
+ typedef void (*OpDispatcher)(FrameBuilder & frameBuilder, const RecordedOp& op);
static OpDispatcher receivers[] = BUILD_DEFERRABLE_OP_LUT(OP_RECEIVER);
// can't be null, since DL=null node rejection happens before deferNodePropsAndOps
@@ -526,9 +512,9 @@ void FrameBuilder::deferNodeOps(const RenderNode& renderNode) {
const RecordedOp* op = displayList.getOps()[opIndex];
receivers[op->opId](*this, *op);
- if (CC_UNLIKELY(!renderNode.mProjectedNodes.empty()
- && displayList.projectionReceiveIndex >= 0
- && static_cast<int>(opIndex) == displayList.projectionReceiveIndex)) {
+ if (CC_UNLIKELY(!renderNode.mProjectedNodes.empty() &&
+ displayList.projectionReceiveIndex >= 0 &&
+ static_cast<int>(opIndex) == displayList.projectionReceiveIndex)) {
deferProjectedChildren(renderNode);
}
}
@@ -542,7 +528,7 @@ void FrameBuilder::deferRenderNodeOpImpl(const RenderNodeOp& op) {
// apply state from RecordedOp (clip first, since op's clip is transformed by current matrix)
mCanvasState.writableSnapshot()->applyClip(op.localClip,
- *mCanvasState.currentSnapshot()->transform);
+ *mCanvasState.currentSnapshot()->transform);
mCanvasState.concatMatrix(op.localMatrix);
// then apply state from node properties, and defer ops
@@ -562,12 +548,12 @@ void FrameBuilder::deferRenderNodeOp(const RenderNodeOp& op) {
* for paint's style on the bounds being computed.
*/
BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
- BakedOpState::StrokeBehavior strokeBehavior, bool expandForPathTexture) {
+ BakedOpState::StrokeBehavior strokeBehavior,
+ bool expandForPathTexture) {
// Note: here we account for stroke when baking the op
BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
- mAllocator, *mCanvasState.writableSnapshot(), op,
- strokeBehavior, expandForPathTexture);
- if (!bakedState) return nullptr; // quick rejected
+ mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior, expandForPathTexture);
+ if (!bakedState) return nullptr; // quick rejected
if (op.opId == RecordedOpId::RectOp && op.paint->getStyle() != SkPaint::kStroke_Style) {
bakedState->setupOpacity(op.paint);
@@ -586,8 +572,8 @@ BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t ba
static batchid_t tessBatchId(const RecordedOp& op) {
const SkPaint& paint = *(op.paint);
return paint.getPathEffect()
- ? OpBatchType::AlphaMaskTexture
- : (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices);
+ ? OpBatchType::AlphaMaskTexture
+ : (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices);
}
void FrameBuilder::deferArcOp(const ArcOp& op) {
@@ -598,13 +584,13 @@ void FrameBuilder::deferArcOp(const ArcOp& op) {
}
static bool hasMergeableClip(const BakedOpState& state) {
- return !state.computedState.clipState
- || state.computedState.clipState->mode == ClipMode::Rectangle;
+ return !state.computedState.clipState ||
+ state.computedState.clipState->mode == ClipMode::Rectangle;
}
void FrameBuilder::deferBitmapOp(const BitmapOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
if (op.bitmap->isOpaque()) {
bakedState->setupOpacity(op.paint);
@@ -613,11 +599,10 @@ void FrameBuilder::deferBitmapOp(const BitmapOp& op) {
// Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
// Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
// MergingDrawBatch::canMergeWith()
- if (bakedState->computedState.transform.isSimple()
- && bakedState->computedState.transform.positiveScale()
- && PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver
- && op.bitmap->colorType() != kAlpha_8_SkColorType
- && hasMergeableClip(*bakedState)) {
+ if (bakedState->computedState.transform.isSimple() &&
+ bakedState->computedState.transform.positiveScale() &&
+ PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver &&
+ op.bitmap->colorType() != kAlpha_8_SkColorType && hasMergeableClip(*bakedState)) {
mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.bitmap->getGenerationID());
currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::Bitmap, mergeId);
} else {
@@ -627,24 +612,21 @@ void FrameBuilder::deferBitmapOp(const BitmapOp& op) {
void FrameBuilder::deferBitmapMeshOp(const BitmapMeshOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
}
void FrameBuilder::deferBitmapRectOp(const BitmapRectOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
}
void FrameBuilder::deferVectorDrawableOp(const VectorDrawableOp& op) {
Bitmap& bitmap = op.vectorDrawable->getBitmapUpdateIfDirty();
SkPaint* paint = op.vectorDrawable->getPaint();
- const BitmapRectOp* resolvedOp = mAllocator.create_trivial<BitmapRectOp>(op.unmappedBounds,
- op.localMatrix,
- op.localClip,
- paint,
- &bitmap,
+ const BitmapRectOp* resolvedOp = mAllocator.create_trivial<BitmapRectOp>(
+ op.unmappedBounds, op.localMatrix, op.localClip, paint, &bitmap,
Rect(bitmap.width(), bitmap.height()));
deferBitmapRectOp(*resolvedOp);
}
@@ -656,23 +638,20 @@ void FrameBuilder::deferCirclePropsOp(const CirclePropsOp& op) {
float y = *(op.y);
float radius = *(op.radius);
Rect unmappedBounds(x - radius, y - radius, x + radius, y + radius);
- const OvalOp* resolvedOp = mAllocator.create_trivial<OvalOp>(
- unmappedBounds,
- op.localMatrix,
- op.localClip,
- op.paint);
+ const OvalOp* resolvedOp = mAllocator.create_trivial<OvalOp>(unmappedBounds, op.localMatrix,
+ op.localClip, op.paint);
deferOvalOp(*resolvedOp);
}
void FrameBuilder::deferColorOp(const ColorOp& op) {
BakedOpState* bakedState = tryBakeUnboundedOpState(op);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices);
}
void FrameBuilder::deferFunctorOp(const FunctorOp& op) {
BakedOpState* bakedState = tryBakeUnboundedOpState(op);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Functor);
}
@@ -687,11 +666,11 @@ void FrameBuilder::deferOvalOp(const OvalOp& op) {
void FrameBuilder::deferPatchOp(const PatchOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
- if (bakedState->computedState.transform.isPureTranslate()
- && PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver
- && hasMergeableClip(*bakedState)) {
+ if (bakedState->computedState.transform.isPureTranslate() &&
+ PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver &&
+ hasMergeableClip(*bakedState)) {
mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.bitmap->getGenerationID());
// Only use the MergedPatch batchId when merged, so Bitmap+Patch don't try to merge together
@@ -723,7 +702,8 @@ void FrameBuilder::deferRoundRectOp(const RoundRectOp& op) {
if (CC_LIKELY(state && !op.paint->getPathEffect())) {
// TODO: consider storing tessellation task in BakedOpState
mCaches.tessellationCache.precacheRoundRect(state->computedState.transform, *(op.paint),
- op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.rx, op.ry);
+ op.unmappedBounds.getWidth(),
+ op.unmappedBounds.getHeight(), op.rx, op.ry);
}
}
@@ -731,16 +711,14 @@ void FrameBuilder::deferRoundRectPropsOp(const RoundRectPropsOp& op) {
// allocate a temporary round rect op (with mAllocator, so it persists until render), so the
// renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple.
const RoundRectOp* resolvedOp = mAllocator.create_trivial<RoundRectOp>(
- Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)),
- op.localMatrix,
- op.localClip,
+ Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)), op.localMatrix, op.localClip,
op.paint, *op.rx, *op.ry);
deferRoundRectOp(*resolvedOp);
}
void FrameBuilder::deferSimpleRectsOp(const SimpleRectsOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices);
}
@@ -753,12 +731,12 @@ void FrameBuilder::deferTextOp(const TextOp& op) {
BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
mAllocator, *mCanvasState.writableSnapshot(), op,
BakedOpState::StrokeBehavior::StyleDefined, false);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
batchid_t batchId = textBatchId(*(op.paint));
- if (bakedState->computedState.transform.isPureTranslate()
- && PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver
- && hasMergeableClip(*bakedState)) {
+ if (bakedState->computedState.transform.isPureTranslate() &&
+ PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver &&
+ hasMergeableClip(*bakedState)) {
mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.paint->getColor());
currentLayer().deferMergeableOp(mAllocator, bakedState, batchId, mergeId);
} else {
@@ -773,19 +751,19 @@ void FrameBuilder::deferTextOp(const TextOp& op) {
// Partial transform case, see BakedOpDispatcher::renderTextOp
float sx, sy;
totalTransform.decomposeScale(sx, sy);
- fontRenderer.precache(op.paint, op.glyphs, op.glyphCount, SkMatrix::MakeScale(
- roundf(std::max(1.0f, sx)),
- roundf(std::max(1.0f, sy))));
+ fontRenderer.precache(
+ op.paint, op.glyphs, op.glyphCount,
+ SkMatrix::MakeScale(roundf(std::max(1.0f, sx)), roundf(std::max(1.0f, sy))));
}
}
void FrameBuilder::deferTextOnPathOp(const TextOnPathOp& op) {
BakedOpState* bakedState = tryBakeUnboundedOpState(op);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, textBatchId(*(op.paint)));
- mCaches.fontRenderer.getFontRenderer().precache(
- op.paint, op.glyphs, op.glyphCount, SkMatrix::I());
+ mCaches.fontRenderer.getFontRenderer().precache(op.paint, op.glyphs, op.glyphCount,
+ SkMatrix::I());
}
void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) {
@@ -802,28 +780,27 @@ void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) {
}
BakedOpState* bakedState = tryBakeOpState(*textureLayerOp);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer);
}
-void FrameBuilder::saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
- float contentTranslateX, float contentTranslateY,
- const Rect& repaintRect,
- const Vector3& lightCenter,
- const BeginLayerOp* beginLayerOp, RenderNode* renderNode) {
+void FrameBuilder::saveForLayer(uint32_t layerWidth, uint32_t layerHeight, float contentTranslateX,
+ float contentTranslateY, const Rect& repaintRect,
+ const Vector3& lightCenter, const BeginLayerOp* beginLayerOp,
+ RenderNode* renderNode) {
mCanvasState.save(SaveFlags::MatrixClip);
mCanvasState.writableSnapshot()->initializeViewport(layerWidth, layerHeight);
mCanvasState.writableSnapshot()->roundRectClipState = nullptr;
mCanvasState.writableSnapshot()->setRelativeLightCenter(lightCenter);
- mCanvasState.writableSnapshot()->transform->loadTranslate(
- contentTranslateX, contentTranslateY, 0);
- mCanvasState.writableSnapshot()->setClip(
- repaintRect.left, repaintRect.top, repaintRect.right, repaintRect.bottom);
+ mCanvasState.writableSnapshot()->transform->loadTranslate(contentTranslateX, contentTranslateY,
+ 0);
+ mCanvasState.writableSnapshot()->setClip(repaintRect.left, repaintRect.top, repaintRect.right,
+ repaintRect.bottom);
// create a new layer repaint, and push its index on the stack
mLayerStack.push_back(mLayerBuilders.size());
- auto newFbo = mAllocator.create<LayerBuilder>(layerWidth, layerHeight,
- repaintRect, beginLayerOp, renderNode);
+ auto newFbo = mAllocator.create<LayerBuilder>(layerWidth, layerHeight, repaintRect,
+ beginLayerOp, renderNode);
mLayerBuilders.push_back(newFbo);
}
@@ -836,8 +813,8 @@ void FrameBuilder::restoreForLayer() {
// TODO: defer time rejection (when bounds become empty) + tests
// Option - just skip layers with no bounds at playback + defer?
void FrameBuilder::deferBeginLayerOp(const BeginLayerOp& op) {
- uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth();
- uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight();
+ uint32_t layerWidth = (uint32_t)op.unmappedBounds.getWidth();
+ uint32_t layerHeight = (uint32_t)op.unmappedBounds.getHeight();
auto previous = mCanvasState.currentSnapshot();
Vector3 lightCenter = previous->getRelativeLightCenter();
@@ -873,11 +850,8 @@ void FrameBuilder::deferBeginLayerOp(const BeginLayerOp& op) {
float contentTranslateX = -saveLayerBounds.left;
float contentTranslateY = -saveLayerBounds.top;
- saveForLayer(layerWidth, layerHeight,
- contentTranslateX, contentTranslateY,
- Rect(layerWidth, layerHeight),
- lightCenter,
- &op, nullptr);
+ saveForLayer(layerWidth, layerHeight, contentTranslateX, contentTranslateY,
+ Rect(layerWidth, layerHeight), lightCenter, &op, nullptr);
}
void FrameBuilder::deferEndLayerOp(const EndLayerOp& /* ignored */) {
@@ -890,8 +864,8 @@ void FrameBuilder::deferEndLayerOp(const EndLayerOp& /* ignored */) {
// to translate the drawLayer by how much the contents was translated
// TODO: Unify this with beginLayerOp so we don't have to calculate this
// twice
- uint32_t layerWidth = (uint32_t) beginLayerOp.unmappedBounds.getWidth();
- uint32_t layerHeight = (uint32_t) beginLayerOp.unmappedBounds.getHeight();
+ uint32_t layerWidth = (uint32_t)beginLayerOp.unmappedBounds.getWidth();
+ uint32_t layerHeight = (uint32_t)beginLayerOp.unmappedBounds.getHeight();
auto previous = mCanvasState.currentSnapshot();
Vector3 lightCenter = previous->getRelativeLightCenter();
@@ -900,8 +874,7 @@ void FrameBuilder::deferEndLayerOp(const EndLayerOp& /* ignored */) {
// parent content transform * canvas transform * bounds offset
Matrix4 contentTransform(*(previous->transform));
contentTransform.multiply(beginLayerOp.localMatrix);
- contentTransform.translate(beginLayerOp.unmappedBounds.left,
- beginLayerOp.unmappedBounds.top);
+ contentTransform.translate(beginLayerOp.unmappedBounds.left, beginLayerOp.unmappedBounds.top);
Matrix4 inverseContentTransform;
inverseContentTransform.loadInverse(contentTransform);
@@ -927,10 +900,7 @@ void FrameBuilder::deferEndLayerOp(const EndLayerOp& /* ignored */) {
// record the draw operation into the previous layer's list of draw commands
// uses state from the associated beginLayerOp, since it has all the state needed for drawing
LayerOp* drawLayerOp = mAllocator.create_trivial<LayerOp>(
- beginLayerOp.unmappedBounds,
- localMatrix,
- beginLayerOp.localClip,
- beginLayerOp.paint,
+ beginLayerOp.unmappedBounds, localMatrix, beginLayerOp.localClip, beginLayerOp.paint,
&(mLayerBuilders[finishedLayerIndex]->offscreenBuffer));
BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
@@ -959,15 +929,16 @@ void FrameBuilder::deferBeginUnclippedLayerOp(const BeginUnclippedLayerOp& op) {
// Unclipped layer rejected - push a null op, so next EndUnclippedLayerOp is ignored
currentLayer().activeUnclippedSaveLayers.push_back(nullptr);
} else {
- // Allocate a holding position for the layer object (copyTo will produce, copyFrom will consume)
+ // Allocate a holding position for the layer object (copyTo will produce, copyFrom will
+ // consume)
OffscreenBuffer** layerHandle = mAllocator.create<OffscreenBuffer*>(nullptr);
/**
* First, defer an operation to copy out the content from the rendertarget into a layer.
*/
auto copyToOp = mAllocator.create_trivial<CopyToLayerOp>(op, layerHandle);
- BakedOpState* bakedState = BakedOpState::directConstruct(mAllocator,
- &(currentLayer().repaintClip), dstRect, *copyToOp);
+ BakedOpState* bakedState = BakedOpState::directConstruct(
+ mAllocator, &(currentLayer().repaintClip), dstRect, *copyToOp);
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::CopyToLayer);
/**
@@ -981,8 +952,8 @@ void FrameBuilder::deferBeginUnclippedLayerOp(const BeginUnclippedLayerOp& op) {
* a balanced EndUnclippedLayerOp is seen
*/
auto copyFromOp = mAllocator.create_trivial<CopyFromLayerOp>(op, layerHandle);
- bakedState = BakedOpState::directConstruct(mAllocator,
- &(currentLayer().repaintClip), dstRect, *copyFromOp);
+ bakedState = BakedOpState::directConstruct(mAllocator, &(currentLayer().repaintClip),
+ dstRect, *copyFromOp);
currentLayer().activeUnclippedSaveLayers.push_back(bakedState);
}
}
@@ -1001,5 +972,5 @@ void FrameBuilder::finishDefer() {
mCaches.fontRenderer.endPrecaching();
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h
index 46048f7125ce..974daf8a17bb 100644
--- a/libs/hwui/FrameBuilder.h
+++ b/libs/hwui/FrameBuilder.h
@@ -23,8 +23,8 @@
#include "RecordedOp.h"
#include "utils/GLUtils.h"
-#include <vector>
#include <unordered_map>
+#include <vector>
struct SkRect;
@@ -60,12 +60,11 @@ public:
float radius;
};
- FrameBuilder(const SkRect& clip,
- uint32_t viewportWidth, uint32_t viewportHeight,
- const LightGeometry& lightGeometry, Caches& caches);
+ FrameBuilder(const SkRect& clip, uint32_t viewportWidth, uint32_t viewportHeight,
+ const LightGeometry& lightGeometry, Caches& caches);
- FrameBuilder(const LayerUpdateQueue& layerUpdateQueue,
- const LightGeometry& lightGeometry, Caches& caches);
+ FrameBuilder(const LayerUpdateQueue& layerUpdateQueue, const LightGeometry& lightGeometry,
+ Caches& caches);
void deferLayers(const LayerUpdateQueue& layers);
@@ -73,8 +72,8 @@ public:
void deferRenderNode(float tx, float ty, Rect clipRect, RenderNode& renderNode);
- void deferRenderNodeScene(const std::vector< sp<RenderNode> >& nodes,
- const Rect& contentDrawBounds);
+ void deferRenderNodeScene(const std::vector<sp<RenderNode> >& nodes,
+ const Rect& contentDrawBounds);
virtual ~FrameBuilder() {}
@@ -88,32 +87,32 @@ public:
void replayBakedOps(Renderer& renderer) {
std::vector<OffscreenBuffer*> temporaryLayers;
finishDefer();
- /**
- * Defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to
- * dispatch the op via a method on a static dispatcher when the op is replayed.
- *
- * For example a BitmapOp would resolve, via the lambda lookup, to calling:
- *
- * StaticDispatcher::onBitmapOp(Renderer& renderer, const BitmapOp& op, const BakedOpState& state);
- */
- #define X(Type) \
- [](void* renderer, const BakedOpState& state) { \
- StaticDispatcher::on##Type(*(static_cast<Renderer*>(renderer)), \
- static_cast<const Type&>(*(state.op)), state); \
- },
+/**
+ * Defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to
+ * dispatch the op via a method on a static dispatcher when the op is replayed.
+ *
+ * For example a BitmapOp would resolve, via the lambda lookup, to calling:
+ *
+ * StaticDispatcher::onBitmapOp(Renderer& renderer, const BitmapOp& op, const BakedOpState& state);
+ */
+#define X(Type) \
+ [](void* renderer, const BakedOpState& state) { \
+ StaticDispatcher::on##Type(*(static_cast<Renderer*>(renderer)), \
+ static_cast<const Type&>(*(state.op)), state); \
+ },
static BakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X);
- #undef X
-
- /**
- * Defines a LUT of lambdas which allow merged arrays of BakedOpState* to be passed to a
- * static dispatcher when the group of merged ops is replayed.
- */
- #define X(Type) \
- [](void* renderer, const MergedBakedOpList& opList) { \
- StaticDispatcher::onMerged##Type##s(*(static_cast<Renderer*>(renderer)), opList); \
- },
+#undef X
+
+/**
+ * Defines a LUT of lambdas which allow merged arrays of BakedOpState* to be passed to a
+ * static dispatcher when the group of merged ops is replayed.
+ */
+#define X(Type) \
+ [](void* renderer, const MergedBakedOpList& opList) { \
+ StaticDispatcher::onMerged##Type##s(*(static_cast<Renderer*>(renderer)), opList); \
+ },
static MergedOpReceiver mergedReceivers[] = BUILD_MERGEABLE_OP_LUT(X);
- #undef X
+#undef X
// Relay through layers in reverse order, since layers
// later in the list will be drawn by earlier ones
@@ -168,15 +167,10 @@ public:
private:
void finishDefer();
- enum class ChildrenSelectMode {
- Negative,
- Positive
- };
- void saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
- float contentTranslateX, float contentTranslateY,
- const Rect& repaintRect,
- const Vector3& lightCenter,
- const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
+ enum class ChildrenSelectMode { Negative, Positive };
+ void saveForLayer(uint32_t layerWidth, uint32_t layerHeight, float contentTranslateX,
+ float contentTranslateY, const Rect& repaintRect, const Vector3& lightCenter,
+ const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
void restoreForLayer();
LayerBuilder& currentLayer() { return *(mLayerBuilders[mLayerStack.back()]); }
@@ -185,16 +179,16 @@ private:
return BakedOpState::tryConstruct(mAllocator, *mCanvasState.writableSnapshot(), recordedOp);
}
BakedOpState* tryBakeUnboundedOpState(const RecordedOp& recordedOp) {
- return BakedOpState::tryConstructUnbounded(mAllocator, *mCanvasState.writableSnapshot(), recordedOp);
+ return BakedOpState::tryConstructUnbounded(mAllocator, *mCanvasState.writableSnapshot(),
+ recordedOp);
}
-
// should always be surrounded by a save/restore pair, and not called if DisplayList is null
void deferNodePropsAndOps(RenderNode& node);
template <typename V>
void defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMode mode,
- const V& zTranslatedNodes);
+ const V& zTranslatedNodes);
void deferShadow(const ClipBase* reorderClip, const RenderNodeOp& casterOp);
@@ -206,20 +200,19 @@ private:
void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers);
- SkPath* createFrameAllocatedPath() {
- return mAllocator.create<SkPath>();
- }
+ SkPath* createFrameAllocatedPath() { return mAllocator.create<SkPath>(); }
BakedOpState* deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
- BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined,
- bool expandForPathTexture = false);
+ BakedOpState::StrokeBehavior strokeBehavior =
+ BakedOpState::StrokeBehavior::StyleDefined,
+ bool expandForPathTexture = false);
- /**
- * Declares all FrameBuilder::deferXXXXOp() methods for every RecordedOp type.
- *
- * These private methods are called from within deferImpl to defer each individual op
- * type differently.
- */
+/**
+ * Declares all FrameBuilder::deferXXXXOp() methods for every RecordedOp type.
+ *
+ * These private methods are called from within deferImpl to defer each individual op
+ * type differently.
+ */
#define X(Type) void defer##Type(const Type& op);
MAP_DEFERRABLE_OPS(X)
#undef X
@@ -254,5 +247,5 @@ private:
const bool mDrawFbo0;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp
index 826f0bba294c..71cc9a81a09f 100644
--- a/libs/hwui/FrameInfo.cpp
+++ b/libs/hwui/FrameInfo.cpp
@@ -21,30 +21,30 @@ namespace android {
namespace uirenderer {
const std::string FrameInfoNames[] = {
- "Flags",
- "IntendedVsync",
- "Vsync",
- "OldestInputEvent",
- "NewestInputEvent",
- "HandleInputStart",
- "AnimationStart",
- "PerformTraversalsStart",
- "DrawStart",
- "SyncQueued",
- "SyncStart",
- "IssueDrawCommandsStart",
- "SwapBuffers",
- "FrameCompleted",
- "DequeueBufferDuration",
- "QueueBufferDuration",
+ "Flags",
+ "IntendedVsync",
+ "Vsync",
+ "OldestInputEvent",
+ "NewestInputEvent",
+ "HandleInputStart",
+ "AnimationStart",
+ "PerformTraversalsStart",
+ "DrawStart",
+ "SyncQueued",
+ "SyncStart",
+ "IssueDrawCommandsStart",
+ "SwapBuffers",
+ "FrameCompleted",
+ "DequeueBufferDuration",
+ "QueueBufferDuration",
};
-static_assert((sizeof(FrameInfoNames)/sizeof(FrameInfoNames[0]))
- == static_cast<int>(FrameInfoIndex::NumIndexes),
- "size mismatch: FrameInfoNames doesn't match the enum!");
+static_assert((sizeof(FrameInfoNames) / sizeof(FrameInfoNames[0])) ==
+ static_cast<int>(FrameInfoIndex::NumIndexes),
+ "size mismatch: FrameInfoNames doesn't match the enum!");
static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 16,
- "Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)");
+ "Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)");
void FrameInfo::importUiThreadInfo(int64_t* info) {
memcpy(mFrameInfo, info, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index bac9d12d273c..0aab58c38ba0 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -59,12 +59,12 @@ enum class FrameInfoIndex {
extern const std::string FrameInfoNames[];
namespace FrameInfoFlags {
- enum {
- WindowLayoutChanged = 1 << 0,
- RTAnimation = 1 << 1,
- SurfaceCanvas = 1 << 2,
- SkippedFrame = 1 << 3,
- };
+enum {
+ WindowLayoutChanged = 1 << 0,
+ RTAnimation = 1 << 1,
+ SurfaceCanvas = 1 << 2,
+ SkippedFrame = 1 << 3,
+};
};
class ANDROID_API UiFrameInfoBuilder {
@@ -91,9 +91,7 @@ public:
}
private:
- inline int64_t& set(FrameInfoIndex index) {
- return mBuffer[static_cast<int>(index)];
- }
+ inline int64_t& set(FrameInfoIndex index) { return mBuffer[static_cast<int>(index)]; }
int64_t* mBuffer;
};
@@ -102,33 +100,23 @@ class FrameInfo {
public:
void importUiThreadInfo(int64_t* info);
- void markSyncStart() {
- set(FrameInfoIndex::SyncStart) = systemTime(CLOCK_MONOTONIC);
- }
+ void markSyncStart() { set(FrameInfoIndex::SyncStart) = systemTime(CLOCK_MONOTONIC); }
void markIssueDrawCommandsStart() {
set(FrameInfoIndex::IssueDrawCommandsStart) = systemTime(CLOCK_MONOTONIC);
}
- void markSwapBuffers() {
- set(FrameInfoIndex::SwapBuffers) = systemTime(CLOCK_MONOTONIC);
- }
+ void markSwapBuffers() { set(FrameInfoIndex::SwapBuffers) = systemTime(CLOCK_MONOTONIC); }
- void markFrameCompleted() {
- set(FrameInfoIndex::FrameCompleted) = systemTime(CLOCK_MONOTONIC);
- }
+ void markFrameCompleted() { set(FrameInfoIndex::FrameCompleted) = systemTime(CLOCK_MONOTONIC); }
void addFlag(int frameInfoFlag) {
set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag);
}
- const int64_t* data() const {
- return mFrameInfo;
- }
+ const int64_t* data() const { return mFrameInfo; }
- inline int64_t operator[](FrameInfoIndex index) const {
- return get(index);
- }
+ inline int64_t operator[](FrameInfoIndex index) const { return get(index); }
inline int64_t operator[](int index) const {
if (index < 0 || index >= static_cast<int>(FrameInfoIndex::NumIndexes)) return 0;
@@ -140,12 +128,10 @@ public:
int64_t starttime = get(start);
int64_t gap = endtime - starttime;
gap = starttime > 0 ? gap : 0;
- if (end > FrameInfoIndex::SyncQueued &&
- start < FrameInfoIndex::SyncQueued) {
+ if (end > FrameInfoIndex::SyncQueued && start < FrameInfoIndex::SyncQueued) {
// Need to subtract out the time spent in a stalled state
// as this will be captured by the previous frame's info
- int64_t offset = get(FrameInfoIndex::SyncStart)
- - get(FrameInfoIndex::SyncQueued);
+ int64_t offset = get(FrameInfoIndex::SyncStart) - get(FrameInfoIndex::SyncQueued);
if (offset > 0) {
gap -= offset;
}
@@ -157,9 +143,7 @@ public:
return duration(FrameInfoIndex::IntendedVsync, FrameInfoIndex::FrameCompleted);
}
- inline int64_t& set(FrameInfoIndex index) {
- return mFrameInfo[static_cast<int>(index)];
- }
+ inline int64_t& set(FrameInfoIndex index) { return mFrameInfo[static_cast<int>(index)]; }
inline int64_t get(FrameInfoIndex index) const {
if (index == FrameInfoIndex::NumIndexes) return 0;
diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp
index d3adc32da848..5aea04d94cbe 100644
--- a/libs/hwui/FrameInfoVisualizer.cpp
+++ b/libs/hwui/FrameInfoVisualizer.cpp
@@ -22,8 +22,10 @@
#include <cutils/compiler.h>
#include <array>
-#define RETURN_IF_PROFILING_DISABLED() if (CC_LIKELY(mType == ProfileType::None)) return
-#define RETURN_IF_DISABLED() if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return
+#define RETURN_IF_PROFILING_DISABLED() \
+ if (CC_LIKELY(mType == ProfileType::None)) return
+#define RETURN_IF_DISABLED() \
+ if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return
#define PROFILE_DRAW_WIDTH 3
#define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2
@@ -48,22 +50,22 @@ struct BarSegment {
SkColor color;
};
-static const std::array<BarSegment,7> Bar {{
- { FrameInfoIndex::IntendedVsync, FrameInfoIndex::HandleInputStart, Color::Teal_700 },
- { FrameInfoIndex::HandleInputStart, FrameInfoIndex::PerformTraversalsStart, Color::Green_700 },
- { FrameInfoIndex::PerformTraversalsStart, FrameInfoIndex::DrawStart, Color::LightGreen_700 },
- { FrameInfoIndex::DrawStart, FrameInfoIndex::SyncStart, Color::Blue_500 },
- { FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart, Color::LightBlue_300 },
- { FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers, Color::Red_500},
- { FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted, Color::Orange_500},
+static const std::array<BarSegment, 7> Bar{{
+ {FrameInfoIndex::IntendedVsync, FrameInfoIndex::HandleInputStart, Color::Teal_700},
+ {FrameInfoIndex::HandleInputStart, FrameInfoIndex::PerformTraversalsStart,
+ Color::Green_700},
+ {FrameInfoIndex::PerformTraversalsStart, FrameInfoIndex::DrawStart, Color::LightGreen_700},
+ {FrameInfoIndex::DrawStart, FrameInfoIndex::SyncStart, Color::Blue_500},
+ {FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart, Color::LightBlue_300},
+ {FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers, Color::Red_500},
+ {FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted, Color::Orange_500},
}};
static int dpToPx(int dp, float density) {
- return (int) (dp * density + 0.5f);
+ return (int)(dp * density + 0.5f);
}
-FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source)
- : mFrameSource(source) {
+FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source) : mFrameSource(source) {
setDensity(1);
}
@@ -97,8 +99,8 @@ void FrameInfoVisualizer::draw(IProfileRenderer& renderer) {
if (mFlashToggle) {
SkPaint paint;
paint.setColor(0x7fff0000);
- renderer.drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop,
- mDirtyRegion.fRight, mDirtyRegion.fBottom, paint);
+ renderer.drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop, mDirtyRegion.fRight,
+ mDirtyRegion.fBottom, paint);
}
}
@@ -169,7 +171,8 @@ void FrameInfoVisualizer::initializeRects(const int baseline, const int width) {
void FrameInfoVisualizer::nextBarSegment(FrameInfoIndex start, FrameInfoIndex end) {
int fast_i = (mNumFastRects - 1) * 4;
- int janky_i = (mNumJankyRects - 1) * 4;;
+ int janky_i = (mNumJankyRects - 1) * 4;
+ ;
for (size_t fi = 0; fi < mFrameSource.size(); fi++) {
if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) {
continue;
@@ -210,11 +213,8 @@ void FrameInfoVisualizer::drawThreshold(IProfileRenderer& renderer) {
SkPaint paint;
paint.setColor(THRESHOLD_COLOR);
float yLocation = renderer.getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
- renderer.drawRect(0.0f,
- yLocation - mThresholdStroke/2,
- renderer.getViewportWidth(),
- yLocation + mThresholdStroke/2,
- paint);
+ renderer.drawRect(0.0f, yLocation - mThresholdStroke / 2, renderer.getViewportWidth(),
+ yLocation + mThresholdStroke / 2, paint);
}
bool FrameInfoVisualizer::consumeProperties() {
@@ -245,22 +245,19 @@ void FrameInfoVisualizer::dumpData(int fd) {
// last call to dumpData(). In other words if there's a dumpData(), draw frame,
// dumpData(), the last dumpData() should only log 1 frame.
- FILE *file = fdopen(fd, "a");
- fprintf(file, "\n\tDraw\tPrepare\tProcess\tExecute\n");
+ dprintf(fd, "\n\tDraw\tPrepare\tProcess\tExecute\n");
for (size_t i = 0; i < mFrameSource.size(); i++) {
if (mFrameSource[i][FrameInfoIndex::IntendedVsync] <= mLastFrameLogged) {
continue;
}
mLastFrameLogged = mFrameSource[i][FrameInfoIndex::IntendedVsync];
- fprintf(file, "\t%3.2f\t%3.2f\t%3.2f\t%3.2f\n",
+ dprintf(fd, "\t%3.2f\t%3.2f\t%3.2f\t%3.2f\n",
durationMS(i, FrameInfoIndex::IntendedVsync, FrameInfoIndex::SyncStart),
durationMS(i, FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart),
durationMS(i, FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers),
durationMS(i, FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted));
}
-
- fflush(file);
}
} /* namespace uirenderer */
diff --git a/libs/hwui/FrameMetricsObserver.h b/libs/hwui/FrameMetricsObserver.h
index 4f81c8681fc8..ba72e937095f 100644
--- a/libs/hwui/FrameMetricsObserver.h
+++ b/libs/hwui/FrameMetricsObserver.h
@@ -26,5 +26,5 @@ public:
virtual void notify(const int64_t* buffer);
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/FrameMetricsReporter.h b/libs/hwui/FrameMetricsReporter.h
index c1cd0a9224b6..d920a99f5ee3 100644
--- a/libs/hwui/FrameMetricsReporter.h
+++ b/libs/hwui/FrameMetricsReporter.h
@@ -16,8 +16,8 @@
#pragma once
-#include <utils/RefBase.h>
#include <utils/Log.h>
+#include <utils/RefBase.h>
#include "FrameInfo.h"
#include "FrameMetricsObserver.h"
@@ -32,9 +32,7 @@ class FrameMetricsReporter {
public:
FrameMetricsReporter() {}
- void addObserver(FrameMetricsObserver* observer) {
- mObservers.push_back(observer);
- }
+ void addObserver(FrameMetricsObserver* observer) { mObservers.push_back(observer); }
bool removeObserver(FrameMetricsObserver* observer) {
for (size_t i = 0; i < mObservers.size(); i++) {
@@ -46,9 +44,7 @@ public:
return false;
}
- bool hasObservers() {
- return mObservers.size() > 0;
- }
+ bool hasObservers() { return mObservers.size() > 0; }
void reportFrameMetrics(const int64_t* stats) {
for (size_t i = 0; i < mObservers.size(); i++) {
@@ -57,9 +53,8 @@ public:
}
private:
- std::vector< sp<FrameMetricsObserver> > mObservers;
+ std::vector<sp<FrameMetricsObserver> > mObservers;
};
-}; // namespace uirenderer
-}; // namespace android
-
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp
index 8aff0a24b4f0..88fb16234388 100644
--- a/libs/hwui/GammaFontRenderer.cpp
+++ b/libs/hwui/GammaFontRenderer.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include "Debug.h"
#include "GammaFontRenderer.h"
+#include "Debug.h"
#include "Properties.h"
namespace android {
@@ -39,5 +39,5 @@ void GammaFontRenderer::endPrecaching() {
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index c9cf69bc7d9f..e9002442c64f 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -26,9 +26,7 @@ class GammaFontRenderer {
public:
GammaFontRenderer();
- void clear() {
- mRenderer.reset(nullptr);
- }
+ void clear() { mRenderer.reset(nullptr); }
void flush() {
if (mRenderer) {
@@ -55,9 +53,7 @@ public:
}
}
- uint32_t getSize() const {
- return mRenderer ? mRenderer->getSize() : 0;
- }
+ uint32_t getSize() const { return mRenderer ? mRenderer->getSize() : 0; }
void endPrecaching();
@@ -68,7 +64,7 @@ private:
#endif
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_GAMMA_FONT_RENDERER_H
+#endif // ANDROID_HWUI_GAMMA_FONT_RENDERER_H
diff --git a/libs/hwui/GlFunctorLifecycleListener.h b/libs/hwui/GlFunctorLifecycleListener.h
index 357090eb31ca..5d07b46919d4 100644
--- a/libs/hwui/GlFunctorLifecycleListener.h
+++ b/libs/hwui/GlFunctorLifecycleListener.h
@@ -28,5 +28,5 @@ public:
virtual void onGlFunctorReleased(Functor* functor) = 0;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/GlLayer.cpp b/libs/hwui/GlLayer.cpp
index 070e95432a11..32a30149e476 100644
--- a/libs/hwui/GlLayer.cpp
+++ b/libs/hwui/GlLayer.cpp
@@ -23,17 +23,16 @@
#include <utils/Log.h>
-#define ATRACE_LAYER_WORK(label) \
- ATRACE_FORMAT("%s HW Layer DisplayList %s %ux%u", \
- label, \
- (renderNode.get() != NULL) ? renderNode->getName() : "", \
- getWidth(), getHeight())
+#define ATRACE_LAYER_WORK(label) \
+ ATRACE_FORMAT("%s HW Layer DisplayList %s %ux%u", label, \
+ (renderNode.get() != NULL) ? renderNode->getName() : "", getWidth(), \
+ getHeight())
namespace android {
namespace uirenderer {
GlLayer::GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
+ SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
: Layer(renderState, Api::OpenGL, colorFilter, alpha, mode)
, caches(Caches::getInstance())
, texture(caches) {
@@ -73,5 +72,5 @@ void GlLayer::generateTexture() {
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/GlLayer.h b/libs/hwui/GlLayer.h
index c4f7fe2a56b8..1b091914f318 100644
--- a/libs/hwui/GlLayer.h
+++ b/libs/hwui/GlLayer.h
@@ -35,42 +35,26 @@ public:
SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend);
virtual ~GlLayer();
- uint32_t getWidth() const override {
- return texture.mWidth;
- }
+ uint32_t getWidth() const override { return texture.mWidth; }
- uint32_t getHeight() const override {
- return texture.mHeight;
- }
+ uint32_t getHeight() const override { return texture.mHeight; }
void setSize(uint32_t width, uint32_t height) override {
texture.updateLayout(width, height, texture.internalFormat(), texture.format(),
- texture.target());
+ texture.target());
}
- void setBlend(bool blend) override {
- texture.blend = blend;
- }
+ void setBlend(bool blend) override { texture.blend = blend; }
- bool isBlend() const override {
- return texture.blend;
- }
+ bool isBlend() const override { return texture.blend; }
- inline GLuint getTextureId() const {
- return texture.id();
- }
+ inline GLuint getTextureId() const { return texture.id(); }
- inline Texture& getTexture() {
- return texture;
- }
+ inline Texture& getTexture() { return texture; }
- inline GLenum getRenderTarget() const {
- return texture.target();
- }
+ inline GLenum getRenderTarget() const { return texture.target(); }
- inline bool isRenderable() const {
- return texture.target() != GL_NONE;
- }
+ inline bool isRenderable() const { return texture.target() != GL_NONE; }
void setRenderTarget(GLenum renderTarget);
@@ -89,7 +73,7 @@ private:
* The texture backing this layer.
*/
Texture texture;
-}; // struct GlLayer
+}; // struct GlLayer
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index e91c08d5a351..c68d51604bea 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -41,34 +41,34 @@ class Texture;
*/
namespace VertexAttribFlags {
- enum {
- // Mesh is pure x,y vertex pairs
- None = 0,
- // Mesh has texture coordinates embedded. Note that texture can exist without this flag
- // being set, if coordinates passed to sampler are determined another way.
- TextureCoord = 1 << 0,
- // Mesh has color embedded (to export to varying)
- Color = 1 << 1,
- // Mesh has alpha embedded (to export to varying)
- Alpha = 1 << 2,
- };
+enum {
+ // Mesh is pure x,y vertex pairs
+ None = 0,
+ // Mesh has texture coordinates embedded. Note that texture can exist without this flag
+ // being set, if coordinates passed to sampler are determined another way.
+ TextureCoord = 1 << 0,
+ // Mesh has color embedded (to export to varying)
+ Color = 1 << 1,
+ // Mesh has alpha embedded (to export to varying)
+ Alpha = 1 << 2,
+};
};
/*
* Enumerates transform features
*/
namespace TransformFlags {
- enum {
- None = 0,
+enum {
+ None = 0,
- // offset the eventual drawing matrix by a tiny amount to
- // disambiguate sampling patterns with non-AA rendering
- OffsetByFudgeFactor = 1 << 0,
+ // offset the eventual drawing matrix by a tiny amount to
+ // disambiguate sampling patterns with non-AA rendering
+ OffsetByFudgeFactor = 1 << 0,
- // Canvas transform isn't applied to the mesh at draw time,
- // since it's already built in.
- MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove for HWUI_NEW_OPS
- };
+ // Canvas transform isn't applied to the mesh at draw time,
+ // since it's already built in.
+ MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove for HWUI_NEW_OPS
+};
};
/**
@@ -86,10 +86,11 @@ namespace TransformFlags {
*/
struct Glop {
PREVENT_COPY_AND_ASSIGN(Glop);
+
public:
- Glop() { }
+ Glop() {}
struct Mesh {
- GLuint primitiveMode; // GL_TRIANGLES and GL_TRIANGLE_STRIP supported
+ GLuint primitiveMode; // GL_TRIANGLES and GL_TRIANGLE_STRIP supported
// buffer object and void* are mutually exclusive.
// Only GL_UNSIGNED_SHORT supported.
@@ -110,7 +111,7 @@ public:
} vertices;
int elementCount;
- int vertexCount; // only used for meshes (for glDrawRangeElements)
+ int vertexCount; // only used for meshes (for glDrawRangeElements)
TextureVertex mappedVertices[4];
} mesh;
@@ -148,10 +149,11 @@ public:
Matrix4 canvas;
int transformFlags;
- const Matrix4& meshTransform() const {
- return (transformFlags & TransformFlags::MeshIgnoresCanvasTransform)
- ? Matrix4::identity() : canvas;
- }
+ const Matrix4& meshTransform() const {
+ return (transformFlags & TransformFlags::MeshIgnoresCanvasTransform)
+ ? Matrix4::identity()
+ : canvas;
+ }
} transform;
const RoundRectClipState* roundRectClipState = nullptr;
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 8727a1d20dfd..2f107a004731 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -22,12 +22,12 @@
#include "Matrix.h"
#include "Patch.h"
#include "PathCache.h"
-#include "renderstate/MeshState.h"
-#include "renderstate/RenderState.h"
#include "SkiaShader.h"
#include "Texture.h"
-#include "utils/PaintUtils.h"
#include "VertexBuffer.h"
+#include "renderstate/MeshState.h"
+#include "renderstate/RenderState.h"
+#include "utils/PaintUtils.h"
#include <GLES2/gl2.h>
#include <SkPaint.h>
@@ -36,13 +36,13 @@
#if DEBUG_GLOP_BUILDER
-#define TRIGGER_STAGE(stageFlag) \
- LOG_ALWAYS_FATAL_IF((stageFlag) & mStageFlags, "Stage %d cannot be run twice", (stageFlag)); \
+#define TRIGGER_STAGE(stageFlag) \
+ LOG_ALWAYS_FATAL_IF((stageFlag)&mStageFlags, "Stage %d cannot be run twice", (stageFlag)); \
mStageFlags = static_cast<StageFlags>(mStageFlags | (stageFlag))
-#define REQUIRE_STAGES(requiredFlags) \
+#define REQUIRE_STAGES(requiredFlags) \
LOG_ALWAYS_FATAL_IF((mStageFlags & (requiredFlags)) != (requiredFlags), \
- "not prepared for current stage")
+ "not prepared for current stage")
#else
@@ -62,10 +62,7 @@ static void setUnitQuadTextureCoords(Rect uvs, TextureVertex* quadVertex) {
}
GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop)
- : mRenderState(renderState)
- , mCaches(caches)
- , mShader(nullptr)
- , mOutGlop(outGlop) {
+ : mRenderState(renderState), mCaches(caches), mShader(nullptr), mOutGlop(outGlop) {
mStageFlags = kInitialStage;
}
@@ -77,12 +74,10 @@ GlopBuilder& GlopBuilder::setMeshTexturedIndexedVbo(GLuint vbo, GLsizei elementC
TRIGGER_STAGE(kMeshStage);
mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
- mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
- mOutGlop->mesh.vertices = {
- vbo,
- VertexAttribFlags::TextureCoord,
- nullptr, (const void*) kMeshTextureOffset, nullptr,
- kTextureVertexStride };
+ mOutGlop->mesh.indices = {mRenderState.meshState().getQuadListIBO(), nullptr};
+ mOutGlop->mesh.vertices = {vbo, VertexAttribFlags::TextureCoord,
+ nullptr, (const void*)kMeshTextureOffset,
+ nullptr, kTextureVertexStride};
mOutGlop->mesh.elementCount = elementCount;
return *this;
}
@@ -91,12 +86,13 @@ GlopBuilder& GlopBuilder::setMeshUnitQuad() {
TRIGGER_STAGE(kMeshStage);
mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
- mOutGlop->mesh.indices = { 0, nullptr };
- mOutGlop->mesh.vertices = {
- mRenderState.meshState().getUnitQuadVBO(),
- VertexAttribFlags::None,
- nullptr, nullptr, nullptr,
- kTextureVertexStride };
+ mOutGlop->mesh.indices = {0, nullptr};
+ mOutGlop->mesh.vertices = {mRenderState.meshState().getUnitQuadVBO(),
+ VertexAttribFlags::None,
+ nullptr,
+ nullptr,
+ nullptr,
+ kTextureVertexStride};
mOutGlop->mesh.elementCount = 4;
return *this;
}
@@ -110,12 +106,13 @@ GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper) {
TRIGGER_STAGE(kMeshStage);
mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
- mOutGlop->mesh.indices = { 0, nullptr };
- mOutGlop->mesh.vertices = {
- mRenderState.meshState().getUnitQuadVBO(),
- VertexAttribFlags::TextureCoord,
- nullptr, (const void*) kMeshTextureOffset, nullptr,
- kTextureVertexStride };
+ mOutGlop->mesh.indices = {0, nullptr};
+ mOutGlop->mesh.vertices = {mRenderState.meshState().getUnitQuadVBO(),
+ VertexAttribFlags::TextureCoord,
+ nullptr,
+ (const void*)kMeshTextureOffset,
+ nullptr,
+ kTextureVertexStride};
mOutGlop->mesh.elementCount = 4;
return *this;
}
@@ -130,12 +127,13 @@ GlopBuilder& GlopBuilder::setMeshTexturedUvQuad(const UvMapper* uvMapper, Rect u
const TextureVertex* textureVertex = mOutGlop->mesh.mappedVertices;
mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
- mOutGlop->mesh.indices = { 0, nullptr };
- mOutGlop->mesh.vertices = {
- 0,
- VertexAttribFlags::TextureCoord,
- &textureVertex[0].x, &textureVertex[0].u, nullptr,
- kTextureVertexStride };
+ mOutGlop->mesh.indices = {0, nullptr};
+ mOutGlop->mesh.vertices = {0,
+ VertexAttribFlags::TextureCoord,
+ &textureVertex[0].x,
+ &textureVertex[0].u,
+ nullptr,
+ kTextureVertexStride};
mOutGlop->mesh.elementCount = 4;
return *this;
}
@@ -144,12 +142,9 @@ GlopBuilder& GlopBuilder::setMeshIndexedQuads(Vertex* vertexData, int quadCount)
TRIGGER_STAGE(kMeshStage);
mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
- mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
+ mOutGlop->mesh.indices = {mRenderState.meshState().getQuadListIBO(), nullptr};
mOutGlop->mesh.vertices = {
- 0,
- VertexAttribFlags::None,
- vertexData, nullptr, nullptr,
- kVertexStride };
+ 0, VertexAttribFlags::None, vertexData, nullptr, nullptr, kVertexStride};
mOutGlop->mesh.elementCount = 6 * quadCount;
return *this;
}
@@ -158,26 +153,29 @@ GlopBuilder& GlopBuilder::setMeshTexturedIndexedQuads(TextureVertex* vertexData,
TRIGGER_STAGE(kMeshStage);
mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
- mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
- mOutGlop->mesh.vertices = {
- 0,
- VertexAttribFlags::TextureCoord,
- &vertexData[0].x, &vertexData[0].u, nullptr,
- kTextureVertexStride };
+ mOutGlop->mesh.indices = {mRenderState.meshState().getQuadListIBO(), nullptr};
+ mOutGlop->mesh.vertices = {0,
+ VertexAttribFlags::TextureCoord,
+ &vertexData[0].x,
+ &vertexData[0].u,
+ nullptr,
+ kTextureVertexStride};
mOutGlop->mesh.elementCount = elementCount;
return *this;
}
-GlopBuilder& GlopBuilder::setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount) {
+GlopBuilder& GlopBuilder::setMeshColoredTexturedMesh(ColorTextureVertex* vertexData,
+ int elementCount) {
TRIGGER_STAGE(kMeshStage);
mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
- mOutGlop->mesh.indices = { 0, nullptr };
- mOutGlop->mesh.vertices = {
- 0,
- VertexAttribFlags::TextureCoord | VertexAttribFlags::Color,
- &vertexData[0].x, &vertexData[0].u, &vertexData[0].r,
- kColorTextureVertexStride };
+ mOutGlop->mesh.indices = {0, nullptr};
+ mOutGlop->mesh.vertices = {0,
+ VertexAttribFlags::TextureCoord | VertexAttribFlags::Color,
+ &vertexData[0].x,
+ &vertexData[0].u,
+ &vertexData[0].r,
+ kColorTextureVertexStride};
mOutGlop->mesh.elementCount = elementCount;
return *this;
}
@@ -191,15 +189,16 @@ GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer)
bool indices = flags & VertexBuffer::kIndices;
mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
- mOutGlop->mesh.indices = { 0, vertexBuffer.getIndices() };
- mOutGlop->mesh.vertices = {
- 0,
- alphaVertex ? VertexAttribFlags::Alpha : VertexAttribFlags::None,
- vertexBuffer.getBuffer(), nullptr, nullptr,
- alphaVertex ? kAlphaVertexStride : kVertexStride };
- mOutGlop->mesh.elementCount = indices
- ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
- mOutGlop->mesh.vertexCount = vertexBuffer.getVertexCount(); // used for glDrawRangeElements()
+ mOutGlop->mesh.indices = {0, vertexBuffer.getIndices()};
+ mOutGlop->mesh.vertices = {0,
+ alphaVertex ? VertexAttribFlags::Alpha : VertexAttribFlags::None,
+ vertexBuffer.getBuffer(),
+ nullptr,
+ nullptr,
+ alphaVertex ? kAlphaVertexStride : kVertexStride};
+ mOutGlop->mesh.elementCount =
+ indices ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
+ mOutGlop->mesh.vertexCount = vertexBuffer.getVertexCount(); // used for glDrawRangeElements()
return *this;
}
@@ -207,12 +206,13 @@ GlopBuilder& GlopBuilder::setMeshPatchQuads(const Patch& patch) {
TRIGGER_STAGE(kMeshStage);
mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
- mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
- mOutGlop->mesh.vertices = {
- mCaches.patchCache.getMeshBuffer(),
- VertexAttribFlags::TextureCoord,
- (void*)patch.positionOffset, (void*)patch.textureOffset, nullptr,
- kTextureVertexStride };
+ mOutGlop->mesh.indices = {mRenderState.meshState().getQuadListIBO(), nullptr};
+ mOutGlop->mesh.vertices = {mCaches.patchCache.getMeshBuffer(),
+ VertexAttribFlags::TextureCoord,
+ (void*)patch.positionOffset,
+ (void*)patch.textureOffset,
+ nullptr,
+ kTextureVertexStride};
mOutGlop->mesh.elementCount = patch.indexCount;
return *this;
}
@@ -221,9 +221,9 @@ GlopBuilder& GlopBuilder::setMeshPatchQuads(const Patch& patch) {
// Fill
////////////////////////////////////////////////////////////////////////////////
-void GlopBuilder::setFill(int color, float alphaScale,
- SkBlendMode mode, Blend::ModeOrderSwap modeUsage,
- const SkShader* shader, const SkColorFilter* colorFilter) {
+void GlopBuilder::setFill(int color, float alphaScale, SkBlendMode mode,
+ Blend::ModeOrderSwap modeUsage, const SkShader* shader,
+ const SkColorFilter* colorFilter) {
if (mode != SkBlendMode::kClear) {
if (!shader) {
FloatColor c;
@@ -235,23 +235,20 @@ void GlopBuilder::setFill(int color, float alphaScale,
mOutGlop->fill.color = c;
} else {
float alpha = (SkColorGetA(color) / 255.0f) * alphaScale;
- mOutGlop->fill.color = { 1, 1, 1, alpha };
+ mOutGlop->fill.color = {1, 1, 1, alpha};
}
} else {
- mOutGlop->fill.color = { 0, 0, 0, 1 };
+ mOutGlop->fill.color = {0, 0, 0, 1};
}
- mOutGlop->blend = { GL_ZERO, GL_ZERO };
- if (mOutGlop->fill.color.a < 1.0f
- || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha)
- || (mOutGlop->fill.texture.texture && mOutGlop->fill.texture.texture->blend)
- || mOutGlop->roundRectClipState
- || PaintUtils::isBlendedShader(shader)
- || PaintUtils::isBlendedColorFilter(colorFilter)
- || mode != SkBlendMode::kSrcOver) {
+ mOutGlop->blend = {GL_ZERO, GL_ZERO};
+ if (mOutGlop->fill.color.a < 1.0f ||
+ (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha) ||
+ (mOutGlop->fill.texture.texture && mOutGlop->fill.texture.texture->blend) ||
+ mOutGlop->roundRectClipState || PaintUtils::isBlendedShader(shader) ||
+ PaintUtils::isBlendedColorFilter(colorFilter) || mode != SkBlendMode::kSrcOver) {
if (CC_LIKELY(mode <= SkBlendMode::kScreen)) {
- Blend::getFactors(mode, modeUsage,
- &mOutGlop->blend.src, &mOutGlop->blend.dst);
+ Blend::getFactors(mode, modeUsage, &mOutGlop->blend.src, &mOutGlop->blend.dst);
} else {
// These blend modes are not supported by OpenGL directly and have
// to be implemented using shaders. Since the shader will perform
@@ -264,23 +261,25 @@ void GlopBuilder::setFill(int color, float alphaScale,
// blending in shader, don't enable
} else {
// unsupported
- Blend::getFactors(SkBlendMode::kSrcOver, modeUsage,
- &mOutGlop->blend.src, &mOutGlop->blend.dst);
+ Blend::getFactors(SkBlendMode::kSrcOver, modeUsage, &mOutGlop->blend.src,
+ &mOutGlop->blend.dst);
}
}
}
- mShader = shader; // shader resolved in ::build()
+ mShader = shader; // shader resolved in ::build()
if (colorFilter) {
SkColor color;
SkBlendMode bmode;
SkScalar srcColorMatrix[20];
if (colorFilter->asColorMode(&color, &bmode)) {
- mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Blend;
+ mOutGlop->fill.filterMode = mDescription.colorOp =
+ ProgramDescription::ColorFilterMode::Blend;
mDescription.colorMode = bmode;
mOutGlop->fill.filter.color.set(color);
} else if (colorFilter->asColorMatrix(srcColorMatrix)) {
- mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Matrix;
+ mOutGlop->fill.filterMode = mDescription.colorOp =
+ ProgramDescription::ColorFilterMode::Matrix;
float* colorMatrix = mOutGlop->fill.filter.matrix.matrix;
memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
@@ -291,10 +290,10 @@ void GlopBuilder::setFill(int color, float alphaScale,
// Skia uses the range [0..255] for the addition vector, but we need
// the [0..1] range to apply the vector in GLSL
float* colorVector = mOutGlop->fill.filter.matrix.vector;
- colorVector[0] = EOCF(srcColorMatrix[4] / 255.0f);
- colorVector[1] = EOCF(srcColorMatrix[9] / 255.0f);
+ colorVector[0] = EOCF(srcColorMatrix[4] / 255.0f);
+ colorVector[1] = EOCF(srcColorMatrix[9] / 255.0f);
colorVector[2] = EOCF(srcColorMatrix[14] / 255.0f);
- colorVector[3] = srcColorMatrix[19] / 255.0f; // alpha is linear
+ colorVector[3] = srcColorMatrix[19] / 255.0f; // alpha is linear
} else {
ALOGE("unsupported ColorFilter type: %s", colorFilter->getTypeName());
LOG_ALWAYS_FATAL("unsupported ColorFilter");
@@ -304,14 +303,15 @@ void GlopBuilder::setFill(int color, float alphaScale,
}
}
-GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture,
- const int textureFillFlags, const SkPaint* paint, float alphaScale) {
+GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture, const int textureFillFlags,
+ const SkPaint* paint, float alphaScale) {
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
GLenum filter = (textureFillFlags & TextureFillFlags::ForceFilter)
- ? GL_LINEAR : PaintUtils::getFilter(paint);
- mOutGlop->fill.texture = { &texture, filter, GL_CLAMP_TO_EDGE, nullptr };
+ ? GL_LINEAR
+ : PaintUtils::getFilter(paint);
+ mOutGlop->fill.texture = {&texture, filter, GL_CLAMP_TO_EDGE, nullptr};
if (paint) {
int color = paint->getColor();
@@ -322,20 +322,17 @@ GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture,
color |= 0x00FFFFFF;
shader = nullptr;
}
- setFill(color, alphaScale,
- paint->getBlendMode(), Blend::ModeOrderSwap::NoSwap,
- shader, paint->getColorFilter());
+ setFill(color, alphaScale, paint->getBlendMode(), Blend::ModeOrderSwap::NoSwap, shader,
+ paint->getColorFilter());
} else {
- mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale };
+ mOutGlop->fill.color = {alphaScale, alphaScale, alphaScale, alphaScale};
- if (alphaScale < 1.0f
- || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha)
- || texture.blend
- || mOutGlop->roundRectClipState) {
+ if (alphaScale < 1.0f || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha) ||
+ texture.blend || mOutGlop->roundRectClipState) {
Blend::getFactors(SkBlendMode::kSrcOver, Blend::ModeOrderSwap::NoSwap,
- &mOutGlop->blend.src, &mOutGlop->blend.dst);
+ &mOutGlop->blend.src, &mOutGlop->blend.dst);
} else {
- mOutGlop->blend = { GL_ZERO, GL_ZERO };
+ mOutGlop->blend = {GL_ZERO, GL_ZERO};
}
}
@@ -353,32 +350,28 @@ GlopBuilder& GlopBuilder::setFillPaint(const SkPaint& paint, float alphaScale, b
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
if (CC_LIKELY(!shadowInterp)) {
- mOutGlop->fill.texture = {
- nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
+ mOutGlop->fill.texture = {nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
} else {
- mOutGlop->fill.texture = {
- mCaches.textureState().getShadowLutTexture(),
- GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
+ mOutGlop->fill.texture = {mCaches.textureState().getShadowLutTexture(), GL_INVALID_ENUM,
+ GL_INVALID_ENUM, nullptr};
}
- setFill(paint.getColor(), alphaScale,
- paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
+ setFill(paint.getColor(), alphaScale, paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
paint.getShader(), paint.getColorFilter());
mDescription.useShadowAlphaInterp = shadowInterp;
mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
return *this;
}
-GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture,
- const SkPaint& paint, float alphaScale) {
+GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture, const SkPaint& paint,
+ float alphaScale) {
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
- //specify invalid filter/clamp, since these are always static for PathTextures
- mOutGlop->fill.texture = { &texture, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
+ // specify invalid filter/clamp, since these are always static for PathTextures
+ mOutGlop->fill.texture = {&texture, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
- setFill(paint.getColor(), alphaScale,
- paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
+ setFill(paint.getColor(), alphaScale, paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
paint.getShader(), paint.getColorFilter());
mDescription.hasAlpha8Texture = true;
@@ -387,12 +380,12 @@ GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture,
}
GlopBuilder& GlopBuilder::setFillShadowTexturePaint(ShadowTexture& texture, int shadowColor,
- const SkPaint& paint, float alphaScale) {
+ const SkPaint& paint, float alphaScale) {
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
- //specify invalid filter/clamp, since these are always static for ShadowTextures
- mOutGlop->fill.texture = { &texture, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
+ // specify invalid filter/clamp, since these are always static for ShadowTextures
+ mOutGlop->fill.texture = {&texture, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
const int ALPHA_BITMASK = SK_ColorBLACK;
const int COLOR_BITMASK = ~ALPHA_BITMASK;
@@ -401,8 +394,7 @@ GlopBuilder& GlopBuilder::setFillShadowTexturePaint(ShadowTexture& texture, int
shadowColor &= paint.getColor() | COLOR_BITMASK;
}
- setFill(shadowColor, alphaScale,
- paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
+ setFill(shadowColor, alphaScale, paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
paint.getShader(), paint.getColorFilter());
mDescription.hasAlpha8Texture = true;
@@ -414,9 +406,9 @@ GlopBuilder& GlopBuilder::setFillBlack() {
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
- mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
- setFill(SK_ColorBLACK, 1.0f, SkBlendMode::kSrcOver, Blend::ModeOrderSwap::NoSwap,
- nullptr, nullptr);
+ mOutGlop->fill.texture = {nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
+ setFill(SK_ColorBLACK, 1.0f, SkBlendMode::kSrcOver, Blend::ModeOrderSwap::NoSwap, nullptr,
+ nullptr);
return *this;
}
@@ -424,18 +416,19 @@ GlopBuilder& GlopBuilder::setFillClear() {
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
- mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
- setFill(SK_ColorBLACK, 1.0f, SkBlendMode::kClear, Blend::ModeOrderSwap::NoSwap,
- nullptr, nullptr);
+ mOutGlop->fill.texture = {nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
+ setFill(SK_ColorBLACK, 1.0f, SkBlendMode::kClear, Blend::ModeOrderSwap::NoSwap, nullptr,
+ nullptr);
return *this;
}
GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
- float alpha, SkBlendMode mode, Blend::ModeOrderSwap modeUsage) {
+ float alpha, SkBlendMode mode,
+ Blend::ModeOrderSwap modeUsage) {
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
- mOutGlop->fill.texture = { &texture, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr };
+ mOutGlop->fill.texture = {&texture, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr};
setFill(SK_ColorWHITE, alpha, mode, modeUsage, nullptr, colorFilter);
@@ -447,11 +440,11 @@ GlopBuilder& GlopBuilder::setFillTextureLayer(GlLayer& layer, float alpha) {
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
- mOutGlop->fill.texture = { &(layer.getTexture()),
- GL_LINEAR, GL_CLAMP_TO_EDGE, &layer.getTexTransform() };
+ mOutGlop->fill.texture = {&(layer.getTexture()), GL_LINEAR, GL_CLAMP_TO_EDGE,
+ &layer.getTexTransform()};
- setFill(SK_ColorWHITE, alpha, layer.getMode(), Blend::ModeOrderSwap::NoSwap,
- nullptr, layer.getColorFilter());
+ setFill(SK_ColorWHITE, alpha, layer.getMode(), Blend::ModeOrderSwap::NoSwap, nullptr,
+ layer.getColorFilter());
mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
mDescription.hasTextureTransform = true;
@@ -459,15 +452,14 @@ GlopBuilder& GlopBuilder::setFillTextureLayer(GlLayer& layer, float alpha) {
}
GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture, Matrix4& textureTransform,
- bool requiresFilter) {
+ bool requiresFilter) {
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
GLenum filter = requiresFilter ? GL_LINEAR : GL_NEAREST;
- mOutGlop->fill.texture = { &texture, filter, GL_CLAMP_TO_EDGE, &textureTransform };
+ mOutGlop->fill.texture = {&texture, filter, GL_CLAMP_TO_EDGE, &textureTransform};
- setFill(SK_ColorWHITE, 1.0f, SkBlendMode::kSrc, Blend::ModeOrderSwap::NoSwap,
- nullptr, nullptr);
+ setFill(SK_ColorWHITE, 1.0f, SkBlendMode::kSrc, Blend::ModeOrderSwap::NoSwap, nullptr, nullptr);
mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
mDescription.hasTextureTransform = true;
@@ -518,8 +510,8 @@ GlopBuilder& GlopBuilder::setModelViewMapUnitToRectSnap(const Rect destination)
const float translateX = meshTransform.getTranslateX();
const float translateY = meshTransform.getTranslateY();
- left = (int) floorf(left + translateX + 0.5f) - translateX;
- top = (int) floorf(top + translateY + 0.5f) - translateY;
+ left = (int)floorf(left + translateX + 0.5f) - translateX;
+ top = (int)floorf(top + translateY + 0.5f) - translateY;
mOutGlop->fill.texture.filter = GL_NEAREST;
}
@@ -535,7 +527,8 @@ GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, c
return *this;
}
-GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source) {
+GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offsetY,
+ const Rect source) {
TRIGGER_STAGE(kModelViewStage);
REQUIRE_STAGES(kTransformStage | kFillStage);
@@ -545,8 +538,8 @@ GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offset
const float translateX = meshTransform.getTranslateX();
const float translateY = meshTransform.getTranslateY();
- offsetX = (int) floorf(offsetX + translateX + source.left + 0.5f) - translateX - source.left;
- offsetY = (int) floorf(offsetY + translateY + source.top + 0.5f) - translateY - source.top;
+ offsetX = (int)floorf(offsetX + translateX + source.left + 0.5f) - translateX - source.left;
+ offsetY = (int)floorf(offsetY + translateY + source.top + 0.5f) - translateY - source.top;
mOutGlop->fill.texture.filter = GL_NEAREST;
}
@@ -572,27 +565,25 @@ GlopBuilder& GlopBuilder::setRoundRectClipState(const RoundRectClipState* roundR
void verify(const ProgramDescription& description, const Glop& glop) {
if (glop.fill.texture.texture != nullptr) {
- LOG_ALWAYS_FATAL_IF(((description.hasTexture && description.hasExternalTexture)
- || (!description.hasTexture
- && !description.hasExternalTexture
- && !description.useShadowAlphaInterp)
- || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) == 0
- && !description.useShadowAlphaInterp)),
- "Texture %p, hT%d, hET %d, attribFlags %x",
- glop.fill.texture.texture,
+ LOG_ALWAYS_FATAL_IF(
+ ((description.hasTexture && description.hasExternalTexture) ||
+ (!description.hasTexture && !description.hasExternalTexture &&
+ !description.useShadowAlphaInterp) ||
+ ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) == 0 &&
+ !description.useShadowAlphaInterp)),
+ "Texture %p, hT%d, hET %d, attribFlags %x", glop.fill.texture.texture,
description.hasTexture, description.hasExternalTexture,
glop.mesh.vertices.attribFlags);
} else {
- LOG_ALWAYS_FATAL_IF((description.hasTexture
- || description.hasExternalTexture
- || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) != 0)),
- "No texture, hT%d, hET %d, attribFlags %x",
- description.hasTexture, description.hasExternalTexture,
- glop.mesh.vertices.attribFlags);
+ LOG_ALWAYS_FATAL_IF(
+ (description.hasTexture || description.hasExternalTexture ||
+ ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) != 0)),
+ "No texture, hT%d, hET %d, attribFlags %x", description.hasTexture,
+ description.hasExternalTexture, glop.mesh.vertices.attribFlags);
}
- if ((glop.mesh.vertices.attribFlags & VertexAttribFlags::Alpha)
- && glop.mesh.vertices.bufferObject) {
+ if ((glop.mesh.vertices.attribFlags & VertexAttribFlags::Alpha) &&
+ glop.mesh.vertices.bufferObject) {
LOG_ALWAYS_FATAL("VBO and alpha attributes are not currently compatible");
}
@@ -621,9 +612,10 @@ void GlopBuilder::build() {
// Enable debug highlight when what we're about to draw is tested against
// the stencil buffer and if stencil highlight debugging is on
- mDescription.hasDebugHighlight = !Properties::debugOverdraw
- && Properties::debugStencilClip == StencilClipDebug::ShowHighlight
- && mRenderState.stencil().isTestEnabled();
+ mDescription.hasDebugHighlight =
+ !Properties::debugOverdraw &&
+ Properties::debugStencilClip == StencilClipDebug::ShowHighlight &&
+ mRenderState.stencil().isTestEnabled();
// serialize shader info into ShaderData
GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0;
@@ -640,15 +632,13 @@ void GlopBuilder::build() {
} else {
shaderMatrix = mOutGlop->transform.modelView;
}
- SkiaShader::store(mCaches, *mShader, shaderMatrix,
- &textureUnit, &mDescription, &(mOutGlop->fill.skiaShaderData));
+ SkiaShader::store(mCaches, *mShader, shaderMatrix, &textureUnit, &mDescription,
+ &(mOutGlop->fill.skiaShaderData));
}
// duplicates ProgramCache's definition of color uniform presence
- const bool singleColor = !mDescription.hasTexture
- && !mDescription.hasExternalTexture
- && !mDescription.hasGradient
- && !mDescription.hasBitmap;
+ const bool singleColor = !mDescription.hasTexture && !mDescription.hasExternalTexture &&
+ !mDescription.hasGradient && !mDescription.hasBitmap;
mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor;
verify(mDescription, *mOutGlop);
@@ -661,31 +651,31 @@ void GlopBuilder::dump(const Glop& glop) {
ALOGD("Glop Mesh");
const Glop::Mesh& mesh = glop.mesh;
ALOGD(" primitive mode: %d", mesh.primitiveMode);
- ALOGD(" indices: buffer obj %x, indices %p", mesh.indices.bufferObject, mesh.indices.indices);
+ ALOGD(" indices: buffer obj %x, indices %p", mesh.indices.bufferObject,
+ mesh.indices.indices);
const Glop::Mesh::Vertices& vertices = glop.mesh.vertices;
ALOGD(" vertices: buffer obj %x, flags %x, pos %p, tex %p, clr %p, stride %d",
- vertices.bufferObject, vertices.attribFlags,
- vertices.position, vertices.texCoord, vertices.color, vertices.stride);
+ vertices.bufferObject, vertices.attribFlags, vertices.position, vertices.texCoord,
+ vertices.color, vertices.stride);
ALOGD(" element count: %d", mesh.elementCount);
ALOGD("Glop Fill");
const Glop::Fill& fill = glop.fill;
ALOGD(" program %p", fill.program);
if (fill.texture.texture) {
- ALOGD(" texture %p, target %d, filter %d, clamp %d",
- fill.texture.texture, fill.texture.texture->target(),
- fill.texture.filter, fill.texture.clamp);
+ ALOGD(" texture %p, target %d, filter %d, clamp %d", fill.texture.texture,
+ fill.texture.texture->target(), fill.texture.filter, fill.texture.clamp);
if (fill.texture.textureTransform) {
fill.texture.textureTransform->dump("texture transform");
}
}
- ALOGD_IF(fill.colorEnabled, " color (argb) %.2f %.2f %.2f %.2f",
- fill.color.a, fill.color.r, fill.color.g, fill.color.b);
- ALOGD_IF(fill.filterMode != ProgramDescription::ColorFilterMode::None,
- " filterMode %d", (int)fill.filterMode);
+ ALOGD_IF(fill.colorEnabled, " color (argb) %.2f %.2f %.2f %.2f", fill.color.a, fill.color.r,
+ fill.color.g, fill.color.b);
+ ALOGD_IF(fill.filterMode != ProgramDescription::ColorFilterMode::None, " filterMode %d",
+ (int)fill.filterMode);
ALOGD_IF(fill.skiaShaderData.skiaShaderType, " shader type %d",
- fill.skiaShaderData.skiaShaderType);
+ fill.skiaShaderData.skiaShaderType);
ALOGD("Glop transform");
glop.transform.modelView.dump(" model view");
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index 6d11da19e138..dac38223b877 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -39,15 +39,16 @@ struct PathTexture;
struct ShadowTexture;
namespace TextureFillFlags {
- enum {
- None = 0,
- IsAlphaMaskTexture = 1 << 0,
- ForceFilter = 1 << 1,
- };
+enum {
+ None = 0,
+ IsAlphaMaskTexture = 1 << 0,
+ ForceFilter = 1 << 1,
+};
}
class GlopBuilder {
PREVENT_COPY_AND_ASSIGN(GlopBuilder);
+
public:
GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop);
@@ -57,26 +58,29 @@ public:
GlopBuilder& setMeshTexturedUvQuad(const UvMapper* uvMapper, const Rect uvs);
GlopBuilder& setMeshVertexBuffer(const VertexBuffer& vertexBuffer);
GlopBuilder& setMeshIndexedQuads(Vertex* vertexData, int quadCount);
- GlopBuilder& setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount); // TODO: use indexed quads
- GlopBuilder& setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount); // TODO: take quadCount
+ GlopBuilder& setMeshColoredTexturedMesh(ColorTextureVertex* vertexData,
+ int elementCount); // TODO: use indexed quads
+ GlopBuilder& setMeshTexturedIndexedQuads(TextureVertex* vertexData,
+ int elementCount); // TODO: take quadCount
GlopBuilder& setMeshPatchQuads(const Patch& patch);
- GlopBuilder& setFillPaint(const SkPaint& paint, float alphaScale, bool shadowInterp = false); // TODO: avoid boolean with default
+ GlopBuilder& setFillPaint(const SkPaint& paint, float alphaScale,
+ bool shadowInterp = false); // TODO: avoid boolean with default
GlopBuilder& setFillTexturePaint(Texture& texture, const int textureFillFlags,
- const SkPaint* paint, float alphaScale);
- GlopBuilder& setFillPathTexturePaint(PathTexture& texture,
- const SkPaint& paint, float alphaScale);
+ const SkPaint* paint, float alphaScale);
+ GlopBuilder& setFillPathTexturePaint(PathTexture& texture, const SkPaint& paint,
+ float alphaScale);
GlopBuilder& setFillShadowTexturePaint(ShadowTexture& texture, int shadowColor,
- const SkPaint& paint, float alphaScale);
+ const SkPaint& paint, float alphaScale);
GlopBuilder& setFillBlack();
GlopBuilder& setFillClear();
- GlopBuilder& setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
- float alpha, SkBlendMode mode, Blend::ModeOrderSwap modeUsage);
+ GlopBuilder& setFillLayer(Texture& texture, const SkColorFilter* colorFilter, float alpha,
+ SkBlendMode mode, Blend::ModeOrderSwap modeUsage);
GlopBuilder& setFillTextureLayer(GlLayer& layer, float alpha);
// TODO: setFillLayer normally forces its own wrap & filter mode,
// which isn't always correct.
GlopBuilder& setFillExternalTexture(Texture& texture, Matrix4& textureTransform,
- bool requiresFilter);
+ bool requiresFilter);
GlopBuilder& setTransform(const Matrix4& canvas, const int transformFlags);
@@ -91,8 +95,8 @@ public:
}
GlopBuilder& setModelViewOffsetRect(float offsetX, float offsetY, const Rect source);
GlopBuilder& setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source);
- GlopBuilder& setModelViewOffsetRectOptionalSnap(bool snap,
- float offsetX, float offsetY, const Rect& source) {
+ GlopBuilder& setModelViewOffsetRectOptionalSnap(bool snap, float offsetX, float offsetY,
+ const Rect& source) {
if (snap) {
return setModelViewOffsetRectSnap(offsetX, offsetY, source);
} else {
@@ -111,10 +115,10 @@ public:
void build();
static void dump(const Glop& glop);
+
private:
- void setFill(int color, float alphaScale,
- SkBlendMode mode, Blend::ModeOrderSwap modeUsage,
- const SkShader* shader, const SkColorFilter* colorFilter);
+ void setFill(int color, float alphaScale, SkBlendMode mode, Blend::ModeOrderSwap modeUsage,
+ const SkShader* shader, const SkColorFilter* colorFilter);
enum StageFlags {
kInitialStage = 0,
@@ -123,7 +127,8 @@ private:
kModelViewStage = 1 << 2,
kFillStage = 1 << 3,
kRoundRectClipStage = 1 << 4,
- kAllStages = kMeshStage | kFillStage | kTransformStage | kModelViewStage | kRoundRectClipStage,
+ kAllStages =
+ kMeshStage | kFillStage | kTransformStage | kModelViewStage | kRoundRectClipStage,
} mStageFlags;
ProgramDescription mDescription;
diff --git a/libs/hwui/GpuMemoryTracker.cpp b/libs/hwui/GpuMemoryTracker.cpp
index a52ec8738015..612bfde1a3fa 100644
--- a/libs/hwui/GpuMemoryTracker.cpp
+++ b/libs/hwui/GpuMemoryTracker.cpp
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-#include "utils/StringUtils.h"
#include "Texture.h"
+#include "utils/StringUtils.h"
-#include <cutils/compiler.h>
#include <GpuMemoryTracker.h>
+#include <cutils/compiler.h>
#include <utils/Trace.h>
#include <array>
#include <sstream>
@@ -33,9 +33,7 @@ pthread_t gGpuThread = 0;
#define NUM_TYPES static_cast<int>(GpuObjectType::TypeCount)
const char* TYPE_NAMES[] = {
- "Texture",
- "OffscreenBuffer",
- "Layer",
+ "Texture", "OffscreenBuffer", "Layer",
};
struct TypeStats {
@@ -55,21 +53,22 @@ void GpuMemoryTracker::notifySizeChanged(int newSize) {
void GpuMemoryTracker::startTrackingObject() {
auto result = gObjectSet.insert(this);
LOG_ALWAYS_FATAL_IF(!result.second,
- "startTrackingObject() on %p failed, already being tracked!", this);
+ "startTrackingObject() on %p failed, already being tracked!", this);
gObjectStats[static_cast<int>(mType)].count++;
}
void GpuMemoryTracker::stopTrackingObject() {
size_t removed = gObjectSet.erase(this);
- LOG_ALWAYS_FATAL_IF(removed != 1,
- "stopTrackingObject removed %zd, is %p not being tracked?",
- removed, this);
+ LOG_ALWAYS_FATAL_IF(removed != 1, "stopTrackingObject removed %zd, is %p not being tracked?",
+ removed, this);
gObjectStats[static_cast<int>(mType)].count--;
}
void GpuMemoryTracker::onGpuContextCreated() {
- LOG_ALWAYS_FATAL_IF(gGpuThread != 0, "We already have a gpu thread? "
- "current = %lu, gpu thread = %lu", pthread_self(), gGpuThread);
+ LOG_ALWAYS_FATAL_IF(gGpuThread != 0,
+ "We already have a gpu thread? "
+ "current = %lu, gpu thread = %lu",
+ pthread_self(), gGpuThread);
gGpuThread = pthread_self();
}
@@ -124,8 +123,8 @@ void GpuMemoryTracker::onFrameCompleted() {
if (obj->objectType() == GpuObjectType::Texture) {
const Texture* texture = static_cast<Texture*>(obj);
if (texture->cleanup) {
- ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u",
- texture->id(), texture->width(), texture->height());
+ ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u", texture->id(),
+ texture->width(), texture->height());
freeList.push_back(texture);
}
}
@@ -136,5 +135,5 @@ void GpuMemoryTracker::onFrameCompleted() {
}
}
-} // namespace uirenderer
-} // namespace android;
+} // namespace uirenderer
+} // namespace android;
diff --git a/libs/hwui/GpuMemoryTracker.h b/libs/hwui/GpuMemoryTracker.h
index 18e2330668b0..de3ca99ef14b 100644
--- a/libs/hwui/GpuMemoryTracker.h
+++ b/libs/hwui/GpuMemoryTracker.h
@@ -25,11 +25,11 @@ namespace uirenderer {
extern pthread_t gGpuThread;
-#define ASSERT_GPU_THREAD() LOG_ALWAYS_FATAL_IF( \
- !pthread_equal(gGpuThread, pthread_self()), \
- "Error, %p of type %d (size=%d) used on wrong thread! cur thread %lu " \
- "!= gpu thread %lu", this, static_cast<int>(mType), mSize, \
- pthread_self(), gGpuThread)
+#define ASSERT_GPU_THREAD() \
+ LOG_ALWAYS_FATAL_IF(!pthread_equal(gGpuThread, pthread_self()), \
+ "Error, %p of type %d (size=%d) used on wrong thread! cur thread %lu " \
+ "!= gpu thread %lu", \
+ this, static_cast<int>(mType), mSize, pthread_self(), gGpuThread)
enum class GpuObjectType {
Texture = 0,
@@ -73,5 +73,5 @@ private:
GpuObjectType mType;
};
-} // namespace uirenderer
-} // namespace android;
+} // namespace uirenderer
+} // namespace android;
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 20262349dda4..21e3c730cbec 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -18,9 +18,9 @@
#include "Caches.h"
#include "Debug.h"
+#include "DeviceInfo.h"
#include "GradientCache.h"
#include "Properties.h"
-#include "DeviceInfo.h"
#include <cutils/properties.h>
@@ -31,7 +31,7 @@ namespace uirenderer {
// Functions
///////////////////////////////////////////////////////////////////////////////
-template<typename T>
+template <typename T>
static inline T min(T a, T b) {
return a < b ? a : b;
}
@@ -122,8 +122,7 @@ void GradientCache::clear() {
mCache.clear();
}
-void GradientCache::getGradientInfo(const uint32_t* colors, const int count,
- GradientInfo& info) {
+void GradientCache::getGradientInfo(const uint32_t* colors, const int count, GradientInfo& info) {
uint32_t width = 256 * (count - 1);
// If the npot extension is not supported we cannot use non-clamp
@@ -145,9 +144,8 @@ void GradientCache::getGradientInfo(const uint32_t* colors, const int count,
info.hasAlpha = hasAlpha;
}
-Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient,
- uint32_t* colors, float* positions, int count) {
-
+Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient, uint32_t* colors,
+ float* positions, int count) {
GradientInfo info;
getGradientInfo(colors, count, info);
@@ -159,18 +157,19 @@ Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient,
const uint32_t size = info.width * 2 * bytesPerPixel();
while (getSize() + size > mMaxSize) {
LOG_ALWAYS_FATAL_IF(!mCache.removeOldest(),
- "Ran out of things to remove from the cache? getSize() = %" PRIu32
- ", size = %" PRIu32 ", mMaxSize = %" PRIu32 ", width = %" PRIu32,
- getSize(), size, mMaxSize, info.width);
+ "Ran out of things to remove from the cache? getSize() = %" PRIu32
+ ", size = %" PRIu32 ", mMaxSize = %" PRIu32 ", width = %" PRIu32,
+ getSize(), size, mMaxSize, info.width);
}
generateTexture(colors, positions, info.width, 2, texture);
mSize += size;
LOG_ALWAYS_FATAL_IF((int)size != texture->objectSize(),
- "size != texture->objectSize(), size %" PRIu32 ", objectSize %d"
- " width = %" PRIu32 " bytesPerPixel() = %zu",
- size, texture->objectSize(), info.width, bytesPerPixel());
+ "size != texture->objectSize(), size %" PRIu32
+ ", objectSize %d"
+ " width = %" PRIu32 " bytesPerPixel() = %zu",
+ size, texture->objectSize(), info.width, bytesPerPixel());
mCache.put(gradient, texture);
return texture;
@@ -186,8 +185,8 @@ size_t GradientCache::sourceBytesPerPixel() const {
return 4 * (mUseFloatTexture ? sizeof(float) : sizeof(uint8_t));
}
-void GradientCache::mixBytes(const FloatColor& start, const FloatColor& end,
- float amount, uint8_t*& dst) const {
+void GradientCache::mixBytes(const FloatColor& start, const FloatColor& end, float amount,
+ uint8_t*& dst) const {
float oppAmount = 1.0f - amount;
float a = start.a * oppAmount + end.a * amount;
*dst++ = uint8_t(OECF(start.r * oppAmount + end.r * amount) * 255.0f);
@@ -196,11 +195,11 @@ void GradientCache::mixBytes(const FloatColor& start, const FloatColor& end,
*dst++ = uint8_t(a * 255.0f);
}
-void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end,
- float amount, uint8_t*& dst) const {
+void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end, float amount,
+ uint8_t*& dst) const {
float oppAmount = 1.0f - amount;
float a = start.a * oppAmount + end.a * amount;
- float* d = (float*) dst;
+ float* d = (float*)dst;
#ifdef ANDROID_ENABLE_LINEAR_BLENDING
// We want to stay linear
*d++ = (start.r * oppAmount + end.r * amount);
@@ -215,8 +214,8 @@ void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end,
dst += 4 * sizeof(float);
}
-void GradientCache::generateTexture(uint32_t* colors, float* positions,
- const uint32_t width, const uint32_t height, Texture* texture) {
+void GradientCache::generateTexture(uint32_t* colors, float* positions, const uint32_t width,
+ const uint32_t height, Texture* texture) {
const GLsizei rowBytes = width * sourceBytesPerPixel();
uint8_t pixels[rowBytes * height];
@@ -269,5 +268,5 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions,
texture->setWrap(GL_CLAMP_TO_EDGE);
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
index d95589c514eb..ff426cd3425b 100644
--- a/libs/hwui/GradientCache.h
+++ b/libs/hwui/GradientCache.h
@@ -60,13 +60,9 @@ struct GradientCacheEntry {
static int compare(const GradientCacheEntry& lhs, const GradientCacheEntry& rhs);
- bool operator==(const GradientCacheEntry& other) const {
- return compare(*this, other) == 0;
- }
+ bool operator==(const GradientCacheEntry& other) const { return compare(*this, other) == 0; }
- bool operator!=(const GradientCacheEntry& other) const {
- return compare(*this, other) != 0;
- }
+ bool operator!=(const GradientCacheEntry& other) const { return compare(*this, other) != 0; }
std::unique_ptr<uint32_t[]> colors;
std::unique_ptr<float[]> positions;
@@ -82,7 +78,7 @@ private:
memcpy(this->positions.get(), positions, count * sizeof(float));
}
-}; // GradientCacheEntry
+}; // GradientCacheEntry
// Caching support
@@ -103,7 +99,7 @@ inline hash_t hash_type(const GradientCacheEntry& entry) {
* Any texture added to the cache causing the cache to grow beyond the maximum
* allowed size will also cause the oldest texture to be kicked out.
*/
-class GradientCache: public OnEntryRemoved<GradientCacheEntry, Texture*> {
+class GradientCache : public OnEntryRemoved<GradientCacheEntry, Texture*> {
public:
explicit GradientCache(const Extensions& extensions);
~GradientCache();
@@ -138,11 +134,11 @@ private:
* Adds a new linear gradient to the cache. The generated texture is
* returned.
*/
- Texture* addLinearGradient(GradientCacheEntry& gradient,
- uint32_t* colors, float* positions, int count);
+ Texture* addLinearGradient(GradientCacheEntry& gradient, uint32_t* colors, float* positions,
+ int count);
- void generateTexture(uint32_t* colors, float* positions,
- const uint32_t width, const uint32_t height, Texture* texture);
+ void generateTexture(uint32_t* colors, float* positions, const uint32_t width,
+ const uint32_t height, Texture* texture);
struct GradientInfo {
uint32_t width;
@@ -155,12 +151,12 @@ private:
size_t sourceBytesPerPixel() const;
typedef void (GradientCache::*ChannelMixer)(const FloatColor& start, const FloatColor& end,
- float amount, uint8_t*& dst) const;
+ float amount, uint8_t*& dst) const;
- void mixBytes(const FloatColor& start, const FloatColor& end,
- float amount, uint8_t*& dst) const;
- void mixFloats(const FloatColor& start, const FloatColor& end,
- float amount, uint8_t*& dst) const;
+ void mixBytes(const FloatColor& start, const FloatColor& end, float amount,
+ uint8_t*& dst) const;
+ void mixFloats(const FloatColor& start, const FloatColor& end, float amount,
+ uint8_t*& dst) const;
LruCache<GradientCacheEntry, Texture*> mCache;
@@ -173,9 +169,9 @@ private:
bool mHasLinearBlending;
mutable Mutex mLock;
-}; // class GradientCache
+}; // class GradientCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_GRADIENT_CACHE_H
+#endif // ANDROID_HWUI_GRADIENT_CACHE_H
diff --git a/libs/hwui/IProfileRenderer.h b/libs/hwui/IProfileRenderer.h
index 947ed34cc070..935ab4e35f26 100644
--- a/libs/hwui/IProfileRenderer.h
+++ b/libs/hwui/IProfileRenderer.h
@@ -22,7 +22,7 @@ namespace uirenderer {
class IProfileRenderer {
public:
virtual void drawRect(float left, float top, float right, float bottom,
- const SkPaint& paint) = 0;
+ const SkPaint& paint) = 0;
virtual void drawRects(const float* rects, int count, const SkPaint& paint) = 0;
virtual uint32_t getViewportWidth() = 0;
virtual uint32_t getViewportHeight() = 0;
diff --git a/libs/hwui/Image.cpp b/libs/hwui/Image.cpp
index 68a356ba1be0..d30796d01479 100644
--- a/libs/hwui/Image.cpp
+++ b/libs/hwui/Image.cpp
@@ -25,11 +25,11 @@ namespace uirenderer {
Image::Image(sp<GraphicBuffer> buffer) {
// Create the EGLImage object that maps the GraphicBuffer
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer->getNativeBuffer();
- EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
+ EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer->getNativeBuffer();
+ EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
- mImage = eglCreateImageKHR(display, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
+ mImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer,
+ attrs);
if (mImage == EGL_NO_IMAGE_KHR) {
ALOGW("Error creating image (%#x)", eglGetError());
@@ -57,5 +57,5 @@ Image::~Image() {
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Image.h b/libs/hwui/Image.h
index b8f5a5bec087..989b6ff3648d 100644
--- a/libs/hwui/Image.h
+++ b/libs/hwui/Image.h
@@ -45,23 +45,19 @@ public:
* Returns the name of the GL texture that can be used to sample
* from this image.
*/
- GLuint getTexture() const {
- return mTexture;
- }
+ GLuint getTexture() const { return mTexture; }
/**
* Returns the name of the EGL image represented by this object.
*/
- EGLImageKHR getImage() const {
- return mImage;
- }
+ EGLImageKHR getImage() const { return mImage; }
private:
GLuint mTexture;
EGLImageKHR mImage;
-}; // class Image
+}; // class Image
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_IMAGE_H
+#endif // ANDROID_HWUI_IMAGE_H
diff --git a/libs/hwui/Interpolator.cpp b/libs/hwui/Interpolator.cpp
index d740c038f36d..7bdca2ee0f00 100644
--- a/libs/hwui/Interpolator.cpp
+++ b/libs/hwui/Interpolator.cpp
@@ -54,8 +54,10 @@ static float o(float t, float s) {
}
float AnticipateOvershootInterpolator::interpolate(float t) {
- if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension);
- else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);
+ if (t < 0.5f)
+ return 0.5f * a(t * 2.0f, mTension);
+ else
+ return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);
}
static float bounce(float t) {
@@ -64,10 +66,14 @@ static float bounce(float t) {
float BounceInterpolator::interpolate(float t) {
t *= 1.1226f;
- if (t < 0.3535f) return bounce(t);
- else if (t < 0.7408f) return bounce(t - 0.54719f) + 0.7f;
- else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f;
- else return bounce(t - 1.0435f) + 0.95f;
+ if (t < 0.3535f)
+ return bounce(t);
+ else if (t < 0.7408f)
+ return bounce(t - 0.54719f) + 0.7f;
+ else if (t < 0.9644f)
+ return bounce(t - 0.8526f) + 0.9f;
+ else
+ return bounce(t - 1.0435f) + 0.95f;
}
float CycleInterpolator::interpolate(float input) {
@@ -119,16 +125,11 @@ float PathInterpolator::interpolate(float t) {
float startY = mY[startIndex];
float endY = mY[endIndex];
return startY + (fraction * (endY - startY));
-
}
-LUTInterpolator::LUTInterpolator(float* values, size_t size)
- : mValues(values)
- , mSize(size) {
-}
+LUTInterpolator::LUTInterpolator(float* values, size_t size) : mValues(values), mSize(size) {}
-LUTInterpolator::~LUTInterpolator() {
-}
+LUTInterpolator::~LUTInterpolator() {}
float LUTInterpolator::interpolate(float input) {
// lut position should only be at the end of the table when input is 1f.
@@ -140,10 +141,12 @@ float LUTInterpolator::interpolate(float input) {
float ipart, weight;
weight = modff(lutpos, &ipart);
- int i1 = (int) ipart;
- int i2 = std::min(i1 + 1, (int) mSize - 1);
+ int i1 = (int)ipart;
+ int i2 = std::min(i1 + 1, (int)mSize - 1);
- LOG_ALWAYS_FATAL_IF(i1 < 0 || i2 < 0, "negatives in interpolation!"
+ LOG_ALWAYS_FATAL_IF(
+ i1 < 0 || i2 < 0,
+ "negatives in interpolation!"
" i1=%d, i2=%d, input=%f, lutpos=%f, size=%zu, values=%p, ipart=%f, weight=%f",
i1, i2, input, lutpos, mSize, mValues.get(), ipart, weight);
@@ -153,6 +156,5 @@ float LUTInterpolator::interpolate(float input) {
return MathUtils::lerp(v1, v2, weight);
}
-
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/Interpolator.h b/libs/hwui/Interpolator.h
index 224cee70acc7..452988fc8711 100644
--- a/libs/hwui/Interpolator.h
+++ b/libs/hwui/Interpolator.h
@@ -44,8 +44,9 @@ public:
class ANDROID_API AccelerateInterpolator : public Interpolator {
public:
- explicit AccelerateInterpolator(float factor) : mFactor(factor), mDoubleFactor(factor*2) {}
+ explicit AccelerateInterpolator(float factor) : mFactor(factor), mDoubleFactor(factor * 2) {}
virtual float interpolate(float input) override;
+
private:
const float mFactor;
const float mDoubleFactor;
@@ -55,6 +56,7 @@ class ANDROID_API AnticipateInterpolator : public Interpolator {
public:
explicit AnticipateInterpolator(float tension) : mTension(tension) {}
virtual float interpolate(float input) override;
+
private:
const float mTension;
};
@@ -63,6 +65,7 @@ class ANDROID_API AnticipateOvershootInterpolator : public Interpolator {
public:
explicit AnticipateOvershootInterpolator(float tension) : mTension(tension) {}
virtual float interpolate(float input) override;
+
private:
const float mTension;
};
@@ -76,6 +79,7 @@ class ANDROID_API CycleInterpolator : public Interpolator {
public:
explicit CycleInterpolator(float cycles) : mCycles(cycles) {}
virtual float interpolate(float input) override;
+
private:
const float mCycles;
};
@@ -84,6 +88,7 @@ class ANDROID_API DecelerateInterpolator : public Interpolator {
public:
explicit DecelerateInterpolator(float factor) : mFactor(factor) {}
virtual float interpolate(float input) override;
+
private:
const float mFactor;
};
@@ -97,15 +102,16 @@ class ANDROID_API OvershootInterpolator : public Interpolator {
public:
explicit OvershootInterpolator(float tension) : mTension(tension) {}
virtual float interpolate(float input) override;
+
private:
const float mTension;
};
class ANDROID_API PathInterpolator : public Interpolator {
public:
- explicit PathInterpolator(std::vector<float>&& x, std::vector<float>&& y)
- : mX (x), mY(y) {}
+ explicit PathInterpolator(std::vector<float>&& x, std::vector<float>&& y) : mX(x), mY(y) {}
virtual float interpolate(float input) override;
+
private:
std::vector<float> mX;
std::vector<float> mY;
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 9d1182819444..afdd339ba0a2 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -106,25 +106,23 @@ void JankTracker::setFrameInterval(nsecs_t frameInterval) {
mThresholds[kSlowUI] = static_cast<int64_t>(.5 * frameInterval);
mThresholds[kSlowSync] = static_cast<int64_t>(.2 * frameInterval);
mThresholds[kSlowRT] = static_cast<int64_t>(.75 * frameInterval);
-
}
void JankTracker::finishFrame(const FrameInfo& frame) {
// Fast-path for jank-free frames
int64_t totalDuration = frame.duration(sFrameStart, FrameInfoIndex::FrameCompleted);
- if (mDequeueTimeForgiveness
- && frame[FrameInfoIndex::DequeueBufferDuration] > 500_us) {
- nsecs_t expectedDequeueDuration =
- mDequeueTimeForgiveness + frame[FrameInfoIndex::Vsync]
- - frame[FrameInfoIndex::IssueDrawCommandsStart];
+ if (mDequeueTimeForgiveness && frame[FrameInfoIndex::DequeueBufferDuration] > 500_us) {
+ nsecs_t expectedDequeueDuration = mDequeueTimeForgiveness + frame[FrameInfoIndex::Vsync] -
+ frame[FrameInfoIndex::IssueDrawCommandsStart];
if (expectedDequeueDuration > 0) {
// Forgive only up to the expected amount, but not more than
// the actual time spent blocked.
- nsecs_t forgiveAmount = std::min(expectedDequeueDuration,
- frame[FrameInfoIndex::DequeueBufferDuration]);
+ nsecs_t forgiveAmount =
+ std::min(expectedDequeueDuration, frame[FrameInfoIndex::DequeueBufferDuration]);
LOG_ALWAYS_FATAL_IF(forgiveAmount >= totalDuration,
- "Impossible dequeue duration! dequeue duration reported %" PRId64
- ", total duration %" PRId64, forgiveAmount, totalDuration);
+ "Impossible dequeue duration! dequeue duration reported %" PRId64
+ ", total duration %" PRId64,
+ forgiveAmount, totalDuration);
totalDuration -= forgiveAmount;
}
}
@@ -148,13 +146,14 @@ void JankTracker::finishFrame(const FrameInfo& frame) {
for (int i = 0; i < NUM_BUCKETS; i++) {
int64_t delta = frame.duration(COMPARISONS[i].start, COMPARISONS[i].end);
if (delta >= mThresholds[i] && delta < IGNORE_EXCEEDING) {
- mData->reportJankType((JankType) i);
- (*mGlobalData)->reportJankType((JankType) i);
+ mData->reportJankType((JankType)i);
+ (*mGlobalData)->reportJankType((JankType)i);
}
}
}
-void JankTracker::dumpData(int fd, const ProfileDataDescription* description, const ProfileData* data) {
+void JankTracker::dumpData(int fd, const ProfileDataDescription* description,
+ const ProfileData* data) {
if (description) {
switch (description->type) {
case JankTrackerType::Generic:
@@ -175,33 +174,30 @@ void JankTracker::dumpData(int fd, const ProfileDataDescription* description, co
}
void JankTracker::dumpFrames(int fd) {
- FILE* file = fdopen(fd, "a");
- fprintf(file, "\n\n---PROFILEDATA---\n");
+ dprintf(fd, "\n\n---PROFILEDATA---\n");
for (size_t i = 0; i < static_cast<size_t>(FrameInfoIndex::NumIndexes); i++) {
- fprintf(file, "%s", FrameInfoNames[i].c_str());
- fprintf(file, ",");
+ dprintf(fd, "%s", FrameInfoNames[i].c_str());
+ dprintf(fd, ",");
}
for (size_t i = 0; i < mFrames.size(); i++) {
FrameInfo& frame = mFrames[i];
if (frame[FrameInfoIndex::SyncStart] == 0) {
continue;
}
- fprintf(file, "\n");
+ dprintf(fd, "\n");
for (int i = 0; i < static_cast<int>(FrameInfoIndex::NumIndexes); i++) {
- fprintf(file, "%" PRId64 ",", frame[i]);
+ dprintf(fd, "%" PRId64 ",", frame[i]);
}
}
- fprintf(file, "\n---PROFILEDATA---\n\n");
- fflush(file);
+ dprintf(fd, "\n---PROFILEDATA---\n\n");
}
void JankTracker::reset() {
mFrames.clear();
mData->reset();
(*mGlobalData)->reset();
- sFrameStart = Properties::filterOutTestOverhead
- ? FrameInfoIndex::HandleInputStart
- : FrameInfoIndex::IntendedVsync;
+ sFrameStart = Properties::filterOutTestOverhead ? FrameInfoIndex::HandleInputStart
+ : FrameInfoIndex::IntendedVsync;
}
} /* namespace uirenderer */
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index e56c0791d3a4..dc6a7ff5ddb7 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -70,7 +70,8 @@ public:
private:
void setFrameInterval(nsecs_t frameIntervalNanos);
- static void dumpData(int fd, const ProfileDataDescription* description, const ProfileData* data);
+ static void dumpData(int fd, const ProfileDataDescription* description,
+ const ProfileData* data);
std::array<int64_t, NUM_BUCKETS> mThresholds;
int64_t mFrameInterval;
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index b58dfce787ef..86950d5ebb10 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -24,7 +24,7 @@ namespace android {
namespace uirenderer {
Layer::Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
- SkBlendMode mode)
+ SkBlendMode mode)
: GpuMemoryTracker(GpuObjectType::Layer)
, mRenderState(renderState)
, mApi(api)
@@ -52,5 +52,5 @@ void Layer::postDecStrong() {
mRenderState.postDecStrong(this);
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index e5520ea0e811..69213817f8af 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -16,11 +16,11 @@
#pragma once
-#include <utils/RefBase.h>
#include <GpuMemoryTracker.h>
+#include <utils/RefBase.h>
-#include <SkPaint.h>
#include <SkBlendMode.h>
+#include <SkPaint.h>
#include "Matrix.h"
@@ -43,9 +43,7 @@ public:
Vulkan = 1,
};
- Api getApi() const {
- return mApi;
- }
+ Api getApi() const { return mApi; }
~Layer();
@@ -59,44 +57,28 @@ public:
virtual bool isBlend() const = 0;
- inline void setForceFilter(bool forceFilter) {
- this->forceFilter = forceFilter;
- }
+ inline void setForceFilter(bool forceFilter) { this->forceFilter = forceFilter; }
- inline bool getForceFilter() const {
- return forceFilter;
- }
+ inline bool getForceFilter() const { return forceFilter; }
- inline void setAlpha(int alpha) {
- this->alpha = alpha;
- }
+ inline void setAlpha(int alpha) { this->alpha = alpha; }
inline void setAlpha(int alpha, SkBlendMode mode) {
this->alpha = alpha;
this->mode = mode;
}
- inline int getAlpha() const {
- return alpha;
- }
+ inline int getAlpha() const { return alpha; }
- inline SkBlendMode getMode() const {
- return mode;
- }
+ inline SkBlendMode getMode() const { return mode; }
- inline SkColorFilter* getColorFilter() const {
- return colorFilter;
- }
+ inline SkColorFilter* getColorFilter() const { return colorFilter; }
void setColorFilter(SkColorFilter* filter);
- inline mat4& getTexTransform() {
- return texTransform;
- }
+ inline mat4& getTexTransform() { return texTransform; }
- inline mat4& getTransform() {
- return transform;
- }
+ inline mat4& getTransform() { return transform; }
/**
* Posts a decStrong call to the appropriate thread.
@@ -106,7 +88,7 @@ public:
protected:
Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
- SkBlendMode mode);
+ SkBlendMode mode);
RenderState& mRenderState;
@@ -143,7 +125,7 @@ private:
*/
mat4 transform;
-}; // struct Layer
+}; // struct Layer
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/LayerBuilder.cpp b/libs/hwui/LayerBuilder.cpp
index c5d5492d4fd1..15ede4ca148a 100644
--- a/libs/hwui/LayerBuilder.cpp
+++ b/libs/hwui/LayerBuilder.cpp
@@ -29,8 +29,7 @@ namespace uirenderer {
class BatchBase {
public:
BatchBase(batchid_t batchId, BakedOpState* op, bool merging)
- : mBatchId(batchId)
- , mMerging(merging) {
+ : mBatchId(batchId), mMerging(merging) {
mBounds = op->computedState.clippedBounds;
mOps.push_back(op);
}
@@ -52,9 +51,10 @@ public:
const std::vector<BakedOpState*>& getOps() const { return mOps; }
void dump() const {
- ALOGD(" Batch %p, id %d, merging %d, count %d, bounds " RECT_STRING,
- this, mBatchId, mMerging, (int) mOps.size(), RECT_ARGS(mBounds));
+ ALOGD(" Batch %p, id %d, merging %d, count %d, bounds " RECT_STRING, this, mBatchId,
+ mMerging, (int)mOps.size(), RECT_ARGS(mBounds));
}
+
protected:
batchid_t mBatchId;
Rect mBounds;
@@ -64,9 +64,7 @@ protected:
class OpBatch : public BatchBase {
public:
- OpBatch(batchid_t batchId, BakedOpState* op)
- : BatchBase(batchId, op, false) {
- }
+ OpBatch(batchid_t batchId, BakedOpState* op) : BatchBase(batchId, op, false) {}
void batchOp(BakedOpState* op) {
mBounds.unionWith(op->computedState.clippedBounds);
@@ -77,16 +75,14 @@ public:
class MergingOpBatch : public BatchBase {
public:
MergingOpBatch(batchid_t batchId, BakedOpState* op)
- : BatchBase(batchId, op, true)
- , mClipSideFlags(op->computedState.clipSideFlags) {
- }
+ : BatchBase(batchId, op, true), mClipSideFlags(op->computedState.clipSideFlags) {}
/*
* Helper for determining if a new op can merge with a MergingDrawBatch based on their bounds
* and clip side flags. Positive bounds delta means new bounds fit in old.
*/
static inline bool checkSide(const int currentFlags, const int newFlags, const int side,
- float boundsDelta) {
+ float boundsDelta) {
bool currentClipExists = currentFlags & side;
bool newClipExists = newFlags & side;
@@ -100,16 +96,14 @@ public:
}
static bool paintIsDefault(const SkPaint& paint) {
- return paint.getAlpha() == 255
- && paint.getColorFilter() == nullptr
- && paint.getShader() == nullptr;
+ return paint.getAlpha() == 255 && paint.getColorFilter() == nullptr &&
+ paint.getShader() == nullptr;
}
static bool paintsAreEquivalent(const SkPaint& a, const SkPaint& b) {
// Note: don't check color, since all currently mergeable ops can merge across colors
- return a.getAlpha() == b.getAlpha()
- && a.getColorFilter() == b.getColorFilter()
- && a.getShader() == b.getShader();
+ return a.getAlpha() == b.getAlpha() && a.getColorFilter() == b.getColorFilter() &&
+ a.getShader() == b.getShader();
}
/*
@@ -123,8 +117,8 @@ public:
* dropped, so we make simplifying qualifications on the ops that can merge, per op type.
*/
bool canMergeWith(BakedOpState* op) const {
- bool isTextBatch = getBatchId() == OpBatchType::Text
- || getBatchId() == OpBatchType::ColorText;
+ bool isTextBatch =
+ getBatchId() == OpBatchType::Text || getBatchId() == OpBatchType::ColorText;
// Overlapping other operations is only allowed for text without shadow. For other ops,
// multiDraw isn't guaranteed to overdraw correctly
@@ -142,8 +136,9 @@ public:
if (lhs->roundRectClipState != rhs->roundRectClipState) return false;
// Local masks prevent merge, since they're potentially in different coordinate spaces
- if (lhs->computedState.localProjectionPathMask
- || rhs->computedState.localProjectionPathMask) return false;
+ if (lhs->computedState.localProjectionPathMask ||
+ rhs->computedState.localProjectionPathMask)
+ return false;
/* Clipping compatibility check
*
@@ -155,15 +150,18 @@ public:
if (currentFlags != OpClipSideFlags::None || newFlags != OpClipSideFlags::None) {
const Rect& opBounds = op->computedState.clippedBounds;
float boundsDelta = mBounds.left - opBounds.left;
- if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Left, boundsDelta)) return false;
+ if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Left, boundsDelta))
+ return false;
boundsDelta = mBounds.top - opBounds.top;
if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Top, boundsDelta)) return false;
// right and bottom delta calculation reversed to account for direction
boundsDelta = opBounds.right - mBounds.right;
- if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Right, boundsDelta)) return false;
+ if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Right, boundsDelta))
+ return false;
boundsDelta = opBounds.bottom - mBounds.bottom;
- if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Bottom, boundsDelta)) return false;
+ if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Bottom, boundsDelta))
+ return false;
}
const SkPaint* newPaint = op->op->paint;
@@ -197,8 +195,8 @@ private:
int mClipSideFlags;
};
-LayerBuilder::LayerBuilder(uint32_t width, uint32_t height,
- const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode)
+LayerBuilder::LayerBuilder(uint32_t width, uint32_t height, const Rect& repaintRect,
+ const BeginLayerOp* beginLayerOp, RenderNode* renderNode)
: width(width)
, height(height)
, repaintRect(repaintRect)
@@ -210,7 +208,7 @@ LayerBuilder::LayerBuilder(uint32_t width, uint32_t height,
// iterate back toward target to see if anything drawn since should overlap the new op
// if no target, merging ops still iterate to find similar batch to insert after
void LayerBuilder::locateInsertIndex(int batchId, const Rect& clippedBounds,
- BatchBase** targetBatch, size_t* insertBatchIndex) const {
+ BatchBase** targetBatch, size_t* insertBatchIndex) const {
for (int i = mBatches.size() - 1; i >= 0; i--) {
BatchBase* overBatch = mBatches[i];
@@ -219,7 +217,7 @@ void LayerBuilder::locateInsertIndex(int batchId, const Rect& clippedBounds,
// TODO: also consider shader shared between batch types
if (batchId == overBatch->getBatchId()) {
*insertBatchIndex = i + 1;
- if (!*targetBatch) break; // found insert position, quit
+ if (!*targetBatch) break; // found insert position, quit
}
if (overBatch->intersects(clippedBounds)) {
@@ -242,10 +240,10 @@ void LayerBuilder::onDeferOp(LinearAllocator& allocator, const BakedOpState* bak
// and issue them together in one draw.
flushLayerClears(allocator);
- if (CC_UNLIKELY(activeUnclippedSaveLayers.empty()
- && bakedState->computedState.opaqueOverClippedBounds
- && bakedState->computedState.clippedBounds.contains(repaintRect)
- && !Properties::debugOverdraw)) {
+ if (CC_UNLIKELY(activeUnclippedSaveLayers.empty() &&
+ bakedState->computedState.opaqueOverClippedBounds &&
+ bakedState->computedState.clippedBounds.contains(repaintRect) &&
+ !Properties::debugOverdraw)) {
// discard all deferred drawing ops, since new one will occlude them
clear();
}
@@ -258,7 +256,7 @@ void LayerBuilder::flushLayerClears(LinearAllocator& allocator) {
// put the verts in the frame allocator, since
// 1) SimpleRectsOps needs verts, not rects
// 2) even if mClearRects stored verts, std::vectors will move their contents
- Vertex* const verts = (Vertex*) allocator.create_trivial_array<Vertex>(vertCount);
+ Vertex* const verts = (Vertex*)allocator.create_trivial_array<Vertex>(vertCount);
Vertex* currentVert = verts;
Rect bounds = mClearRects[0];
@@ -269,35 +267,34 @@ void LayerBuilder::flushLayerClears(LinearAllocator& allocator) {
Vertex::set(currentVert++, rect.left, rect.bottom);
Vertex::set(currentVert++, rect.right, rect.bottom);
}
- mClearRects.clear(); // discard rects before drawing so this method isn't reentrant
+ mClearRects.clear(); // discard rects before drawing so this method isn't reentrant
// One or more unclipped saveLayers have been enqueued, with deferred clears.
// Flush all of these clears with a single draw
SkPaint* paint = allocator.create<SkPaint>();
paint->setBlendMode(SkBlendMode::kClear);
- SimpleRectsOp* op = allocator.create_trivial<SimpleRectsOp>(bounds,
- Matrix4::identity(), nullptr, paint,
- verts, vertCount);
- BakedOpState* bakedState = BakedOpState::directConstruct(allocator,
- &repaintClip, bounds, *op);
+ SimpleRectsOp* op = allocator.create_trivial<SimpleRectsOp>(
+ bounds, Matrix4::identity(), nullptr, paint, verts, vertCount);
+ BakedOpState* bakedState =
+ BakedOpState::directConstruct(allocator, &repaintClip, bounds, *op);
deferUnmergeableOp(allocator, bakedState, OpBatchType::Vertices);
}
}
-void LayerBuilder::deferUnmergeableOp(LinearAllocator& allocator,
- BakedOpState* op, batchid_t batchId) {
+void LayerBuilder::deferUnmergeableOp(LinearAllocator& allocator, BakedOpState* op,
+ batchid_t batchId) {
onDeferOp(allocator, op);
OpBatch* targetBatch = mBatchLookup[batchId];
size_t insertBatchIndex = mBatches.size();
if (targetBatch) {
- locateInsertIndex(batchId, op->computedState.clippedBounds,
- (BatchBase**)(&targetBatch), &insertBatchIndex);
+ locateInsertIndex(batchId, op->computedState.clippedBounds, (BatchBase**)(&targetBatch),
+ &insertBatchIndex);
}
if (targetBatch) {
targetBatch->batchOp(op);
- } else {
+ } else {
// new non-merging batch
targetBatch = allocator.create<OpBatch>(batchId, op);
mBatchLookup[batchId] = targetBatch;
@@ -305,8 +302,8 @@ void LayerBuilder::deferUnmergeableOp(LinearAllocator& allocator,
}
}
-void LayerBuilder::deferMergeableOp(LinearAllocator& allocator,
- BakedOpState* op, batchid_t batchId, mergeid_t mergeId) {
+void LayerBuilder::deferMergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId,
+ mergeid_t mergeId) {
onDeferOp(allocator, op);
MergingOpBatch* targetBatch = nullptr;
@@ -320,12 +317,12 @@ void LayerBuilder::deferMergeableOp(LinearAllocator& allocator,
}
size_t insertBatchIndex = mBatches.size();
- locateInsertIndex(batchId, op->computedState.clippedBounds,
- (BatchBase**)(&targetBatch), &insertBatchIndex);
+ locateInsertIndex(batchId, op->computedState.clippedBounds, (BatchBase**)(&targetBatch),
+ &insertBatchIndex);
if (targetBatch) {
targetBatch->mergeOp(op);
- } else {
+ } else {
// new merging batch
targetBatch = allocator.create<MergingOpBatch>(batchId, op);
mMergingBatchLookup[batchId].insert(std::make_pair(mergeId, targetBatch));
@@ -334,11 +331,11 @@ void LayerBuilder::deferMergeableOp(LinearAllocator& allocator,
}
}
-void LayerBuilder::replayBakedOpsImpl(void* arg,
- BakedOpReceiver* unmergedReceivers, MergedOpReceiver* mergedReceivers) const {
+void LayerBuilder::replayBakedOpsImpl(void* arg, BakedOpReceiver* unmergedReceivers,
+ MergedOpReceiver* mergedReceivers) const {
if (renderNode) {
- ATRACE_FORMAT_BEGIN("Issue HW Layer DisplayList %s %ux%u",
- renderNode->getName(), width, height);
+ ATRACE_FORMAT_BEGIN("Issue HW Layer DisplayList %s %ux%u", renderNode->getName(), width,
+ height);
} else {
ATRACE_BEGIN("flush drawing commands");
}
@@ -348,12 +345,9 @@ void LayerBuilder::replayBakedOpsImpl(void* arg,
if (size > 1 && batch->isMerging()) {
int opId = batch->getOps()[0]->op->opId;
const MergingOpBatch* mergingBatch = static_cast<const MergingOpBatch*>(batch);
- MergedBakedOpList data = {
- batch->getOps().data(),
- size,
- mergingBatch->getClipSideFlags(),
- mergingBatch->getClipRect()
- };
+ MergedBakedOpList data = {batch->getOps().data(), size,
+ mergingBatch->getClipSideFlags(),
+ mergingBatch->getClipRect()};
mergedReceivers[opId](arg, data);
} else {
for (const BakedOpState* op : batch->getOps()) {
@@ -373,13 +367,12 @@ void LayerBuilder::clear() {
}
void LayerBuilder::dump() const {
- ALOGD("LayerBuilder %p, %ux%u buffer %p, blo %p, rn %p (%s)",
- this, width, height, offscreenBuffer, beginLayerOp,
- renderNode, renderNode ? renderNode->getName() : "-");
+ ALOGD("LayerBuilder %p, %ux%u buffer %p, blo %p, rn %p (%s)", this, width, height,
+ offscreenBuffer, beginLayerOp, renderNode, renderNode ? renderNode->getName() : "-");
for (const BatchBase* batch : mBatches) {
batch->dump();
}
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/LayerBuilder.h b/libs/hwui/LayerBuilder.h
index 4de432c5e7be..c799d48f7821 100644
--- a/libs/hwui/LayerBuilder.h
+++ b/libs/hwui/LayerBuilder.h
@@ -20,8 +20,8 @@
#include "Rect.h"
#include "utils/Macros.h"
-#include <vector>
#include <unordered_map>
+#include <vector>
struct SkRect;
@@ -42,22 +42,22 @@ typedef int batchid_t;
typedef const void* mergeid_t;
namespace OpBatchType {
- enum {
- Bitmap,
- MergedPatch,
- AlphaVertices,
- Vertices,
- AlphaMaskTexture,
- Text,
- ColorText,
- Shadow,
- TextureLayer,
- Functor,
- CopyToLayer,
- CopyFromLayer,
-
- Count // must be last
- };
+enum {
+ Bitmap,
+ MergedPatch,
+ AlphaVertices,
+ Vertices,
+ AlphaMaskTexture,
+ Text,
+ ColorText,
+ Shadow,
+ TextureLayer,
+ Functor,
+ CopyToLayer,
+ CopyFromLayer,
+
+ Count // must be last
+};
}
typedef void (*BakedOpReceiver)(void*, const BakedOpState&);
@@ -68,37 +68,36 @@ typedef void (*MergedOpReceiver)(void*, const MergedBakedOpList& opList);
* for a single FBO/layer.
*/
class LayerBuilder {
-// Prevent copy/assign because users may stash pointer to offscreenBuffer and viewportClip
-PREVENT_COPY_AND_ASSIGN(LayerBuilder);
+ // Prevent copy/assign because users may stash pointer to offscreenBuffer and viewportClip
+ PREVENT_COPY_AND_ASSIGN(LayerBuilder);
+
public:
// Create LayerBuilder for Fbo0
LayerBuilder(uint32_t width, uint32_t height, const Rect& repaintRect)
- : LayerBuilder(width, height, repaintRect, nullptr, nullptr) {};
+ : LayerBuilder(width, height, repaintRect, nullptr, nullptr){};
// Create LayerBuilder for an offscreen layer, where beginLayerOp is present for a
// saveLayer, renderNode is present for a HW layer.
- LayerBuilder(uint32_t width, uint32_t height,
- const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
+ LayerBuilder(uint32_t width, uint32_t height, const Rect& repaintRect,
+ const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
// iterate back toward target to see if anything drawn since should overlap the new op
// if no target, merging ops still iterate to find similar batch to insert after
- void locateInsertIndex(int batchId, const Rect& clippedBounds,
- BatchBase** targetBatch, size_t* insertBatchIndex) const;
+ void locateInsertIndex(int batchId, const Rect& clippedBounds, BatchBase** targetBatch,
+ size_t* insertBatchIndex) const;
void deferUnmergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId);
// insertion point of a new batch, will hopefully be immediately after similar batch
// (generally, should be similar shader)
- void deferMergeableOp(LinearAllocator& allocator,
- BakedOpState* op, batchid_t batchId, mergeid_t mergeId);
+ void deferMergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId,
+ mergeid_t mergeId);
void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers, MergedOpReceiver*) const;
void deferLayerClear(const Rect& dstRect);
- bool empty() const {
- return mBatches.empty();
- }
+ bool empty() const { return mBatches.empty(); }
void clear();
@@ -114,6 +113,7 @@ public:
// list of deferred CopyFromLayer ops, to be deferred upon encountering EndUnclippedLayerOps
std::vector<BakedOpState*> activeUnclippedSaveLayers;
+
private:
void onDeferOp(LinearAllocator& allocator, const BakedOpState* bakedState);
void flushLayerClears(LinearAllocator& allocator);
@@ -128,10 +128,10 @@ private:
std::unordered_map<mergeid_t, MergingOpBatch*> mMergingBatchLookup[OpBatchType::Count];
// Maps batch ids to the most recent *non-merging* batch of that id
- OpBatch* mBatchLookup[OpBatchType::Count] = { nullptr };
+ OpBatch* mBatchLookup[OpBatchType::Count] = {nullptr};
std::vector<Rect> mClearRects;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/LayerUpdateQueue.cpp b/libs/hwui/LayerUpdateQueue.cpp
index 95f5cfb33474..fd5c66101cd3 100644
--- a/libs/hwui/LayerUpdateQueue.cpp
+++ b/libs/hwui/LayerUpdateQueue.cpp
@@ -39,5 +39,5 @@ void LayerUpdateQueue::enqueueLayerWithDamage(RenderNode* renderNode, Rect damag
}
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/LayerUpdateQueue.h b/libs/hwui/LayerUpdateQueue.h
index 38f3596d70df..b14b80cc598a 100644
--- a/libs/hwui/LayerUpdateQueue.h
+++ b/libs/hwui/LayerUpdateQueue.h
@@ -17,12 +17,12 @@
#ifndef ANDROID_HWUI_LAYER_UPDATE_QUEUE_H
#define ANDROID_HWUI_LAYER_UPDATE_QUEUE_H
+#include <utils/StrongPointer.h>
#include "Rect.h"
#include "utils/Macros.h"
-#include <utils/StrongPointer.h>
-#include <vector>
#include <unordered_map>
+#include <vector>
namespace android {
namespace uirenderer {
@@ -31,11 +31,11 @@ class RenderNode;
class LayerUpdateQueue {
PREVENT_COPY_AND_ASSIGN(LayerUpdateQueue);
+
public:
struct Entry {
Entry(RenderNode* renderNode, const Rect& damage)
- : renderNode(renderNode)
- , damage(damage) {}
+ : renderNode(renderNode), damage(damage) {}
sp<RenderNode> renderNode;
Rect damage;
};
@@ -44,11 +44,12 @@ public:
void enqueueLayerWithDamage(RenderNode* renderNode, Rect dirty);
void clear();
const std::vector<Entry>& entries() const { return mEntries; }
+
private:
std::vector<Entry> mEntries;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_LAYER_UPDATE_QUEUE_H
+#endif // ANDROID_HWUI_LAYER_UPDATE_QUEUE_H
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index a936661f86f9..d84ed321a4cb 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -43,24 +43,24 @@ const Matrix4& Matrix4::identity() {
}
void Matrix4::loadIdentity() {
- data[kScaleX] = 1.0f;
- data[kSkewY] = 0.0f;
- data[2] = 0.0f;
+ data[kScaleX] = 1.0f;
+ data[kSkewY] = 0.0f;
+ data[2] = 0.0f;
data[kPerspective0] = 0.0f;
- data[kSkewX] = 0.0f;
- data[kScaleY] = 1.0f;
- data[6] = 0.0f;
+ data[kSkewX] = 0.0f;
+ data[kScaleY] = 1.0f;
+ data[6] = 0.0f;
data[kPerspective1] = 0.0f;
- data[8] = 0.0f;
- data[9] = 0.0f;
- data[kScaleZ] = 1.0f;
- data[11] = 0.0f;
+ data[8] = 0.0f;
+ data[9] = 0.0f;
+ data[kScaleZ] = 1.0f;
+ data[11] = 0.0f;
- data[kTranslateX] = 0.0f;
- data[kTranslateY] = 0.0f;
- data[kTranslateZ] = 0.0f;
+ data[kTranslateX] = 0.0f;
+ data[kTranslateY] = 0.0f;
+ data[kTranslateZ] = 0.0f;
data[kPerspective2] = 1.0f;
mType = kTypeIdentity | kTypeRectToRect;
@@ -75,7 +75,7 @@ uint8_t Matrix4::getType() const {
mType = kTypeIdentity;
if (data[kPerspective0] != 0.0f || data[kPerspective1] != 0.0f ||
- data[kPerspective2] != 1.0f) {
+ data[kPerspective2] != 1.0f) {
mType |= kTypePerspective;
}
@@ -105,7 +105,7 @@ uint8_t Matrix4::getType() const {
// it doesn't preserve rectangles.
if (!(mType & kTypePerspective)) {
if ((isZero(m00) && isZero(m11) && !isZero(m01) && !isZero(m10)) ||
- (isZero(m01) && isZero(m10) && !isZero(m00) && !isZero(m11))) {
+ (isZero(m01) && isZero(m10) && !isZero(m00) && !isZero(m11))) {
mType |= kTypeRectToRect;
}
}
@@ -155,17 +155,17 @@ void Matrix4::load(const float* v) {
void Matrix4::load(const SkMatrix& v) {
memset(data, 0, sizeof(data));
- data[kScaleX] = v[SkMatrix::kMScaleX];
- data[kSkewX] = v[SkMatrix::kMSkewX];
+ data[kScaleX] = v[SkMatrix::kMScaleX];
+ data[kSkewX] = v[SkMatrix::kMSkewX];
data[kTranslateX] = v[SkMatrix::kMTransX];
- data[kSkewY] = v[SkMatrix::kMSkewY];
- data[kScaleY] = v[SkMatrix::kMScaleY];
+ data[kSkewY] = v[SkMatrix::kMSkewY];
+ data[kScaleY] = v[SkMatrix::kMScaleY];
data[kTranslateY] = v[SkMatrix::kMTransY];
- data[kPerspective0] = v[SkMatrix::kMPersp0];
- data[kPerspective1] = v[SkMatrix::kMPersp1];
- data[kPerspective2] = v[SkMatrix::kMPersp2];
+ data[kPerspective0] = v[SkMatrix::kMPersp0];
+ data[kPerspective1] = v[SkMatrix::kMPersp1];
+ data[kPerspective2] = v[SkMatrix::kMPersp2];
data[kScaleZ] = 1.0f;
@@ -183,10 +183,10 @@ void Matrix4::copyTo(SkMatrix& v) const {
v.reset();
v.set(SkMatrix::kMScaleX, data[kScaleX]);
- v.set(SkMatrix::kMSkewX, data[kSkewX]);
+ v.set(SkMatrix::kMSkewX, data[kSkewX]);
v.set(SkMatrix::kMTransX, data[kTranslateX]);
- v.set(SkMatrix::kMSkewY, data[kSkewY]);
+ v.set(SkMatrix::kMSkewY, data[kSkewY]);
v.set(SkMatrix::kMScaleY, data[kScaleY]);
v.set(SkMatrix::kMTransY, data[kTranslateY]);
@@ -201,13 +201,13 @@ void Matrix4::loadInverse(const Matrix4& v) {
// Reset the matrix
// Unnamed fields are never written to except by
// loadIdentity(), they don't need to be reset
- data[kScaleX] = 1.0f;
- data[kSkewX] = 0.0f;
+ data[kScaleX] = 1.0f;
+ data[kSkewX] = 0.0f;
- data[kScaleY] = 1.0f;
- data[kSkewY] = 0.0f;
+ data[kScaleY] = 1.0f;
+ data[kSkewY] = 0.0f;
- data[kScaleZ] = 1.0f;
+ data[kScaleZ] = 1.0f;
data[kPerspective0] = 0.0f;
data[kPerspective1] = 0.0f;
@@ -215,43 +215,48 @@ void Matrix4::loadInverse(const Matrix4& v) {
// No need to deal with kTranslateZ because isPureTranslate()
// only returns true when the kTranslateZ component is 0
- data[kTranslateX] = -v.data[kTranslateX];
- data[kTranslateY] = -v.data[kTranslateY];
- data[kTranslateZ] = 0.0f;
+ data[kTranslateX] = -v.data[kTranslateX];
+ data[kTranslateY] = -v.data[kTranslateY];
+ data[kTranslateZ] = 0.0f;
// A "pure translate" matrix can be identity or translation
mType = v.getType();
return;
}
- double scale = 1.0 /
- (v.data[kScaleX] * ((double) v.data[kScaleY] * v.data[kPerspective2] -
- (double) v.data[kTranslateY] * v.data[kPerspective1]) +
- v.data[kSkewX] * ((double) v.data[kTranslateY] * v.data[kPerspective0] -
- (double) v.data[kSkewY] * v.data[kPerspective2]) +
- v.data[kTranslateX] * ((double) v.data[kSkewY] * v.data[kPerspective1] -
- (double) v.data[kScaleY] * v.data[kPerspective0]));
+ double scale = 1.0 / (v.data[kScaleX] * ((double)v.data[kScaleY] * v.data[kPerspective2] -
+ (double)v.data[kTranslateY] * v.data[kPerspective1]) +
+ v.data[kSkewX] * ((double)v.data[kTranslateY] * v.data[kPerspective0] -
+ (double)v.data[kSkewY] * v.data[kPerspective2]) +
+ v.data[kTranslateX] * ((double)v.data[kSkewY] * v.data[kPerspective1] -
+ (double)v.data[kScaleY] * v.data[kPerspective0]));
data[kScaleX] = (v.data[kScaleY] * v.data[kPerspective2] -
- v.data[kTranslateY] * v.data[kPerspective1]) * scale;
- data[kSkewX] = (v.data[kTranslateX] * v.data[kPerspective1] -
- v.data[kSkewX] * v.data[kPerspective2]) * scale;
- data[kTranslateX] = (v.data[kSkewX] * v.data[kTranslateY] -
- v.data[kTranslateX] * v.data[kScaleY]) * scale;
-
- data[kSkewY] = (v.data[kTranslateY] * v.data[kPerspective0] -
- v.data[kSkewY] * v.data[kPerspective2]) * scale;
+ v.data[kTranslateY] * v.data[kPerspective1]) *
+ scale;
+ data[kSkewX] =
+ (v.data[kTranslateX] * v.data[kPerspective1] - v.data[kSkewX] * v.data[kPerspective2]) *
+ scale;
+ data[kTranslateX] =
+ (v.data[kSkewX] * v.data[kTranslateY] - v.data[kTranslateX] * v.data[kScaleY]) * scale;
+
+ data[kSkewY] =
+ (v.data[kTranslateY] * v.data[kPerspective0] - v.data[kSkewY] * v.data[kPerspective2]) *
+ scale;
data[kScaleY] = (v.data[kScaleX] * v.data[kPerspective2] -
- v.data[kTranslateX] * v.data[kPerspective0]) * scale;
- data[kTranslateY] = (v.data[kTranslateX] * v.data[kSkewY] -
- v.data[kScaleX] * v.data[kTranslateY]) * scale;
-
- data[kPerspective0] = (v.data[kSkewY] * v.data[kPerspective1] -
- v.data[kScaleY] * v.data[kPerspective0]) * scale;
- data[kPerspective1] = (v.data[kSkewX] * v.data[kPerspective0] -
- v.data[kScaleX] * v.data[kPerspective1]) * scale;
- data[kPerspective2] = (v.data[kScaleX] * v.data[kScaleY] -
- v.data[kSkewX] * v.data[kSkewY]) * scale;
+ v.data[kTranslateX] * v.data[kPerspective0]) *
+ scale;
+ data[kTranslateY] =
+ (v.data[kTranslateX] * v.data[kSkewY] - v.data[kScaleX] * v.data[kTranslateY]) * scale;
+
+ data[kPerspective0] =
+ (v.data[kSkewY] * v.data[kPerspective1] - v.data[kScaleY] * v.data[kPerspective0]) *
+ scale;
+ data[kPerspective1] =
+ (v.data[kSkewX] * v.data[kPerspective0] - v.data[kScaleX] * v.data[kPerspective1]) *
+ scale;
+ data[kPerspective2] =
+ (v.data[kScaleX] * v.data[kScaleY] - v.data[kSkewX] * v.data[kSkewY]) * scale;
mType = kTypeUnknown;
}
@@ -298,13 +303,13 @@ void Matrix4::loadScale(float sx, float sy, float sz) {
void Matrix4::loadSkew(float sx, float sy) {
loadIdentity();
- data[kScaleX] = 1.0f;
- data[kSkewX] = sx;
- data[kTranslateX] = 0.0f;
+ data[kScaleX] = 1.0f;
+ data[kSkewX] = sx;
+ data[kTranslateX] = 0.0f;
- data[kSkewY] = sy;
- data[kScaleY] = 1.0f;
- data[kTranslateY] = 0.0f;
+ data[kSkewY] = sy;
+ data[kScaleY] = 1.0f;
+ data[kTranslateY] = 0.0f;
data[kPerspective0] = 0.0f;
data[kPerspective1] = 0.0f;
@@ -320,23 +325,23 @@ void Matrix4::loadRotate(float angle) {
loadIdentity();
- data[kScaleX] = c;
- data[kSkewX] = -s;
+ data[kScaleX] = c;
+ data[kSkewX] = -s;
- data[kSkewY] = s;
- data[kScaleY] = c;
+ data[kSkewY] = s;
+ data[kScaleY] = c;
mType = kTypeUnknown;
}
void Matrix4::loadRotate(float angle, float x, float y, float z) {
- data[kPerspective0] = 0.0f;
- data[kPerspective1] = 0.0f;
- data[11] = 0.0f;
- data[kTranslateX] = 0.0f;
- data[kTranslateY] = 0.0f;
- data[kTranslateZ] = 0.0f;
- data[kPerspective2] = 1.0f;
+ data[kPerspective0] = 0.0f;
+ data[kPerspective1] = 0.0f;
+ data[11] = 0.0f;
+ data[kTranslateX] = 0.0f;
+ data[kTranslateY] = 0.0f;
+ data[kTranslateZ] = 0.0f;
+ data[kPerspective2] = 1.0f;
angle *= float(M_PI / 180.0f);
float c = cosf(angle);
@@ -356,27 +361,27 @@ void Matrix4::loadRotate(float angle, float x, float y, float z) {
const float ys = y * s;
const float zs = z * s;
- data[kScaleX] = x * x * nc + c;
- data[kSkewX] = xy * nc - zs;
- data[8] = zx * nc + ys;
- data[kSkewY] = xy * nc + zs;
- data[kScaleY] = y * y * nc + c;
- data[9] = yz * nc - xs;
- data[2] = zx * nc - ys;
- data[6] = yz * nc + xs;
- data[kScaleZ] = z * z * nc + c;
+ data[kScaleX] = x * x * nc + c;
+ data[kSkewX] = xy * nc - zs;
+ data[8] = zx * nc + ys;
+ data[kSkewY] = xy * nc + zs;
+ data[kScaleY] = y * y * nc + c;
+ data[9] = yz * nc - xs;
+ data[2] = zx * nc - ys;
+ data[6] = yz * nc + xs;
+ data[kScaleZ] = z * z * nc + c;
mType = kTypeUnknown;
}
void Matrix4::loadMultiply(const Matrix4& u, const Matrix4& v) {
- for (int i = 0 ; i < 4 ; i++) {
+ for (int i = 0; i < 4; i++) {
float x = 0;
float y = 0;
float z = 0;
float w = 0;
- for (int j = 0 ; j < 4 ; j++) {
+ for (int j = 0; j < 4; j++) {
const float e = v.get(i, j);
x += u.get(j, 0) * e;
y += u.get(j, 1) * e;
@@ -412,7 +417,7 @@ float Matrix4::mapZ(const Vector3& orig) const {
}
void Matrix4::mapPoint3d(Vector3& vec) const {
- //TODO: optimize simple case
+ // TODO: optimize simple case
const Vector3 orig(vec);
vec.x = orig.x * data[kScaleX] + orig.y * data[kSkewX] + orig.z * data[8] + data[kTranslateX];
vec.y = orig.x * data[kSkewY] + orig.y * data[kScaleY] + orig.z * data[9] + data[kTranslateY];
@@ -469,16 +474,11 @@ void Matrix4::mapRect(Rect& r) const {
return;
}
- float vertices[] = {
- r.left, r.top,
- r.right, r.top,
- r.right, r.bottom,
- r.left, r.bottom
- };
+ float vertices[] = {r.left, r.top, r.right, r.top, r.right, r.bottom, r.left, r.bottom};
float x, y, z;
- for (int i = 0; i < 8; i+= 2) {
+ for (int i = 0; i < 8; i += 2) {
float px = vertices[i];
float py = vertices[i + 1];
@@ -498,10 +498,14 @@ void Matrix4::mapRect(Rect& r) const {
x = vertices[i];
y = vertices[i + 1];
- if (x < r.left) r.left = x;
- else if (x > r.right) r.right = x;
- if (y < r.top) r.top = y;
- else if (y > r.bottom) r.bottom = y;
+ if (x < r.left)
+ r.left = x;
+ else if (x > r.right)
+ r.right = x;
+ if (y < r.top)
+ r.top = y;
+ else if (y > r.bottom)
+ r.bottom = y;
}
}
@@ -522,5 +526,5 @@ void Matrix4::dump(const char* label) const {
ALOGD("]");
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index ba9cbbe02ec1..f0a3a959617d 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -18,27 +18,26 @@
#include "Rect.h"
+#include <SkMatrix.h>
#include <cutils/compiler.h>
#include <iomanip>
#include <ostream>
-#include <SkMatrix.h>
namespace android {
namespace uirenderer {
#define SK_MATRIX_STRING "[%.2f %.2f %.2f] [%.2f %.2f %.2f] [%.2f %.2f %.2f]"
-#define SK_MATRIX_ARGS(m) \
- (m)->get(0), (m)->get(1), (m)->get(2), \
- (m)->get(3), (m)->get(4), (m)->get(5), \
- (m)->get(6), (m)->get(7), (m)->get(8)
+#define SK_MATRIX_ARGS(m) \
+ (m)->get(0), (m)->get(1), (m)->get(2), (m)->get(3), (m)->get(4), (m)->get(5), (m)->get(6), \
+ (m)->get(7), (m)->get(8)
-#define MATRIX_4_STRING "[%.2f %.2f %.2f %.2f] [%.2f %.2f %.2f %.2f]" \
+#define MATRIX_4_STRING \
+ "[%.2f %.2f %.2f %.2f] [%.2f %.2f %.2f %.2f]" \
" [%.2f %.2f %.2f %.2f] [%.2f %.2f %.2f %.2f]"
-#define MATRIX_4_ARGS(m) \
- (m)->data[0], (m)->data[4], (m)->data[8], (m)->data[12], \
- (m)->data[1], (m)->data[5], (m)->data[9], (m)->data[13], \
- (m)->data[2], (m)->data[6], (m)->data[10], (m)->data[14], \
- (m)->data[3], (m)->data[7], (m)->data[11], (m)->data[15] \
+#define MATRIX_4_ARGS(m) \
+ (m)->data[0], (m)->data[4], (m)->data[8], (m)->data[12], (m)->data[1], (m)->data[5], \
+ (m)->data[9], (m)->data[13], (m)->data[2], (m)->data[6], (m)->data[10], (m)->data[14], \
+ (m)->data[3], (m)->data[7], (m)->data[11], (m)->data[15]
///////////////////////////////////////////////////////////////////////////////
// Classes
@@ -77,21 +76,15 @@ public:
static const int sGeometryMask = 0xf;
- Matrix4() {
- loadIdentity();
- }
+ Matrix4() { loadIdentity(); }
- explicit Matrix4(const float* v) {
- load(v);
- }
+ explicit Matrix4(const float* v) { load(v); }
Matrix4(const SkMatrix& v) { // NOLINT, implicit
load(v);
}
- float operator[](int index) const {
- return data[index];
- }
+ float operator[](int index) const { return data[index]; }
float& operator[](int index) {
mType = kTypeUnknown;
@@ -107,9 +100,7 @@ public:
return !memcmp(&a.data[0], &b.data[0], 16 * sizeof(float));
}
- friend bool operator!=(const Matrix4& a, const Matrix4& b) {
- return !(a == b);
- }
+ friend bool operator!=(const Matrix4& a, const Matrix4& b) { return !(a == b); }
void loadIdentity();
@@ -126,9 +117,7 @@ public:
void loadMultiply(const Matrix4& u, const Matrix4& v);
void loadOrtho(float left, float right, float bottom, float top, float near, float far);
- void loadOrtho(int width, int height) {
- loadOrtho(0, width, height, 0, -1, 1);
- }
+ void loadOrtho(int width, int height) { loadOrtho(0, width, height, 0, -1, 1); }
uint8_t getType() const;
@@ -208,8 +197,8 @@ public:
float mapZ(const Vector3& orig) const;
void mapPoint3d(Vector3& vec) const;
- void mapPoint(float& x, float& y) const; // 2d only
- void mapRect(Rect& r) const; // 2d only
+ void mapPoint(float& x, float& y) const; // 2d only
+ void mapRect(Rect& r) const; // 2d only
float getTranslateX() const;
float getTranslateY() const;
@@ -241,17 +230,13 @@ public:
private:
mutable uint8_t mType;
- inline float get(int i, int j) const {
- return data[i * 4 + j];
- }
+ inline float get(int i, int j) const { return data[i * 4 + j]; }
- inline void set(int i, int j, float v) {
- data[i * 4 + j] = v;
- }
+ inline void set(int i, int j, float v) { data[i * 4 + j] = v; }
uint8_t getGeometryType() const;
-}; // class Matrix4
+}; // class Matrix4
///////////////////////////////////////////////////////////////////////////////
// Types
@@ -259,6 +244,5 @@ private:
typedef Matrix4 mat4;
-}; // namespace uirenderer
-}; // namespace android
-
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/NinePatchUtils.h b/libs/hwui/NinePatchUtils.h
index e989a4680a60..8f866f50e450 100644
--- a/libs/hwui/NinePatchUtils.h
+++ b/libs/hwui/NinePatchUtils.h
@@ -20,7 +20,7 @@ namespace android {
namespace NinePatchUtils {
static inline void SetLatticeDivs(SkCanvas::Lattice* lattice, const Res_png_9patch& chunk,
- int width, int height) {
+ int width, int height) {
lattice->fXCount = chunk.numXDivs;
lattice->fYCount = chunk.numYDivs;
lattice->fXDivs = chunk.getXDivs();
@@ -54,7 +54,7 @@ static inline int NumDistinctRects(const SkCanvas::Lattice& lattice) {
}
static inline void SetLatticeFlags(SkCanvas::Lattice* lattice, SkCanvas::Lattice::Flags* flags,
- int numFlags, const Res_png_9patch& chunk) {
+ int numFlags, const Res_png_9patch& chunk) {
lattice->fFlags = flags;
sk_bzero(flags, numFlags * sizeof(SkCanvas::Lattice::Flags));
@@ -92,5 +92,5 @@ static inline void SetLatticeFlags(SkCanvas::Lattice* lattice, SkCanvas::Lattice
}
}
-}; // namespace NinePatchUtils
-}; // namespace android
+}; // namespace NinePatchUtils
+}; // namespace android
diff --git a/libs/hwui/OpDumper.cpp b/libs/hwui/OpDumper.cpp
index f4b7ee0fe430..5d2ccc77e82f 100644
--- a/libs/hwui/OpDumper.cpp
+++ b/libs/hwui/OpDumper.cpp
@@ -34,14 +34,13 @@ void OpDumper::dump(const RecordedOp& op, std::ostream& output, int level) {
op.localMatrix.mapRect(localBounds);
output << sOpNameLut[op.opId] << " " << localBounds;
- if (op.localClip
- && (!op.localClip->rect.contains(localBounds) || op.localClip->intersectWithRoot)) {
- output << std::fixed << std::setprecision(0)
- << " clip=" << op.localClip->rect
- << " mode=" << (int)op.localClip->mode;
+ if (op.localClip &&
+ (!op.localClip->rect.contains(localBounds) || op.localClip->intersectWithRoot)) {
+ output << std::fixed << std::setprecision(0) << " clip=" << op.localClip->rect
+ << " mode=" << (int)op.localClip->mode;
if (op.localClip->intersectWithRoot) {
- output << " iwr";
+ output << " iwr";
}
}
}
@@ -50,5 +49,5 @@ const char* OpDumper::opName(const RecordedOp& op) {
return sOpNameLut[op.opId];
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/OpDumper.h b/libs/hwui/OpDumper.h
index a82289c7cca2..edbe381fcc72 100644
--- a/libs/hwui/OpDumper.h
+++ b/libs/hwui/OpDumper.h
@@ -29,5 +29,5 @@ public:
static const char* opName(const RecordedOp& op);
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp
index 751e2037db91..11432d629650 100644
--- a/libs/hwui/OpenGLReadback.cpp
+++ b/libs/hwui/OpenGLReadback.cpp
@@ -17,30 +17,29 @@
#include "OpenGLReadback.h"
#include "Caches.h"
-#include "Image.h"
-#include "GlopBuilder.h"
#include "GlLayer.h"
+#include "GlopBuilder.h"
+#include "Image.h"
#include "renderstate/RenderState.h"
#include "renderthread/EglManager.h"
#include "utils/GLUtils.h"
#include <GLES2/gl2.h>
+#include <gui/Surface.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
-#include <gui/Surface.h>
namespace android {
namespace uirenderer {
CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect,
- SkBitmap* bitmap) {
+ SkBitmap* bitmap) {
ATRACE_CALL();
// Setup the source
sp<GraphicBuffer> sourceBuffer;
sp<Fence> sourceFence;
Matrix4 texTransform;
- status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence,
- texTransform.data);
+ status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, texTransform.data);
texTransform.invalidateType();
if (err != NO_ERROR) {
ALOGW("Failed to get last queued buffer, error = %d", err);
@@ -64,7 +63,8 @@ CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect
}
CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
- Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap) {
+ Matrix4& texTransform, const Rect& srcRect,
+ SkBitmap* bitmap) {
mRenderThread.eglManager().initialize();
// TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via
// GL_OES_EGL_image, which doesn't work since we need samplerExternalOES
@@ -72,11 +72,11 @@ CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
// Create the EGLImage object that maps the GraphicBuffer
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- EGLClientBuffer clientBuffer = (EGLClientBuffer) graphicBuffer->getNativeBuffer();
- EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
+ EGLClientBuffer clientBuffer = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
+ EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
- EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
+ EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ clientBuffer, attrs);
if (sourceImage == EGL_NO_IMAGE_KHR) {
ALOGW("eglCreateImageKHR failed (%#x)", eglGetError());
@@ -85,8 +85,8 @@ CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
uint32_t width = graphicBuffer->getWidth();
uint32_t height = graphicBuffer->getHeight();
- CopyResult copyResult = copyImageInto(sourceImage, texTransform, width, height,
- srcRect, bitmap);
+ CopyResult copyResult =
+ copyImageInto(sourceImage, texTransform, width, height, srcRect, bitmap);
// All we're flushing & finishing is the deletion of the texture since
// copyImageInto already did a major flush & finish as an implicit
@@ -105,10 +105,7 @@ CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, S
}
static float sFlipVInit[16] = {
- 1, 0, 0, 0,
- 0, -1, 0, 0,
- 0, 0, 1, 0,
- 0, 1, 0, 1,
+ 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1,
};
static const Matrix4 sFlipV(sFlipVInit);
@@ -116,20 +113,19 @@ static const Matrix4 sFlipV(sFlipVInit);
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
-inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
- Texture& sourceTexture, const Matrix4& texTransform, const Rect& srcRect,
- SkBitmap* bitmap) {
+inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState, Texture& sourceTexture,
+ const Matrix4& texTransform, const Rect& srcRect,
+ SkBitmap* bitmap) {
int destWidth = bitmap->width();
int destHeight = bitmap->height();
- if (destWidth > caches.maxTextureSize
- || destHeight > caches.maxTextureSize) {
- ALOGW("Can't copy surface into bitmap, %dx%d exceeds max texture size %d",
- destWidth, destHeight, caches.maxTextureSize);
+ if (destWidth > caches.maxTextureSize || destHeight > caches.maxTextureSize) {
+ ALOGW("Can't copy surface into bitmap, %dx%d exceeds max texture size %d", destWidth,
+ destHeight, caches.maxTextureSize);
return CopyResult::DestinationInvalid;
}
if (bitmap->colorType() == kRGBA_F16_SkColorType &&
- !caches.extensions().hasRenderableFloatTextures()) {
+ !caches.extensions().hasRenderableFloatTextures()) {
ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
return CopyResult::DestinationInvalid;
}
@@ -189,10 +185,8 @@ inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, destWidth, destHeight,
- 0, format, type, nullptr);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, texture, 0);
+ glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, destWidth, destHeight, 0, format, type, nullptr);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
{
bool requiresFilter;
@@ -209,15 +203,15 @@ inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
// GLES coordinates.
croppedTexTransform.multiply(sFlipV);
croppedTexTransform.translate(srcRect.left / sourceTexture.width(),
- srcRect.top / sourceTexture.height(), 0);
+ srcRect.top / sourceTexture.height(), 0);
croppedTexTransform.scale(srcRect.getWidth() / sourceTexture.width(),
- srcRect.getHeight() / sourceTexture.height(), 1);
+ srcRect.getHeight() / sourceTexture.height(), 1);
croppedTexTransform.multiply(sFlipV);
- requiresFilter = srcRect.getWidth() != (float) destWidth
- || srcRect.getHeight() != (float) destHeight;
+ requiresFilter = srcRect.getWidth() != (float)destWidth ||
+ srcRect.getHeight() != (float)destHeight;
} else {
- requiresFilter = sourceTexture.width() != (uint32_t) destWidth
- || sourceTexture.height() != (uint32_t) destHeight;
+ requiresFilter = sourceTexture.width() != (uint32_t)destWidth ||
+ sourceTexture.height() != (uint32_t)destHeight;
}
Glop glop;
GlopBuilder(renderState, caches, &glop)
@@ -232,8 +226,7 @@ inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
renderState.render(glop, ortho, false);
// TODO: We should convert to linear space when the target is RGBA16F
- glReadPixels(0, 0, bitmap->width(), bitmap->height(), format,
- type, bitmap->getPixels());
+ glReadPixels(0, 0, bitmap->width(), bitmap->height(), format, type, bitmap->getPixels());
bitmap->notifyPixelsChanged();
}
@@ -246,10 +239,9 @@ inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
return CopyResult::Success;
}
-CopyResult OpenGLReadbackImpl::copyImageInto(EGLImageKHR eglImage,
- const Matrix4& imgTransform, int imgWidth, int imgHeight, const Rect& srcRect,
- SkBitmap* bitmap) {
-
+CopyResult OpenGLReadbackImpl::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
+ int imgWidth, int imgHeight, const Rect& srcRect,
+ SkBitmap* bitmap) {
// If this is a 90 or 270 degree rotation we need to swap width/height
// This is a fuzzy way of checking that.
if (imgTransform[Matrix4::kSkewX] >= 0.5f || imgTransform[Matrix4::kSkewX] <= -0.5f) {
@@ -271,26 +263,25 @@ CopyResult OpenGLReadbackImpl::copyImageInto(EGLImageKHR eglImage,
Texture sourceTexture(caches);
sourceTexture.wrap(sourceTexId, imgWidth, imgHeight, 0, 0 /* total lie */,
- GL_TEXTURE_EXTERNAL_OES);
+ GL_TEXTURE_EXTERNAL_OES);
- CopyResult copyResult = copyTextureInto(caches, mRenderThread.renderState(),
- sourceTexture, imgTransform, srcRect, bitmap);
+ CopyResult copyResult = copyTextureInto(caches, mRenderThread.renderState(), sourceTexture,
+ imgTransform, srcRect, bitmap);
sourceTexture.deleteTexture();
return copyResult;
}
-bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread,
- GlLayer& layer, SkBitmap* bitmap) {
+bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread, GlLayer& layer,
+ SkBitmap* bitmap) {
if (!layer.isRenderable()) {
// layer has never been updated by DeferredLayerUpdater, abort copy
return false;
}
- return CopyResult::Success == copyTextureInto(Caches::getInstance(),
- renderThread.renderState(), layer.getTexture(), layer.getTexTransform(),
- Rect(), bitmap);
+ return CopyResult::Success == copyTextureInto(Caches::getInstance(), renderThread.renderState(),
+ layer.getTexture(), layer.getTexTransform(),
+ Rect(), bitmap);
}
-
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/OpenGLReadback.h b/libs/hwui/OpenGLReadback.h
index 403f2e34d515..ca40738b4901 100644
--- a/libs/hwui/OpenGLReadback.h
+++ b/libs/hwui/OpenGLReadback.h
@@ -30,19 +30,21 @@ class GlLayer;
class OpenGLReadback : public Readback {
public:
virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
- SkBitmap* bitmap) override;
+ SkBitmap* bitmap) override;
virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
- SkBitmap* bitmap) override;
+ SkBitmap* bitmap) override;
protected:
explicit OpenGLReadback(renderthread::RenderThread& thread) : Readback(thread) {}
virtual ~OpenGLReadback() {}
virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
- int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) = 0;
+ int imgWidth, int imgHeight, const Rect& srcRect,
+ SkBitmap* bitmap) = 0;
+
private:
CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform,
- const Rect& srcRect, SkBitmap* bitmap);
+ const Rect& srcRect, SkBitmap* bitmap);
};
class OpenGLReadbackImpl : public OpenGLReadback {
@@ -53,12 +55,13 @@ public:
* Copies the layer's contents into the provided bitmap.
*/
static bool copyLayerInto(renderthread::RenderThread& renderThread, GlLayer& layer,
- SkBitmap* bitmap);
+ SkBitmap* bitmap);
protected:
virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
- int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) override;
+ int imgWidth, int imgHeight, const Rect& srcRect,
+ SkBitmap* bitmap) override;
};
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h
index 922ff7caecb8..77d7bef9c9e1 100644
--- a/libs/hwui/Outline.h
+++ b/libs/hwui/Outline.h
@@ -26,27 +26,14 @@ namespace uirenderer {
class Outline {
public:
- enum class Type {
- None = 0,
- Empty = 1,
- ConvexPath = 2,
- RoundRect = 3
- };
-
- Outline()
- : mShouldClip(false)
- , mType(Type::None)
- , mRadius(0)
- , mAlpha(0.0f) {}
+ enum class Type { None = 0, Empty = 1, ConvexPath = 2, RoundRect = 3 };
+
+ Outline() : mShouldClip(false), mType(Type::None), mRadius(0), mAlpha(0.0f) {}
void setRoundRect(int left, int top, int right, int bottom, float radius, float alpha) {
mAlpha = alpha;
- if (mType == Type::RoundRect
- && left == mBounds.left
- && right == mBounds.right
- && top == mBounds.top
- && bottom == mBounds.bottom
- && radius == mRadius) {
+ if (mType == Type::RoundRect && left == mBounds.left && right == mBounds.right &&
+ top == mBounds.top && bottom == mBounds.bottom && radius == mRadius) {
// nothing to change, don't do any work
return;
}
@@ -58,8 +45,7 @@ public:
// update mPath to reflect new outline
mPath.reset();
if (MathUtils::isPositive(radius)) {
- mPath.addRoundRect(SkRect::MakeLTRB(left, top, right, bottom),
- radius, radius);
+ mPath.addRoundRect(SkRect::MakeLTRB(left, top, right, bottom), radius, radius);
} else {
mPath.addRect(left, top, right, bottom);
}
@@ -88,21 +74,13 @@ public:
mAlpha = 0.0f;
}
- bool isEmpty() const {
- return mType == Type::Empty;
- }
+ bool isEmpty() const { return mType == Type::Empty; }
- float getAlpha() const {
- return mAlpha;
- }
+ float getAlpha() const { return mAlpha; }
- void setShouldClip(bool clip) {
- mShouldClip = clip;
- }
+ void setShouldClip(bool clip) { mShouldClip = clip; }
- bool getShouldClip() const {
- return mShouldClip;
- }
+ bool getShouldClip() const { return mShouldClip; }
bool willClip() const {
// only round rect outlines can be used for clipping
@@ -129,17 +107,11 @@ public:
return &mPath;
}
- Type getType() const {
- return mType;
- }
+ Type getType() const { return mType; }
- const Rect& getBounds() const {
- return mBounds;
- }
+ const Rect& getBounds() const { return mBounds; }
- float getRadius() const {
- return mRadius;
- }
+ float getRadius() const { return mRadius; }
private:
bool mShouldClip;
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index b471e7850a99..c243dad01f04 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -21,8 +21,8 @@
#include "UvMapper.h"
#include "utils/MathUtils.h"
-#include <algorithm>
#include <utils/Log.h>
+#include <algorithm>
namespace android {
namespace uirenderer {
@@ -35,10 +35,9 @@ uint32_t Patch::getSize() const {
return verticesCount * sizeof(TextureVertex);
}
-Patch::Patch(const float bitmapWidth, const float bitmapHeight,
- float width, float height, const UvMapper& mapper, const Res_png_9patch* patch)
+Patch::Patch(const float bitmapWidth, const float bitmapHeight, float width, float height,
+ const UvMapper& mapper, const Res_png_9patch* patch)
: mColors(patch->getColors()) {
-
int8_t emptyQuads = 0;
const int8_t numColors = patch->numColors;
if (uint8_t(numColors) < sizeof(uint32_t) * 4) {
@@ -121,8 +120,8 @@ Patch::Patch(const float bitmapWidth, const float bitmapHeight,
v1 += vOffset / bitmapHeight;
if (stepY > 0.0f) {
- generateRow(xDivs, xCount, vertex, y1, y2, v1, v2, stretchX, rescaleX,
- width, bitmapWidth, quadCount);
+ generateRow(xDivs, xCount, vertex, y1, y2, v1, v2, stretchX, rescaleX, width,
+ bitmapWidth, quadCount);
}
y1 = y2;
@@ -133,8 +132,8 @@ Patch::Patch(const float bitmapWidth, const float bitmapHeight,
if (previousStepY != bitmapHeight) {
y2 = height;
- generateRow(xDivs, xCount, vertex, y1, y2, v1, 1.0f, stretchX, rescaleX,
- width, bitmapWidth, quadCount);
+ generateRow(xDivs, xCount, vertex, y1, y2, v1, 1.0f, stretchX, rescaleX, width, bitmapWidth,
+ quadCount);
}
if (verticesCount != maxVertices) {
@@ -144,9 +143,9 @@ Patch::Patch(const float bitmapWidth, const float bitmapHeight,
}
}
-void Patch::generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex,
- float y1, float y2, float v1, float v2, float stretchX, float rescaleX,
- float width, float bitmapWidth, uint32_t& quadCount) {
+void Patch::generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex, float y1,
+ float y2, float v1, float v2, float stretchX, float rescaleX, float width,
+ float bitmapWidth, uint32_t& quadCount) {
float previousStepX = 0.0f;
float x1 = 0.0f;
@@ -184,8 +183,8 @@ void Patch::generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& v
}
}
-void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
- float u1, float v1, float u2, float v2, uint32_t& quadCount) {
+void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2, float u1,
+ float v1, float u2, float v2, uint32_t& quadCount) {
const uint32_t oldQuadCount = quadCount;
quadCount++;
@@ -226,5 +225,5 @@ void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, f
#endif
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index f04416ccabf9..a659ed227bec 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -39,9 +39,8 @@ struct TextureVertex;
class Patch {
public:
- Patch(const float bitmapWidth, const float bitmapHeight,
- float width, float height,
- const UvMapper& mapper, const Res_png_9patch* patch);
+ Patch(const float bitmapWidth, const float bitmapHeight, float width, float height,
+ const UvMapper& mapper, const Res_png_9patch* patch);
/**
* Returns the size of this patch's mesh in bytes.
@@ -58,17 +57,17 @@ public:
GLintptr textureOffset = 0;
private:
- void generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex,
- float y1, float y2, float v1, float v2, float stretchX, float rescaleX,
- float width, float bitmapWidth, uint32_t& quadCount);
- void generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
- float u1, float v1, float u2, float v2, uint32_t& quadCount);
+ void generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex, float y1,
+ float y2, float v1, float v2, float stretchX, float rescaleX, float width,
+ float bitmapWidth, uint32_t& quadCount);
+ void generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2, float u1,
+ float v1, float u2, float v2, uint32_t& quadCount);
const uint32_t* mColors;
UvMapper mUvMapper;
-}; // struct Patch
+}; // struct Patch
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_PATCH_H
+#endif // ANDROID_HWUI_PATCH_H
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index 78c7eb9ad809..673d73c5475d 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -56,7 +56,7 @@ hash_t PatchCache::PatchDescription::hash() const {
}
int PatchCache::PatchDescription::compare(const PatchCache::PatchDescription& lhs,
- const PatchCache::PatchDescription& rhs) {
+ const PatchCache::PatchDescription& rhs) {
return memcmp(&lhs, &rhs, sizeof(PatchDescription));
}
@@ -115,7 +115,7 @@ void PatchCache::removeDeferred(Res_png_9patch* patch) {
void PatchCache::clearGarbage() {
Vector<patch_pair_t> patchesToRemove;
- { // scope for the mutex
+ { // scope for the mutex
Mutex::Autolock _l(mLock);
size_t count = mGarbage.size();
for (size_t i = 0; i < count; i++) {
@@ -123,7 +123,7 @@ void PatchCache::clearGarbage() {
remove(patchesToRemove, patch);
// A Res_png_9patch is actually an array of byte that's larger
// than sizeof(Res_png_9patch). It must be freed as an array.
- delete[] (int8_t*) patch;
+ delete[](int8_t*) patch;
}
mGarbage.clear();
}
@@ -153,8 +153,8 @@ void PatchCache::clearGarbage() {
}
void PatchCache::createVertexBuffer() {
- mRenderState.meshState().genOrUpdateMeshBuffer(&mMeshBuffer,
- mMaxSize, nullptr, GL_DYNAMIC_DRAW);
+ mRenderState.meshState().genOrUpdateMeshBuffer(&mMeshBuffer, mMaxSize, nullptr,
+ GL_DYNAMIC_DRAW);
mSize = 0;
mFreeBlocks = new BufferBlock(0, mMaxSize);
}
@@ -198,11 +198,11 @@ void PatchCache::setupMesh(Patch* newMesh) {
}
// Copy the 9patch mesh in the VBO
- newMesh->positionOffset = (GLintptr) (block->offset);
+ newMesh->positionOffset = (GLintptr)(block->offset);
newMesh->textureOffset = newMesh->positionOffset + kMeshTextureOffset;
mRenderState.meshState().updateMeshBufferSubData(mMeshBuffer, newMesh->positionOffset, size,
- newMesh->vertices.get());
+ newMesh->vertices.get());
// Remove the block since we've used it entirely
if (block->size == size) {
@@ -223,15 +223,15 @@ void PatchCache::setupMesh(Patch* newMesh) {
static const UvMapper sIdentity;
-const Patch* PatchCache::get( const uint32_t bitmapWidth, const uint32_t bitmapHeight,
- const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch) {
-
+const Patch* PatchCache::get(const uint32_t bitmapWidth, const uint32_t bitmapHeight,
+ const float pixelWidth, const float pixelHeight,
+ const Res_png_9patch* patch) {
const PatchDescription description(bitmapWidth, bitmapHeight, pixelWidth, pixelHeight, patch);
const Patch* mesh = mCache.get(description);
if (!mesh) {
- Patch* newMesh = new Patch(bitmapWidth, bitmapHeight,
- pixelWidth, pixelHeight, sIdentity, patch);
+ Patch* newMesh =
+ new Patch(bitmapWidth, bitmapHeight, pixelWidth, pixelHeight, sIdentity, patch);
if (newMesh->vertices) {
setupMesh(newMesh);
@@ -260,5 +260,5 @@ void PatchCache::dumpFreeBlocks(const char* prefix) {
}
#endif
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index aa746c7dfa15..273c3f56f2cd 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -36,9 +36,9 @@ class Patch;
// Debug
#if DEBUG_PATCHES
- #define PATCH_LOGD(...) ALOGD(__VA_ARGS__)
+#define PATCH_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define PATCH_LOGD(...)
+#define PATCH_LOGD(...)
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -54,20 +54,14 @@ public:
~PatchCache();
const Patch* get(const uint32_t bitmapWidth, const uint32_t bitmapHeight,
- const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch);
+ const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch);
void clear();
- uint32_t getSize() const {
- return mSize;
- }
+ uint32_t getSize() const { return mSize; }
- uint32_t getMaxSize() const {
- return mMaxSize;
- }
+ uint32_t getMaxSize() const { return mMaxSize; }
- GLuint getMeshBuffer() const {
- return mMeshBuffer;
- }
+ GLuint getMeshBuffer() const { return mMeshBuffer; }
/**
* Removes the entries associated with the specified 9-patch. This is meant
@@ -81,18 +75,23 @@ public:
*/
void clearGarbage();
-
private:
struct PatchDescription {
- PatchDescription(): mPatch(nullptr), mBitmapWidth(0), mBitmapHeight(0),
- mPixelWidth(0), mPixelHeight(0) {
- }
+ PatchDescription()
+ : mPatch(nullptr)
+ , mBitmapWidth(0)
+ , mBitmapHeight(0)
+ , mPixelWidth(0)
+ , mPixelHeight(0) {}
PatchDescription(const uint32_t bitmapWidth, const uint32_t bitmapHeight,
- const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch):
- mPatch(patch), mBitmapWidth(bitmapWidth), mBitmapHeight(bitmapHeight),
- mPixelWidth(pixelWidth), mPixelHeight(pixelHeight) {
- }
+ const float pixelWidth, const float pixelHeight,
+ const Res_png_9patch* patch)
+ : mPatch(patch)
+ , mBitmapWidth(bitmapWidth)
+ , mBitmapHeight(bitmapHeight)
+ , mPixelWidth(pixelWidth)
+ , mPixelHeight(pixelHeight) {}
hash_t hash() const;
@@ -100,27 +99,20 @@ private:
static int compare(const PatchDescription& lhs, const PatchDescription& rhs);
- bool operator==(const PatchDescription& other) const {
- return compare(*this, other) == 0;
- }
+ bool operator==(const PatchDescription& other) const { return compare(*this, other) == 0; }
- bool operator!=(const PatchDescription& other) const {
- return compare(*this, other) != 0;
- }
+ bool operator!=(const PatchDescription& other) const { return compare(*this, other) != 0; }
friend inline int strictly_order_type(const PatchDescription& lhs,
- const PatchDescription& rhs) {
+ const PatchDescription& rhs) {
return PatchDescription::compare(lhs, rhs) < 0;
}
- friend inline int compare_type(const PatchDescription& lhs,
- const PatchDescription& rhs) {
+ friend inline int compare_type(const PatchDescription& lhs, const PatchDescription& rhs) {
return PatchDescription::compare(lhs, rhs);
}
- friend inline hash_t hash_type(const PatchDescription& entry) {
- return entry.hash();
- }
+ friend inline hash_t hash_type(const PatchDescription& entry) { return entry.hash(); }
private:
const Res_png_9patch* mPatch;
@@ -129,7 +121,7 @@ private:
float mPixelWidth;
float mPixelHeight;
- }; // struct PatchDescription
+ }; // struct PatchDescription
/**
* A buffer block represents an empty range in the mesh buffer
@@ -139,14 +131,13 @@ private:
* to track available regions of memory in the VBO.
*/
struct BufferBlock {
- BufferBlock(uint32_t offset, uint32_t size): offset(offset), size(size), next(nullptr) {
- }
+ BufferBlock(uint32_t offset, uint32_t size) : offset(offset), size(size), next(nullptr) {}
uint32_t offset;
uint32_t size;
BufferBlock* next;
- }; // struct BufferBlock
+ }; // struct BufferBlock
typedef Pair<const PatchDescription*, Patch*> patch_pair_t;
@@ -174,7 +165,7 @@ private:
// Garbage tracking, required to handle GC events on the VM side
Vector<Res_png_9patch*> mGarbage;
mutable Mutex mLock;
-}; // class PatchCache
+}; // class PatchCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 8d4ae1b6622a..e67c5bddd354 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -46,13 +46,14 @@ static bool compareWidthHeight(const T& lhs, const T& rhs) {
}
static bool compareRoundRects(const PathDescription::Shape::RoundRect& lhs,
- const PathDescription::Shape::RoundRect& rhs) {
+ const PathDescription::Shape::RoundRect& rhs) {
return compareWidthHeight(lhs, rhs) && lhs.mRx == rhs.mRx && lhs.mRy == rhs.mRy;
}
-static bool compareArcs(const PathDescription::Shape::Arc& lhs, const PathDescription::Shape::Arc& rhs) {
+static bool compareArcs(const PathDescription::Shape::Arc& lhs,
+ const PathDescription::Shape::Arc& rhs) {
return compareWidthHeight(lhs, rhs) && lhs.mStartAngle == rhs.mStartAngle &&
- lhs.mSweepAngle == rhs.mSweepAngle && lhs.mUseCenter == rhs.mUseCenter;
+ lhs.mSweepAngle == rhs.mSweepAngle && lhs.mUseCenter == rhs.mUseCenter;
}
///////////////////////////////////////////////////////////////////////////////
@@ -91,7 +92,7 @@ hash_t PathDescription::hash() const {
hash = JenkinsHashMix(hash, android::hash_type(miter));
hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
hash = JenkinsHashMix(hash, android::hash_type(pathEffect));
- hash = JenkinsHashMixBytes(hash, (uint8_t*) &shape, sizeof(Shape));
+ hash = JenkinsHashMixBytes(hash, (uint8_t*)&shape, sizeof(Shape));
return JenkinsHashWhiten(hash);
}
@@ -126,7 +127,7 @@ bool PathDescription::operator==(const PathDescription& rhs) const {
///////////////////////////////////////////////////////////////////////////////
static void computePathBounds(const SkPath* path, const SkPaint* paint, PathTexture* texture,
- uint32_t& width, uint32_t& height) {
+ uint32_t& width, uint32_t& height) {
const SkRect& bounds = path->getBounds();
const float pathWidth = std::max(bounds.width(), 1.0f);
const float pathHeight = std::max(bounds.height(), 1.0f);
@@ -134,7 +135,7 @@ static void computePathBounds(const SkPath* path, const SkPaint* paint, PathText
texture->left = floorf(bounds.fLeft);
texture->top = floorf(bounds.fTop);
- texture->offset = (int) floorf(std::max(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
+ texture->offset = (int)floorf(std::max(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
width = uint32_t(pathWidth + texture->offset * 2.0 + 0.5);
height = uint32_t(pathHeight + texture->offset * 2.0 + 0.5);
@@ -152,12 +153,12 @@ static void initPaint(SkPaint& paint) {
}
static sk_sp<Bitmap> drawPath(const SkPath* path, const SkPaint* paint, PathTexture* texture,
- uint32_t maxTextureSize) {
+ uint32_t maxTextureSize) {
uint32_t width, height;
computePathBounds(path, paint, texture, width, height);
if (width > maxTextureSize || height > maxTextureSize) {
- ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)",
- width, height, maxTextureSize, maxTextureSize);
+ ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)", width, height,
+ maxTextureSize, maxTextureSize);
return nullptr;
}
@@ -230,13 +231,13 @@ void PathCache::removeTexture(PathTexture* texture) {
// to the cache and the size wasn't increased
if (size > mSize) {
ALOGE("Removing path texture of size %d will leave "
- "the cache in an inconsistent state", size);
+ "the cache in an inconsistent state",
+ size);
}
mSize -= size;
}
- PATH_LOGD("PathCache::delete name, size, mSize = %d, %d, %d",
- texture->id, size, mSize);
+ PATH_LOGD("PathCache::delete name, size, mSize = %d, %d, %d", texture->id, size, mSize);
if (mDebugEnabled) {
ALOGD("Shape deleted, size = %d", size);
}
@@ -258,14 +259,16 @@ void PathCache::purgeCache(uint32_t width, uint32_t height) {
void PathCache::trim() {
while (mSize > mMaxSize || mCache.size() > PATH_CACHE_COUNT_LIMIT) {
- LOG_ALWAYS_FATAL_IF(!mCache.size(), "Inconsistent mSize! Ran out of items to remove!"
- " mSize = %u, mMaxSize = %u", mSize, mMaxSize);
+ LOG_ALWAYS_FATAL_IF(!mCache.size(),
+ "Inconsistent mSize! Ran out of items to remove!"
+ " mSize = %u, mMaxSize = %u",
+ mSize, mMaxSize);
mCache.removeOldest();
}
}
-PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *path,
- const SkPaint* paint) {
+PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath* path,
+ const SkPaint* paint) {
ATRACE_NAME("Generate Path Texture");
PathTexture* texture = new PathTexture(Caches::getInstance(), path->getGenerationID());
@@ -280,8 +283,8 @@ PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *p
return texture;
}
-void PathCache::generateTexture(const PathDescription& entry, Bitmap& bitmap,
- PathTexture* texture, bool addToCache) {
+void PathCache::generateTexture(const PathDescription& entry, Bitmap& bitmap, PathTexture* texture,
+ bool addToCache) {
generateTexture(bitmap, texture);
// Note here that we upload to a texture even if it's bigger than mMaxSize.
@@ -289,8 +292,7 @@ void PathCache::generateTexture(const PathDescription& entry, Bitmap& bitmap,
// immediately on trim, or on any other Path entering the cache.
uint32_t size = texture->width() * texture->height();
mSize += size;
- PATH_LOGD("PathCache::get/create: name, size, mSize = %d, %d, %d",
- texture->id, size, mSize);
+ PATH_LOGD("PathCache::get/create: name, size, mSize = %d, %d, %d", texture->id, size, mSize);
if (mDebugEnabled) {
ALOGD("Shape created, size = %d", size);
}
@@ -313,9 +315,8 @@ void PathCache::generateTexture(Bitmap& bitmap, Texture* texture) {
// Path precaching
///////////////////////////////////////////////////////////////////////////////
-PathCache::PathProcessor::PathProcessor(Caches& caches):
- TaskProcessor<sk_sp<Bitmap> >(&caches.tasks), mMaxTextureSize(caches.maxTextureSize) {
-}
+PathCache::PathProcessor::PathProcessor(Caches& caches)
+ : TaskProcessor<sk_sp<Bitmap> >(&caches.tasks), mMaxTextureSize(caches.maxTextureSize) {}
void PathCache::PathProcessor::onProcess(const sp<Task<sk_sp<Bitmap> > >& task) {
PathTask* t = static_cast<PathTask*>(task.get());
@@ -336,7 +337,7 @@ void PathCache::removeDeferred(const SkPath* path) {
void PathCache::clearGarbage() {
Vector<PathDescription> pathsToRemove;
- { // scope for the mutex
+ { // scope for the mutex
Mutex::Autolock l(mLock);
for (const uint32_t generationID : mGarbage) {
LruCache<PathDescription, PathTexture*>::Iterator iter(mCache);
@@ -433,8 +434,8 @@ void PathCache::precache(const SkPath* path, const SkPaint* paint) {
// Rounded rects
///////////////////////////////////////////////////////////////////////////////
-PathTexture* PathCache::getRoundRect(float width, float height,
- float rx, float ry, const SkPaint* paint) {
+PathTexture* PathCache::getRoundRect(float width, float height, float rx, float ry,
+ const SkPaint* paint) {
PathDescription entry(ShapeType::RoundRect, paint);
entry.shape.roundRect.mWidth = width;
entry.shape.roundRect.mHeight = height;
@@ -525,8 +526,8 @@ PathTexture* PathCache::getRect(float width, float height, const SkPaint* paint)
// Arcs
///////////////////////////////////////////////////////////////////////////////
-PathTexture* PathCache::getArc(float width, float height,
- float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) {
+PathTexture* PathCache::getArc(float width, float height, float startAngle, float sweepAngle,
+ bool useCenter, const SkPaint* paint) {
PathDescription entry(ShapeType::Arc, paint);
entry.shape.arc.mWidth = width;
entry.shape.arc.mHeight = height;
@@ -554,5 +555,5 @@ PathTexture* PathCache::getArc(float width, float height,
return texture;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index 7bd190df951b..28c8bbb8ca6e 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -47,9 +47,9 @@ class Caches;
// Debug
#if DEBUG_PATHS
- #define PATH_LOGD(...) ALOGD(__VA_ARGS__)
+#define PATH_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define PATH_LOGD(...)
+#define PATH_LOGD(...)
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -57,11 +57,10 @@ class Caches;
///////////////////////////////////////////////////////////////////////////////
struct PathTexture;
-class PathTask: public Task<sk_sp<Bitmap>> {
+class PathTask : public Task<sk_sp<Bitmap>> {
public:
- PathTask(const SkPath* path, const SkPaint* paint, PathTexture* texture):
- path(*path), paint(*paint), texture(texture) {
- }
+ PathTask(const SkPath* path, const SkPaint* paint, PathTexture* texture)
+ : path(*path), paint(*paint), texture(texture) {}
// copied, since input path not guaranteed to survive for duration of task
const SkPath path;
@@ -74,15 +73,10 @@ public:
/**
* Alpha texture used to represent a path.
*/
-struct PathTexture: public Texture {
- PathTexture(Caches& caches, int generation)
- : Texture(caches) {
- this->generation = generation;
- }
+struct PathTexture : public Texture {
+ PathTexture(Caches& caches, int generation) : Texture(caches) { this->generation = generation; }
- ~PathTexture() {
- clearTask();
- }
+ ~PathTexture() { clearTask(); }
/**
* Left coordinate of the path bounds.
@@ -97,13 +91,9 @@ struct PathTexture: public Texture {
*/
float offset = 0;
- sp<PathTask> task() const {
- return mTask;
- }
+ sp<PathTask> task() const { return mTask; }
- void setTask(const sp<PathTask>& task) {
- mTask = task;
- }
+ void setTask(const sp<PathTask>& task) { mTask = task; }
void clearTask() {
if (mTask != nullptr) {
@@ -113,17 +103,9 @@ struct PathTexture: public Texture {
private:
sp<PathTask> mTask;
-}; // struct PathTexture
-
-enum class ShapeType {
- None,
- Rect,
- RoundRect,
- Circle,
- Oval,
- Arc,
- Path
-};
+}; // struct PathTexture
+
+enum class ShapeType { None, Rect, RoundRect, Circle, Oval, Arc, Path };
struct PathDescription {
HASHABLE_TYPE(PathDescription);
@@ -173,7 +155,7 @@ struct PathDescription {
* Any texture added to the cache causing the cache to grow beyond the maximum
* allowed size will also cause the oldest texture to be kicked out.
*/
-class PathCache: public OnEntryRemoved<PathDescription, PathTexture*> {
+class PathCache : public OnEntryRemoved<PathDescription, PathTexture*> {
public:
PathCache();
~PathCache();
@@ -203,9 +185,9 @@ public:
PathTexture* getOval(float width, float height, const SkPaint* paint);
PathTexture* getRect(float width, float height, const SkPaint* paint);
PathTexture* getArc(float width, float height, float startAngle, float sweepAngle,
- bool useCenter, const SkPaint* paint);
+ bool useCenter, const SkPaint* paint);
PathTexture* get(const SkPath* path, const SkPaint* paint);
- void remove(const SkPath* path, const SkPaint* paint);
+ void remove(const SkPath* path, const SkPaint* paint);
/**
* Removes the specified path. This is meant to be called from threads
@@ -234,19 +216,16 @@ public:
void precache(const SkPath* path, const SkPaint* paint);
private:
- PathTexture* addTexture(const PathDescription& entry,
- const SkPath *path, const SkPaint* paint);
+ PathTexture* addTexture(const PathDescription& entry, const SkPath* path, const SkPaint* paint);
/**
* Generates the texture from a bitmap into the specified texture structure.
*/
void generateTexture(Bitmap& bitmap, Texture* texture);
void generateTexture(const PathDescription& entry, Bitmap& bitmap, PathTexture* texture,
- bool addToCache = true);
+ bool addToCache = true);
- PathTexture* get(const PathDescription& entry) {
- return mCache.get(entry);
- }
+ PathTexture* get(const PathDescription& entry) { return mCache.get(entry); }
/**
* Ensures there is enough space in the cache for a texture of the specified
@@ -258,13 +237,12 @@ private:
void init();
-
- class PathProcessor: public TaskProcessor<sk_sp<Bitmap> > {
+ class PathProcessor : public TaskProcessor<sk_sp<Bitmap>> {
public:
explicit PathProcessor(Caches& caches);
- ~PathProcessor() { }
+ ~PathProcessor() {}
- virtual void onProcess(const sp<Task<sk_sp<Bitmap> > >& task) override;
+ virtual void onProcess(const sp<Task<sk_sp<Bitmap>>>& task) override;
private:
uint32_t mMaxTextureSize;
@@ -281,9 +259,9 @@ private:
std::vector<uint32_t> mGarbage;
mutable Mutex mLock;
-}; // class PathCache
+}; // class PathCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_PATH_CACHE_H
+#endif // ANDROID_HWUI_PATH_CACHE_H
diff --git a/libs/hwui/PathParser.cpp b/libs/hwui/PathParser.cpp
index 2179f146115a..a48fdfc41c0c 100644
--- a/libs/hwui/PathParser.cpp
+++ b/libs/hwui/PathParser.cpp
@@ -19,9 +19,9 @@
#include "jni.h"
#include <errno.h>
+#include <stdlib.h>
#include <utils/Log.h>
#include <sstream>
-#include <stdlib.h>
#include <string>
#include <vector>
@@ -36,8 +36,8 @@ static size_t nextStart(const char* s, size_t length, size_t startIndex) {
// used for floating point numbers' scientific notation.
// Therefore, when searching for next command, we should ignore 'e'
// and 'E'.
- if ((((c - 'A') * (c - 'Z') <= 0) || ((c - 'a') * (c - 'z') <= 0))
- && c != 'e' && c != 'E') {
+ if ((((c - 'A') * (c - 'Z') <= 0) || ((c - 'a') * (c - 'z') <= 0)) && c != 'e' &&
+ c != 'E') {
return index;
}
index++;
@@ -52,7 +52,8 @@ static size_t nextStart(const char* s, size_t length, size_t startIndex) {
* @param result the result of the extraction, including the position of the
* the starting position of next number, whether it is ending with a '-'.
*/
-static void extract(int* outEndPosition, bool* outEndWithNegOrDot, const char* s, int start, int end) {
+static void extract(int* outEndPosition, bool* outEndWithNegOrDot, const char* s, int start,
+ int end) {
// Now looking for ' ', ',', '.' or '-' from the start.
int currentIndex = start;
bool foundSeparator = false;
@@ -64,30 +65,30 @@ static void extract(int* outEndPosition, bool* outEndWithNegOrDot, const char* s
isExponential = false;
char currentChar = s[currentIndex];
switch (currentChar) {
- case ' ':
- case ',':
- foundSeparator = true;
- break;
- case '-':
- // The negative sign following a 'e' or 'E' is not a separator.
- if (currentIndex != start && !isPrevExponential) {
- foundSeparator = true;
- *outEndWithNegOrDot = true;
- }
- break;
- case '.':
- if (!secondDot) {
- secondDot = true;
- } else {
- // This is the second dot, and it is considered as a separator.
+ case ' ':
+ case ',':
foundSeparator = true;
- *outEndWithNegOrDot = true;
- }
- break;
- case 'e':
- case 'E':
- isExponential = true;
- break;
+ break;
+ case '-':
+ // The negative sign following a 'e' or 'E' is not a separator.
+ if (currentIndex != start && !isPrevExponential) {
+ foundSeparator = true;
+ *outEndWithNegOrDot = true;
+ }
+ break;
+ case '.':
+ if (!secondDot) {
+ secondDot = true;
+ } else {
+ // This is the second dot, and it is considered as a separator.
+ foundSeparator = true;
+ *outEndWithNegOrDot = true;
+ }
+ break;
+ case 'e':
+ case 'E':
+ isExponential = true;
+ break;
}
if (foundSeparator) {
break;
@@ -98,7 +99,8 @@ static void extract(int* outEndPosition, bool* outEndWithNegOrDot, const char* s
*outEndPosition = currentIndex;
}
-static float parseFloat(PathParser::ParseResult* result, const char* startPtr, size_t expectedLength) {
+static float parseFloat(PathParser::ParseResult* result, const char* startPtr,
+ size_t expectedLength) {
char* endPtr = NULL;
float currentValue = strtof(startPtr, &endPtr);
if ((currentValue == HUGE_VALF || currentValue == -HUGE_VALF) && errno == ERANGE) {
@@ -122,8 +124,7 @@ static float parseFloat(PathParser::ParseResult* result, const char* startPtr, s
* @return true on success
*/
static void getFloats(std::vector<float>* outPoints, PathParser::ParseResult* result,
- const char* pathStr, int start, int end) {
-
+ const char* pathStr, int start, int end) {
if (pathStr[start] == 'z' || pathStr[start] == 'Z') {
return;
}
@@ -138,8 +139,7 @@ static void getFloats(std::vector<float>* outPoints, PathParser::ParseResult* re
extract(&endPosition, &endWithNegOrDot, pathStr, startPosition, end);
if (startPosition < endPosition) {
- float currentValue = parseFloat(result, &pathStr[startPosition],
- end - startPosition);
+ float currentValue = parseFloat(result, &pathStr[startPosition], end - startPosition);
if (result->failureOccurred) {
return;
}
@@ -158,12 +158,12 @@ static void getFloats(std::vector<float>* outPoints, PathParser::ParseResult* re
bool PathParser::isVerbValid(char verb) {
verb = tolower(verb);
- return verb == 'a' || verb == 'c' || verb == 'h' || verb == 'l' || verb == 'm' || verb == 'q'
- || verb == 's' || verb == 't' || verb == 'v' || verb == 'z';
+ return verb == 'a' || verb == 'c' || verb == 'h' || verb == 'l' || verb == 'm' || verb == 'q' ||
+ verb == 's' || verb == 't' || verb == 'v' || verb == 'z';
}
void PathParser::getPathDataFromAsciiString(PathData* data, ParseResult* result,
- const char* pathStr, size_t strLen) {
+ const char* pathStr, size_t strLen) {
if (pathStr == NULL) {
result->failureOccurred = true;
result->failureMessage = "Path string cannot be NULL.";
@@ -188,8 +188,8 @@ void PathParser::getPathDataFromAsciiString(PathData* data, ParseResult* result,
getFloats(&points, result, pathStr, start, end);
if (!isVerbValid(pathStr[start])) {
result->failureOccurred = true;
- result->failureMessage = "Invalid pathData. Failure occurred at position "
- + std::to_string(start) + " of path: " + pathStr;
+ result->failureMessage = "Invalid pathData. Failure occurred at position " +
+ std::to_string(start) + " of path: " + pathStr;
}
// If either verb or points is not valid, return immediately.
if (result->failureOccurred) {
@@ -205,8 +205,8 @@ void PathParser::getPathDataFromAsciiString(PathData* data, ParseResult* result,
if ((end - start) == 1 && start < strLen) {
if (!isVerbValid(pathStr[start])) {
result->failureOccurred = true;
- result->failureMessage = "Invalid pathData. Failure occurred at position "
- + std::to_string(start) + " of path: " + pathStr;
+ result->failureMessage = "Invalid pathData. Failure occurred at position " +
+ std::to_string(start) + " of path: " + pathStr;
return;
}
data->verbs.push_back(pathStr[start]);
@@ -235,7 +235,8 @@ void PathParser::dump(const PathData& data) {
ALOGD("points are : %s", os.str().c_str());
}
-void PathParser::parseAsciiStringForSkPath(SkPath* skPath, ParseResult* result, const char* pathStr, size_t strLen) {
+void PathParser::parseAsciiStringForSkPath(SkPath* skPath, ParseResult* result, const char* pathStr,
+ size_t strLen) {
PathData pathData;
getPathDataFromAsciiString(&pathData, result, pathStr, strLen);
if (result->failureOccurred) {
@@ -252,5 +253,5 @@ void PathParser::parseAsciiStringForSkPath(SkPath* skPath, ParseResult* result,
return;
}
-}; // namespace uirenderer
-}; //namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/PathParser.h b/libs/hwui/PathParser.h
index 5578e8d42e2f..e4ec7be5ee8e 100644
--- a/libs/hwui/PathParser.h
+++ b/libs/hwui/PathParser.h
@@ -20,16 +20,15 @@
#include "VectorDrawable.h"
#include "utils/VectorDrawableUtils.h"
-#include <jni.h>
#include <android/log.h>
#include <cutils/compiler.h>
+#include <jni.h>
#include <string>
namespace android {
namespace uirenderer {
-
class PathParser {
public:
struct ANDROID_API ParseResult {
@@ -40,13 +39,13 @@ public:
* Parse the string literal and create a Skia Path. Return true on success.
*/
ANDROID_API static void parseAsciiStringForSkPath(SkPath* outPath, ParseResult* result,
- const char* pathStr, size_t strLength);
+ const char* pathStr, size_t strLength);
ANDROID_API static void getPathDataFromAsciiString(PathData* outData, ParseResult* result,
- const char* pathStr, size_t strLength);
+ const char* pathStr, size_t strLength);
static void dump(const PathData& data);
static bool isVerbValid(char verb);
};
-}; // namespace uirenderer
-}; // namespace android
-#endif //ANDROID_HWUI_PATHPARSER_H
+}; // namespace uirenderer
+}; // namespace android
+#endif // ANDROID_HWUI_PATHPARSER_H
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index 64b2c4564d7b..973b1d14b77e 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -18,13 +18,12 @@
#define VERTEX_DEBUG 0
#if VERTEX_DEBUG
-#define DEBUG_DUMP_ALPHA_BUFFER() \
- for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { \
- ALOGD("point %d at %f %f, alpha %f", \
- i, buffer[i].x, buffer[i].y, buffer[i].alpha); \
+#define DEBUG_DUMP_ALPHA_BUFFER() \
+ for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { \
+ ALOGD("point %d at %f %f, alpha %f", i, buffer[i].x, buffer[i].y, buffer[i].alpha); \
}
-#define DEBUG_DUMP_BUFFER() \
- for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { \
+#define DEBUG_DUMP_BUFFER() \
+ for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { \
ALOGD("point %d at %f %f", i, buffer[i].x, buffer[i].y); \
}
#else
@@ -41,13 +40,13 @@
#include <algorithm>
-#include <SkPath.h>
+#include <SkGeometry.h> // WARNING: Internal Skia Header
#include <SkPaint.h>
+#include <SkPath.h>
#include <SkPoint.h>
-#include <SkGeometry.h> // WARNING: Internal Skia Header
-#include <stdlib.h>
#include <stdint.h>
+#include <stdlib.h>
#include <sys/types.h>
#include <utils/Log.h>
@@ -64,8 +63,8 @@ namespace uirenderer {
/**
* Extracts the x and y scale from the transform as positive values, and clamps them
*/
-void PathTessellator::extractTessellationScales(const Matrix4& transform,
- float* scaleX, float* scaleY) {
+void PathTessellator::extractTessellationScales(const Matrix4& transform, float* scaleX,
+ float* scaleY) {
if (CC_LIKELY(transform.isPureTranslate())) {
*scaleX = 1.0f;
*scaleY = 1.0f;
@@ -98,9 +97,12 @@ inline static Vector2 totalOffsetFromNormals(const Vector2& normalA, const Vecto
*/
struct PaintInfo {
public:
- PaintInfo(const SkPaint* paint, const mat4& transform) :
- style(paint->getStyle()), cap(paint->getStrokeCap()), isAA(paint->isAntiAlias()),
- halfStrokeWidth(paint->getStrokeWidth() * 0.5f), maxAlpha(1.0f) {
+ PaintInfo(const SkPaint* paint, const mat4& transform)
+ : style(paint->getStyle())
+ , cap(paint->getStrokeCap())
+ , isAA(paint->isAntiAlias())
+ , halfStrokeWidth(paint->getStrokeWidth() * 0.5f)
+ , maxAlpha(1.0f) {
// compute inverse scales
if (CC_LIKELY(transform.isPureTranslate())) {
inverseScaleX = 1.0f;
@@ -113,7 +115,7 @@ public:
}
if (isAA && halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
- 2 * halfStrokeWidth < inverseScaleX) {
+ 2 * halfStrokeWidth < inverseScaleX) {
// AA, with non-hairline stroke, width < 1 pixel. Scale alpha and treat as hairline.
maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX;
halfStrokeWidth = 0.0f;
@@ -171,17 +173,17 @@ public:
if (halfStrokeWidth == 0) {
// hairline, outset by (0.5f + fudge factor) in post-scaling space
bounds->outset(fabs(inverseScaleX) * (0.5f + Vertex::GeometryFudgeFactor()),
- fabs(inverseScaleY) * (0.5f + Vertex::GeometryFudgeFactor()));
+ fabs(inverseScaleY) * (0.5f + Vertex::GeometryFudgeFactor()));
} else {
// non hairline, outset by half stroke width pre-scaled, and fudge factor post scaled
bounds->outset(halfStrokeWidth + fabs(inverseScaleX) * Vertex::GeometryFudgeFactor(),
- halfStrokeWidth + fabs(inverseScaleY) * Vertex::GeometryFudgeFactor());
+ halfStrokeWidth + fabs(inverseScaleY) * Vertex::GeometryFudgeFactor());
}
}
};
void getFillVerticesFromPerimeter(const std::vector<Vertex>& perimeter,
- VertexBuffer& vertexBuffer) {
+ VertexBuffer& vertexBuffer) {
Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size());
int currentIndex = 0;
@@ -206,7 +208,8 @@ void getFillVerticesFromPerimeter(const std::vector<Vertex>& perimeter,
* (for a total of perimeter.size() * 2 + 2 vertices)
*/
void getStrokeVerticesFromPerimeter(const PaintInfo& paintInfo,
- const std::vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) {
+ const std::vector<Vertex>& perimeter,
+ VertexBuffer& vertexBuffer) {
Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size() * 2 + 2);
int currentIndex = 0;
@@ -222,13 +225,11 @@ void getStrokeVerticesFromPerimeter(const PaintInfo& paintInfo,
Vector2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
paintInfo.scaleOffsetForStrokeWidth(totalOffset);
- Vertex::set(&buffer[currentIndex++],
- current->x + totalOffset.x,
- current->y + totalOffset.y);
+ Vertex::set(&buffer[currentIndex++], current->x + totalOffset.x,
+ current->y + totalOffset.y);
- Vertex::set(&buffer[currentIndex++],
- current->x - totalOffset.x,
- current->y - totalOffset.y);
+ Vertex::set(&buffer[currentIndex++], current->x - totalOffset.x,
+ current->y - totalOffset.y);
current = next;
lastNormal = nextNormal;
@@ -242,7 +243,8 @@ void getStrokeVerticesFromPerimeter(const PaintInfo& paintInfo,
}
static inline void storeBeginEnd(const PaintInfo& paintInfo, const Vertex& center,
- const Vector2& normal, Vertex* buffer, int& currentIndex, bool begin) {
+ const Vector2& normal, Vertex* buffer, int& currentIndex,
+ bool begin) {
Vector2 strokeOffset = normal;
paintInfo.scaleOffsetForStrokeWidth(strokeOffset);
@@ -264,7 +266,8 @@ static inline void storeBeginEnd(const PaintInfo& paintInfo, const Vertex& cente
* 2 - can zig-zag across 'extra' vertices at either end, to create round caps
*/
void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo,
- const std::vector<Vertex>& vertices, VertexBuffer& vertexBuffer) {
+ const std::vector<Vertex>& vertices,
+ VertexBuffer& vertexBuffer) {
const int extra = paintInfo.capExtraDivisions();
const int allocSize = (vertices.size() + extra) * 2;
Vertex* buffer = vertexBuffer.alloc<Vertex>(allocSize);
@@ -272,12 +275,9 @@ void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo,
const int lastIndex = vertices.size() - 1;
if (extra > 0) {
// tessellate both round caps
- float beginTheta = atan2(
- - (vertices[0].x - vertices[1].x),
- vertices[0].y - vertices[1].y);
- float endTheta = atan2(
- - (vertices[lastIndex].x - vertices[lastIndex - 1].x),
- vertices[lastIndex].y - vertices[lastIndex - 1].y);
+ float beginTheta = atan2(-(vertices[0].x - vertices[1].x), vertices[0].y - vertices[1].y);
+ float endTheta = atan2(-(vertices[lastIndex].x - vertices[lastIndex - 1].x),
+ vertices[lastIndex].y - vertices[lastIndex - 1].y);
const float dTheta = PI / (extra + 1);
int capOffset;
@@ -291,16 +291,15 @@ void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo,
beginTheta += dTheta;
Vector2 beginRadialOffset = {cosf(beginTheta), sinf(beginTheta)};
paintInfo.scaleOffsetForStrokeWidth(beginRadialOffset);
- Vertex::set(&buffer[capOffset],
- vertices[0].x + beginRadialOffset.x,
- vertices[0].y + beginRadialOffset.y);
+ Vertex::set(&buffer[capOffset], vertices[0].x + beginRadialOffset.x,
+ vertices[0].y + beginRadialOffset.y);
endTheta += dTheta;
Vector2 endRadialOffset = {cosf(endTheta), sinf(endTheta)};
paintInfo.scaleOffsetForStrokeWidth(endRadialOffset);
Vertex::set(&buffer[allocSize - 1 - capOffset],
- vertices[lastIndex].x + endRadialOffset.x,
- vertices[lastIndex].y + endRadialOffset.y);
+ vertices[lastIndex].x + endRadialOffset.x,
+ vertices[lastIndex].y + endRadialOffset.y);
}
}
@@ -317,7 +316,7 @@ void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo,
Vector2 nextNormal = {next->y - current->y, current->x - next->x};
nextNormal.normalize();
- Vector2 strokeOffset = totalOffsetFromNormals(lastNormal, nextNormal);
+ Vector2 strokeOffset = totalOffsetFromNormals(lastNormal, nextNormal);
paintInfo.scaleOffsetForStrokeWidth(strokeOffset);
Vector2 center = {current->x, current->y};
@@ -344,8 +343,8 @@ void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo,
* 3 - zig zag back and forth inside the shape to fill it (using perimeter.size() vertices)
*/
void getFillVerticesFromPerimeterAA(const PaintInfo& paintInfo,
- const std::vector<Vertex>& perimeter, VertexBuffer& vertexBuffer,
- float maxAlpha = 1.0f) {
+ const std::vector<Vertex>& perimeter,
+ VertexBuffer& vertexBuffer, float maxAlpha = 1.0f) {
AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(perimeter.size() * 3 + 2);
// generate alpha points - fill Alpha vertex gaps in between each point with
@@ -362,16 +361,13 @@ void getFillVerticesFromPerimeterAA(const PaintInfo& paintInfo,
// AA point offset from original point is that point's normal, such that each side is offset
// by .5 pixels
- Vector2 totalOffset = paintInfo.deriveAAOffset(totalOffsetFromNormals(lastNormal, nextNormal));
+ Vector2 totalOffset =
+ paintInfo.deriveAAOffset(totalOffsetFromNormals(lastNormal, nextNormal));
- AlphaVertex::set(&buffer[currentIndex++],
- current->x + totalOffset.x,
- current->y + totalOffset.y,
- 0.0f);
- AlphaVertex::set(&buffer[currentIndex++],
- current->x - totalOffset.x,
- current->y - totalOffset.y,
- maxAlpha);
+ AlphaVertex::set(&buffer[currentIndex++], current->x + totalOffset.x,
+ current->y + totalOffset.y, 0.0f);
+ AlphaVertex::set(&buffer[currentIndex++], current->x - totalOffset.x,
+ current->y - totalOffset.y, maxAlpha);
current = next;
lastNormal = nextNormal;
@@ -404,12 +400,11 @@ void getFillVerticesFromPerimeterAA(const PaintInfo& paintInfo,
* getStrokeVerticesFromUnclosedVerticesAA() below.
*/
inline static void storeCapAA(const PaintInfo& paintInfo, const std::vector<Vertex>& vertices,
- AlphaVertex* buffer, bool isFirst, Vector2 normal, int offset) {
+ AlphaVertex* buffer, bool isFirst, Vector2 normal, int offset) {
const int extra = paintInfo.capExtraDivisions();
const int extraOffset = (extra + 1) / 2;
- const int capIndex = isFirst
- ? 2 * offset + 6 + 2 * (extra + extraOffset)
- : offset + 2 + 2 * extraOffset;
+ const int capIndex =
+ isFirst ? 2 * offset + 6 + 2 * (extra + extraOffset) : offset + 2 + 2 * extraOffset;
if (isFirst) normal *= -1;
// TODO: this normal should be scaled by radialScale if extra != 0, see totalOffsetFromNormals()
@@ -437,26 +432,18 @@ inline static void storeCapAA(const PaintInfo& paintInfo, const std::vector<Vert
referencePoint += rotated;
}
- AlphaVertex::set(&buffer[capIndex + 0],
- referencePoint.x + outerOffset.x + capAAOffset.x,
- referencePoint.y + outerOffset.y + capAAOffset.y,
- 0.0f);
- AlphaVertex::set(&buffer[capIndex + 1],
- referencePoint.x + innerOffset.x - capAAOffset.x,
- referencePoint.y + innerOffset.y - capAAOffset.y,
- paintInfo.maxAlpha);
+ AlphaVertex::set(&buffer[capIndex + 0], referencePoint.x + outerOffset.x + capAAOffset.x,
+ referencePoint.y + outerOffset.y + capAAOffset.y, 0.0f);
+ AlphaVertex::set(&buffer[capIndex + 1], referencePoint.x + innerOffset.x - capAAOffset.x,
+ referencePoint.y + innerOffset.y - capAAOffset.y, paintInfo.maxAlpha);
bool isRound = paintInfo.cap == SkPaint::kRound_Cap;
const int postCapIndex = (isRound && isFirst) ? (2 * extraOffset - 2) : capIndex + (2 * extra);
- AlphaVertex::set(&buffer[postCapIndex + 2],
- referencePoint.x - outerOffset.x + capAAOffset.x,
- referencePoint.y - outerOffset.y + capAAOffset.y,
- 0.0f);
- AlphaVertex::set(&buffer[postCapIndex + 3],
- referencePoint.x - innerOffset.x - capAAOffset.x,
- referencePoint.y - innerOffset.y - capAAOffset.y,
- paintInfo.maxAlpha);
+ AlphaVertex::set(&buffer[postCapIndex + 2], referencePoint.x - outerOffset.x + capAAOffset.x,
+ referencePoint.y - outerOffset.y + capAAOffset.y, 0.0f);
+ AlphaVertex::set(&buffer[postCapIndex + 3], referencePoint.x - innerOffset.x - capAAOffset.x,
+ referencePoint.y - innerOffset.y - capAAOffset.y, paintInfo.maxAlpha);
if (isRound) {
const float dTheta = PI / (extra + 1);
@@ -475,20 +462,18 @@ inline static void storeCapAA(const PaintInfo& paintInfo, const std::vector<Vert
AAOffset = paintInfo.deriveAAOffset(radialOffset);
paintInfo.scaleOffsetForStrokeWidth(radialOffset);
AlphaVertex::set(&buffer[capPerimIndex++],
- referencePoint.x + radialOffset.x + AAOffset.x,
- referencePoint.y + radialOffset.y + AAOffset.y,
- 0.0f);
+ referencePoint.x + radialOffset.x + AAOffset.x,
+ referencePoint.y + radialOffset.y + AAOffset.y, 0.0f);
AlphaVertex::set(&buffer[capPerimIndex++],
- referencePoint.x + radialOffset.x - AAOffset.x,
- referencePoint.y + radialOffset.y - AAOffset.y,
- paintInfo.maxAlpha);
+ referencePoint.x + radialOffset.x - AAOffset.x,
+ referencePoint.y + radialOffset.y - AAOffset.y, paintInfo.maxAlpha);
if (isFirst && i == extra - extraOffset) {
- //copy most recent two points to first two points
+ // copy most recent two points to first two points
buffer[0] = buffer[capPerimIndex - 2];
buffer[1] = buffer[capPerimIndex - 1];
- capPerimIndex = 2; // start writing the rest of the round cap at index 2
+ capPerimIndex = 2; // start writing the rest of the round cap at index 2
}
}
@@ -513,7 +498,7 @@ inline static void storeCapAA(const PaintInfo& paintInfo, const std::vector<Vert
if (isFirst) {
buffer[0] = buffer[postCapIndex + 2];
buffer[1] = buffer[postCapIndex + 3];
- buffer[postCapIndex + 4] = buffer[1]; // degenerate tris (the only two!)
+ buffer[postCapIndex + 4] = buffer[1]; // degenerate tris (the only two!)
buffer[postCapIndex + 5] = buffer[postCapIndex + 1];
} else {
buffer[6 * vertices.size()] = buffer[postCapIndex + 1];
@@ -574,8 +559,8 @@ or, for rounded caps:
= 2 + 6 * pts + 6 * roundDivs
*/
void getStrokeVerticesFromUnclosedVerticesAA(const PaintInfo& paintInfo,
- const std::vector<Vertex>& vertices, VertexBuffer& vertexBuffer) {
-
+ const std::vector<Vertex>& vertices,
+ VertexBuffer& vertexBuffer) {
const int extra = paintInfo.capExtraDivisions();
const int allocSize = 6 * vertices.size() + 2 + 6 * extra;
@@ -609,32 +594,20 @@ void getStrokeVerticesFromUnclosedVerticesAA(const PaintInfo& paintInfo,
Vector2 outerOffset = innerOffset + AAOffset;
innerOffset -= AAOffset;
- AlphaVertex::set(&buffer[currentAAOuterIndex++],
- current->x + outerOffset.x,
- current->y + outerOffset.y,
- 0.0f);
- AlphaVertex::set(&buffer[currentAAOuterIndex++],
- current->x + innerOffset.x,
- current->y + innerOffset.y,
- paintInfo.maxAlpha);
-
- AlphaVertex::set(&buffer[currentStrokeIndex++],
- current->x + innerOffset.x,
- current->y + innerOffset.y,
- paintInfo.maxAlpha);
- AlphaVertex::set(&buffer[currentStrokeIndex++],
- current->x - innerOffset.x,
- current->y - innerOffset.y,
- paintInfo.maxAlpha);
-
- AlphaVertex::set(&buffer[currentAAInnerIndex--],
- current->x - innerOffset.x,
- current->y - innerOffset.y,
- paintInfo.maxAlpha);
- AlphaVertex::set(&buffer[currentAAInnerIndex--],
- current->x - outerOffset.x,
- current->y - outerOffset.y,
- 0.0f);
+ AlphaVertex::set(&buffer[currentAAOuterIndex++], current->x + outerOffset.x,
+ current->y + outerOffset.y, 0.0f);
+ AlphaVertex::set(&buffer[currentAAOuterIndex++], current->x + innerOffset.x,
+ current->y + innerOffset.y, paintInfo.maxAlpha);
+
+ AlphaVertex::set(&buffer[currentStrokeIndex++], current->x + innerOffset.x,
+ current->y + innerOffset.y, paintInfo.maxAlpha);
+ AlphaVertex::set(&buffer[currentStrokeIndex++], current->x - innerOffset.x,
+ current->y - innerOffset.y, paintInfo.maxAlpha);
+
+ AlphaVertex::set(&buffer[currentAAInnerIndex--], current->x - innerOffset.x,
+ current->y - innerOffset.y, paintInfo.maxAlpha);
+ AlphaVertex::set(&buffer[currentAAInnerIndex--], current->x - outerOffset.x,
+ current->y - outerOffset.y, 0.0f);
current = next;
lastNormal = nextNormal;
@@ -646,9 +619,9 @@ void getStrokeVerticesFromUnclosedVerticesAA(const PaintInfo& paintInfo,
DEBUG_DUMP_ALPHA_BUFFER();
}
-
void getStrokeVerticesFromPerimeterAA(const PaintInfo& paintInfo,
- const std::vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) {
+ const std::vector<Vertex>& perimeter,
+ VertexBuffer& vertexBuffer) {
AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * perimeter.size() + 8);
int offset = 2 * perimeter.size() + 3;
@@ -673,32 +646,20 @@ void getStrokeVerticesFromPerimeterAA(const PaintInfo& paintInfo,
Vector2 outerOffset = innerOffset + AAOffset;
innerOffset -= AAOffset;
- AlphaVertex::set(&buffer[currentAAOuterIndex++],
- current->x + outerOffset.x,
- current->y + outerOffset.y,
- 0.0f);
- AlphaVertex::set(&buffer[currentAAOuterIndex++],
- current->x + innerOffset.x,
- current->y + innerOffset.y,
- paintInfo.maxAlpha);
-
- AlphaVertex::set(&buffer[currentStrokeIndex++],
- current->x + innerOffset.x,
- current->y + innerOffset.y,
- paintInfo.maxAlpha);
- AlphaVertex::set(&buffer[currentStrokeIndex++],
- current->x - innerOffset.x,
- current->y - innerOffset.y,
- paintInfo.maxAlpha);
-
- AlphaVertex::set(&buffer[currentAAInnerIndex++],
- current->x - innerOffset.x,
- current->y - innerOffset.y,
- paintInfo.maxAlpha);
- AlphaVertex::set(&buffer[currentAAInnerIndex++],
- current->x - outerOffset.x,
- current->y - outerOffset.y,
- 0.0f);
+ AlphaVertex::set(&buffer[currentAAOuterIndex++], current->x + outerOffset.x,
+ current->y + outerOffset.y, 0.0f);
+ AlphaVertex::set(&buffer[currentAAOuterIndex++], current->x + innerOffset.x,
+ current->y + innerOffset.y, paintInfo.maxAlpha);
+
+ AlphaVertex::set(&buffer[currentStrokeIndex++], current->x + innerOffset.x,
+ current->y + innerOffset.y, paintInfo.maxAlpha);
+ AlphaVertex::set(&buffer[currentStrokeIndex++], current->x - innerOffset.x,
+ current->y - innerOffset.y, paintInfo.maxAlpha);
+
+ AlphaVertex::set(&buffer[currentAAInnerIndex++], current->x - innerOffset.x,
+ current->y - innerOffset.y, paintInfo.maxAlpha);
+ AlphaVertex::set(&buffer[currentAAInnerIndex++], current->x - outerOffset.x,
+ current->y - outerOffset.y, 0.0f);
current = next;
lastNormal = nextNormal;
@@ -720,8 +681,8 @@ void getStrokeVerticesFromPerimeterAA(const PaintInfo& paintInfo,
DEBUG_DUMP_ALPHA_BUFFER();
}
-void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint,
- const mat4& transform, VertexBuffer& vertexBuffer) {
+void PathTessellator::tessellatePath(const SkPath& path, const SkPaint* paint,
+ const mat4& transform, VertexBuffer& vertexBuffer) {
ATRACE_CALL();
const PaintInfo paintInfo(paint, transform);
@@ -742,9 +703,9 @@ void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint,
// force close if we're filling the path, since fill path expects closed perimeter.
bool forceClose = paintInfo.style != SkPaint::kStroke_Style;
PathApproximationInfo approximationInfo(threshInvScaleX, threshInvScaleY,
- OUTLINE_REFINE_THRESHOLD);
- bool wasClosed = approximatePathOutlineVertices(path, forceClose,
- approximationInfo, tempVertices);
+ OUTLINE_REFINE_THRESHOLD);
+ bool wasClosed =
+ approximatePathOutlineVertices(path, forceClose, approximationInfo, tempVertices);
if (!tempVertices.size()) {
// path was empty, return without allocating vertex buffer
@@ -753,8 +714,7 @@ void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint,
#if VERTEX_DEBUG
for (unsigned int i = 0; i < tempVertices.size(); i++) {
- ALOGD("orig path: point at %f %f",
- tempVertices[i].x, tempVertices[i].y);
+ ALOGD("orig path: point at %f %f", tempVertices[i].x, tempVertices[i].y);
}
#endif
@@ -790,8 +750,8 @@ void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint,
}
template <class TYPE>
-static void instanceVertices(VertexBuffer& srcBuffer, VertexBuffer& dstBuffer,
- const float* points, int count, Rect& bounds) {
+static void instanceVertices(VertexBuffer& srcBuffer, VertexBuffer& dstBuffer, const float* points,
+ int count, Rect& bounds) {
bounds.set(points[0], points[1], points[0], points[1]);
int numPoints = count / 2;
@@ -806,7 +766,7 @@ static void instanceVertices(VertexBuffer& srcBuffer, VertexBuffer& dstBuffer,
}
void PathTessellator::tessellatePoints(const float* points, int count, const SkPaint* paint,
- const mat4& transform, VertexBuffer& vertexBuffer) {
+ const mat4& transform, VertexBuffer& vertexBuffer) {
const PaintInfo paintInfo(paint, transform);
// determine point shape
@@ -823,7 +783,7 @@ void PathTessellator::tessellatePoints(const float* points, int count, const SkP
// calculate outline
std::vector<Vertex> outlineVertices;
PathApproximationInfo approximationInfo(paintInfo.inverseScaleX, paintInfo.inverseScaleY,
- OUTLINE_REFINE_THRESHOLD);
+ OUTLINE_REFINE_THRESHOLD);
approximatePathOutlineVertices(path, true, approximationInfo, outlineVertices);
if (!outlineVertices.size()) return;
@@ -847,7 +807,7 @@ void PathTessellator::tessellatePoints(const float* points, int count, const SkP
}
void PathTessellator::tessellateLines(const float* points, int count, const SkPaint* paint,
- const mat4& transform, VertexBuffer& vertexBuffer) {
+ const mat4& transform, VertexBuffer& vertexBuffer) {
ATRACE_CALL();
const PaintInfo paintInfo(paint, transform);
@@ -900,7 +860,7 @@ void PathTessellator::tessellateLines(const float* points, int count, const SkPa
///////////////////////////////////////////////////////////////////////////////
bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, float threshold,
- std::vector<Vertex>& outputVertices) {
+ std::vector<Vertex>& outputVertices) {
PathApproximationInfo approximationInfo(1.0f, 1.0f, threshold);
return approximatePathOutlineVertices(path, true, approximationInfo, outputVertices);
}
@@ -932,6 +892,7 @@ public:
}
}
}
+
private:
bool initialized = false;
double lastX = 0;
@@ -940,7 +901,8 @@ private:
};
bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool forceClose,
- const PathApproximationInfo& approximationInfo, std::vector<Vertex>& outputVertices) {
+ const PathApproximationInfo& approximationInfo,
+ std::vector<Vertex>& outputVertices) {
ATRACE_CALL();
// TODO: to support joins other than sharp miter, join vertices should be labelled in the
@@ -950,7 +912,7 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
SkPath::Verb v;
ClockwiseEnforcer clockwiseEnforcer;
while (SkPath::kDone_Verb != (v = iter.next(pts))) {
- switch (v) {
+ switch (v) {
case SkPath::kMove_Verb:
outputVertices.push_back(Vertex{pts[0].x(), pts[0].y()});
ALOGV("Move to pos %f %f", pts[0].x(), pts[0].y());
@@ -967,22 +929,17 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
break;
case SkPath::kQuad_Verb:
ALOGV("kQuad_Verb");
- recursiveQuadraticBezierVertices(
- pts[0].x(), pts[0].y(),
- pts[2].x(), pts[2].y(),
- pts[1].x(), pts[1].y(),
- approximationInfo, outputVertices);
+ recursiveQuadraticBezierVertices(pts[0].x(), pts[0].y(), pts[2].x(), pts[2].y(),
+ pts[1].x(), pts[1].y(), approximationInfo,
+ outputVertices);
clockwiseEnforcer.addPoint(pts[1]);
clockwiseEnforcer.addPoint(pts[2]);
break;
case SkPath::kCubic_Verb:
ALOGV("kCubic_Verb");
- recursiveCubicBezierVertices(
- pts[0].x(), pts[0].y(),
- pts[1].x(), pts[1].y(),
- pts[3].x(), pts[3].y(),
- pts[2].x(), pts[2].y(),
- approximationInfo, outputVertices);
+ recursiveCubicBezierVertices(pts[0].x(), pts[0].y(), pts[1].x(), pts[1].y(),
+ pts[3].x(), pts[3].y(), pts[2].x(), pts[2].y(),
+ approximationInfo, outputVertices);
clockwiseEnforcer.addPoint(pts[1]);
clockwiseEnforcer.addPoint(pts[2]);
clockwiseEnforcer.addPoint(pts[3]);
@@ -990,37 +947,33 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
case SkPath::kConic_Verb: {
ALOGV("kConic_Verb");
SkAutoConicToQuads converter;
- const SkPoint* quads = converter.computeQuads(pts, iter.conicWeight(),
- approximationInfo.thresholdForConicQuads);
+ const SkPoint* quads = converter.computeQuads(
+ pts, iter.conicWeight(), approximationInfo.thresholdForConicQuads);
for (int i = 0; i < converter.countQuads(); ++i) {
const int offset = 2 * i;
- recursiveQuadraticBezierVertices(
- quads[offset].x(), quads[offset].y(),
- quads[offset+2].x(), quads[offset+2].y(),
- quads[offset+1].x(), quads[offset+1].y(),
- approximationInfo, outputVertices);
+ recursiveQuadraticBezierVertices(quads[offset].x(), quads[offset].y(),
+ quads[offset + 2].x(), quads[offset + 2].y(),
+ quads[offset + 1].x(), quads[offset + 1].y(),
+ approximationInfo, outputVertices);
}
clockwiseEnforcer.addPoint(pts[1]);
clockwiseEnforcer.addPoint(pts[2]);
break;
}
default:
- static_assert(SkPath::kMove_Verb == 0
- && SkPath::kLine_Verb == 1
- && SkPath::kQuad_Verb == 2
- && SkPath::kConic_Verb == 3
- && SkPath::kCubic_Verb == 4
- && SkPath::kClose_Verb == 5
- && SkPath::kDone_Verb == 6,
- "Path enum changed, new types may have been added");
+ static_assert(SkPath::kMove_Verb == 0 && SkPath::kLine_Verb == 1 &&
+ SkPath::kQuad_Verb == 2 && SkPath::kConic_Verb == 3 &&
+ SkPath::kCubic_Verb == 4 && SkPath::kClose_Verb == 5 &&
+ SkPath::kDone_Verb == 6,
+ "Path enum changed, new types may have been added");
break;
- }
+ }
}
bool wasClosed = false;
int size = outputVertices.size();
if (size >= 2 && outputVertices[0].x == outputVertices[size - 1].x &&
- outputVertices[0].y == outputVertices[size - 1].y) {
+ outputVertices[0].y == outputVertices[size - 1].y) {
outputVertices.pop_back();
wasClosed = true;
}
@@ -1045,19 +998,17 @@ static inline float getThreshold(const PathApproximationInfo& info, float dx, fl
return info.thresholdSquared * scale;
}
-void PathTessellator::recursiveCubicBezierVertices(
- float p1x, float p1y, float c1x, float c1y,
- float p2x, float p2y, float c2x, float c2y,
- const PathApproximationInfo& approximationInfo,
- std::vector<Vertex>& outputVertices, int depth) {
+void PathTessellator::recursiveCubicBezierVertices(float p1x, float p1y, float c1x, float c1y,
+ float p2x, float p2y, float c2x, float c2y,
+ const PathApproximationInfo& approximationInfo,
+ std::vector<Vertex>& outputVertices, int depth) {
float dx = p2x - p1x;
float dy = p2y - p1y;
float d1 = fabs((c1x - p2x) * dy - (c1y - p2y) * dx);
float d2 = fabs((c2x - p2x) * dy - (c2y - p2y) * dx);
float d = d1 + d2;
- if (depth >= MAX_DEPTH
- || d * d <= getThreshold(approximationInfo, dx, dy)) {
+ if (depth >= MAX_DEPTH || d * d <= getThreshold(approximationInfo, dx, dy)) {
// below thresh, draw line by adding endpoint
outputVertices.push_back(Vertex{p2x, p2y});
} else {
@@ -1078,30 +1029,23 @@ void PathTessellator::recursiveCubicBezierVertices(
float mx = (p1c1c2x + p2c1c2x) * 0.5f;
float my = (p1c1c2y + p2c1c2y) * 0.5f;
- recursiveCubicBezierVertices(
- p1x, p1y, p1c1x, p1c1y,
- mx, my, p1c1c2x, p1c1c2y,
- approximationInfo, outputVertices, depth + 1);
- recursiveCubicBezierVertices(
- mx, my, p2c1c2x, p2c1c2y,
- p2x, p2y, p2c2x, p2c2y,
- approximationInfo, outputVertices, depth + 1);
+ recursiveCubicBezierVertices(p1x, p1y, p1c1x, p1c1y, mx, my, p1c1c2x, p1c1c2y,
+ approximationInfo, outputVertices, depth + 1);
+ recursiveCubicBezierVertices(mx, my, p2c1c2x, p2c1c2y, p2x, p2y, p2c2x, p2c2y,
+ approximationInfo, outputVertices, depth + 1);
}
}
void PathTessellator::recursiveQuadraticBezierVertices(
- float ax, float ay,
- float bx, float by,
- float cx, float cy,
- const PathApproximationInfo& approximationInfo,
- std::vector<Vertex>& outputVertices, int depth) {
+ float ax, float ay, float bx, float by, float cx, float cy,
+ const PathApproximationInfo& approximationInfo, std::vector<Vertex>& outputVertices,
+ int depth) {
float dx = bx - ax;
float dy = by - ay;
// d is the cross product of vector (B-A) and (C-B).
float d = (cx - bx) * dy - (cy - by) * dx;
- if (depth >= MAX_DEPTH
- || d * d <= getThreshold(approximationInfo, dx, dy)) {
+ if (depth >= MAX_DEPTH || d * d <= getThreshold(approximationInfo, dx, dy)) {
// below thresh, draw line by adding endpoint
outputVertices.push_back(Vertex{bx, by});
} else {
@@ -1114,12 +1058,12 @@ void PathTessellator::recursiveQuadraticBezierVertices(
float mx = (acx + bcx) * 0.5f;
float my = (acy + bcy) * 0.5f;
- recursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy,
- approximationInfo, outputVertices, depth + 1);
- recursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy,
- approximationInfo, outputVertices, depth + 1);
+ recursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy, approximationInfo,
+ outputVertices, depth + 1);
+ recursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy, approximationInfo,
+ outputVertices, depth + 1);
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/PathTessellator.h b/libs/hwui/PathTessellator.h
index cddfb049212c..ed268324b341 100644
--- a/libs/hwui/PathTessellator.h
+++ b/libs/hwui/PathTessellator.h
@@ -39,11 +39,10 @@ namespace uirenderer {
*/
struct PathApproximationInfo {
PathApproximationInfo(float invScaleX, float invScaleY, float pixelThreshold)
- : thresholdSquared(pixelThreshold * pixelThreshold)
- , sqrInvScaleX(invScaleX * invScaleX)
- , sqrInvScaleY(invScaleY * invScaleY)
- , thresholdForConicQuads(pixelThreshold * std::min(invScaleX, invScaleY) / 2.0f) {
- };
+ : thresholdSquared(pixelThreshold * pixelThreshold)
+ , sqrInvScaleX(invScaleX * invScaleX)
+ , sqrInvScaleY(invScaleY * invScaleY)
+ , thresholdForConicQuads(pixelThreshold * std::min(invScaleX, invScaleY) / 2.0f){};
const float thresholdSquared;
const float sqrInvScaleX;
@@ -64,7 +63,8 @@ public:
static void extractTessellationScales(const Matrix4& transform, float* scaleX, float* scaleY);
/**
- * Populates a VertexBuffer with a tessellated approximation of the input convex path, as a single
+ * Populates a VertexBuffer with a tessellated approximation of the input convex path, as a
+ * single
* triangle strip. Note: joins are not currently supported.
*
* @param path The path to be approximated
@@ -74,8 +74,8 @@ public:
* vertex approximation, and correct AA ramp offsetting.
* @param vertexBuffer The output buffer
*/
- static void tessellatePath(const SkPath& path, const SkPaint* paint,
- const mat4& transform, VertexBuffer& vertexBuffer);
+ static void tessellatePath(const SkPath& path, const SkPaint* paint, const mat4& transform,
+ VertexBuffer& vertexBuffer);
/**
* Populates a VertexBuffer with a tessellated approximation of points as a single triangle
@@ -84,12 +84,13 @@ public:
* @param points The center vertices of the points to be drawn
* @param count The number of floats making up the point vertices
* @param paint The paint the points will be drawn with indicating AA, stroke width & cap
- * @param transform The transform the points will be drawn with, used to drive stretch-aware path
+ * @param transform The transform the points will be drawn with, used to drive stretch-aware
+ * path
* vertex approximation, and correct AA ramp offsetting
* @param vertexBuffer The output buffer
*/
static void tessellatePoints(const float* points, int count, const SkPaint* paint,
- const mat4& transform, VertexBuffer& vertexBuffer);
+ const mat4& transform, VertexBuffer& vertexBuffer);
/**
* Populates a VertexBuffer with a tessellated approximation of lines as a single triangle
@@ -98,12 +99,13 @@ public:
* @param points Pairs of endpoints defining the lines to be drawn
* @param count The number of floats making up the line vertices
* @param paint The paint the lines will be drawn with indicating AA, stroke width & cap
- * @param transform The transform the points will be drawn with, used to drive stretch-aware path
+ * @param transform The transform the points will be drawn with, used to drive stretch-aware
+ * path
* vertex approximation, and correct AA ramp offsetting
* @param vertexBuffer The output buffer
*/
static void tessellateLines(const float* points, int count, const SkPaint* paint,
- const mat4& transform, VertexBuffer& vertexBuffer);
+ const mat4& transform, VertexBuffer& vertexBuffer);
/**
* Approximates a convex outline into a clockwise Vector of 2d vertices.
@@ -112,38 +114,35 @@ public:
* @param threshold The threshold of acceptable error (in pixels) when approximating
* @param outputVertices An empty Vector which will be populated with the output
*/
- static bool approximatePathOutlineVertices(const SkPath &path, float threshold,
- std::vector<Vertex> &outputVertices);
+ static bool approximatePathOutlineVertices(const SkPath& path, float threshold,
+ std::vector<Vertex>& outputVertices);
private:
- static bool approximatePathOutlineVertices(const SkPath &path, bool forceClose,
- const PathApproximationInfo& approximationInfo, std::vector<Vertex> &outputVertices);
+ static bool approximatePathOutlineVertices(const SkPath& path, bool forceClose,
+ const PathApproximationInfo& approximationInfo,
+ std::vector<Vertex>& outputVertices);
-/*
- endpoints a & b,
- control c
- */
- static void recursiveQuadraticBezierVertices(
- float ax, float ay,
- float bx, float by,
- float cx, float cy,
- const PathApproximationInfo& approximationInfo,
- std::vector<Vertex> &outputVertices, int depth = 0);
-
-/*
- endpoints p1, p2
- control c1, c2
- */
- static void recursiveCubicBezierVertices(
- float p1x, float p1y,
- float c1x, float c1y,
- float p2x, float p2y,
- float c2x, float c2y,
- const PathApproximationInfo& approximationInfo,
- std::vector<Vertex> &outputVertices, int depth = 0);
+ /*
+ endpoints a & b,
+ control c
+ */
+ static void recursiveQuadraticBezierVertices(float ax, float ay, float bx, float by, float cx,
+ float cy,
+ const PathApproximationInfo& approximationInfo,
+ std::vector<Vertex>& outputVertices,
+ int depth = 0);
+
+ /*
+ endpoints p1, p2
+ control c1, c2
+ */
+ static void recursiveCubicBezierVertices(float p1x, float p1y, float c1x, float c1y, float p2x,
+ float p2y, float c2x, float c2y,
+ const PathApproximationInfo& approximationInfo,
+ std::vector<Vertex>& outputVertices, int depth = 0);
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_PATH_TESSELLATOR_H
+#endif // ANDROID_HWUI_PATH_TESSELLATOR_H
diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp
index 2a96b6914afc..910a9889db1f 100644
--- a/libs/hwui/PixelBuffer.cpp
+++ b/libs/hwui/PixelBuffer.cpp
@@ -31,7 +31,7 @@ namespace uirenderer {
// CPU pixel buffer
///////////////////////////////////////////////////////////////////////////////
-class CpuPixelBuffer: public PixelBuffer {
+class CpuPixelBuffer : public PixelBuffer {
public:
CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
@@ -48,8 +48,7 @@ private:
CpuPixelBuffer::CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height)
: PixelBuffer(format, width, height)
- , mBuffer(new uint8_t[width * height * formatSize(format)]) {
-}
+ , mBuffer(new uint8_t[width * height * formatSize(format)]) {}
uint8_t* CpuPixelBuffer::map(AccessMode mode) {
if (mAccessMode == kAccessMode_None) {
@@ -63,15 +62,15 @@ void CpuPixelBuffer::unmap() {
}
void CpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height,
- mFormat, GL_UNSIGNED_BYTE, &mBuffer[offset]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, GL_UNSIGNED_BYTE,
+ &mBuffer[offset]);
}
///////////////////////////////////////////////////////////////////////////////
// GPU pixel buffer
///////////////////////////////////////////////////////////////////////////////
-class GpuPixelBuffer: public PixelBuffer {
+class GpuPixelBuffer : public PixelBuffer {
public:
GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
~GpuPixelBuffer();
@@ -89,11 +88,10 @@ private:
Caches& mCaches;
};
-GpuPixelBuffer::GpuPixelBuffer(GLenum format,
- uint32_t width, uint32_t height)
+GpuPixelBuffer::GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height)
: PixelBuffer(format, width, height)
, mMappedPointer(nullptr)
- , mCaches(Caches::getInstance()){
+ , mCaches(Caches::getInstance()) {
glGenBuffers(1, &mBuffer);
mCaches.pixelBufferState().bind(mBuffer);
@@ -108,7 +106,7 @@ GpuPixelBuffer::~GpuPixelBuffer() {
uint8_t* GpuPixelBuffer::map(AccessMode mode) {
if (mAccessMode == kAccessMode_None) {
mCaches.pixelBufferState().bind(mBuffer);
- mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode);
+ mMappedPointer = (uint8_t*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode);
if (CC_UNLIKELY(!mMappedPointer)) {
GLUtils::dumpGLErrors();
LOG_ALWAYS_FATAL("Failed to map PBO");
@@ -138,8 +136,8 @@ void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t hei
// If the buffer is not mapped, unmap() will not bind it
mCaches.pixelBufferState().bind(mBuffer);
unmap();
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat,
- GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset));
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, GL_UNSIGNED_BYTE,
+ reinterpret_cast<void*>(offset));
mCaches.pixelBufferState().unbind();
}
@@ -147,13 +145,12 @@ void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t hei
// Factory
///////////////////////////////////////////////////////////////////////////////
-PixelBuffer* PixelBuffer::create(GLenum format,
- uint32_t width, uint32_t height, BufferType type) {
+PixelBuffer* PixelBuffer::create(GLenum format, uint32_t width, uint32_t height, BufferType type) {
if (type == kBufferType_Auto && Caches::getInstance().gpuPixelBuffersEnabled) {
return new GpuPixelBuffer(format, width, height);
}
return new CpuPixelBuffer(format, width, height);
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h
index 77d5e413cb36..e7e341b90ad3 100644
--- a/libs/hwui/PixelBuffer.h
+++ b/libs/hwui/PixelBuffer.h
@@ -45,10 +45,7 @@ namespace uirenderer {
*/
class PixelBuffer {
public:
- enum BufferType {
- kBufferType_Auto,
- kBufferType_CPU
- };
+ enum BufferType { kBufferType_Auto, kBufferType_CPU };
enum AccessMode {
kAccessMode_None = 0,
@@ -66,17 +63,14 @@ public:
* a CPU or GPU buffer.
*/
static PixelBuffer* create(GLenum format, uint32_t width, uint32_t height,
- BufferType type = kBufferType_Auto);
+ BufferType type = kBufferType_Auto);
- virtual ~PixelBuffer() {
- }
+ virtual ~PixelBuffer() {}
/**
* Returns the format of this render buffer.
*/
- GLenum getFormat() const {
- return mFormat;
- }
+ GLenum getFormat() const { return mFormat; }
/**
* Maps this before with the specified access mode. This method
@@ -95,9 +89,7 @@ public:
* Returns the current access mode for this buffer. If the buffer
* is not mapped, this method returns kAccessMode_None.
*/
- AccessMode getAccessMode() const {
- return mAccessMode;
- }
+ AccessMode getAccessMode() const { return mAccessMode; }
/**
* Upload the specified rectangle of this pixel buffer as a
@@ -121,23 +113,17 @@ public:
/**
* Returns the width of the render buffer in pixels.
*/
- uint32_t getWidth() const {
- return mWidth;
- }
+ uint32_t getWidth() const { return mWidth; }
/**
* Returns the height of the render buffer in pixels.
*/
- uint32_t getHeight() const {
- return mHeight;
- }
+ uint32_t getHeight() const { return mHeight; }
/**
* Returns the size of this pixel buffer in bytes.
*/
- uint32_t getSize() const {
- return mWidth * mHeight * formatSize(mFormat);
- }
+ uint32_t getSize() const { return mWidth * mHeight * formatSize(mFormat); }
/**
* Returns the offset of a pixel in this pixel buffer, in bytes.
@@ -178,7 +164,7 @@ public:
return 3;
}
- ALOGE("unsupported format: %d",format);
+ ALOGE("unsupported format: %d", format);
return 0;
}
@@ -187,9 +173,8 @@ protected:
* Creates a new render buffer in the specified format and dimensions.
* The format must be GL_ALPHA or GL_RGBA.
*/
- PixelBuffer(GLenum format, uint32_t width, uint32_t height):
- mFormat(format), mWidth(width), mHeight(height), mAccessMode(kAccessMode_None) {
- }
+ PixelBuffer(GLenum format, uint32_t width, uint32_t height)
+ : mFormat(format), mWidth(width), mHeight(height), mAccessMode(kAccessMode_None) {}
/**
* Unmaps this buffer, if needed. After the buffer is unmapped,
@@ -205,9 +190,9 @@ protected:
AccessMode mAccessMode;
-}; // class PixelBuffer
+}; // class PixelBuffer
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_PIXEL_BUFFER_H
+#endif // ANDROID_HWUI_PIXEL_BUFFER_H
diff --git a/libs/hwui/ProfileData.cpp b/libs/hwui/ProfileData.cpp
index a295c5debc67..b392ecdde18f 100644
--- a/libs/hwui/ProfileData.cpp
+++ b/libs/hwui/ProfileData.cpp
@@ -22,11 +22,8 @@ namespace android {
namespace uirenderer {
static const char* JANK_TYPE_NAMES[] = {
- "Missed Vsync",
- "High input latency",
- "Slow UI thread",
- "Slow bitmap uploads",
- "Slow issue draw commands",
+ "Missed Vsync", "High input latency", "Slow UI thread",
+ "Slow bitmap uploads", "Slow issue draw commands",
};
// The bucketing algorithm controls so to speak
@@ -54,10 +51,8 @@ static uint32_t frameCountIndexForFrameTime(nsecs_t frameTime) {
// index = threshold + (amountAboveThreshold / 2)
// However if index is <= this will do nothing. It will underflow, do
// a right shift by 0 (no-op), then overflow back to the original value
- index = ((index - kBucket4msIntervals) >> (index > kBucket4msIntervals))
- + kBucket4msIntervals;
- index = ((index - kBucket2msIntervals) >> (index > kBucket2msIntervals))
- + kBucket2msIntervals;
+ index = ((index - kBucket4msIntervals) >> (index > kBucket4msIntervals)) + kBucket4msIntervals;
+ index = ((index - kBucket2msIntervals) >> (index > kBucket2msIntervals)) + kBucket2msIntervals;
// If index was < minThreshold at the start of all this it's going to
// be a pretty garbage value right now. However, mask is 0 so we'll end
// up with the desired result of 0.
@@ -101,8 +96,7 @@ void ProfileData::mergeWith(const ProfileData& other) {
mJankFrameCount += other.mJankFrameCount;
mTotalFrameCount >>= divider;
mTotalFrameCount += other.mTotalFrameCount;
- if (mStatStartTime > other.mStatStartTime
- || mStatStartTime == 0) {
+ if (mStatStartTime > other.mStatStartTime || mStatStartTime == 0) {
mStatStartTime = other.mStatStartTime;
}
}
@@ -111,7 +105,7 @@ void ProfileData::dump(int fd) const {
dprintf(fd, "\nStats since: %" PRIu64 "ns", mStatStartTime);
dprintf(fd, "\nTotal frames rendered: %u", mTotalFrameCount);
dprintf(fd, "\nJanky frames: %u (%.2f%%)", mJankFrameCount,
- (float) mJankFrameCount / (float) mTotalFrameCount * 100.0f);
+ (float)mJankFrameCount / (float)mTotalFrameCount * 100.0f);
dprintf(fd, "\n50th percentile: %ums", findPercentile(50));
dprintf(fd, "\n90th percentile: %ums", findPercentile(90));
dprintf(fd, "\n95th percentile: %ums", findPercentile(95));
diff --git a/libs/hwui/ProfileData.h b/libs/hwui/ProfileData.h
index d53ee29511f0..1e688ab6fa68 100644
--- a/libs/hwui/ProfileData.h
+++ b/libs/hwui/ProfileData.h
@@ -70,8 +70,8 @@ public:
void histogramForEach(const std::function<void(HistogramEntry)>& callback) const;
constexpr static int HistogramSize() {
- return std::tuple_size<decltype(ProfileData::mFrameCounts)>::value
- + std::tuple_size<decltype(ProfileData::mSlowFrameCounts)>::value;
+ return std::tuple_size<decltype(ProfileData::mFrameCounts)>::value +
+ std::tuple_size<decltype(ProfileData::mSlowFrameCounts)>::value;
}
// Visible for testing
@@ -82,7 +82,7 @@ private:
// Open our guts up to unit tests
friend class MockProfileData;
- std::array <uint32_t, NUM_BUCKETS> mJankTypeCounts;
+ std::array<uint32_t, NUM_BUCKETS> mJankTypeCounts;
// See comments on kBucket* constants for what this holds
std::array<uint32_t, 57> mFrameCounts;
// Holds a histogram of frame times in 50ms increments from 150ms to 5s
@@ -106,4 +106,3 @@ public:
} /* namespace uirenderer */
} /* namespace android */
-
diff --git a/libs/hwui/ProfileDataContainer.cpp b/libs/hwui/ProfileDataContainer.cpp
index 70a77ed5f10e..8e0b4e2eef5b 100644
--- a/libs/hwui/ProfileDataContainer.cpp
+++ b/libs/hwui/ProfileDataContainer.cpp
@@ -18,8 +18,8 @@
#include <errno.h>
-#include <log/log.h>
#include <cutils/ashmem.h>
+#include <log/log.h>
#include <sys/mman.h>
@@ -52,21 +52,20 @@ void ProfileDataContainer::switchStorageToAshmem(int ashmemfd) {
int regionSize = ashmem_get_size_region(ashmemfd);
if (regionSize < 0) {
int err = errno;
- ALOGW("Failed to get ashmem region size from fd %d, err %d %s", ashmemfd, err, strerror(err));
+ ALOGW("Failed to get ashmem region size from fd %d, err %d %s", ashmemfd, err,
+ strerror(err));
return;
}
if (regionSize < static_cast<int>(sizeof(ProfileData))) {
- ALOGW("Ashmem region is too small! Received %d, required %u",
- regionSize, static_cast<unsigned int>(sizeof(ProfileData)));
+ ALOGW("Ashmem region is too small! Received %d, required %u", regionSize,
+ static_cast<unsigned int>(sizeof(ProfileData)));
return;
}
ProfileData* newData = reinterpret_cast<ProfileData*>(
- mmap(NULL, sizeof(ProfileData), PROT_READ | PROT_WRITE,
- MAP_SHARED, ashmemfd, 0));
+ mmap(NULL, sizeof(ProfileData), PROT_READ | PROT_WRITE, MAP_SHARED, ashmemfd, 0));
if (newData == MAP_FAILED) {
int err = errno;
- ALOGW("Failed to move profile data to ashmem fd %d, error = %d",
- ashmemfd, err);
+ ALOGW("Failed to move profile data to ashmem fd %d, error = %d", ashmemfd, err);
return;
}
diff --git a/libs/hwui/ProfileDataContainer.h b/libs/hwui/ProfileDataContainer.h
index d2de24188c7c..a39869491ede 100644
--- a/libs/hwui/ProfileDataContainer.h
+++ b/libs/hwui/ProfileDataContainer.h
@@ -24,6 +24,7 @@ namespace uirenderer {
class ProfileDataContainer {
PREVENT_COPY_AND_ASSIGN(ProfileDataContainer);
+
public:
explicit ProfileDataContainer() {}
diff --git a/libs/hwui/ProfileRenderer.cpp b/libs/hwui/ProfileRenderer.cpp
index 0ad484ce0687..8a00ffa54c58 100644
--- a/libs/hwui/ProfileRenderer.cpp
+++ b/libs/hwui/ProfileRenderer.cpp
@@ -20,7 +20,7 @@ namespace android {
namespace uirenderer {
void ProfileRenderer::drawRect(float left, float top, float right, float bottom,
- const SkPaint& paint) {
+ const SkPaint& paint) {
mRenderer.drawRect(left, top, right, bottom, &paint);
}
diff --git a/libs/hwui/ProfileRenderer.h b/libs/hwui/ProfileRenderer.h
index b9e586f592e8..5c8bb2529fb4 100644
--- a/libs/hwui/ProfileRenderer.h
+++ b/libs/hwui/ProfileRenderer.h
@@ -23,9 +23,7 @@ namespace uirenderer {
class ProfileRenderer : public IProfileRenderer {
public:
- ProfileRenderer(BakedOpRenderer& renderer)
- : mRenderer(renderer) {
- }
+ ProfileRenderer(BakedOpRenderer& renderer) : mRenderer(renderer) {}
void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override;
void drawRects(const float* rects, int count, const SkPaint& paint) override;
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index e43b80d440e7..052798b9cea9 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -151,7 +151,7 @@ GLuint Program::buildShader(const char* source, GLenum type) {
}
void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
- const mat4& transformMatrix, bool offset) {
+ const mat4& transformMatrix, bool offset) {
if (projectionMatrix != mProjection || offset != mOffset) {
if (CC_LIKELY(!offset)) {
glUniformMatrix4fv(projection, 1, GL_FALSE, &projectionMatrix.data[0]);
@@ -195,5 +195,5 @@ void Program::remove() {
mUse = false;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 2becfcb709c3..dcc2bd410ebd 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -39,25 +39,25 @@ namespace uirenderer {
// Debug
#if DEBUG_PROGRAMS
- #define PROGRAM_LOGD(...) ALOGD(__VA_ARGS__)
+#define PROGRAM_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define PROGRAM_LOGD(...)
+#define PROGRAM_LOGD(...)
#endif
#define COLOR_COMPONENT_THRESHOLD 1.0f
#define COLOR_COMPONENT_INV_THRESHOLD 0.0f
-#define PROGRAM_KEY_TEXTURE 0x01
-#define PROGRAM_KEY_A8_TEXTURE 0x02
-#define PROGRAM_KEY_BITMAP 0x04
-#define PROGRAM_KEY_GRADIENT 0x08
-#define PROGRAM_KEY_BITMAP_FIRST 0x10
-#define PROGRAM_KEY_COLOR_MATRIX 0x20
-#define PROGRAM_KEY_COLOR_BLEND 0x40
-#define PROGRAM_KEY_BITMAP_NPOT 0x80
-#define PROGRAM_KEY_BITMAP_EXTERNAL 0x100
-
-#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
+#define PROGRAM_KEY_TEXTURE 0x01
+#define PROGRAM_KEY_A8_TEXTURE 0x02
+#define PROGRAM_KEY_BITMAP 0x04
+#define PROGRAM_KEY_GRADIENT 0x08
+#define PROGRAM_KEY_BITMAP_FIRST 0x10
+#define PROGRAM_KEY_COLOR_MATRIX 0x20
+#define PROGRAM_KEY_COLOR_BLEND 0x40
+#define PROGRAM_KEY_BITMAP_NPOT 0x80
+#define PROGRAM_KEY_BITMAP_EXTERNAL 0x100
+
+#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
#define PROGRAM_KEY_SWAP_SRC_DST_SHIFT 13
@@ -71,7 +71,7 @@ namespace uirenderer {
#define PROGRAM_BITMAP_WRAPS_SHIFT 9
#define PROGRAM_BITMAP_WRAPT_SHIFT 11
-#define PROGRAM_GRADIENT_TYPE_SHIFT 33 // 2 bits for gradient type
+#define PROGRAM_GRADIENT_TYPE_SHIFT 33 // 2 bits for gradient type
#define PROGRAM_MODULATE_SHIFT 35
#define PROGRAM_HAS_VERTEX_ALPHA_SHIFT 36
@@ -91,7 +91,7 @@ namespace uirenderer {
#define PROGRAM_HAS_LINEAR_TEXTURE 45
#define PROGRAM_HAS_COLOR_SPACE_CONVERSION 46
-#define PROGRAM_TRANSFER_FUNCTION 47 // 2 bits for transfer function
+#define PROGRAM_TRANSFER_FUNCTION 47 // 2 bits for transfer function
#define PROGRAM_HAS_TRANSLUCENT_CONVERSION 49
///////////////////////////////////////////////////////////////////////////////
@@ -110,21 +110,11 @@ typedef uint64_t programid;
* A ProgramDescription must be used in conjunction with a ProgramCache.
*/
struct ProgramDescription {
- enum class ColorFilterMode : int8_t {
- None = 0,
- Matrix,
- Blend
- };
-
- enum Gradient : int8_t {
- kGradientLinear = 0,
- kGradientCircular,
- kGradientSweep
- };
-
- ProgramDescription() {
- reset();
- }
+ enum class ColorFilterMode : int8_t { None = 0, Matrix, Blend };
+
+ enum Gradient : int8_t { kGradientLinear = 0, kGradientCircular, kGradientSweep };
+
+ ProgramDescription() { reset(); }
// Texturing
bool hasTexture;
@@ -243,7 +233,7 @@ struct ProgramDescription {
*/
bool setAlpha8ColorModulate(const float r, const float g, const float b, const float a) {
modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD ||
- g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
+ g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
return modulate;
}
@@ -277,12 +267,12 @@ struct ProgramDescription {
break;
case ColorFilterMode::Blend:
key |= PROGRAM_KEY_COLOR_BLEND;
- key |= ((int) colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
+ key |= ((int)colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
break;
case ColorFilterMode::None:
break;
}
- key |= ((int) framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
+ key |= ((int)framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
key |= programid(swapSrcDst) << PROGRAM_KEY_SWAP_SRC_DST_SHIFT;
key |= programid(modulate) << PROGRAM_MODULATE_SHIFT;
key |= programid(hasVertexAlpha) << PROGRAM_HAS_VERTEX_ALPHA_SHIFT;
@@ -307,8 +297,7 @@ struct ProgramDescription {
void log(const char* message) const {
#if DEBUG_PROGRAMS
programid k = key();
- PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32),
- uint32_t(k & 0xffffffff));
+ PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32), uint32_t(k & 0xffffffff));
#endif
}
@@ -325,7 +314,7 @@ private:
return 0;
}
-}; // struct ProgramDescription
+}; // struct ProgramDescription
/**
* A program holds a vertex and a fragment shader. It offers several utility
@@ -333,10 +322,7 @@ private:
*/
class Program {
public:
- enum ShaderBindings {
- kBindingPosition,
- kBindingTexCoords
- };
+ enum ShaderBindings { kBindingPosition, kBindingTexCoords };
/**
* Creates a new program with the specified vertex and fragment
@@ -370,23 +356,19 @@ public:
* Indicates whether this program is currently in use with
* the GL context.
*/
- inline bool isInUse() const {
- return mUse;
- }
+ inline bool isInUse() const { return mUse; }
/**
* Indicates whether this program was correctly compiled and linked.
*/
- inline bool isInitialized() const {
- return mInitialized;
- }
+ inline bool isInitialized() const { return mInitialized; }
/**
* Binds the program with the specified projection, modelView and
* transform matrices.
*/
- void set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
- const mat4& transformMatrix, bool offset = false);
+ void set(const mat4& projectionMatrix, const mat4& modelViewMatrix, const mat4& transformMatrix,
+ bool offset = false);
/**
* Sets the color associated with this shader.
@@ -456,9 +438,9 @@ private:
mat4 mProjection;
bool mOffset;
-}; // class Program
+}; // class Program
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_PROGRAM_H
+#endif // ANDROID_HWUI_PROGRAM_H
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index b767046f1a4f..1164ebfdf1e5 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -41,19 +41,14 @@ namespace uirenderer {
const char* gVS_Header_Start =
"#version 100\n"
"attribute vec4 position;\n";
-const char* gVS_Header_Attributes_TexCoords =
- "attribute vec2 texCoords;\n";
-const char* gVS_Header_Attributes_Colors =
- "attribute vec4 colors;\n";
-const char* gVS_Header_Attributes_VertexAlphaParameters =
- "attribute float vtxAlpha;\n";
-const char* gVS_Header_Uniforms_TextureTransform =
- "uniform mat4 mainTextureTransform;\n";
+const char* gVS_Header_Attributes_TexCoords = "attribute vec2 texCoords;\n";
+const char* gVS_Header_Attributes_Colors = "attribute vec4 colors;\n";
+const char* gVS_Header_Attributes_VertexAlphaParameters = "attribute float vtxAlpha;\n";
+const char* gVS_Header_Uniforms_TextureTransform = "uniform mat4 mainTextureTransform;\n";
const char* gVS_Header_Uniforms =
- "uniform mat4 projection;\n" \
+ "uniform mat4 projection;\n"
"uniform mat4 transform;\n";
-const char* gVS_Header_Uniforms_HasGradient =
- "uniform mat4 screenSpace;\n";
+const char* gVS_Header_Uniforms_HasGradient = "uniform mat4 screenSpace;\n";
const char* gVS_Header_Uniforms_HasBitmap =
"uniform mat4 textureTransform;\n"
"uniform mediump vec2 textureDimension;\n";
@@ -61,35 +56,24 @@ const char* gVS_Header_Uniforms_HasRoundRectClip =
"uniform mat4 roundRectInvTransform;\n"
"uniform mediump vec4 roundRectInnerRectLTWH;\n"
"uniform mediump float roundRectRadius;\n";
-const char* gVS_Header_Varyings_HasTexture =
- "varying vec2 outTexCoords;\n";
-const char* gVS_Header_Varyings_HasColors =
- "varying vec4 outColors;\n";
-const char* gVS_Header_Varyings_HasVertexAlpha =
- "varying float alpha;\n";
-const char* gVS_Header_Varyings_HasBitmap =
- "varying highp vec2 outBitmapTexCoords;\n";
+const char* gVS_Header_Varyings_HasTexture = "varying vec2 outTexCoords;\n";
+const char* gVS_Header_Varyings_HasColors = "varying vec4 outColors;\n";
+const char* gVS_Header_Varyings_HasVertexAlpha = "varying float alpha;\n";
+const char* gVS_Header_Varyings_HasBitmap = "varying highp vec2 outBitmapTexCoords;\n";
const char* gVS_Header_Varyings_HasGradient[6] = {
// Linear
- "varying highp vec2 linear;\n",
- "varying float linear;\n",
+ "varying highp vec2 linear;\n", "varying float linear;\n",
// Circular
- "varying highp vec2 circular;\n",
- "varying highp vec2 circular;\n",
+ "varying highp vec2 circular;\n", "varying highp vec2 circular;\n",
// Sweep
- "varying highp vec2 sweep;\n",
- "varying highp vec2 sweep;\n",
+ "varying highp vec2 sweep;\n", "varying highp vec2 sweep;\n",
};
-const char* gVS_Header_Varyings_HasRoundRectClip =
- "varying mediump vec2 roundRectPos;\n";
-const char* gVS_Main =
- "\nvoid main(void) {\n";
-const char* gVS_Main_OutTexCoords =
- " outTexCoords = texCoords;\n";
-const char* gVS_Main_OutColors =
- " outColors = colors;\n";
+const char* gVS_Header_Varyings_HasRoundRectClip = "varying mediump vec2 roundRectPos;\n";
+const char* gVS_Main = "\nvoid main(void) {\n";
+const char* gVS_Main_OutTexCoords = " outTexCoords = texCoords;\n";
+const char* gVS_Main_OutColors = " outColors = colors;\n";
const char* gVS_Main_OutTransformedTexCoords =
" outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
const char* gVS_Main_OutGradient[6] = {
@@ -102,53 +86,42 @@ const char* gVS_Main_OutGradient[6] = {
" circular = (screenSpace * position).xy;\n",
// Sweep
- " sweep = (screenSpace * position).xy;\n",
- " sweep = (screenSpace * position).xy;\n"
-};
+ " sweep = (screenSpace * position).xy;\n", " sweep = (screenSpace * position).xy;\n"};
const char* gVS_Main_OutBitmapTexCoords =
" outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
const char* gVS_Main_Position =
" vec4 transformedPosition = projection * transform * position;\n"
" gl_Position = transformedPosition;\n";
-const char* gVS_Main_VertexAlpha =
- " alpha = vtxAlpha;\n";
+const char* gVS_Main_VertexAlpha = " alpha = vtxAlpha;\n";
const char* gVS_Main_HasRoundRectClip =
- " roundRectPos = ((roundRectInvTransform * transformedPosition).xy / roundRectRadius) - roundRectInnerRectLTWH.xy;\n";
-const char* gVS_Footer =
- "}\n\n";
+ " roundRectPos = ((roundRectInvTransform * transformedPosition).xy / roundRectRadius) - "
+ "roundRectInnerRectLTWH.xy;\n";
+const char* gVS_Footer = "}\n\n";
///////////////////////////////////////////////////////////////////////////////
// Fragment shaders snippets
///////////////////////////////////////////////////////////////////////////////
-const char* gFS_Header_Start =
- "#version 100\n";
+const char* gFS_Header_Start = "#version 100\n";
const char* gFS_Header_Extension_FramebufferFetch =
"#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
const char* gFS_Header_Extension_ExternalTexture =
"#extension GL_OES_EGL_image_external : require\n\n";
-const char* gFS_Header =
- "precision mediump float;\n\n";
-const char* gFS_Uniforms_Color =
- "uniform vec4 color;\n";
-const char* gFS_Uniforms_TextureSampler =
- "uniform sampler2D baseSampler;\n";
-const char* gFS_Uniforms_ExternalTextureSampler =
- "uniform samplerExternalOES baseSampler;\n";
+const char* gFS_Header = "precision mediump float;\n\n";
+const char* gFS_Uniforms_Color = "uniform vec4 color;\n";
+const char* gFS_Uniforms_TextureSampler = "uniform sampler2D baseSampler;\n";
+const char* gFS_Uniforms_ExternalTextureSampler = "uniform samplerExternalOES baseSampler;\n";
const char* gFS_Uniforms_GradientSampler[2] = {
"uniform vec2 screenSize;\n"
"uniform sampler2D gradientSampler;\n",
"uniform vec2 screenSize;\n"
"uniform vec4 startColor;\n"
- "uniform vec4 endColor;\n"
-};
-const char* gFS_Uniforms_BitmapSampler =
- "uniform sampler2D bitmapSampler;\n";
-const char* gFS_Uniforms_BitmapExternalSampler =
- "uniform samplerExternalOES bitmapSampler;\n";
+ "uniform vec4 endColor;\n"};
+const char* gFS_Uniforms_BitmapSampler = "uniform sampler2D bitmapSampler;\n";
+const char* gFS_Uniforms_BitmapExternalSampler = "uniform samplerExternalOES bitmapSampler;\n";
const char* gFS_Uniforms_ColorOp[3] = {
// None
"",
@@ -156,8 +129,7 @@ const char* gFS_Uniforms_ColorOp[3] = {
"uniform mat4 colorMatrix;\n"
"uniform vec4 colorMatrixVector;\n",
// PorterDuff
- "uniform vec4 colorBlend;\n"
-};
+ "uniform vec4 colorBlend;\n"};
const char* gFS_Uniforms_HasRoundRectClip =
"uniform mediump vec4 roundRectInnerRectLTWH;\n"
@@ -172,11 +144,8 @@ const char* gFS_Uniforms_TransferFunction[4] = {
// In this order: g, a, b, c, d, e, f
// See ColorSpace::TransferParameters
// We'll use hardware sRGB conversion as much as possible
- "",
- "uniform float transferFunction[7];\n",
- "uniform float transferFunction[5];\n",
- "uniform float transferFunctionGamma;\n"
-};
+ "", "uniform float transferFunction[7];\n", "uniform float transferFunction[5];\n",
+ "uniform float transferFunctionGamma;\n"};
const char* gFS_OETF[2] = {
R"__SHADER__(
@@ -189,8 +158,7 @@ const char* gFS_OETF[2] = {
vec4 OETF(const vec4 linear) {
return vec4(sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)), linear.a);
}
- )__SHADER__"
-};
+ )__SHADER__"};
const char* gFS_ColorConvert[3] = {
// Just OETF
@@ -274,8 +242,7 @@ const char* gFS_TransferFunction[4] = {
pow(x.g, transferFunctionGamma),
pow(x.b, transferFunctionGamma));
}
- )__SHADER__"
-};
+ )__SHADER__"};
// Dithering must be done in the quantization space
// When we are writing to an sRGB framebuffer, we must do the following:
@@ -327,16 +294,12 @@ const char* gFS_Main =
"\nvoid main(void) {\n"
" vec4 fragColor;\n";
-const char* gFS_Main_AddDither =
- " fragColor = dither(fragColor);\n";
+const char* gFS_Main_AddDither = " fragColor = dither(fragColor);\n";
// General case
-const char* gFS_Main_FetchColor =
- " fragColor = color;\n";
-const char* gFS_Main_ModulateColor =
- " fragColor *= color.a;\n";
-const char* gFS_Main_ApplyVertexAlphaLinearInterp =
- " fragColor *= alpha;\n";
+const char* gFS_Main_FetchColor = " fragColor = color;\n";
+const char* gFS_Main_ModulateColor = " fragColor *= color.a;\n";
+const char* gFS_Main_ApplyVertexAlphaLinearInterp = " fragColor *= alpha;\n";
const char* gFS_Main_ApplyVertexAlphaShadowInterp =
// map alpha through shadow alpha sampler
" fragColor *= texture2D(baseSampler, vec2(alpha, 0.5)).a;\n";
@@ -344,8 +307,7 @@ const char* gFS_Main_FetchTexture[2] = {
// Don't modulate
" fragColor = colorConvert(texture2D(baseSampler, outTexCoords));\n",
// Modulate
- " fragColor = color * colorConvert(texture2D(baseSampler, outTexCoords));\n"
-};
+ " fragColor = color * colorConvert(texture2D(baseSampler, outTexCoords));\n"};
const char* gFS_Main_FetchA8Texture[4] = {
// Don't modulate
" fragColor = texture2D(baseSampler, outTexCoords);\n",
@@ -370,53 +332,46 @@ const char* gFS_Main_FetchGradient[6] = {
" vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
" highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
- " vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
-};
+ " vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, "
+ "1.0));\n"};
const char* gFS_Main_FetchBitmap =
" vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, outBitmapTexCoords));\n";
const char* gFS_Main_FetchBitmapNpot =
- " vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, wrap(outBitmapTexCoords)));\n";
-const char* gFS_Main_BlendShadersBG =
- " fragColor = blendShaders(gradientColor, bitmapColor)";
-const char* gFS_Main_BlendShadersGB =
- " fragColor = blendShaders(bitmapColor, gradientColor)";
+ " vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, "
+ "wrap(outBitmapTexCoords)));\n";
+const char* gFS_Main_BlendShadersBG = " fragColor = blendShaders(gradientColor, bitmapColor)";
+const char* gFS_Main_BlendShadersGB = " fragColor = blendShaders(bitmapColor, gradientColor)";
const char* gFS_Main_BlendShaders_Modulate[6] = {
// Don't modulate
- ";\n",
- ";\n",
+ ";\n", ";\n",
// Modulate
- " * color.a;\n",
- " * color.a;\n",
+ " * color.a;\n", " * color.a;\n",
// Modulate with alpha 8 texture
" * texture2D(baseSampler, outTexCoords).a;\n",
" * gamma(texture2D(baseSampler, outTexCoords).a, color.rgb);\n",
};
const char* gFS_Main_GradientShader_Modulate[6] = {
// Don't modulate
- " fragColor = gradientColor;\n",
- " fragColor = gradientColor;\n",
+ " fragColor = gradientColor;\n", " fragColor = gradientColor;\n",
// Modulate
- " fragColor = gradientColor * color.a;\n",
- " fragColor = gradientColor * color.a;\n",
+ " fragColor = gradientColor * color.a;\n", " fragColor = gradientColor * color.a;\n",
// Modulate with alpha 8 texture
" fragColor = gradientColor * texture2D(baseSampler, outTexCoords).a;\n",
- " fragColor = gradientColor * gamma(texture2D(baseSampler, outTexCoords).a, gradientColor.rgb);\n",
- };
+ " fragColor = gradientColor * gamma(texture2D(baseSampler, outTexCoords).a, "
+ "gradientColor.rgb);\n",
+};
const char* gFS_Main_BitmapShader_Modulate[6] = {
// Don't modulate
- " fragColor = bitmapColor;\n",
- " fragColor = bitmapColor;\n",
+ " fragColor = bitmapColor;\n", " fragColor = bitmapColor;\n",
// Modulate
- " fragColor = bitmapColor * color.a;\n",
- " fragColor = bitmapColor * color.a;\n",
+ " fragColor = bitmapColor * color.a;\n", " fragColor = bitmapColor * color.a;\n",
// Modulate with alpha 8 texture
" fragColor = bitmapColor * texture2D(baseSampler, outTexCoords).a;\n",
- " fragColor = bitmapColor * gamma(texture2D(baseSampler, outTexCoords).a, bitmapColor.rgb);\n",
- };
-const char* gFS_Main_FragColor =
- " gl_FragColor = fragColor;\n";
-const char* gFS_Main_FragColor_HasColors =
- " gl_FragColor *= outColors;\n";
+ " fragColor = bitmapColor * gamma(texture2D(baseSampler, outTexCoords).a, "
+ "bitmapColor.rgb);\n",
+};
+const char* gFS_Main_FragColor = " gl_FragColor = fragColor;\n";
+const char* gFS_Main_FragColor_HasColors = " gl_FragColor *= outColors;\n";
const char* gFS_Main_FragColor_Blend =
" gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n";
const char* gFS_Main_FragColor_Blend_Swap =
@@ -425,13 +380,12 @@ const char* gFS_Main_ApplyColorOp[3] = {
// None
"",
// Matrix
- " fragColor.rgb /= (fragColor.a + 0.0019);\n" // un-premultiply
+ " fragColor.rgb /= (fragColor.a + 0.0019);\n" // un-premultiply
" fragColor *= colorMatrix;\n"
" fragColor += colorMatrixVector;\n"
- " fragColor.rgb *= (fragColor.a + 0.0019);\n", // re-premultiply
+ " fragColor.rgb *= (fragColor.a + 0.0019);\n", // re-premultiply
// PorterDuff
- " fragColor = blendColors(colorBlend, fragColor);\n"
-};
+ " fragColor = blendColors(colorBlend, fragColor);\n"};
// Note: LTWH (left top width height) -> xyzw
// roundRectPos is now divided by roundRectRadius in vertex shader
@@ -443,13 +397,12 @@ const char* gFS_Main_FragColor_HasRoundRectClip =
// since distance is divided by radius, it's in [0;1] so precision is not an issue
// this also lets us clamp(0.0, 1.0) instead of max() which is cheaper on GPUs
" mediump vec2 dist = clamp(max(fragToLT, fragFromRB), 0.0, 1.0);\n"
- " mediump float linearDist = clamp(roundRectRadius - (length(dist) * roundRectRadius), 0.0, 1.0);\n"
+ " mediump float linearDist = clamp(roundRectRadius - (length(dist) * roundRectRadius), "
+ "0.0, 1.0);\n"
" gl_FragColor *= linearDist;\n";
-const char* gFS_Main_DebugHighlight =
- " gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n";
-const char* gFS_Footer =
- "}\n\n";
+const char* gFS_Main_DebugHighlight = " gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n";
+const char* gFS_Footer = "}\n\n";
///////////////////////////////////////////////////////////////////////////////
// PorterDuff snippets
@@ -480,7 +433,7 @@ const char* gBlendOps[18] = {
"return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n",
// Xor
"return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
- "src.a + dst.a - 2.0 * src.a * dst.a);\n",
+ "src.a + dst.a - 2.0 * src.a * dst.a);\n",
// Plus
"return min(src + dst, 1.0);\n",
// Modulate
@@ -489,16 +442,17 @@ const char* gBlendOps[18] = {
"return src + dst - src * dst;\n",
// Overlay
"return clamp(vec4(mix("
- "2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
- "src.a * dst.a - 2.0 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
- "step(dst.a, 2.0 * dst.rgb)), "
- "src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n",
+ "2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
+ "src.a * dst.a - 2.0 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1.0 - dst.a) + "
+ "dst.rgb * (1.0 - src.a), "
+ "step(dst.a, 2.0 * dst.rgb)), "
+ "src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n",
// Darken
"return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
- "min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
+ "min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
// Lighten
"return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
- "max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
+ "max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
};
///////////////////////////////////////////////////////////////////////////////
@@ -507,8 +461,7 @@ const char* gBlendOps[18] = {
ProgramCache::ProgramCache(const Extensions& extensions)
: mHasES3(extensions.getMajorGlVersion() >= 3)
- , mHasLinearBlending(extensions.hasLinearBlending()) {
-}
+ , mHasLinearBlending(extensions.hasLinearBlending()) {}
ProgramCache::~ProgramCache() {
clear();
@@ -605,7 +558,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
}
// Begin the shader
- shader.append(gVS_Main); {
+ shader.append(gVS_Main);
+ {
if (description.hasTextureTransform) {
shader.append(gVS_Main_OutTransformedTexCoords);
} else if (description.hasTexture || description.hasExternalTexture) {
@@ -637,8 +591,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
return shader;
}
-static bool shaderOp(const ProgramDescription& description, String8& shader,
- const int modulateOp, const char** snippets) {
+static bool shaderOp(const ProgramDescription& description, String8& shader, const int modulateOp,
+ const char** snippets) {
int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
op = op * 2 + description.hasGammaCorrection;
shader.append(snippets[op]);
@@ -652,8 +606,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
if (blendFramebuffer) {
shader.append(gFS_Header_Extension_FramebufferFetch);
}
- if (description.hasExternalTexture
- || (description.hasBitmap && description.isShaderBitmapExternal)) {
+ if (description.hasExternalTexture ||
+ (description.hasBitmap && description.isShaderBitmapExternal)) {
shader.append(gFS_Header_Extension_ExternalTexture);
}
@@ -682,7 +636,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
// Uniforms
int modulateOp = MODULATE_OP_NO_MODULATE;
const bool singleColor = !description.hasTexture && !description.hasExternalTexture &&
- !description.hasGradient && !description.hasBitmap;
+ !description.hasGradient && !description.hasBitmap;
if (description.modulate || singleColor) {
shader.append(gFS_Uniforms_Color);
@@ -701,7 +655,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
}
if (description.hasGammaCorrection) {
- shader.appendFormat(gFS_Gamma_Preamble, Properties::textGamma, 1.0f / Properties::textGamma);
+ shader.appendFormat(gFS_Gamma_Preamble, Properties::textGamma,
+ 1.0f / Properties::textGamma);
}
if (description.hasBitmap) {
@@ -731,17 +686,19 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
if (description.useShaderBasedWrap) {
generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
}
- if (description.hasGradient || description.hasLinearTexture
- || description.hasColorSpaceConversion) {
+ if (description.hasGradient || description.hasLinearTexture ||
+ description.hasColorSpaceConversion) {
shader.append(gFS_sRGB_TransferFunctions);
}
if (description.hasBitmap || ((description.hasTexture || description.hasExternalTexture) &&
- !description.hasAlpha8Texture)) {
+ !description.hasAlpha8Texture)) {
shader.append(gFS_TransferFunction[static_cast<int>(description.transferFunction)]);
- shader.append(gFS_OETF[(description.hasLinearTexture || description.hasColorSpaceConversion)
- && !mHasLinearBlending]);
+ shader.append(
+ gFS_OETF[(description.hasLinearTexture || description.hasColorSpaceConversion) &&
+ !mHasLinearBlending]);
shader.append(gFS_ColorConvert[description.hasColorSpaceConversion
- ? 1 + description.hasTranslucentConversion : 0]);
+ ? 1 + description.hasTranslucentConversion
+ : 0]);
}
if (description.hasGradient) {
shader.append(gFS_GradientFunctions);
@@ -749,13 +706,14 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
}
// Begin the shader
- shader.append(gFS_Main); {
+ shader.append(gFS_Main);
+ {
// Stores the result in fragColor directly
if (description.hasTexture || description.hasExternalTexture) {
if (description.hasAlpha8Texture) {
if (!description.hasGradient && !description.hasBitmap) {
- shader.append(
- gFS_Main_FetchA8Texture[modulateOp * 2 + description.hasGammaCorrection]);
+ shader.append(gFS_Main_FetchA8Texture[modulateOp * 2 +
+ description.hasGammaCorrection]);
}
} else {
shader.append(gFS_Main_FetchTexture[modulateOp]);
@@ -783,15 +741,15 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
} else {
shader.append(gFS_Main_BlendShadersGB);
}
- applyModulate = shaderOp(description, shader, modulateOp,
- gFS_Main_BlendShaders_Modulate);
+ applyModulate =
+ shaderOp(description, shader, modulateOp, gFS_Main_BlendShaders_Modulate);
} else {
if (description.hasGradient) {
- applyModulate = shaderOp(description, shader, modulateOp,
- gFS_Main_GradientShader_Modulate);
+ applyModulate =
+ shaderOp(description, shader, modulateOp, gFS_Main_GradientShader_Modulate);
} else if (description.hasBitmap) {
- applyModulate = shaderOp(description, shader, modulateOp,
- gFS_Main_BitmapShader_Modulate);
+ applyModulate =
+ shaderOp(description, shader, modulateOp, gFS_Main_BitmapShader_Modulate);
}
}
@@ -818,8 +776,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
if (!blendFramebuffer) {
shader.append(gFS_Main_FragColor);
} else {
- shader.append(!description.swapSrcDst ?
- gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap);
+ shader.append(!description.swapSrcDst ? gFS_Main_FragColor_Blend
+ : gFS_Main_FragColor_Blend_Swap);
}
if (description.hasColors) {
shader.append(gFS_Main_FragColor_HasColors);
@@ -835,8 +793,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
shader.append(gFS_Footer);
#if DEBUG_PROGRAMS
- PROGRAM_LOGD("*** Generated fragment shader:\n\n");
- printLongString(shader);
+ PROGRAM_LOGD("*** Generated fragment shader:\n\n");
+ printLongString(shader);
#endif
return shader;
@@ -903,5 +861,5 @@ void ProgramCache::printLongString(const String8& shader) const {
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index ee76f22f35d4..488a4994ba95 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -60,9 +60,9 @@ private:
const bool mHasES3;
const bool mHasLinearBlending;
-}; // class ProgramCache
+}; // class ProgramCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_PROGRAM_CACHE_H
+#endif // ANDROID_HWUI_PROGRAM_CACHE_H
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 588c4dea998f..d41db63aed92 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -61,7 +61,9 @@ bool Properties::disableVsync = false;
bool Properties::skpCaptureEnabled = false;
static int property_get_int(const char* key, int defaultValue) {
- char buf[PROPERTY_VALUE_MAX] = {'\0',};
+ char buf[PROPERTY_VALUE_MAX] = {
+ '\0',
+ };
if (property_get(key, buf, "") > 0) {
return atoi(buf);
@@ -121,7 +123,7 @@ bool Properties::load() {
showDirtyRegions = property_get_bool(PROPERTY_DEBUG_SHOW_DIRTY_REGIONS, false);
- debugLevel = (DebugLevel) property_get_int(PROPERTY_DEBUG, kDebugDisabled);
+ debugLevel = (DebugLevel)property_get_int(PROPERTY_DEBUG, kDebugDisabled);
skipEmptyFrames = property_get_bool(PROPERTY_SKIP_EMPTY_DAMAGE, true);
useBufferAge = property_get_bool(PROPERTY_USE_BUFFER_AGE, true);
@@ -129,12 +131,11 @@ bool Properties::load() {
filterOutTestOverhead = property_get_bool(PROPERTY_FILTER_TEST_OVERHEAD, false);
- skpCaptureEnabled = property_get_bool("ro.debuggable", false)
- && property_get_bool(PROPERTY_CAPTURE_SKP_ENABLED, false);
+ skpCaptureEnabled = property_get_bool("ro.debuggable", false) &&
+ property_get_bool(PROPERTY_CAPTURE_SKP_ENABLED, false);
- return (prevDebugLayersUpdates != debugLayersUpdates)
- || (prevDebugOverdraw != debugOverdraw)
- || (prevDebugStencilClip != debugStencilClip);
+ return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw) ||
+ (prevDebugStencilClip != debugStencilClip);
}
void Properties::overrideProperty(const char* name, const char* value) {
@@ -177,35 +178,40 @@ ProfileType Properties::getProfileType() {
}
RenderPipelineType Properties::getRenderPipelineType() {
- if (RenderPipelineType::NotInitialized != sRenderPipelineType) {
+ if (sRenderPipelineType != RenderPipelineType::NotInitialized) {
return sRenderPipelineType;
}
char prop[PROPERTY_VALUE_MAX];
property_get(PROPERTY_RENDERER, prop, "skiagl");
- if (!strcmp(prop, "skiagl") ) {
+ if (!strcmp(prop, "skiagl")) {
ALOGD("Skia GL Pipeline");
sRenderPipelineType = RenderPipelineType::SkiaGL;
- } else if (!strcmp(prop, "skiavk") ) {
+ } else if (!strcmp(prop, "skiavk")) {
ALOGD("Skia Vulkan Pipeline");
sRenderPipelineType = RenderPipelineType::SkiaVulkan;
- } else { //"opengl"
+ } else { //"opengl"
ALOGD("HWUI GL Pipeline");
sRenderPipelineType = RenderPipelineType::OpenGL;
}
return sRenderPipelineType;
}
-#ifdef HWUI_GLES_WRAP_ENABLED
void Properties::overrideRenderPipelineType(RenderPipelineType type) {
+#if !defined(HWUI_GLES_WRAP_ENABLED)
+ // If we're doing actual rendering then we can't change the renderer after it's been set.
+ // Unit tests can freely change this as often as it wants, though, as there's no actual
+ // GL rendering happening
+ if (sRenderPipelineType != RenderPipelineType::NotInitialized) {
+ return;
+ }
+#endif
sRenderPipelineType = type;
}
-#endif
bool Properties::isSkiaEnabled() {
auto renderType = getRenderPipelineType();
- return RenderPipelineType::SkiaGL == renderType
- || RenderPipelineType::SkiaVulkan == renderType;
+ return RenderPipelineType::SkiaGL == renderType || RenderPipelineType::SkiaVulkan == renderType;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 077e7aee6579..9c30e4a166f3 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -170,11 +170,10 @@ enum DebugLevel {
*/
#define PROPERTY_CAPTURE_SKP_ENABLED "debug.hwui.capture_skp_enabled"
-
/**
* Defines how many frames in a sequence to capture.
*/
-#define PROPERTY_CAPTURE_SKP_FRAMES "debug.hwui.capture_skp_frames"
+#define PROPERTY_CAPTURE_SKP_FRAMES "debug.hwui.capture_skp_frames"
/**
* File name and location, where a SKP recording will be saved.
@@ -186,33 +185,17 @@ enum DebugLevel {
///////////////////////////////////////////////////////////////////////////////
// Converts a number of mega-bytes into bytes
-#define MB(s) ((s) * 1024 * 1024)
+#define MB(s) ((s)*1024 * 1024)
// Converts a number of kilo-bytes into bytes
-#define KB(s) ((s) * 1024)
+#define KB(s) ((s)*1024)
-enum class ProfileType {
- None,
- Console,
- Bars
-};
+enum class ProfileType { None, Console, Bars };
-enum class OverdrawColorSet {
- Default = 0,
- Deuteranomaly
-};
+enum class OverdrawColorSet { Default = 0, Deuteranomaly };
-enum class StencilClipDebug {
- Hide,
- ShowHighlight,
- ShowRegion
-};
+enum class StencilClipDebug { Hide, ShowHighlight, ShowRegion };
-enum class RenderPipelineType {
- OpenGL = 0,
- SkiaGL,
- SkiaVulkan,
- NotInitialized = 128
-};
+enum class RenderPipelineType { OpenGL = 0, SkiaGL, SkiaVulkan, NotInitialized = 128 };
/**
* Renderthread-only singleton which manages several static rendering properties. Most of these
@@ -251,7 +234,7 @@ public:
static int overrideSpotShadowStrength;
static ProfileType getProfileType();
- static RenderPipelineType getRenderPipelineType();
+ ANDROID_API static RenderPipelineType getRenderPipelineType();
static bool isSkiaEnabled();
ANDROID_API static bool enableHighContrastText;
@@ -273,17 +256,15 @@ public:
static bool skpCaptureEnabled;
// Used for testing only to change the render pipeline.
-#ifdef HWUI_GLES_WRAP_ENABLED
static void overrideRenderPipelineType(RenderPipelineType);
-#endif
private:
static ProfileType sProfileType;
static bool sDisableProfileBars;
static RenderPipelineType sRenderPipelineType;
-}; // class Caches
+}; // class Caches
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_PROPERTIES_H
+#endif // ANDROID_HWUI_PROPERTIES_H
diff --git a/libs/hwui/PropertyValuesAnimatorSet.cpp b/libs/hwui/PropertyValuesAnimatorSet.cpp
index e3258e3c1a48..65a5aa4c0112 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.cpp
+++ b/libs/hwui/PropertyValuesAnimatorSet.cpp
@@ -23,11 +23,11 @@ namespace android {
namespace uirenderer {
void PropertyValuesAnimatorSet::addPropertyAnimator(PropertyValuesHolder* propertyValuesHolder,
- Interpolator* interpolator, nsecs_t startDelay, nsecs_t duration, int repeatCount,
- RepeatMode repeatMode) {
-
- PropertyAnimator* animator = new PropertyAnimator(propertyValuesHolder,
- interpolator, startDelay, duration, repeatCount, repeatMode);
+ Interpolator* interpolator, nsecs_t startDelay,
+ nsecs_t duration, int repeatCount,
+ RepeatMode repeatMode) {
+ PropertyAnimator* animator = new PropertyAnimator(
+ propertyValuesHolder, interpolator, startDelay, duration, repeatCount, repeatMode);
mAnimators.emplace_back(animator);
// Check whether any child animator is infinite after adding it them to the set.
@@ -36,8 +36,7 @@ void PropertyValuesAnimatorSet::addPropertyAnimator(PropertyValuesHolder* proper
}
}
-PropertyValuesAnimatorSet::PropertyValuesAnimatorSet()
- : BaseRenderNodeAnimator(1.0f) {
+PropertyValuesAnimatorSet::PropertyValuesAnimatorSet() : BaseRenderNodeAnimator(1.0f) {
setStartValue(0);
mLastFraction = 0.0f;
setInterpolator(new LinearInterpolator());
@@ -77,7 +76,7 @@ void PropertyValuesAnimatorSet::onPlayTimeChanged(nsecs_t playTime) {
// have the final say on what the property value should be.
(*it)->setFraction(0, 0);
}
- } else {
+ } else {
for (auto& anim : mAnimators) {
anim->setCurrentPlayTime(playTime);
}
@@ -116,9 +115,8 @@ void PropertyValuesAnimatorSet::init() {
// Sort the animators by their total duration. Note that all the animators in the set start at
// the same time, so the ones with longer total duration (which includes start delay) will
// be the ones that end later.
- std::sort(mAnimators.begin(), mAnimators.end(), [](auto& a, auto&b) {
- return a->getTotalDuration() < b->getTotalDuration();
- });
+ std::sort(mAnimators.begin(), mAnimators.end(),
+ [](auto& a, auto& b) { return a->getTotalDuration() < b->getTotalDuration(); });
mDuration = mAnimators.empty() ? 0 : mAnimators[mAnimators.size() - 1]->getTotalDuration();
mInitialized = true;
}
@@ -128,17 +126,19 @@ uint32_t PropertyValuesAnimatorSet::dirtyMask() {
}
PropertyAnimator::PropertyAnimator(PropertyValuesHolder* holder, Interpolator* interpolator,
- nsecs_t startDelay, nsecs_t duration, int repeatCount,
- RepeatMode repeatMode)
- : mPropertyValuesHolder(holder), mInterpolator(interpolator), mStartDelay(startDelay),
- mDuration(duration) {
+ nsecs_t startDelay, nsecs_t duration, int repeatCount,
+ RepeatMode repeatMode)
+ : mPropertyValuesHolder(holder)
+ , mInterpolator(interpolator)
+ , mStartDelay(startDelay)
+ , mDuration(duration) {
if (repeatCount < 0) {
mRepeatCount = UINT32_MAX;
} else {
mRepeatCount = repeatCount;
}
mRepeatMode = repeatMode;
- mTotalDuration = ((nsecs_t) mRepeatCount + 1) * mDuration + mStartDelay;
+ mTotalDuration = ((nsecs_t)mRepeatCount + 1) * mDuration + mStartDelay;
}
void PropertyAnimator::setCurrentPlayTime(nsecs_t playTime) {
@@ -155,7 +155,7 @@ void PropertyAnimator::setCurrentPlayTime(nsecs_t playTime) {
} else {
// play time here is in range [mStartDelay, mTotalDuration)
iteration = (playTime - mStartDelay) / mDuration;
- currentIterationFraction = ((playTime - mStartDelay) % mDuration) / (float) mDuration;
+ currentIterationFraction = ((playTime - mStartDelay) % mDuration) / (float)mDuration;
}
setFraction(currentIterationFraction, iteration);
}
@@ -182,6 +182,5 @@ void PropertyAnimator::setFraction(float fraction, long iteration) {
void PropertyAnimatorSetListener::onAnimationFinished(BaseRenderNodeAnimator* animator) {
mSet->onFinished(animator);
}
-
}
}
diff --git a/libs/hwui/PropertyValuesAnimatorSet.h b/libs/hwui/PropertyValuesAnimatorSet.h
index a5d9e869196f..e4214b22d1cc 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.h
+++ b/libs/hwui/PropertyValuesAnimatorSet.h
@@ -17,8 +17,8 @@
#pragma once
#include "Animator.h"
-#include "PropertyValuesHolder.h"
#include "Interpolator.h"
+#include "PropertyValuesHolder.h"
namespace android {
namespace uirenderer {
@@ -26,11 +26,9 @@ namespace uirenderer {
class PropertyAnimator {
public:
PropertyAnimator(PropertyValuesHolder* holder, Interpolator* interpolator, nsecs_t startDelay,
- nsecs_t duration, int repeatCount, RepeatMode repeatMode);
+ nsecs_t duration, int repeatCount, RepeatMode repeatMode);
void setCurrentPlayTime(nsecs_t playTime);
- nsecs_t getTotalDuration() {
- return mTotalDuration;
- }
+ nsecs_t getTotalDuration() { return mTotalDuration; }
// fraction range: [0, 1], iteration range [0, repeatCount]
void setFraction(float fraction, long iteration);
@@ -57,8 +55,8 @@ public:
virtual void end() override;
void addPropertyAnimator(PropertyValuesHolder* propertyValuesHolder,
- Interpolator* interpolators, int64_t startDelays,
- nsecs_t durations, int repeatCount, RepeatMode repeatMode);
+ Interpolator* interpolators, int64_t startDelays, nsecs_t durations,
+ int repeatCount, RepeatMode repeatMode);
virtual uint32_t dirtyMask();
bool isInfinite() { return mIsInfinite; }
void setVectorDrawable(VectorDrawableRoot* vd) { mVectorDrawable = vd; }
@@ -77,7 +75,7 @@ private:
void onFinished(BaseRenderNodeAnimator* animator);
// Listener set from outside
sp<AnimationListener> mOneShotListener;
- std::vector< std::unique_ptr<PropertyAnimator> > mAnimators;
+ std::vector<std::unique_ptr<PropertyAnimator> > mAnimators;
float mLastFraction = 0.0f;
bool mInitialized = false;
sp<VectorDrawableRoot> mVectorDrawable;
@@ -96,5 +94,5 @@ private:
PropertyValuesAnimatorSet* mSet;
};
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/PropertyValuesHolder.cpp b/libs/hwui/PropertyValuesHolder.cpp
index 2a03e6a3ebc5..35526255759f 100644
--- a/libs/hwui/PropertyValuesHolder.cpp
+++ b/libs/hwui/PropertyValuesHolder.cpp
@@ -27,7 +27,7 @@ namespace uirenderer {
using namespace VectorDrawable;
inline constexpr float lerp(float fromValue, float toValue, float fraction) {
- return float (fromValue * (1 - fraction) + toValue * fraction);
+ return float(fromValue * (1 - fraction) + toValue * fraction);
}
inline constexpr float linearize(U8CPU component) {
@@ -35,25 +35,23 @@ inline constexpr float linearize(U8CPU component) {
}
// TODO: Add a test for this
-void ColorEvaluator::evaluate(SkColor* outColor,
- const SkColor& fromColor, const SkColor& toColor, float fraction) const {
+void ColorEvaluator::evaluate(SkColor* outColor, const SkColor& fromColor, const SkColor& toColor,
+ float fraction) const {
float a = lerp(SkColorGetA(fromColor) / 255.0f, SkColorGetA(toColor) / 255.0f, fraction);
float r = lerp(linearize(SkColorGetR(fromColor)), linearize(SkColorGetR(toColor)), fraction);
float g = lerp(linearize(SkColorGetG(fromColor)), linearize(SkColorGetG(toColor)), fraction);
float b = lerp(linearize(SkColorGetB(fromColor)), linearize(SkColorGetB(toColor)), fraction);
- *outColor = SkColorSetARGB(
- (U8CPU) roundf(a * 255.0f),
- (U8CPU) roundf(OECF_sRGB(r) * 255.0f),
- (U8CPU) roundf(OECF_sRGB(g) * 255.0f),
- (U8CPU) roundf(OECF_sRGB(b) * 255.0f));
+ *outColor = SkColorSetARGB((U8CPU)roundf(a * 255.0f), (U8CPU)roundf(OECF_sRGB(r) * 255.0f),
+ (U8CPU)roundf(OECF_sRGB(g) * 255.0f),
+ (U8CPU)roundf(OECF_sRGB(b) * 255.0f));
}
-void PathEvaluator::evaluate(PathData* out,
- const PathData& from, const PathData& to, float fraction) const {
+void PathEvaluator::evaluate(PathData* out, const PathData& from, const PathData& to,
+ float fraction) const {
VectorDrawableUtils::interpolatePaths(out, from, to, fraction);
}
-template<typename T>
+template <typename T>
const T PropertyValuesHolderImpl<T>::getValueFromData(float fraction) const {
if (mDataSource.size() == 0) {
LOG_ALWAYS_FATAL("No data source is defined");
@@ -75,7 +73,7 @@ const T PropertyValuesHolderImpl<T>::getValueFromData(float fraction) const {
return value;
}
-template<typename T>
+template <typename T>
const T PropertyValuesHolderImpl<T>::calculateAnimatedValue(float fraction) const {
if (mDataSource.size() > 0) {
return getValueFromData(fraction);
@@ -111,5 +109,5 @@ void RootAlphaPropertyValuesHolder::setFraction(float fraction) {
mTree->mutateProperties()->setRootAlpha(animatedValue);
}
-} // namepace uirenderer
-} // namespace android
+} // namepace uirenderer
+} // namespace android
diff --git a/libs/hwui/PropertyValuesHolder.h b/libs/hwui/PropertyValuesHolder.h
index 432f8ba82afb..0a799d3c0b5c 100644
--- a/libs/hwui/PropertyValuesHolder.h
+++ b/libs/hwui/PropertyValuesHolder.h
@@ -43,8 +43,8 @@ public:
class FloatEvaluator : public Evaluator<float> {
public:
- virtual void evaluate(float* out, const float& from, const float& to, float fraction)
- const override {
+ virtual void evaluate(float* out, const float& from, const float& to,
+ float fraction) const override {
*out = from * (1 - fraction) + to * fraction;
}
};
@@ -52,20 +52,19 @@ public:
class ANDROID_API ColorEvaluator : public Evaluator<SkColor> {
public:
virtual void evaluate(SkColor* outColor, const SkColor& from, const SkColor& to,
- float fraction) const override;
+ float fraction) const override;
};
class ANDROID_API PathEvaluator : public Evaluator<PathData> {
- virtual void evaluate(PathData* out, const PathData& from, const PathData& to, float fraction)
- const override;
+ virtual void evaluate(PathData* out, const PathData& from, const PathData& to,
+ float fraction) const override;
};
template <typename T>
class ANDROID_API PropertyValuesHolderImpl : public PropertyValuesHolder {
public:
PropertyValuesHolderImpl(const T& startValue, const T& endValue)
- : mStartValue(startValue)
- , mEndValue(endValue) {}
+ : mStartValue(startValue), mEndValue(endValue) {}
void setPropertyDataSource(T* dataSource, int length) {
mDataSource.insert(mDataSource.begin(), dataSource, dataSource + length);
}
@@ -74,27 +73,27 @@ public:
// Convenient method to favor getting animated value from data source. If no data source is set
// fall back to linear interpolation.
const T calculateAnimatedValue(float fraction) const;
+
protected:
- std::unique_ptr<Evaluator<T>> mEvaluator = nullptr;
- // This contains uniformly sampled data throughout the animation duration. The first element
- // should be the start value and the last should be the end value of the animation. When the
- // data source is set, we'll favor data source over the linear interpolation of start/end value
- // for calculation of animated value.
- std::vector<T> mDataSource;
- T mStartValue;
- T mEndValue;
+ std::unique_ptr<Evaluator<T>> mEvaluator = nullptr;
+ // This contains uniformly sampled data throughout the animation duration. The first element
+ // should be the start value and the last should be the end value of the animation. When the
+ // data source is set, we'll favor data source over the linear interpolation of start/end value
+ // for calculation of animated value.
+ std::vector<T> mDataSource;
+ T mStartValue;
+ T mEndValue;
};
class ANDROID_API GroupPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
public:
GroupPropertyValuesHolder(VectorDrawable::Group* ptr, int propertyId, float startValue,
- float endValue)
- : PropertyValuesHolderImpl(startValue, endValue)
- , mGroup(ptr)
- , mPropertyId(propertyId) {
+ float endValue)
+ : PropertyValuesHolderImpl(startValue, endValue), mGroup(ptr), mPropertyId(propertyId) {
mEvaluator.reset(new FloatEvaluator());
}
void setFraction(float fraction) override;
+
private:
VectorDrawable::Group* mGroup;
int mPropertyId;
@@ -103,7 +102,7 @@ private:
class ANDROID_API FullPathColorPropertyValuesHolder : public PropertyValuesHolderImpl<SkColor> {
public:
FullPathColorPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId,
- SkColor startValue, SkColor endValue)
+ SkColor startValue, SkColor endValue)
: PropertyValuesHolderImpl(startValue, endValue)
, mFullPath(ptr)
, mPropertyId(propertyId) {
@@ -111,6 +110,7 @@ public:
}
void setFraction(float fraction) override;
static SkColor interpolateColors(SkColor fromColor, SkColor toColor, float fraction);
+
private:
VectorDrawable::FullPath* mFullPath;
int mPropertyId;
@@ -119,13 +119,14 @@ private:
class ANDROID_API FullPathPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
public:
FullPathPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId, float startValue,
- float endValue)
+ float endValue)
: PropertyValuesHolderImpl(startValue, endValue)
, mFullPath(ptr)
, mPropertyId(propertyId) {
mEvaluator.reset(new FloatEvaluator());
};
void setFraction(float fraction) override;
+
private:
VectorDrawable::FullPath* mFullPath;
int mPropertyId;
@@ -134,12 +135,12 @@ private:
class ANDROID_API PathDataPropertyValuesHolder : public PropertyValuesHolderImpl<PathData> {
public:
PathDataPropertyValuesHolder(VectorDrawable::Path* ptr, PathData* startValue,
- PathData* endValue)
- : PropertyValuesHolderImpl(*startValue, *endValue)
- , mPath(ptr) {
+ PathData* endValue)
+ : PropertyValuesHolderImpl(*startValue, *endValue), mPath(ptr) {
mEvaluator.reset(new PathEvaluator());
};
void setFraction(float fraction) override;
+
private:
VectorDrawable::Path* mPath;
PathData mPathData;
@@ -148,11 +149,11 @@ private:
class ANDROID_API RootAlphaPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
public:
RootAlphaPropertyValuesHolder(VectorDrawable::Tree* tree, float startValue, float endValue)
- : PropertyValuesHolderImpl(startValue, endValue)
- , mTree(tree) {
+ : PropertyValuesHolderImpl(startValue, endValue), mTree(tree) {
mEvaluator.reset(new FloatEvaluator());
}
void setFraction(float fraction) override;
+
private:
VectorDrawable::Tree* mTree;
};
diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h
index 7cf426228af6..ad3a8b690617 100644
--- a/libs/hwui/Readback.h
+++ b/libs/hwui/Readback.h
@@ -16,8 +16,8 @@
#pragma once
-#include "renderthread/RenderThread.h"
#include "Rect.h"
+#include "renderthread/RenderThread.h"
#include <SkBitmap.h>
@@ -41,8 +41,7 @@ public:
/**
* Copies the surface's most recently queued buffer into the provided bitmap.
*/
- virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
- SkBitmap* bitmap) = 0;
+ virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) = 0;
virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) = 0;
protected:
@@ -52,5 +51,5 @@ protected:
renderthread::RenderThread& mRenderThread;
};
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index 3b87aef942b6..2d0185aaa9e2 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -16,15 +16,15 @@
#pragma once
-#include "font/FontUtil.h"
#include "GlLayer.h"
#include "Matrix.h"
#include "Rect.h"
#include "RenderNode.h"
#include "TessellationCache.h"
+#include "Vector.h"
+#include "font/FontUtil.h"
#include "utils/LinearAllocator.h"
#include "utils/PaintUtils.h"
-#include "Vector.h"
#include <androidfw/ResourceTypes.h>
@@ -73,39 +73,40 @@ class Tree;
* MERGEABLE - These ops can be recorded into DisplayLists and rendered individually, or merged
* under certain circumstances.
*/
-#define MAP_OPS_BASED_ON_TYPE(PRE_RENDER_OP_FN, RENDER_ONLY_OP_FN, UNMERGEABLE_OP_FN, MERGEABLE_OP_FN) \
- PRE_RENDER_OP_FN(RenderNodeOp) \
- PRE_RENDER_OP_FN(CirclePropsOp) \
- PRE_RENDER_OP_FN(RoundRectPropsOp) \
- PRE_RENDER_OP_FN(BeginLayerOp) \
- PRE_RENDER_OP_FN(EndLayerOp) \
- PRE_RENDER_OP_FN(BeginUnclippedLayerOp) \
- PRE_RENDER_OP_FN(EndUnclippedLayerOp) \
- PRE_RENDER_OP_FN(VectorDrawableOp) \
- \
- RENDER_ONLY_OP_FN(ShadowOp) \
- RENDER_ONLY_OP_FN(LayerOp) \
- RENDER_ONLY_OP_FN(CopyToLayerOp) \
- RENDER_ONLY_OP_FN(CopyFromLayerOp) \
- \
- UNMERGEABLE_OP_FN(ArcOp) \
- UNMERGEABLE_OP_FN(BitmapMeshOp) \
- UNMERGEABLE_OP_FN(BitmapRectOp) \
- UNMERGEABLE_OP_FN(ColorOp) \
- UNMERGEABLE_OP_FN(FunctorOp) \
- UNMERGEABLE_OP_FN(LinesOp) \
- UNMERGEABLE_OP_FN(OvalOp) \
- UNMERGEABLE_OP_FN(PathOp) \
- UNMERGEABLE_OP_FN(PointsOp) \
- UNMERGEABLE_OP_FN(RectOp) \
- UNMERGEABLE_OP_FN(RoundRectOp) \
- UNMERGEABLE_OP_FN(SimpleRectsOp) \
- UNMERGEABLE_OP_FN(TextOnPathOp) \
- UNMERGEABLE_OP_FN(TextureLayerOp) \
- \
- MERGEABLE_OP_FN(BitmapOp) \
- MERGEABLE_OP_FN(PatchOp) \
- MERGEABLE_OP_FN(TextOp)
+#define MAP_OPS_BASED_ON_TYPE(PRE_RENDER_OP_FN, RENDER_ONLY_OP_FN, UNMERGEABLE_OP_FN, \
+ MERGEABLE_OP_FN) \
+ PRE_RENDER_OP_FN(RenderNodeOp) \
+ PRE_RENDER_OP_FN(CirclePropsOp) \
+ PRE_RENDER_OP_FN(RoundRectPropsOp) \
+ PRE_RENDER_OP_FN(BeginLayerOp) \
+ PRE_RENDER_OP_FN(EndLayerOp) \
+ PRE_RENDER_OP_FN(BeginUnclippedLayerOp) \
+ PRE_RENDER_OP_FN(EndUnclippedLayerOp) \
+ PRE_RENDER_OP_FN(VectorDrawableOp) \
+ \
+ RENDER_ONLY_OP_FN(ShadowOp) \
+ RENDER_ONLY_OP_FN(LayerOp) \
+ RENDER_ONLY_OP_FN(CopyToLayerOp) \
+ RENDER_ONLY_OP_FN(CopyFromLayerOp) \
+ \
+ UNMERGEABLE_OP_FN(ArcOp) \
+ UNMERGEABLE_OP_FN(BitmapMeshOp) \
+ UNMERGEABLE_OP_FN(BitmapRectOp) \
+ UNMERGEABLE_OP_FN(ColorOp) \
+ UNMERGEABLE_OP_FN(FunctorOp) \
+ UNMERGEABLE_OP_FN(LinesOp) \
+ UNMERGEABLE_OP_FN(OvalOp) \
+ UNMERGEABLE_OP_FN(PathOp) \
+ UNMERGEABLE_OP_FN(PointsOp) \
+ UNMERGEABLE_OP_FN(RectOp) \
+ UNMERGEABLE_OP_FN(RoundRectOp) \
+ UNMERGEABLE_OP_FN(SimpleRectsOp) \
+ UNMERGEABLE_OP_FN(TextOnPathOp) \
+ UNMERGEABLE_OP_FN(TextureLayerOp) \
+ \
+ MERGEABLE_OP_FN(BitmapOp) \
+ MERGEABLE_OP_FN(PatchOp) \
+ MERGEABLE_OP_FN(TextOp)
/**
* LUT generators, which will insert nullptr for unsupported ops
@@ -113,16 +114,16 @@ class Tree;
#define NULLPTR_OP_FN(Type) nullptr,
#define BUILD_DEFERRABLE_OP_LUT(OP_FN) \
- { MAP_OPS_BASED_ON_TYPE(OP_FN, NULLPTR_OP_FN, OP_FN, OP_FN) }
+ { MAP_OPS_BASED_ON_TYPE(OP_FN, NULLPTR_OP_FN, OP_FN, OP_FN) }
#define BUILD_MERGEABLE_OP_LUT(OP_FN) \
- { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, NULLPTR_OP_FN, NULLPTR_OP_FN, OP_FN) }
+ { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, NULLPTR_OP_FN, NULLPTR_OP_FN, OP_FN) }
#define BUILD_RENDERABLE_OP_LUT(OP_FN) \
- { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, OP_FN, OP_FN, OP_FN) }
+ { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, OP_FN, OP_FN, OP_FN) }
#define BUILD_FULL_OP_LUT(OP_FN) \
- { MAP_OPS_BASED_ON_TYPE(OP_FN, OP_FN, OP_FN, OP_FN) }
+ { MAP_OPS_BASED_ON_TYPE(OP_FN, OP_FN, OP_FN, OP_FN) }
/**
* Op mapping functions, which skip unsupported ops.
@@ -131,30 +132,29 @@ class Tree;
*/
#define NULL_OP_FN(Type)
-#define MAP_DEFERRABLE_OPS(OP_FN) \
- MAP_OPS_BASED_ON_TYPE(OP_FN, NULL_OP_FN, OP_FN, OP_FN)
+#define MAP_DEFERRABLE_OPS(OP_FN) MAP_OPS_BASED_ON_TYPE(OP_FN, NULL_OP_FN, OP_FN, OP_FN)
-#define MAP_MERGEABLE_OPS(OP_FN) \
- MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, NULL_OP_FN, NULL_OP_FN, OP_FN)
+#define MAP_MERGEABLE_OPS(OP_FN) MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, NULL_OP_FN, NULL_OP_FN, OP_FN)
-#define MAP_RENDERABLE_OPS(OP_FN) \
- MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, OP_FN, OP_FN, OP_FN)
+#define MAP_RENDERABLE_OPS(OP_FN) MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, OP_FN, OP_FN, OP_FN)
// Generate OpId enum
#define IDENTITY_FN(Type) Type,
namespace RecordedOpId {
- enum {
- MAP_OPS_BASED_ON_TYPE(IDENTITY_FN, IDENTITY_FN, IDENTITY_FN, IDENTITY_FN)
- Count,
- };
+enum {
+ MAP_OPS_BASED_ON_TYPE(IDENTITY_FN, IDENTITY_FN, IDENTITY_FN, IDENTITY_FN) Count,
+};
}
-static_assert(RecordedOpId::RenderNodeOp == 0,
- "First index must be zero for LUTs to work");
+static_assert(RecordedOpId::RenderNodeOp == 0, "First index must be zero for LUTs to work");
-#define BASE_PARAMS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint
-#define BASE_PARAMS_PAINTLESS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip
+#define BASE_PARAMS \
+ const Rect &unmappedBounds, const Matrix4 &localMatrix, const ClipBase *localClip, \
+ const SkPaint *paint
+#define BASE_PARAMS_PAINTLESS \
+ const Rect &unmappedBounds, const Matrix4 &localMatrix, const ClipBase *localClip
#define SUPER(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, paint)
-#define SUPER_PAINTLESS(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, nullptr)
+#define SUPER_PAINTLESS(Type) \
+ RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, nullptr)
struct RecordedOp {
/* ID from RecordedOpId - generally used for jumping into function tables */
@@ -171,6 +171,7 @@ struct RecordedOp {
/* optional paint, stored in base object to simplify merging logic */
const SkPaint* paint;
+
protected:
RecordedOp(unsigned int opId, BASE_PARAMS)
: opId(opId)
@@ -182,9 +183,8 @@ protected:
struct RenderNodeOp : RecordedOp {
RenderNodeOp(BASE_PARAMS_PAINTLESS, RenderNode* renderNode)
- : SUPER_PAINTLESS(RenderNodeOp)
- , renderNode(renderNode) {}
- RenderNode * renderNode; // not const, since drawing modifies it
+ : SUPER_PAINTLESS(RenderNodeOp), renderNode(renderNode) {}
+ RenderNode* renderNode; // not const, since drawing modifies it
/**
* Holds the transformation between the projection surface ViewGroup and this RenderNode
@@ -204,25 +204,20 @@ struct RenderNodeOp : RecordedOp {
struct ArcOp : RecordedOp {
ArcOp(BASE_PARAMS, float startAngle, float sweepAngle, bool useCenter)
- : SUPER(ArcOp)
- , startAngle(startAngle)
- , sweepAngle(sweepAngle)
- , useCenter(useCenter) {}
+ : SUPER(ArcOp), startAngle(startAngle), sweepAngle(sweepAngle), useCenter(useCenter) {}
const float startAngle;
const float sweepAngle;
const bool useCenter;
};
struct BitmapOp : RecordedOp {
- BitmapOp(BASE_PARAMS, Bitmap* bitmap)
- : SUPER(BitmapOp)
- , bitmap(bitmap) {}
+ BitmapOp(BASE_PARAMS, Bitmap* bitmap) : SUPER(BitmapOp), bitmap(bitmap) {}
Bitmap* bitmap;
};
struct BitmapMeshOp : RecordedOp {
- BitmapMeshOp(BASE_PARAMS, Bitmap* bitmap, int meshWidth, int meshHeight,
- const float* vertices, const int* colors)
+ BitmapMeshOp(BASE_PARAMS, Bitmap* bitmap, int meshWidth, int meshHeight, const float* vertices,
+ const int* colors)
: SUPER(BitmapMeshOp)
, bitmap(bitmap)
, meshWidth(meshWidth)
@@ -238,16 +233,14 @@ struct BitmapMeshOp : RecordedOp {
struct BitmapRectOp : RecordedOp {
BitmapRectOp(BASE_PARAMS, Bitmap* bitmap, const Rect& src)
- : SUPER(BitmapRectOp)
- , bitmap(bitmap)
- , src(src) {}
+ : SUPER(BitmapRectOp), bitmap(bitmap), src(src) {}
Bitmap* bitmap;
const Rect src;
};
struct CirclePropsOp : RecordedOp {
CirclePropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
- float* x, float* y, float* radius)
+ float* x, float* y, float* radius)
: RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClip, paint)
, x(x)
, y(y)
@@ -278,60 +271,47 @@ struct FunctorOp : RecordedOp {
struct LinesOp : RecordedOp {
LinesOp(BASE_PARAMS, const float* points, const int floatCount)
- : SUPER(LinesOp)
- , points(points)
- , floatCount(floatCount) {}
+ : SUPER(LinesOp), points(points), floatCount(floatCount) {}
const float* points;
const int floatCount;
};
struct OvalOp : RecordedOp {
- OvalOp(BASE_PARAMS)
- : SUPER(OvalOp) {}
+ OvalOp(BASE_PARAMS) : SUPER(OvalOp) {}
};
struct PatchOp : RecordedOp {
PatchOp(BASE_PARAMS, Bitmap* bitmap, const Res_png_9patch* patch)
- : SUPER(PatchOp)
- , bitmap(bitmap)
- , patch(patch) {}
+ : SUPER(PatchOp), bitmap(bitmap), patch(patch) {}
Bitmap* bitmap;
const Res_png_9patch* patch;
};
struct PathOp : RecordedOp {
- PathOp(BASE_PARAMS, const SkPath* path)
- : SUPER(PathOp)
- , path(path) {}
+ PathOp(BASE_PARAMS, const SkPath* path) : SUPER(PathOp), path(path) {}
const SkPath* path;
};
struct PointsOp : RecordedOp {
PointsOp(BASE_PARAMS, const float* points, const int floatCount)
- : SUPER(PointsOp)
- , points(points)
- , floatCount(floatCount) {}
+ : SUPER(PointsOp), points(points), floatCount(floatCount) {}
const float* points;
const int floatCount;
};
struct RectOp : RecordedOp {
- RectOp(BASE_PARAMS)
- : SUPER(RectOp) {}
+ RectOp(BASE_PARAMS) : SUPER(RectOp) {}
};
struct RoundRectOp : RecordedOp {
- RoundRectOp(BASE_PARAMS, float rx, float ry)
- : SUPER(RoundRectOp)
- , rx(rx)
- , ry(ry) {}
+ RoundRectOp(BASE_PARAMS, float rx, float ry) : SUPER(RoundRectOp), rx(rx), ry(ry) {}
const float rx;
const float ry;
};
struct RoundRectPropsOp : RecordedOp {
RoundRectPropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
- float* left, float* top, float* right, float* bottom, float *rx, float *ry)
+ float* left, float* top, float* right, float* bottom, float* rx, float* ry)
: RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClip, paint)
, left(left)
, top(top)
@@ -349,8 +329,7 @@ struct RoundRectPropsOp : RecordedOp {
struct VectorDrawableOp : RecordedOp {
VectorDrawableOp(VectorDrawable::Tree* tree, BASE_PARAMS_PAINTLESS)
- : SUPER_PAINTLESS(VectorDrawableOp)
- , vectorDrawable(tree) {}
+ : SUPER_PAINTLESS(VectorDrawableOp), vectorDrawable(tree) {}
VectorDrawable::Tree* vectorDrawable;
};
@@ -366,24 +345,21 @@ struct ShadowOp : RecordedOp {
ShadowOp(sp<TessellationCache::ShadowTask>& shadowTask, float casterAlpha)
: RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), nullptr, nullptr)
, shadowTask(shadowTask)
- , casterAlpha(casterAlpha) {
- };
+ , casterAlpha(casterAlpha){};
sp<TessellationCache::ShadowTask> shadowTask;
const float casterAlpha;
};
-struct SimpleRectsOp : RecordedOp { // Filled, no AA (TODO: better name?)
+struct SimpleRectsOp : RecordedOp { // Filled, no AA (TODO: better name?)
SimpleRectsOp(BASE_PARAMS, Vertex* vertices, size_t vertexCount)
- : SUPER(SimpleRectsOp)
- , vertices(vertices)
- , vertexCount(vertexCount) {}
+ : SUPER(SimpleRectsOp), vertices(vertices), vertexCount(vertexCount) {}
Vertex* vertices;
const size_t vertexCount;
};
struct TextOp : RecordedOp {
- TextOp(BASE_PARAMS, const glyph_t* glyphs, const float* positions, int glyphCount,
- float x, float y)
+ TextOp(BASE_PARAMS, const glyph_t* glyphs, const float* positions, int glyphCount, float x,
+ float y)
: SUPER(TextOp)
, glyphs(glyphs)
, positions(positions)
@@ -400,7 +376,8 @@ struct TextOp : RecordedOp {
struct TextOnPathOp : RecordedOp {
// TODO: explicitly define bounds
TextOnPathOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
- const glyph_t* glyphs, int glyphCount, const SkPath* path, float hOffset, float vOffset)
+ const glyph_t* glyphs, int glyphCount, const SkPath* path, float hOffset,
+ float vOffset)
: RecordedOp(RecordedOpId::TextOnPathOp, Rect(), localMatrix, localClip, paint)
, glyphs(glyphs)
, glyphCount(glyphCount)
@@ -417,16 +394,13 @@ struct TextOnPathOp : RecordedOp {
struct TextureLayerOp : RecordedOp {
TextureLayerOp(BASE_PARAMS_PAINTLESS, DeferredLayerUpdater* layer)
- : SUPER_PAINTLESS(TextureLayerOp)
- , layerHandle(layer) {}
+ : SUPER_PAINTLESS(TextureLayerOp), layerHandle(layer) {}
// Copy an existing TextureLayerOp, replacing the underlying matrix
TextureLayerOp(const TextureLayerOp& op, const Matrix4& replacementMatrix)
: RecordedOp(RecordedOpId::TextureLayerOp, op.unmappedBounds, replacementMatrix,
- op.localClip, op.paint)
- , layerHandle(op.layerHandle) {
-
- }
+ op.localClip, op.paint)
+ , layerHandle(op.layerHandle) {}
DeferredLayerUpdater* layerHandle;
};
@@ -439,8 +413,7 @@ struct TextureLayerOp : RecordedOp {
* and that commands following will render into it.
*/
struct BeginLayerOp : RecordedOp {
- BeginLayerOp(BASE_PARAMS)
- : SUPER(BeginLayerOp) {}
+ BeginLayerOp(BASE_PARAMS) : SUPER(BeginLayerOp) {}
};
/**
@@ -455,22 +428,20 @@ struct EndLayerOp : RecordedOp {
};
struct BeginUnclippedLayerOp : RecordedOp {
- BeginUnclippedLayerOp(BASE_PARAMS)
- : SUPER(BeginUnclippedLayerOp) {}
+ BeginUnclippedLayerOp(BASE_PARAMS) : SUPER(BeginUnclippedLayerOp) {}
};
struct EndUnclippedLayerOp : RecordedOp {
EndUnclippedLayerOp()
- : RecordedOp(RecordedOpId::EndUnclippedLayerOp, Rect(), Matrix4::identity(), nullptr, nullptr) {}
+ : RecordedOp(RecordedOpId::EndUnclippedLayerOp, Rect(), Matrix4::identity(), nullptr,
+ nullptr) {}
};
struct CopyToLayerOp : RecordedOp {
CopyToLayerOp(const RecordedOp& op, OffscreenBuffer** layerHandle)
- : RecordedOp(RecordedOpId::CopyToLayerOp,
- op.unmappedBounds,
- op.localMatrix,
- nullptr, // clip intentionally ignored
- op.paint)
+ : RecordedOp(RecordedOpId::CopyToLayerOp, op.unmappedBounds, op.localMatrix,
+ nullptr, // clip intentionally ignored
+ op.paint)
, layerHandle(layerHandle) {}
// Records a handle to the Layer object, since the Layer itself won't be
@@ -478,15 +449,12 @@ struct CopyToLayerOp : RecordedOp {
OffscreenBuffer** layerHandle;
};
-
// draw the parameter layer underneath
struct CopyFromLayerOp : RecordedOp {
CopyFromLayerOp(const RecordedOp& op, OffscreenBuffer** layerHandle)
- : RecordedOp(RecordedOpId::CopyFromLayerOp,
- op.unmappedBounds,
- op.localMatrix,
- nullptr, // clip intentionally ignored
- op.paint)
+ : RecordedOp(RecordedOpId::CopyFromLayerOp, op.unmappedBounds, op.localMatrix,
+ nullptr, // clip intentionally ignored
+ op.paint)
, layerHandle(layerHandle) {}
// Records a handle to the Layer object, since the Layer itself won't be
@@ -510,7 +478,8 @@ struct LayerOp : RecordedOp {
, colorFilter(paint ? paint->getColorFilter() : nullptr) {}
explicit LayerOp(RenderNode& node)
- : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), Matrix4::identity(), nullptr, nullptr)
+ : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()),
+ Matrix4::identity(), nullptr, nullptr)
, layerHandle(node.getLayerHandle())
, alpha(node.properties().layerProperties().alpha() / 255.0f)
, mode(node.properties().layerProperties().xferMode())
@@ -527,5 +496,5 @@ struct LayerOp : RecordedOp {
SkColorFilter* colorFilter;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index d966372a7699..3fb1c0d64abf 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -26,19 +26,16 @@ namespace android {
namespace uirenderer {
RecordingCanvas::RecordingCanvas(size_t width, size_t height)
- : mState(*this)
- , mResourceCache(ResourceCache::getInstance()) {
+ : mState(*this), mResourceCache(ResourceCache::getInstance()) {
resetRecording(width, height);
}
RecordingCanvas::~RecordingCanvas() {
- LOG_ALWAYS_FATAL_IF(mDisplayList,
- "Destroyed a RecordingCanvas during a record!");
+ LOG_ALWAYS_FATAL_IF(mDisplayList, "Destroyed a RecordingCanvas during a record!");
}
void RecordingCanvas::resetRecording(int width, int height, RenderNode* node) {
- LOG_ALWAYS_FATAL_IF(mDisplayList,
- "prepareDirty called a second time during a recording!");
+ LOG_ALWAYS_FATAL_IF(mDisplayList, "prepareDirty called a second time during a recording!");
mDisplayList = new DisplayList();
mState.initializeRecordingSaveStack(width, height);
@@ -68,8 +65,7 @@ void RecordingCanvas::insertReorderBarrier(bool enableReorder) {
}
SkCanvas* RecordingCanvas::asSkCanvas() {
- LOG_ALWAYS_FATAL_IF(!mDisplayList,
- "attempting to get an SkCanvas when we are not recording!");
+ LOG_ALWAYS_FATAL_IF(!mDisplayList, "attempting to get an SkCanvas when we are not recording!");
if (!mSkiaCanvasProxy) {
mSkiaCanvasProxy.reset(new SkiaCanvasProxy(this));
}
@@ -88,8 +84,7 @@ SkCanvas* RecordingCanvas::asSkCanvas() {
// CanvasStateClient implementation
// ----------------------------------------------------------------------------
-void RecordingCanvas::onViewportInitialized() {
-}
+void RecordingCanvas::onViewportInitialized() {}
void RecordingCanvas::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
if (removed.flags & Snapshot::kFlagIsFboLayer) {
@@ -104,7 +99,7 @@ void RecordingCanvas::onSnapshotRestored(const Snapshot& removed, const Snapshot
// ----------------------------------------------------------------------------
// Save (layer)
int RecordingCanvas::save(SaveFlags::Flags flags) {
- return mState.save((int) flags);
+ return mState.save((int)flags);
}
void RecordingCanvas::RecordingCanvas::restore() {
@@ -116,7 +111,7 @@ void RecordingCanvas::restoreToCount(int saveCount) {
}
int RecordingCanvas::saveLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, SaveFlags::Flags flags) {
+ const SkPaint* paint, SaveFlags::Flags flags) {
// force matrix/clip isolation for layer
flags |= SaveFlags::MatrixClip;
bool clippedLayer = flags & SaveFlags::ClipToLayer;
@@ -134,9 +129,8 @@ int RecordingCanvas::saveLayer(float left, float top, float right, float bottom,
Rect visibleBounds = unmappedBounds;
previous.transform->mapRect(visibleBounds);
- if (CC_UNLIKELY(!clippedLayer
- && previous.transform->rectToRect()
- && visibleBounds.contains(previous.getRenderTargetClip()))) {
+ if (CC_UNLIKELY(!clippedLayer && previous.transform->rectToRect() &&
+ visibleBounds.contains(previous.getRenderTargetClip()))) {
// unlikely case where an unclipped savelayer is recorded with a clip it can use,
// as none of its unaffected/unclipped area is visible
clippedLayer = true;
@@ -157,18 +151,18 @@ int RecordingCanvas::saveLayer(float left, float top, float right, float bottom,
layerBounds.doIntersect(unmappedBounds);
}
- int saveValue = mState.save((int) flags);
+ int saveValue = mState.save((int)flags);
Snapshot& snapshot = *mState.writableSnapshot();
// layerBounds is in original bounds space, but clipped by current recording clip
if (!layerBounds.isEmpty() && !unmappedBounds.isEmpty()) {
if (CC_LIKELY(clippedLayer)) {
- auto previousClip = getRecordedClip(); // capture before new snapshot clip has changed
+ auto previousClip = getRecordedClip(); // capture before new snapshot clip has changed
if (addOp(alloc().create_trivial<BeginLayerOp>(
- unmappedBounds,
- *previous.transform, // transform to *draw* with
- previousClip, // clip to *draw* with
- refPaint(paint))) >= 0) {
+ unmappedBounds,
+ *previous.transform, // transform to *draw* with
+ previousClip, // clip to *draw* with
+ refPaint(paint))) >= 0) {
snapshot.flags |= Snapshot::kFlagIsLayer | Snapshot::kFlagIsFboLayer;
snapshot.initializeViewport(unmappedBounds.getWidth(), unmappedBounds.getHeight());
snapshot.transform->loadTranslate(-unmappedBounds.left, -unmappedBounds.top, 0.0f);
@@ -181,10 +175,8 @@ int RecordingCanvas::saveLayer(float left, float top, float right, float bottom,
}
} else {
if (addOp(alloc().create_trivial<BeginUnclippedLayerOp>(
- unmappedBounds,
- *mState.currentSnapshot()->transform,
- getRecordedClip(),
- refPaint(paint))) >= 0) {
+ unmappedBounds, *mState.currentSnapshot()->transform, getRecordedClip(),
+ refPaint(paint))) >= 0) {
snapshot.flags |= Snapshot::kFlagIsLayer;
return saveValue;
}
@@ -245,10 +237,7 @@ bool RecordingCanvas::clipPath(const SkPath* path, SkClipOp op) {
// android/graphics/Canvas draw operations
// ----------------------------------------------------------------------------
void RecordingCanvas::drawColor(int color, SkBlendMode mode) {
- addOp(alloc().create_trivial<ColorOp>(
- getRecordedClip(),
- color,
- mode));
+ addOp(alloc().create_trivial<ColorOp>(getRecordedClip(), color, mode));
}
void RecordingCanvas::drawPaint(const SkPaint& paint) {
@@ -269,40 +258,35 @@ static Rect calcBoundsOfPoints(const float* points, int floatCount) {
// Geometry
void RecordingCanvas::drawPoints(const float* points, int floatCount, const SkPaint& paint) {
if (CC_UNLIKELY(floatCount < 2 || paint.nothingToDraw())) return;
- floatCount &= ~0x1; // round down to nearest two
+ floatCount &= ~0x1; // round down to nearest two
addOp(alloc().create_trivial<PointsOp>(
- calcBoundsOfPoints(points, floatCount),
- *mState.currentSnapshot()->transform,
- getRecordedClip(),
- refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
+ calcBoundsOfPoints(points, floatCount), *mState.currentSnapshot()->transform,
+ getRecordedClip(), refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
}
void RecordingCanvas::drawLines(const float* points, int floatCount, const SkPaint& paint) {
if (CC_UNLIKELY(floatCount < 4 || paint.nothingToDraw())) return;
- floatCount &= ~0x3; // round down to nearest four
+ floatCount &= ~0x3; // round down to nearest four
addOp(alloc().create_trivial<LinesOp>(
- calcBoundsOfPoints(points, floatCount),
- *mState.currentSnapshot()->transform,
- getRecordedClip(),
- refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
+ calcBoundsOfPoints(points, floatCount), *mState.currentSnapshot()->transform,
+ getRecordedClip(), refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
}
-void RecordingCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) {
+void RecordingCanvas::drawRect(float left, float top, float right, float bottom,
+ const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
- addOp(alloc().create_trivial<RectOp>(
- Rect(left, top, right, bottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint)));
+ addOp(alloc().create_trivial<RectOp>(Rect(left, top, right, bottom),
+ *(mState.currentSnapshot()->transform), getRecordedClip(),
+ refPaint(&paint)));
}
void RecordingCanvas::drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint) {
if (rects == nullptr) return;
- Vertex* rectData = (Vertex*) mDisplayList->allocator.create_trivial_array<Vertex>(vertexCount);
+ Vertex* rectData = (Vertex*)mDisplayList->allocator.create_trivial_array<Vertex>(vertexCount);
Vertex* vertex = rectData;
float left = FLT_MAX;
@@ -326,17 +310,15 @@ void RecordingCanvas::drawSimpleRects(const float* rects, int vertexCount, const
bottom = std::max(bottom, b);
}
addOp(alloc().create_trivial<SimpleRectsOp>(
- Rect(left, top, right, bottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(paint), rectData, vertexCount));
+ Rect(left, top, right, bottom), *(mState.currentSnapshot()->transform),
+ getRecordedClip(), refPaint(paint), rectData, vertexCount));
}
void RecordingCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
- if (paint.getStyle() == SkPaint::kFill_Style
- && (!paint.isAntiAlias() || mState.currentTransform()->isSimple())) {
+ if (paint.getStyle() == SkPaint::kFill_Style &&
+ (!paint.isAntiAlias() || mState.currentTransform()->isSimple())) {
int count = 0;
Vector<float> rects;
SkRegion::Iterator it(region);
@@ -360,26 +342,23 @@ void RecordingCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
}
}
-void RecordingCanvas::drawRoundRect(float left, float top, float right, float bottom,
- float rx, float ry, const SkPaint& paint) {
+void RecordingCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx,
+ float ry, const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
if (CC_LIKELY(MathUtils::isPositive(rx) || MathUtils::isPositive(ry))) {
- addOp(alloc().create_trivial<RoundRectOp>(
- Rect(left, top, right, bottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint), rx, ry));
+ addOp(alloc().create_trivial<RoundRectOp>(Rect(left, top, right, bottom),
+ *(mState.currentSnapshot()->transform),
+ getRecordedClip(), refPaint(&paint), rx, ry));
} else {
drawRect(left, top, right, bottom, paint);
}
}
-void RecordingCanvas::drawRoundRect(
- CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
- CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
- CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
- CanvasPropertyPaint* paint) {
+void RecordingCanvas::drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
+ CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
+ CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
+ CanvasPropertyPaint* paint) {
mDisplayList->ref(left);
mDisplayList->ref(top);
mDisplayList->ref(right);
@@ -389,11 +368,8 @@ void RecordingCanvas::drawRoundRect(
mDisplayList->ref(paint);
refBitmapsInShader(paint->value.getShader());
addOp(alloc().create_trivial<RoundRectPropsOp>(
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- &paint->value,
- &left->value, &top->value, &right->value, &bottom->value,
- &rx->value, &ry->value));
+ *(mState.currentSnapshot()->transform), getRecordedClip(), &paint->value, &left->value,
+ &top->value, &right->value, &bottom->value, &rx->value, &ry->value));
}
void RecordingCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
@@ -403,65 +379,54 @@ void RecordingCanvas::drawCircle(float x, float y, float radius, const SkPaint&
drawOval(x - radius, y - radius, x + radius, y + radius, paint);
}
-void RecordingCanvas::drawCircle(
- CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
- CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
+void RecordingCanvas::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
+ CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
mDisplayList->ref(x);
mDisplayList->ref(y);
mDisplayList->ref(radius);
mDisplayList->ref(paint);
refBitmapsInShader(paint->value.getShader());
- addOp(alloc().create_trivial<CirclePropsOp>(
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- &paint->value,
- &x->value, &y->value, &radius->value));
+ addOp(alloc().create_trivial<CirclePropsOp>(*(mState.currentSnapshot()->transform),
+ getRecordedClip(), &paint->value, &x->value,
+ &y->value, &radius->value));
}
-void RecordingCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
+void RecordingCanvas::drawOval(float left, float top, float right, float bottom,
+ const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
- addOp(alloc().create_trivial<OvalOp>(
- Rect(left, top, right, bottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint)));
+ addOp(alloc().create_trivial<OvalOp>(Rect(left, top, right, bottom),
+ *(mState.currentSnapshot()->transform), getRecordedClip(),
+ refPaint(&paint)));
}
-void RecordingCanvas::drawArc(float left, float top, float right, float bottom,
- float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
+void RecordingCanvas::drawArc(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle, bool useCenter, const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
if (fabs(sweepAngle) >= 360.0f) {
drawOval(left, top, right, bottom, paint);
} else {
addOp(alloc().create_trivial<ArcOp>(
- Rect(left, top, right, bottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint),
- startAngle, sweepAngle, useCenter));
+ Rect(left, top, right, bottom), *(mState.currentSnapshot()->transform),
+ getRecordedClip(), refPaint(&paint), startAngle, sweepAngle, useCenter));
}
}
void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
- addOp(alloc().create_trivial<PathOp>(
- Rect(path.getBounds()),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint), refPath(&path)));
+ addOp(alloc().create_trivial<PathOp>(Rect(path.getBounds()),
+ *(mState.currentSnapshot()->transform), getRecordedClip(),
+ refPaint(&paint), refPath(&path)));
}
void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
mDisplayList->ref(tree);
mDisplayList->vectorDrawables.push_back(tree);
addOp(alloc().create_trivial<VectorDrawableOp>(
- tree,
- Rect(tree->stagingProperties()->getBounds()),
- *(mState.currentSnapshot()->transform),
- getRecordedClip()));
+ tree, Rect(tree->stagingProperties()->getBounds()),
+ *(mState.currentSnapshot()->transform), getRecordedClip()));
}
// Bitmap-based
@@ -472,20 +437,19 @@ void RecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Sk
restore();
}
-void RecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix,
- const SkPaint* paint) {
+void RecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
if (matrix.isIdentity()) {
drawBitmap(bitmap, paint);
- } else if (!(matrix.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask))
- && MathUtils::isPositive(matrix.getScaleX())
- && MathUtils::isPositive(matrix.getScaleY())) {
+ } else if (!(matrix.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) &&
+ MathUtils::isPositive(matrix.getScaleX()) &&
+ MathUtils::isPositive(matrix.getScaleY())) {
// SkMatrix::isScaleTranslate() not available in L
SkRect src;
SkRect dst;
bitmap.getBounds(&src);
matrix.mapRect(&dst, src);
- drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
- dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
+ drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom, dst.fLeft, dst.fTop,
+ dst.fRight, dst.fBottom, paint);
} else {
save(SaveFlags::Matrix);
concat(matrix);
@@ -494,14 +458,11 @@ void RecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix,
}
}
-void RecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
- float srcRight, float srcBottom, float dstLeft, float dstTop,
- float dstRight, float dstBottom, const SkPaint* paint) {
- if (srcLeft == 0 && srcTop == 0
- && srcRight == bitmap.width()
- && srcBottom == bitmap.height()
- && (srcBottom - srcTop == dstBottom - dstTop)
- && (srcRight - srcLeft == dstRight - dstLeft)) {
+void RecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
+ float srcBottom, float dstLeft, float dstTop, float dstRight,
+ float dstBottom, const SkPaint* paint) {
+ if (srcLeft == 0 && srcTop == 0 && srcRight == bitmap.width() && srcBottom == bitmap.height() &&
+ (srcBottom - srcTop == dstBottom - dstTop) && (srcRight - srcLeft == dstRight - dstLeft)) {
// transform simple rect to rect drawing case into position bitmap ops, since they merge
save(SaveFlags::Matrix);
translate(dstLeft, dstTop);
@@ -509,56 +470,50 @@ void RecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
restore();
} else {
addOp(alloc().create_trivial<BitmapRectOp>(
- Rect(dstLeft, dstTop, dstRight, dstBottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(paint), refBitmap(bitmap),
+ Rect(dstLeft, dstTop, dstRight, dstBottom), *(mState.currentSnapshot()->transform),
+ getRecordedClip(), refPaint(paint), refBitmap(bitmap),
Rect(srcLeft, srcTop, srcRight, srcBottom)));
}
}
void RecordingCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
- const float* vertices, const int* colors, const SkPaint* paint) {
+ const float* vertices, const int* colors,
+ const SkPaint* paint) {
int vertexCount = (meshWidth + 1) * (meshHeight + 1);
addOp(alloc().create_trivial<BitmapMeshOp>(
- calcBoundsOfPoints(vertices, vertexCount * 2),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(paint), refBitmap(bitmap), meshWidth, meshHeight,
- refBuffer<float>(vertices, vertexCount * 2), // 2 floats per vertex
- refBuffer<int>(colors, vertexCount))); // 1 color per vertex
+ calcBoundsOfPoints(vertices, vertexCount * 2), *(mState.currentSnapshot()->transform),
+ getRecordedClip(), refPaint(paint), refBitmap(bitmap), meshWidth, meshHeight,
+ refBuffer<float>(vertices, vertexCount * 2), // 2 floats per vertex
+ refBuffer<int>(colors, vertexCount))); // 1 color per vertex
}
void RecordingCanvas::drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& patch,
- float dstLeft, float dstTop, float dstRight, float dstBottom,
- const SkPaint* paint) {
- addOp(alloc().create_trivial<PatchOp>(
- Rect(dstLeft, dstTop, dstRight, dstBottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(paint), refBitmap(bitmap), refPatch(&patch)));
+ float dstLeft, float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) {
+ addOp(alloc().create_trivial<PatchOp>(Rect(dstLeft, dstTop, dstRight, dstBottom),
+ *(mState.currentSnapshot()->transform), getRecordedClip(),
+ refPaint(paint), refBitmap(bitmap), refPatch(&patch)));
}
// Text
void RecordingCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int glyphCount, const SkPaint& paint,
- float x, float y, float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
- float totalAdvance) {
+ float x, float y, float boundsLeft, float boundsTop,
+ float boundsRight, float boundsBottom, float totalAdvance) {
if (glyphCount <= 0 || paint.nothingToDraw()) return;
uint16_t* glyphs = (glyph_t*)alloc().alloc<glyph_t>(glyphCount * sizeof(glyph_t));
float* positions = (float*)alloc().alloc<float>(2 * glyphCount * sizeof(float));
glyphFunc(glyphs, positions);
// TODO: either must account for text shadow in bounds, or record separate ops for text shadows
- addOp(alloc().create_trivial<TextOp>(
- Rect(boundsLeft, boundsTop, boundsRight, boundsBottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint), glyphs, positions, glyphCount, x, y));
+ addOp(alloc().create_trivial<TextOp>(Rect(boundsLeft, boundsTop, boundsRight, boundsBottom),
+ *(mState.currentSnapshot()->transform), getRecordedClip(),
+ refPaint(&paint), glyphs, positions, glyphCount, x, y));
drawTextDecorations(x, y, totalAdvance, paint);
}
void RecordingCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
- const SkPaint& paint, const SkPath& path, size_t start, size_t end) {
+ const SkPaint& paint, const SkPath& path, size_t start,
+ size_t end) {
uint16_t glyphs[1];
for (size_t i = start; i < end; i++) {
glyphs[0] = layout.getGlyphId(i);
@@ -566,28 +521,23 @@ void RecordingCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOff
float y = vOffset + layout.getY(i);
if (paint.nothingToDraw()) return;
const uint16_t* tempGlyphs = refBuffer<glyph_t>(glyphs, 1);
- addOp(alloc().create_trivial<TextOnPathOp>(
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint), tempGlyphs, 1, refPath(&path), x, y));
+ addOp(alloc().create_trivial<TextOnPathOp>(*(mState.currentSnapshot()->transform),
+ getRecordedClip(), refPaint(&paint), tempGlyphs,
+ 1, refPath(&path), x, y));
}
}
void RecordingCanvas::drawBitmap(Bitmap& bitmap, const SkPaint* paint) {
- addOp(alloc().create_trivial<BitmapOp>(
- Rect(bitmap.width(), bitmap.height()),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(paint), refBitmap(bitmap)));
+ addOp(alloc().create_trivial<BitmapOp>(Rect(bitmap.width(), bitmap.height()),
+ *(mState.currentSnapshot()->transform),
+ getRecordedClip(), refPaint(paint), refBitmap(bitmap)));
}
void RecordingCanvas::drawRenderNode(RenderNode* renderNode) {
auto&& stagingProps = renderNode->stagingProperties();
RenderNodeOp* op = alloc().create_trivial<RenderNodeOp>(
Rect(stagingProps.getWidth(), stagingProps.getHeight()),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- renderNode);
+ *(mState.currentSnapshot()->transform), getRecordedClip(), renderNode);
int opIndex = addOp(op);
if (CC_LIKELY(opIndex >= 0)) {
int childIndex = mDisplayList->addChild(op);
@@ -612,18 +562,14 @@ void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) {
// its width, height, transform, etc...!
addOp(alloc().create_trivial<TextureLayerOp>(
Rect(layerHandle->getWidth(), layerHandle->getHeight()),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(), layerHandle));
+ *(mState.currentSnapshot()->transform), getRecordedClip(), layerHandle));
}
-void RecordingCanvas::callDrawGLFunction(Functor* functor,
- GlFunctorLifecycleListener* listener) {
+void RecordingCanvas::callDrawGLFunction(Functor* functor, GlFunctorLifecycleListener* listener) {
mDisplayList->functors.push_back({functor, listener});
mDisplayList->ref(listener);
- addOp(alloc().create_trivial<FunctorOp>(
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- functor));
+ addOp(alloc().create_trivial<FunctorOp>(*(mState.currentSnapshot()->transform),
+ getRecordedClip(), functor));
}
int RecordingCanvas::addOp(RecordedOp* op) {
@@ -676,5 +622,5 @@ void RecordingCanvas::refBitmapsInShader(const SkShader* shader) {
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 79db496f2acd..3087db0550de 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -40,49 +40,50 @@ struct ClipBase;
class DeferredLayerUpdater;
struct RecordedOp;
-class ANDROID_API RecordingCanvas: public Canvas, public CanvasStateClient {
+class ANDROID_API RecordingCanvas : public Canvas, public CanvasStateClient {
enum class DeferredBarrierType {
None,
InOrder,
OutOfOrder,
};
+
public:
RecordingCanvas(size_t width, size_t height);
virtual ~RecordingCanvas();
virtual void resetRecording(int width, int height, RenderNode* node = nullptr) override;
virtual WARN_UNUSED_RESULT DisplayList* finishRecording() override;
-// ----------------------------------------------------------------------------
-// MISC HWUI OPERATIONS - TODO: CATEGORIZE
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // MISC HWUI OPERATIONS - TODO: CATEGORIZE
+ // ----------------------------------------------------------------------------
virtual void insertReorderBarrier(bool enableReorder) override;
virtual void drawLayer(DeferredLayerUpdater* layerHandle) override;
virtual void drawRenderNode(RenderNode* renderNode) override;
virtual void callDrawGLFunction(Functor* functor,
- GlFunctorLifecycleListener* listener) override;
+ GlFunctorLifecycleListener* listener) override;
-// ----------------------------------------------------------------------------
-// CanvasStateClient interface
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // CanvasStateClient interface
+ // ----------------------------------------------------------------------------
virtual void onViewportInitialized() override;
virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override;
virtual GLuint getTargetFbo() const override { return -1; }
-// ----------------------------------------------------------------------------
-// HWUI Canvas draw operations
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // HWUI Canvas draw operations
+ // ----------------------------------------------------------------------------
virtual void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
- CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
- CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
- CanvasPropertyPaint* paint) override;
+ CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
+ CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
+ CanvasPropertyPaint* paint) override;
virtual void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
- CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) override;
+ CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) override;
-// ----------------------------------------------------------------------------
-// android/graphics/Canvas interface
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // android/graphics/Canvas interface
+ // ----------------------------------------------------------------------------
virtual SkCanvas* asSkCanvas() override;
virtual void setBitmap(const SkBitmap& bitmap) override {
@@ -93,9 +94,9 @@ public:
virtual int width() override { return mState.getWidth(); }
virtual int height() override { return mState.getHeight(); }
-// ----------------------------------------------------------------------------
-// android/graphics/Canvas state operations
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // android/graphics/Canvas state operations
+ // ----------------------------------------------------------------------------
// Save (layer)
virtual int getSaveCount() const override { return mState.getSaveCount(); }
virtual int save(SaveFlags::Flags flags) override;
@@ -103,9 +104,9 @@ public:
virtual void restoreToCount(int saveCount) override;
virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
- SaveFlags::Flags flags) override;
- virtual int saveLayerAlpha(float left, float top, float right, float bottom,
- int alpha, SaveFlags::Flags flags) override {
+ SaveFlags::Flags flags) override;
+ virtual int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
+ SaveFlags::Flags flags) override {
SkPaint paint;
paint.setAlpha(alpha);
return saveLayer(left, top, right, bottom, &paint, flags);
@@ -126,8 +127,7 @@ public:
virtual bool quickRejectRect(float left, float top, float right, float bottom) const override;
virtual bool quickRejectPath(const SkPath& path) const override;
- virtual bool clipRect(float left, float top, float right, float bottom,
- SkClipOp op) override;
+ virtual bool clipRect(float left, float top, float right, float bottom, SkClipOp op) override;
virtual bool clipPath(const SkPath* path, SkClipOp op) override;
// Misc
@@ -136,59 +136,64 @@ public:
mDrawFilter.reset(SkSafeRef(filter));
}
-// ----------------------------------------------------------------------------
-// android/graphics/Canvas draw operations
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // android/graphics/Canvas draw operations
+ // ----------------------------------------------------------------------------
virtual void drawColor(int color, SkBlendMode mode) override;
virtual void drawPaint(const SkPaint& paint) override;
// Geometry
virtual void drawPoint(float x, float y, const SkPaint& paint) override {
- float points[2] = { x, y };
+ float points[2] = {x, y};
drawPoints(points, 2, paint);
}
virtual void drawPoints(const float* points, int floatCount, const SkPaint& paint) override;
virtual void drawLine(float startX, float startY, float stopX, float stopY,
- const SkPaint& paint) override {
- float points[4] = { startX, startY, stopX, stopY };
+ const SkPaint& paint) override {
+ float points[4] = {startX, startY, stopX, stopY};
drawLines(points, 4, paint);
}
virtual void drawLines(const float* points, int floatCount, const SkPaint& paint) override;
- virtual void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override;
+ virtual void drawRect(float left, float top, float right, float bottom,
+ const SkPaint& paint) override;
virtual void drawRegion(const SkRegion& region, const SkPaint& paint) override;
- virtual void drawRoundRect(float left, float top, float right, float bottom,
- float rx, float ry, const SkPaint& paint) override;
+ virtual void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
+ const SkPaint& paint) override;
virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override;
- virtual void drawOval(float left, float top, float right, float bottom, const SkPaint& paint) override;
- virtual void drawArc(float left, float top, float right, float bottom,
- float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) override;
+ virtual void drawOval(float left, float top, float right, float bottom,
+ const SkPaint& paint) override;
+ virtual void drawArc(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle, bool useCenter, const SkPaint& paint) override;
virtual void drawPath(const SkPath& path, const SkPaint& paint) override;
- virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint) override
- { /* RecordingCanvas does not support drawVertices(); ignore */ }
+ virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint)
+ override { /* RecordingCanvas does not support drawVertices(); ignore */
+ }
virtual void drawVectorDrawable(VectorDrawableRoot* tree) override;
// Bitmap-based
virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) override;
virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) override;
- virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
- float srcRight, float srcBottom, float dstLeft, float dstTop,
- float dstRight, float dstBottom, const SkPaint* paint) override;
+ virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
+ float srcBottom, float dstLeft, float dstTop, float dstRight,
+ float dstBottom, const SkPaint* paint) override;
virtual void drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
- const float* vertices, const int* colors, const SkPaint* paint) override;
- virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk,
- float dstLeft, float dstTop, float dstRight, float dstBottom,
- const SkPaint* paint) override;
+ const float* vertices, const int* colors,
+ const SkPaint* paint) override;
+ virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
+ float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) override;
// Text
virtual bool drawTextAbsolutePos() const override { return false; }
protected:
virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x,
- float y, float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
- float totalAdvance) override;
+ float y, float boundsLeft, float boundsTop, float boundsRight,
+ float boundsBottom, float totalAdvance) override;
virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
- const SkPaint& paint, const SkPath& path, size_t start, size_t end) override;
+ const SkPaint& paint, const SkPath& path, size_t start,
+ size_t end) override;
private:
const ClipBase* getRecordedClip() {
@@ -198,20 +203,19 @@ private:
void drawBitmap(Bitmap& bitmap, const SkPaint* paint);
void drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint);
-
int addOp(RecordedOp* op);
-// ----------------------------------------------------------------------------
-// lazy object copy
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // lazy object copy
+ // ----------------------------------------------------------------------------
LinearAllocator& alloc() { return mDisplayList->allocator; }
void refBitmapsInShader(const SkShader* shader);
- template<class T>
+ template <class T>
inline const T* refBuffer(const T* srcBuffer, int32_t count) {
if (!srcBuffer) return nullptr;
- T* dstBuffer = (T*) mDisplayList->allocator.alloc<T>(count * sizeof(T));
+ T* dstBuffer = (T*)mDisplayList->allocator.alloc<T>(count * sizeof(T));
memcpy(dstBuffer, srcBuffer, count * sizeof(T));
return dstBuffer;
}
@@ -307,9 +311,9 @@ private:
const ClipBase* mDeferredBarrierClip = nullptr;
DisplayList* mDisplayList = nullptr;
sk_sp<SkDrawFilter> mDrawFilter;
-}; // class RecordingCanvas
+}; // class RecordingCanvas
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_RECORDING_CANVAS_H
+#endif // ANDROID_HWUI_RECORDING_CANVAS_H
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index eb05e9171335..0715187e19ea 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -20,20 +20,18 @@
#include <utils/Log.h>
+#include <SkRect.h>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <ostream>
-#include <SkRect.h>
namespace android {
namespace uirenderer {
#define RECT_STRING "%5.2f %5.2f %5.2f %5.2f"
-#define RECT_ARGS(r) \
- (r).left, (r).top, (r).right, (r).bottom
-#define SK_RECT_ARGS(r) \
- (r).left(), (r).top(), (r).right(), (r).bottom()
+#define RECT_ARGS(r) (r).left, (r).top, (r).right, (r).bottom
+#define SK_RECT_ARGS(r) (r).left(), (r).top(), (r).right(), (r).bottom()
///////////////////////////////////////////////////////////////////////////////
// Structs
@@ -52,52 +50,32 @@ public:
// we don't provide copy-ctor and operator= on purpose
// because we want the compiler generated versions
- inline Rect():
- left(0),
- top(0),
- right(0),
- bottom(0) {
- }
+ inline Rect() : left(0), top(0), right(0), bottom(0) {}
- inline Rect(float left, float top, float right, float bottom):
- left(left),
- top(top),
- right(right),
- bottom(bottom) {
- }
+ inline Rect(float left, float top, float right, float bottom)
+ : left(left), top(top), right(right), bottom(bottom) {}
- inline Rect(float width, float height):
- left(0.0f),
- top(0.0f),
- right(width),
- bottom(height) {
- }
+ inline Rect(float width, float height) : left(0.0f), top(0.0f), right(width), bottom(height) {}
- inline Rect(const SkIRect& rect): // NOLINT, implicit
- left(rect.fLeft),
- top(rect.fTop),
- right(rect.fRight),
- bottom(rect.fBottom) {
- }
+ inline Rect(const SkIRect& rect)
+ : // NOLINT, implicit
+ left(rect.fLeft)
+ , top(rect.fTop)
+ , right(rect.fRight)
+ , bottom(rect.fBottom) {}
- inline Rect(const SkRect& rect): // NOLINT, implicit
- left(rect.fLeft),
- top(rect.fTop),
- right(rect.fRight),
- bottom(rect.fBottom) {
- }
+ inline Rect(const SkRect& rect)
+ : // NOLINT, implicit
+ left(rect.fLeft)
+ , top(rect.fTop)
+ , right(rect.fRight)
+ , bottom(rect.fBottom) {}
- friend int operator==(const Rect& a, const Rect& b) {
- return !memcmp(&a, &b, sizeof(a));
- }
+ friend int operator==(const Rect& a, const Rect& b) { return !memcmp(&a, &b, sizeof(a)); }
- friend int operator!=(const Rect& a, const Rect& b) {
- return memcmp(&a, &b, sizeof(a));
- }
+ friend int operator!=(const Rect& a, const Rect& b) { return memcmp(&a, &b, sizeof(a)); }
- inline void clear() {
- left = top = right = bottom = 0.0f;
- }
+ inline void clear() { left = top = right = bottom = 0.0f; }
inline bool isEmpty() const {
// this is written in such way this it'll handle NANs to return
@@ -105,9 +83,7 @@ public:
return !((left < right) && (top < bottom));
}
- inline void setEmpty() {
- left = top = right = bottom = 0.0f;
- }
+ inline void setEmpty() { left = top = right = bottom = 0.0f; }
inline void set(float left, float top, float right, float bottom) {
this->left = left;
@@ -116,21 +92,13 @@ public:
this->bottom = bottom;
}
- inline void set(const Rect& r) {
- set(r.left, r.top, r.right, r.bottom);
- }
+ inline void set(const Rect& r) { set(r.left, r.top, r.right, r.bottom); }
- inline void set(const SkIRect& r) {
- set(r.left(), r.top(), r.right(), r.bottom());
- }
+ inline void set(const SkIRect& r) { set(r.left(), r.top(), r.right(), r.bottom()); }
- inline float getWidth() const {
- return right - left;
- }
+ inline float getWidth() const { return right - left; }
- inline float getHeight() const {
- return bottom - top;
- }
+ inline float getHeight() const { return bottom - top; }
bool intersects(float l, float t, float r, float b) const {
float tempLeft = std::max(left, l);
@@ -138,12 +106,10 @@ public:
float tempRight = std::min(right, r);
float tempBottom = std::min(bottom, b);
- return ((tempLeft < tempRight) && (tempTop < tempBottom)); // !isEmpty
+ return ((tempLeft < tempRight) && (tempTop < tempBottom)); // !isEmpty
}
- bool intersects(const Rect& r) const {
- return intersects(r.left, r.top, r.right, r.bottom);
- }
+ bool intersects(const Rect& r) const { return intersects(r.left, r.top, r.right, r.bottom); }
/**
* This method is named 'doIntersect' instead of 'intersect' so as not to be confused with
@@ -157,17 +123,13 @@ public:
bottom = std::min(bottom, b);
}
- void doIntersect(const Rect& r) {
- doIntersect(r.left, r.top, r.right, r.bottom);
- }
+ void doIntersect(const Rect& r) { doIntersect(r.left, r.top, r.right, r.bottom); }
inline bool contains(float l, float t, float r, float b) const {
return l >= left && t >= top && r <= right && b <= bottom;
}
- inline bool contains(const Rect& r) const {
- return contains(r.left, r.top, r.right, r.bottom);
- }
+ inline bool contains(const Rect& r) const { return contains(r.left, r.top, r.right, r.bottom); }
bool unionWith(const Rect& r) {
if (r.left < r.right && r.top < r.bottom) {
@@ -195,9 +157,7 @@ public:
bottom += dy;
}
- void inset(float delta) {
- outset(-delta);
- }
+ void inset(float delta) { outset(-delta); }
void outset(float delta) {
left -= delta;
@@ -279,13 +239,9 @@ public:
bottom = std::max(bottom, y);
}
- SkRect toSkRect() const {
- return SkRect::MakeLTRB(left, top, right, bottom);
- }
+ SkRect toSkRect() const { return SkRect::MakeLTRB(left, top, right, bottom); }
- SkIRect toSkIRect() const {
- return SkIRect::MakeLTRB(left, top, right, bottom);
- }
+ SkIRect toSkIRect() const { return SkIRect::MakeLTRB(left, top, right, bottom); }
void dump(const char* label = nullptr) const {
ALOGD("%s[l=%.2f t=%.2f r=%.2f b=%.2f]", label ? label : "Rect", left, top, right, bottom);
@@ -301,13 +257,10 @@ public:
return os << "[" << rect.right << " x " << rect.bottom << "]";
}
- return os << "[" << rect.left
- << " " << rect.top
- << " " << rect.right
- << " " << rect.bottom << "]";
+ return os << "[" << rect.left << " " << rect.top << " " << rect.right << " " << rect.bottom
+ << "]";
}
-}; // class Rect
-
-}; // namespace uirenderer
-}; // namespace android
+}; // class Rect
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/RenderBuffer.h b/libs/hwui/RenderBuffer.h
index 35a516a58022..191a66a6d741 100644
--- a/libs/hwui/RenderBuffer.h
+++ b/libs/hwui/RenderBuffer.h
@@ -32,9 +32,8 @@ struct RenderBuffer {
* Creates a new render buffer in the specified format and dimensions.
* The format must be one of the formats allowed by glRenderbufferStorage().
*/
- RenderBuffer(GLenum format, uint32_t width, uint32_t height):
- mFormat(format), mWidth(width), mHeight(height), mAllocated(false) {
-
+ RenderBuffer(GLenum format, uint32_t width, uint32_t height)
+ : mFormat(format), mWidth(width), mHeight(height), mAllocated(false) {
glGenRenderbuffers(1, &mName);
}
@@ -47,31 +46,23 @@ struct RenderBuffer {
/**
* Returns the GL name of this render buffer.
*/
- GLuint getName() const {
- return mName;
- }
+ GLuint getName() const { return mName; }
/**
* Returns the format of this render buffer.
*/
- GLenum getFormat() const {
- return mFormat;
- }
+ GLenum getFormat() const { return mFormat; }
/**
* Binds this render buffer to the current GL context.
*/
- void bind() const {
- glBindRenderbuffer(GL_RENDERBUFFER, mName);
- }
+ void bind() const { glBindRenderbuffer(GL_RENDERBUFFER, mName); }
/**
* Indicates whether this render buffer has allocated its
* storage. See allocate() and resize().
*/
- bool isAllocated() const {
- return mAllocated;
- }
+ bool isAllocated() const { return mAllocated; }
/**
* Allocates this render buffer's storage if needed.
@@ -101,23 +92,19 @@ struct RenderBuffer {
/**
* Returns the width of the render buffer in pixels.
*/
- uint32_t getWidth() const {
- return mWidth;
- }
+ uint32_t getWidth() const { return mWidth; }
/**
* Returns the height of the render buffer in pixels.
*/
- uint32_t getHeight() const {
- return mHeight;
- }
+ uint32_t getHeight() const { return mHeight; }
/**
* Returns the size of this render buffer in bytes.
*/
uint32_t getSize() const {
// Round to the nearest byte
- return (uint32_t) ((mWidth * mHeight * formatSize(mFormat)) / 8.0f + 0.5f);
+ return (uint32_t)((mWidth * mHeight * formatSize(mFormat)) / 8.0f + 0.5f);
}
/**
@@ -186,9 +173,9 @@ private:
bool mAllocated;
GLuint mName;
-}; // struct RenderBuffer
+}; // struct RenderBuffer
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_RENDER_BUFFER_H
+#endif // ANDROID_HWUI_RENDER_BUFFER_H
diff --git a/libs/hwui/RenderBufferCache.cpp b/libs/hwui/RenderBufferCache.cpp
index 2f8ddfe6d660..98010d8da1bd 100644
--- a/libs/hwui/RenderBufferCache.cpp
+++ b/libs/hwui/RenderBufferCache.cpp
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#include "Debug.h"
-#include "Properties.h"
#include "RenderBufferCache.h"
+#include "Debug.h"
#include "DeviceInfo.h"
+#include "Properties.h"
#include <utils/Log.h>
@@ -32,9 +32,9 @@ namespace uirenderer {
// Debug
#if DEBUG_RENDER_BUFFERS
- #define RENDER_BUFFER_LOGD(...) ALOGD(__VA_ARGS__)
+#define RENDER_BUFFER_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define RENDER_BUFFER_LOGD(...)
+#define RENDER_BUFFER_LOGD(...)
#endif
static uint32_t calculateRboCacheSize() {
@@ -48,9 +48,7 @@ static uint32_t calculateRboCacheSize() {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-RenderBufferCache::RenderBufferCache()
- : mSize(0)
- , mMaxSize(calculateRboCacheSize()) {}
+RenderBufferCache::RenderBufferCache() : mSize(0), mMaxSize(calculateRboCacheSize()) {}
RenderBufferCache::~RenderBufferCache() {
clear();
@@ -72,9 +70,8 @@ uint32_t RenderBufferCache::getMaxSize() {
// Caching
///////////////////////////////////////////////////////////////////////////////
-int RenderBufferCache::RenderBufferEntry::compare(
- const RenderBufferCache::RenderBufferEntry& lhs,
- const RenderBufferCache::RenderBufferEntry& rhs) {
+int RenderBufferCache::RenderBufferEntry::compare(const RenderBufferCache::RenderBufferEntry& lhs,
+ const RenderBufferCache::RenderBufferEntry& rhs) {
int deltaInt = int(lhs.mWidth) - int(rhs.mWidth);
if (deltaInt != 0) return deltaInt;
@@ -87,8 +84,8 @@ int RenderBufferCache::RenderBufferEntry::compare(
void RenderBufferCache::deleteBuffer(RenderBuffer* buffer) {
if (buffer) {
RENDER_BUFFER_LOGD("Deleted %s render buffer (%dx%d)",
- RenderBuffer::formatName(buffer->getFormat()),
- buffer->getWidth(), buffer->getHeight());
+ RenderBuffer::formatName(buffer->getFormat()), buffer->getWidth(),
+ buffer->getHeight());
mSize -= buffer->getSize();
delete buffer;
@@ -115,13 +112,13 @@ RenderBuffer* RenderBufferCache::get(GLenum format, const uint32_t width, const
buffer = entry.mBuffer;
mSize -= buffer->getSize();
- RENDER_BUFFER_LOGD("Found %s render buffer (%dx%d)",
- RenderBuffer::formatName(format), width, height);
+ RENDER_BUFFER_LOGD("Found %s render buffer (%dx%d)", RenderBuffer::formatName(format),
+ width, height);
} else {
buffer = new RenderBuffer(format, width, height);
- RENDER_BUFFER_LOGD("Created new %s render buffer (%dx%d)",
- RenderBuffer::formatName(format), width, height);
+ RENDER_BUFFER_LOGD("Created new %s render buffer (%dx%d)", RenderBuffer::formatName(format),
+ width, height);
}
buffer->bind();
@@ -147,18 +144,18 @@ bool RenderBufferCache::put(RenderBuffer* buffer) {
mSize += size;
RENDER_BUFFER_LOGD("Added %s render buffer (%dx%d)",
- RenderBuffer::formatName(buffer->getFormat()),
- buffer->getWidth(), buffer->getHeight());
+ RenderBuffer::formatName(buffer->getFormat()), buffer->getWidth(),
+ buffer->getHeight());
return true;
} else {
RENDER_BUFFER_LOGD("Deleted %s render buffer (%dx%d) Size=%d, MaxSize=%d",
- RenderBuffer::formatName(buffer->getFormat()),
- buffer->getWidth(), buffer->getHeight(), size, mMaxSize);
+ RenderBuffer::formatName(buffer->getFormat()), buffer->getWidth(),
+ buffer->getHeight(), size, mMaxSize);
delete buffer;
}
return false;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/RenderBufferCache.h b/libs/hwui/RenderBufferCache.h
index 644433145cd0..c936a5283965 100644
--- a/libs/hwui/RenderBufferCache.h
+++ b/libs/hwui/RenderBufferCache.h
@@ -74,28 +74,22 @@ public:
private:
struct RenderBufferEntry {
- RenderBufferEntry():
- mBuffer(nullptr), mWidth(0), mHeight(0) {
- }
+ RenderBufferEntry() : mBuffer(nullptr), mWidth(0), mHeight(0) {}
- RenderBufferEntry(GLenum format, const uint32_t width, const uint32_t height):
- mBuffer(nullptr), mFormat(format), mWidth(width), mHeight(height) {
- }
+ RenderBufferEntry(GLenum format, const uint32_t width, const uint32_t height)
+ : mBuffer(nullptr), mFormat(format), mWidth(width), mHeight(height) {}
- explicit RenderBufferEntry(RenderBuffer* buffer):
- mBuffer(buffer), mFormat(buffer->getFormat()),
- mWidth(buffer->getWidth()), mHeight(buffer->getHeight()) {
- }
+ explicit RenderBufferEntry(RenderBuffer* buffer)
+ : mBuffer(buffer)
+ , mFormat(buffer->getFormat())
+ , mWidth(buffer->getWidth())
+ , mHeight(buffer->getHeight()) {}
static int compare(const RenderBufferEntry& lhs, const RenderBufferEntry& rhs);
- bool operator==(const RenderBufferEntry& other) const {
- return compare(*this, other) == 0;
- }
+ bool operator==(const RenderBufferEntry& other) const { return compare(*this, other) == 0; }
- bool operator!=(const RenderBufferEntry& other) const {
- return compare(*this, other) != 0;
- }
+ bool operator!=(const RenderBufferEntry& other) const { return compare(*this, other) != 0; }
bool operator<(const RenderBufferEntry& other) const {
return RenderBufferEntry::compare(*this, other) < 0;
@@ -105,7 +99,7 @@ private:
GLenum mFormat;
uint32_t mWidth;
uint32_t mHeight;
- }; // struct RenderBufferEntry
+ }; // struct RenderBufferEntry
void deleteBuffer(RenderBuffer* buffer);
@@ -113,9 +107,9 @@ private:
uint32_t mSize;
uint32_t mMaxSize;
-}; // class RenderBufferCache
+}; // class RenderBufferCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_RENDER_BUFFER_CACHE_H
+#endif // ANDROID_HWUI_RENDER_BUFFER_CACHE_H
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 36a747519c37..fedcc10abb64 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -21,16 +21,16 @@
#include "Debug.h"
#include "RecordedOp.h"
#include "TreeInfo.h"
+#include "VectorDrawable.h"
+#include "renderstate/RenderState.h"
+#include "renderthread/CanvasContext.h"
#include "utils/FatVector.h"
#include "utils/MathUtils.h"
#include "utils/StringUtils.h"
#include "utils/TraceUtils.h"
-#include "VectorDrawable.h"
-#include "renderstate/RenderState.h"
-#include "renderthread/CanvasContext.h"
-#include "protos/hwui.pb.h"
#include "protos/ProtoHelpers.h"
+#include "protos/hwui.pb.h"
#include <SkPathOps.h>
#include <algorithm>
@@ -46,9 +46,7 @@ class ImmediateRemoved : public TreeObserver {
public:
explicit ImmediateRemoved(TreeInfo* info) : mTreeInfo(info) {}
- void onMaybeRemovedFromTree(RenderNode* node) override {
- node->onRemovedFromTree(mTreeInfo);
- }
+ void onMaybeRemovedFromTree(RenderNode* node) override { node->onRemovedFromTree(mTreeInfo); }
private:
TreeInfo* mTreeInfo;
@@ -60,8 +58,7 @@ RenderNode::RenderNode()
, mDisplayList(nullptr)
, mStagingDisplayList(nullptr)
, mAnimatorManager(*this)
- , mParentCount(0) {
-}
+ , mParentCount(0) {}
RenderNode::~RenderNode() {
ImmediateRemoved observer(nullptr);
@@ -89,12 +86,11 @@ void RenderNode::output() {
void RenderNode::output(std::ostream& output, uint32_t level) {
output << " (" << getName() << " " << this
- << (MathUtils::isZero(properties().getAlpha()) ? ", zero alpha" : "")
- << (properties().hasShadow() ? ", casting shadow" : "")
- << (isRenderable() ? "" : ", empty")
- << (properties().getProjectBackwards() ? ", projected" : "")
- << (hasLayer() ? ", on HW Layer" : "")
- << ")" << std::endl;
+ << (MathUtils::isZero(properties().getAlpha()) ? ", zero alpha" : "")
+ << (properties().hasShadow() ? ", casting shadow" : "")
+ << (isRenderable() ? "" : ", empty")
+ << (properties().getProjectBackwards() ? ", projected" : "")
+ << (hasLayer() ? ", on HW Layer" : "") << ")" << std::endl;
properties().debugOutputProperties(output, level + 1);
@@ -105,9 +101,8 @@ void RenderNode::output(std::ostream& output, uint32_t level) {
output << std::endl;
}
-void RenderNode::copyTo(proto::RenderNode *pnode) {
- pnode->set_id(static_cast<uint64_t>(
- reinterpret_cast<uintptr_t>(this)));
+void RenderNode::copyTo(proto::RenderNode* pnode) {
+ pnode->set_id(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(this)));
pnode->set_name(mName.string(), mName.length());
proto::RenderProperties* pprops = pnode->mutable_properties();
@@ -239,18 +234,16 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {
LayerType layerType = properties().effectiveLayerType();
// If we are not a layer OR we cannot be rendered (eg, view was detached)
// we need to destroy any Layers we may have had previously
- if (CC_LIKELY(layerType != LayerType::RenderLayer)
- || CC_UNLIKELY(!isRenderable())
- || CC_UNLIKELY(properties().getWidth() == 0)
- || CC_UNLIKELY(properties().getHeight() == 0)
- || CC_UNLIKELY(!properties().fitsOnLayer())) {
+ if (CC_LIKELY(layerType != LayerType::RenderLayer) || CC_UNLIKELY(!isRenderable()) ||
+ CC_UNLIKELY(properties().getWidth() == 0) || CC_UNLIKELY(properties().getHeight() == 0) ||
+ CC_UNLIKELY(!properties().fitsOnLayer())) {
if (CC_UNLIKELY(hasLayer())) {
renderthread::CanvasContext::destroyLayer(this);
}
return;
}
- if(info.canvasContext.createOrUpdateLayer(this, *info.damageAccumulator)) {
+ if (info.canvasContext.createOrUpdateLayer(this, *info.damageAccumulator)) {
damageSelf(info);
}
@@ -261,8 +254,8 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {
err << "Unable to create layer for " << getName();
const int maxTextureSize = Caches::getInstance().maxTextureSize;
if (getWidth() > maxTextureSize || getHeight() > maxTextureSize) {
- err << ", size " << getWidth() << "x" << getHeight()
- << " exceeds max size " << maxTextureSize;
+ err << ", size " << getWidth() << "x" << getHeight() << " exceeds max size "
+ << maxTextureSize;
} else {
err << ", see logcat for more info";
}
@@ -306,8 +299,8 @@ void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool fu
} else if (mDisplayList) {
willHaveFunctor = mDisplayList->hasFunctor();
}
- bool childFunctorsNeedLayer = mProperties.prepareForFunctorPresence(
- willHaveFunctor, functorsNeedLayer);
+ bool childFunctorsNeedLayer =
+ mProperties.prepareForFunctorPresence(willHaveFunctor, functorsNeedLayer);
if (CC_UNLIKELY(mPositionListener.get())) {
mPositionListener->onPositionUpdated(*this, info);
@@ -320,10 +313,12 @@ void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool fu
if (mDisplayList) {
info.out.hasFunctors |= mDisplayList->hasFunctor();
- bool isDirty = mDisplayList->prepareListAndChildren(observer, info, childFunctorsNeedLayer,
- [](RenderNode* child, TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer) {
- child->prepareTreeImpl(observer, info, functorsNeedLayer);
- });
+ bool isDirty = mDisplayList->prepareListAndChildren(
+ observer, info, childFunctorsNeedLayer,
+ [](RenderNode* child, TreeObserver& observer, TreeInfo& info,
+ bool functorsNeedLayer) {
+ child->prepareTreeImpl(observer, info, functorsNeedLayer);
+ });
if (isDirty) {
damageSelf(info);
}
@@ -363,9 +358,7 @@ void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) {
// Make sure we inc first so that we don't fluctuate between 0 and 1,
// which would thrash the layer cache
if (mStagingDisplayList) {
- mStagingDisplayList->updateChildren([](RenderNode* child) {
- child->incParentRefCount();
- });
+ mStagingDisplayList->updateChildren([](RenderNode* child) { child->incParentRefCount(); });
}
deleteDisplayList(observer, info);
mDisplayList = mStagingDisplayList;
@@ -388,9 +381,8 @@ void RenderNode::pushStagingDisplayListChanges(TreeObserver& observer, TreeInfo&
void RenderNode::deleteDisplayList(TreeObserver& observer, TreeInfo* info) {
if (mDisplayList) {
- mDisplayList->updateChildren([&observer, info](RenderNode* child) {
- child->decParentRefCount(observer, info);
- });
+ mDisplayList->updateChildren(
+ [&observer, info](RenderNode* child) { child->decParentRefCount(observer, info); });
if (!mDisplayList->reuseDisplayList(this, info ? &info->canvasContext : nullptr)) {
delete mDisplayList;
}
@@ -413,9 +405,7 @@ void RenderNode::destroyLayers() {
renderthread::CanvasContext::destroyLayer(this);
}
if (mDisplayList) {
- mDisplayList->updateChildren([](RenderNode* child) {
- child->destroyLayers();
- });
+ mDisplayList->updateChildren([](RenderNode* child) { child->destroyLayers(); });
}
}
@@ -461,16 +451,15 @@ void RenderNode::applyViewPropertyTransforms(mat4& matrix, bool true3dTransform)
if (properties().hasTransformMatrix() || applyTranslationZ) {
if (properties().isTransformTranslateOnly()) {
matrix.translate(properties().getTranslationX(), properties().getTranslationY(),
- true3dTransform ? properties().getZ() : 0.0f);
+ true3dTransform ? properties().getZ() : 0.0f);
} else {
if (!true3dTransform) {
matrix.multiply(*properties().getTransformMatrix());
} else {
mat4 true3dMat;
- true3dMat.loadTranslate(
- properties().getPivotX() + properties().getTranslationX(),
- properties().getPivotY() + properties().getTranslationY(),
- properties().getZ());
+ true3dMat.loadTranslate(properties().getPivotX() + properties().getTranslationX(),
+ properties().getPivotY() + properties().getTranslationY(),
+ properties().getZ());
true3dMat.rotate(properties().getRotationX(), 1, 0, 0);
true3dMat.rotate(properties().getRotationY(), 0, 1, 0);
true3dMat.rotate(properties().getRotation(), 0, 0, 1);
@@ -505,8 +494,7 @@ void RenderNode::computeOrdering() {
}
void RenderNode::computeOrderingImpl(
- RenderNodeOp* opState,
- std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface,
+ RenderNodeOp* opState, std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface,
const mat4* transformFromProjectionSurface) {
mProjectedNodes.clear();
if (mDisplayList == nullptr || mDisplayList->isEmpty()) return;
@@ -569,7 +557,6 @@ const SkPath* RenderNode::getClippedOutline(const SkRect& clipRect) const {
SkPath clipPath;
clipPath.addRect(clipRect);
Op(*outlinePath, clipPath, kIntersect_SkPathOp, &mClippedOutlineCache.clippedOutline);
-
}
return &mClippedOutlineCache.clippedOutline;
}
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 89e022f5e68d..1469a156e2d8 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -63,7 +63,8 @@ class RenderNode;
}
/**
- * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties.
+ * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display
+ * properties.
*
* Recording of canvas commands is somewhat similar to SkPicture, except the canvas-recording
* functionality is split between RecordingCanvas (which manages the recording), DisplayList
@@ -74,33 +75,32 @@ class RenderNode;
* attached.
*/
class RenderNode : public VirtualLightRefBase {
-friend class TestUtils; // allow TestUtils to access syncDisplayList / syncProperties
-friend class FrameBuilder;
+ friend class TestUtils; // allow TestUtils to access syncDisplayList / syncProperties
+ friend class FrameBuilder;
+
public:
enum DirtyPropertyMask {
- GENERIC = 1 << 1,
- TRANSLATION_X = 1 << 2,
- TRANSLATION_Y = 1 << 3,
- TRANSLATION_Z = 1 << 4,
- SCALE_X = 1 << 5,
- SCALE_Y = 1 << 6,
- ROTATION = 1 << 7,
- ROTATION_X = 1 << 8,
- ROTATION_Y = 1 << 9,
- X = 1 << 10,
- Y = 1 << 11,
- Z = 1 << 12,
- ALPHA = 1 << 13,
- DISPLAY_LIST = 1 << 14,
+ GENERIC = 1 << 1,
+ TRANSLATION_X = 1 << 2,
+ TRANSLATION_Y = 1 << 3,
+ TRANSLATION_Z = 1 << 4,
+ SCALE_X = 1 << 5,
+ SCALE_Y = 1 << 6,
+ ROTATION = 1 << 7,
+ ROTATION_X = 1 << 8,
+ ROTATION_Y = 1 << 9,
+ X = 1 << 10,
+ Y = 1 << 11,
+ Z = 1 << 12,
+ ALPHA = 1 << 13,
+ DISPLAY_LIST = 1 << 14,
};
ANDROID_API RenderNode();
ANDROID_API virtual ~RenderNode();
// See flags defined in DisplayList.java
- enum ReplayFlag {
- kReplayFlag_ClipChildren = 0x1
- };
+ enum ReplayFlag { kReplayFlag_ClipChildren = 0x1 };
ANDROID_API void setStagingDisplayList(DisplayList* newData);
@@ -110,17 +110,13 @@ public:
ANDROID_API int getDebugSize();
void copyTo(proto::RenderNode* node);
- bool isRenderable() const {
- return mDisplayList && !mDisplayList->isEmpty();
- }
+ bool isRenderable() const { return mDisplayList && !mDisplayList->isEmpty(); }
bool hasProjectionReceiver() const {
return mDisplayList && mDisplayList->projectionReceiveIndex >= 0;
}
- const char* getName() const {
- return mName.string();
- }
+ const char* getName() const { return mName.string(); }
void setName(const char* name) {
if (name) {
@@ -133,49 +129,29 @@ public:
}
}
- VirtualLightRefBase* getUserContext() const {
- return mUserContext.get();
- }
+ VirtualLightRefBase* getUserContext() const { return mUserContext.get(); }
- void setUserContext(VirtualLightRefBase* context) {
- mUserContext = context;
- }
+ void setUserContext(VirtualLightRefBase* context) { mUserContext = context; }
bool isPropertyFieldDirty(DirtyPropertyMask field) const {
return mDirtyPropertyFields & field;
}
- void setPropertyFieldsDirty(uint32_t fields) {
- mDirtyPropertyFields |= fields;
- }
+ void setPropertyFieldsDirty(uint32_t fields) { mDirtyPropertyFields |= fields; }
- const RenderProperties& properties() const {
- return mProperties;
- }
+ const RenderProperties& properties() const { return mProperties; }
- RenderProperties& animatorProperties() {
- return mProperties;
- }
+ RenderProperties& animatorProperties() { return mProperties; }
- const RenderProperties& stagingProperties() {
- return mStagingProperties;
- }
+ const RenderProperties& stagingProperties() { return mStagingProperties; }
- RenderProperties& mutateStagingProperties() {
- return mStagingProperties;
- }
+ RenderProperties& mutateStagingProperties() { return mStagingProperties; }
- bool isValid() {
- return mValid;
- }
+ bool isValid() { return mValid; }
- int getWidth() const {
- return properties().getWidth();
- }
+ int getWidth() const { return properties().getWidth(); }
- int getHeight() const {
- return properties().getHeight();
- }
+ int getHeight() const { return properties().getHeight(); }
ANDROID_API virtual void prepareTree(TreeInfo& info);
void destroyHardwareResources(TreeInfo* info = nullptr);
@@ -196,18 +172,14 @@ public:
bool nothingToDraw() const {
const Outline& outline = properties().getOutline();
- return mDisplayList == nullptr
- || properties().getAlpha() <= 0
- || (outline.getShouldClip() && outline.isEmpty())
- || properties().getScaleX() == 0
- || properties().getScaleY() == 0;
+ return mDisplayList == nullptr || properties().getAlpha() <= 0 ||
+ (outline.getShouldClip() && outline.isEmpty()) || properties().getScaleX() == 0 ||
+ properties().getScaleY() == 0;
}
- const DisplayList* getDisplayList() const {
- return mDisplayList;
- }
+ const DisplayList* getDisplayList() const { return mDisplayList; }
OffscreenBuffer* getLayer() const { return mLayer; }
- OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh...
+ OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh...
void setLayer(OffscreenBuffer* layer) { mLayer = layer; }
// Note: The position callbacks are relying on the listener using
@@ -234,16 +206,12 @@ public:
// This is only modified in MODE_FULL, so it can be safely accessed
// on the UI thread.
- ANDROID_API bool hasParents() {
- return mParentCount;
- }
+ ANDROID_API bool hasParents() { return mParentCount; }
void onRemovedFromTree(TreeInfo* info);
// Called by CanvasContext to promote a RenderNode to be a root node
- void makeRoot() {
- incParentRefCount();
- }
+ void makeRoot() { incParentRefCount(); }
// Called by CanvasContext when it drops a RenderNode from being a root node
void clearRoot();
@@ -252,8 +220,8 @@ public:
private:
void computeOrderingImpl(RenderNodeOp* opState,
- std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface,
- const mat4* transformFromProjectionSurface);
+ std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface,
+ const mat4* transformFromProjectionSurface);
void syncProperties();
void syncDisplayList(TreeObserver& observer, TreeInfo* info);
@@ -309,7 +277,7 @@ private:
sp<PositionListener> mPositionListener;
-// METHODS & FIELDS ONLY USED BY THE SKIA RENDERER
+ // METHODS & FIELDS ONLY USED BY THE SKIA RENDERER
public:
/**
* Detach and transfer ownership of an already allocated displayList for use
@@ -361,9 +329,7 @@ public:
return mSkiaLayer.get() ? mSkiaLayer->layerSurface.get() : nullptr;
}
- skiapipeline::SkiaLayer* getSkiaLayer() const {
- return mSkiaLayer.get();
- }
+ skiapipeline::SkiaLayer* getSkiaLayer() const { return mSkiaLayer.get(); }
/**
* Returns the path that represents the outline of RenderNode intersected with
@@ -376,6 +342,7 @@ public:
* again or the RenderNode's outline is mutated.
*/
const SkPath* getClippedOutline(const SkRect& clipRect) const;
+
private:
/**
* If this RenderNode has been used in a previous frame then the SkiaDisplayList
@@ -401,17 +368,15 @@ private:
SkPath clippedOutline;
};
mutable ClippedOutlineCache mClippedOutlineCache;
-}; // class RenderNode
+}; // class RenderNode
class MarkAndSweepRemoved : public TreeObserver {
-PREVENT_COPY_AND_ASSIGN(MarkAndSweepRemoved);
+ PREVENT_COPY_AND_ASSIGN(MarkAndSweepRemoved);
public:
explicit MarkAndSweepRemoved(TreeInfo* info) : mTreeInfo(info) {}
- void onMaybeRemovedFromTree(RenderNode* node) override {
- mMarked.emplace_back(node);
- }
+ void onMaybeRemovedFromTree(RenderNode* node) override { mMarked.emplace_back(node); }
~MarkAndSweepRemoved() {
for (auto& node : mMarked) {
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 146fbe73a48a..e49574462e9e 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -44,9 +44,9 @@ void LayerProperties::reset() {
}
bool LayerProperties::setColorFilter(SkColorFilter* filter) {
- if (mColorFilter == filter) return false;
- SkRefCnt_SafeAssign(mColorFilter, filter);
- return true;
+ if (mColorFilter == filter) return false;
+ SkRefCnt_SafeAssign(mColorFilter, filter);
+ return true;
}
bool LayerProperties::setFromPaint(const SkPaint* paint) {
@@ -66,18 +66,13 @@ LayerProperties& LayerProperties::operator=(const LayerProperties& other) {
return *this;
}
-RenderProperties::ComputedFields::ComputedFields()
- : mTransformMatrix(nullptr) {
-}
+RenderProperties::ComputedFields::ComputedFields() : mTransformMatrix(nullptr) {}
RenderProperties::ComputedFields::~ComputedFields() {
delete mTransformMatrix;
}
-RenderProperties::RenderProperties()
- : mStaticMatrix(nullptr)
- , mAnimationMatrix(nullptr) {
-}
+RenderProperties::RenderProperties() : mStaticMatrix(nullptr), mAnimationMatrix(nullptr) {}
RenderProperties::~RenderProperties() {
delete mStaticMatrix;
@@ -99,14 +94,14 @@ RenderProperties& RenderProperties::operator=(const RenderProperties& other) {
return *this;
}
-static void dumpMatrix(std::ostream& output, std::string& indent,
- const char* label, SkMatrix* matrix) {
- if (matrix) {
- output << indent << "(" << label << " " << matrix << ": ";
+static void dumpMatrix(std::ostream& output, std::string& indent, const char* label,
+ SkMatrix* matrix) {
+ if (matrix) {
+ output << indent << "(" << label << " " << matrix << ": ";
output << std::fixed << std::setprecision(2);
- output << "[" << matrix->get(0) << " "<< matrix->get(1) << " " << matrix->get(2) << "]";
- output << " [" << matrix->get(3) << " "<< matrix->get(4) << " " << matrix->get(5) << "]";
- output << " [" << matrix->get(6) << " "<< matrix->get(7) << " " << matrix->get(8) << "]";
+ output << "[" << matrix->get(0) << " " << matrix->get(1) << " " << matrix->get(2) << "]";
+ output << " [" << matrix->get(3) << " " << matrix->get(4) << " " << matrix->get(5) << "]";
+ output << " [" << matrix->get(6) << " " << matrix->get(7) << " " << matrix->get(8) << "]";
output << ")" << std::endl;
}
}
@@ -114,8 +109,8 @@ static void dumpMatrix(std::ostream& output, std::string& indent,
void RenderProperties::debugOutputProperties(std::ostream& output, const int level) const {
auto indent = std::string(level * 2, ' ');
if (mPrimitiveFields.mLeft != 0 || mPrimitiveFields.mTop != 0) {
- output << indent << "(Translate (left, top) " << mPrimitiveFields.mLeft
- << ", " << mPrimitiveFields.mTop << ")" << std::endl;
+ output << indent << "(Translate (left, top) " << mPrimitiveFields.mLeft << ", "
+ << mPrimitiveFields.mTop << ")" << std::endl;
}
dumpMatrix(output, indent, "ConcatMatrix (static)", mStaticMatrix);
dumpMatrix(output, indent, "ConcatMatrix (animation)", mAnimationMatrix);
@@ -124,7 +119,7 @@ void RenderProperties::debugOutputProperties(std::ostream& output, const int lev
if (hasTransformMatrix()) {
if (isTransformTranslateOnly()) {
output << indent << "(Translate " << getTranslationX() << ", " << getTranslationY()
- << ", " << getZ() << ")" << std::endl;
+ << ", " << getZ() << ")" << std::endl;
} else {
dumpMatrix(output, indent, "ConcatMatrix ", mComputedFields.mTransformMatrix);
}
@@ -132,10 +127,9 @@ void RenderProperties::debugOutputProperties(std::ostream& output, const int lev
const bool isLayer = effectiveLayerType() != LayerType::None;
int clipFlags = getClippingFlags();
- if (mPrimitiveFields.mAlpha < 1
- && !MathUtils::isZero(mPrimitiveFields.mAlpha)) {
+ if (mPrimitiveFields.mAlpha < 1 && !MathUtils::isZero(mPrimitiveFields.mAlpha)) {
if (isLayer) {
- clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
+ clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
}
if (CC_LIKELY(isLayer || !getHasOverlappingRendering())) {
@@ -146,31 +140,28 @@ void RenderProperties::debugOutputProperties(std::ostream& output, const int lev
Rect layerBounds(0, 0, getWidth(), getHeight());
if (clipFlags) {
getClippingRectForFlags(clipFlags, &layerBounds);
- clipFlags = 0; // all clipping done by savelayer
+ clipFlags = 0; // all clipping done by savelayer
}
- output << indent << "(SaveLayerAlpha "
- << (int)layerBounds.left << ", " << (int)layerBounds.top << ", "
- << (int)layerBounds.right << ", " << (int)layerBounds.bottom << ", "
- << (int)(mPrimitiveFields.mAlpha * 255) << ", 0x" << std::hex
- << (SaveFlags::HasAlphaLayer | SaveFlags::ClipToLayer) << ")" << std::dec
- << std::endl;
+ output << indent << "(SaveLayerAlpha " << (int)layerBounds.left << ", "
+ << (int)layerBounds.top << ", " << (int)layerBounds.right << ", "
+ << (int)layerBounds.bottom << ", " << (int)(mPrimitiveFields.mAlpha * 255)
+ << ", 0x" << std::hex << (SaveFlags::HasAlphaLayer | SaveFlags::ClipToLayer)
+ << ")" << std::dec << std::endl;
}
}
if (clipFlags) {
Rect clipRect;
getClippingRectForFlags(clipFlags, &clipRect);
- output << indent << "(ClipRect "
- << (int)clipRect.left << ", " << (int)clipRect.top << ", "
- << (int)clipRect.right << ", " << (int)clipRect.bottom << ")" << std::endl;
+ output << indent << "(ClipRect " << (int)clipRect.left << ", " << (int)clipRect.top << ", "
+ << (int)clipRect.right << ", " << (int)clipRect.bottom << ")" << std::endl;
}
if (getRevealClip().willClip()) {
Rect bounds;
getRevealClip().getBounds(&bounds);
- output << indent << "(Clip to reveal clip with bounds "
- << bounds.left << ", " << bounds.top << ", "
- << bounds.right << ", " << bounds.bottom << ")" << std::endl;
+ output << indent << "(Clip to reveal clip with bounds " << bounds.left << ", " << bounds.top
+ << ", " << bounds.right << ", " << bounds.bottom << ")" << std::endl;
}
auto& outline = mPrimitiveFields.mOutline;
@@ -179,9 +170,8 @@ void RenderProperties::debugOutputProperties(std::ostream& output, const int lev
output << indent << "(Clip to empty outline)";
} else if (outline.willClip()) {
const Rect& bounds = outline.getBounds();
- output << indent << "(Clip to outline with bounds "
- << bounds.left << ", " << bounds.top << ", "
- << bounds.right << ", " << bounds.bottom << ")" << std::endl;
+ output << indent << "(Clip to outline with bounds " << bounds.left << ", " << bounds.top
+ << ", " << bounds.right << ", " << bounds.bottom << ")" << std::endl;
}
}
}
@@ -212,7 +202,7 @@ void RenderProperties::updateMatrix() {
mComputedFields.mTransformCamera.getMatrix(&transform3D);
transform3D.preTranslate(-getPivotX(), -getPivotY());
transform3D.postTranslate(getPivotX() + getTranslationX(),
- getPivotY() + getTranslationY());
+ getPivotY() + getTranslationY());
transform->postConcat(transform3D);
mComputedFields.mTransformCamera.restore();
}
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 9ee2f9c69343..3d2c2520624b 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -18,24 +18,25 @@
#include "Caches.h"
#include "DeviceInfo.h"
+#include "Outline.h"
#include "Rect.h"
#include "RevealClip.h"
-#include "Outline.h"
#include "utils/MathUtils.h"
#include "utils/PaintUtils.h"
#include <SkBlendMode.h>
#include <SkCamera.h>
+#include <SkColor.h>
#include <SkMatrix.h>
#include <SkRegion.h>
-#include <algorithm>
-#include <stddef.h>
-#include <vector>
-#include <cutils/compiler.h>
#include <androidfw/ResourceTypes.h>
+#include <cutils/compiler.h>
+#include <stddef.h>
#include <utils/Log.h>
+#include <algorithm>
#include <ostream>
+#include <vector>
class SkBitmap;
class SkColorFilter;
@@ -63,7 +64,7 @@ enum class LayerType {
};
enum ClippingFlags {
- CLIP_TO_BOUNDS = 0x1 << 0,
+ CLIP_TO_BOUNDS = 0x1 << 0,
CLIP_TO_CLIP_BOUNDS = 0x1 << 1,
};
@@ -77,43 +78,27 @@ public:
return false;
}
- bool setOpaque(bool opaque) {
- return RP_SET(mOpaque, opaque);
- }
+ bool setOpaque(bool opaque) { return RP_SET(mOpaque, opaque); }
- bool opaque() const {
- return mOpaque;
- }
+ bool opaque() const { return mOpaque; }
- bool setAlpha(uint8_t alpha) {
- return RP_SET(mAlpha, alpha);
- }
+ bool setAlpha(uint8_t alpha) { return RP_SET(mAlpha, alpha); }
- uint8_t alpha() const {
- return mAlpha;
- }
+ uint8_t alpha() const { return mAlpha; }
- bool setXferMode(SkBlendMode mode) {
- return RP_SET(mMode, mode);
- }
+ bool setXferMode(SkBlendMode mode) { return RP_SET(mMode, mode); }
- SkBlendMode xferMode() const {
- return mMode;
- }
+ SkBlendMode xferMode() const { return mMode; }
bool setColorFilter(SkColorFilter* filter);
- SkColorFilter* colorFilter() const {
- return mColorFilter;
- }
+ SkColorFilter* colorFilter() const { return mColorFilter; }
// Sets alpha, xfermode, and colorfilter from an SkPaint
// paint may be NULL, in which case defaults will be set
bool setFromPaint(const SkPaint* paint);
- bool needsBlending() const {
- return !opaque() || alpha() < 255;
- }
+ bool needsBlending() const { return !opaque() || alpha() < 255; }
LayerProperties& operator=(const LayerProperties& other);
@@ -123,9 +108,7 @@ private:
void reset();
// Private since external users should go through properties().effectiveLayerType()
- LayerType type() const {
- return mType;
- }
+ LayerType type() const { return mType; }
friend class RenderProperties;
@@ -169,16 +152,17 @@ public:
*/
bool prepareForFunctorPresence(bool willHaveFunctor, bool ancestorDictatesFunctorsNeedLayer) {
// parent may have already dictated that a descendant layer is needed
- bool functorsNeedLayer = ancestorDictatesFunctorsNeedLayer
+ bool functorsNeedLayer =
+ ancestorDictatesFunctorsNeedLayer
// Round rect clipping forces layer for functors
- || CC_UNLIKELY(getOutline().willRoundRectClip())
- || CC_UNLIKELY(getRevealClip().willClip())
+ || CC_UNLIKELY(getOutline().willRoundRectClip()) ||
+ CC_UNLIKELY(getRevealClip().willClip())
// Complex matrices forces layer, due to stencil clipping
- || CC_UNLIKELY(getTransformMatrix() && !getTransformMatrix()->isScaleTranslate())
- || CC_UNLIKELY(getAnimationMatrix() && !getAnimationMatrix()->isScaleTranslate())
- || CC_UNLIKELY(getStaticMatrix() && !getStaticMatrix()->isScaleTranslate());
+ || CC_UNLIKELY(getTransformMatrix() && !getTransformMatrix()->isScaleTranslate()) ||
+ CC_UNLIKELY(getAnimationMatrix() && !getAnimationMatrix()->isScaleTranslate()) ||
+ CC_UNLIKELY(getStaticMatrix() && !getStaticMatrix()->isScaleTranslate());
mComputedFields.mNeedLayerForFunctors = (willHaveFunctor && functorsNeedLayer);
@@ -210,9 +194,7 @@ public:
return RP_SET(mPrimitiveFields.mProjectionReceiver, shouldReceive);
}
- bool isProjectionReceiver() const {
- return mPrimitiveFields.mProjectionReceiver;
- }
+ bool isProjectionReceiver() const { return mPrimitiveFields.mProjectionReceiver; }
bool setStaticMatrix(const SkMatrix* matrix) {
delete mStaticMatrix;
@@ -225,9 +207,7 @@ public:
}
// Can return NULL
- const SkMatrix* getStaticMatrix() const {
- return mStaticMatrix;
- }
+ const SkMatrix* getStaticMatrix() const { return mStaticMatrix; }
bool setAnimationMatrix(const SkMatrix* matrix) {
delete mAnimationMatrix;
@@ -244,124 +224,85 @@ public:
return RP_SET(mPrimitiveFields.mAlpha, alpha);
}
- float getAlpha() const {
- return mPrimitiveFields.mAlpha;
- }
+ float getAlpha() const { return mPrimitiveFields.mAlpha; }
bool setHasOverlappingRendering(bool hasOverlappingRendering) {
return RP_SET(mPrimitiveFields.mHasOverlappingRendering, hasOverlappingRendering);
}
- bool hasOverlappingRendering() const {
- return mPrimitiveFields.mHasOverlappingRendering;
- }
+ bool hasOverlappingRendering() const { return mPrimitiveFields.mHasOverlappingRendering; }
bool setElevation(float elevation) {
return RP_SET(mPrimitiveFields.mElevation, elevation);
// Don't dirty matrix/pivot, since they don't respect Z
}
- float getElevation() const {
- return mPrimitiveFields.mElevation;
- }
+ float getElevation() const { return mPrimitiveFields.mElevation; }
bool setTranslationX(float translationX) {
return RP_SET_AND_DIRTY(mPrimitiveFields.mTranslationX, translationX);
}
- float getTranslationX() const {
- return mPrimitiveFields.mTranslationX;
- }
+ float getTranslationX() const { return mPrimitiveFields.mTranslationX; }
bool setTranslationY(float translationY) {
return RP_SET_AND_DIRTY(mPrimitiveFields.mTranslationY, translationY);
}
- float getTranslationY() const {
- return mPrimitiveFields.mTranslationY;
- }
+ float getTranslationY() const { return mPrimitiveFields.mTranslationY; }
bool setTranslationZ(float translationZ) {
return RP_SET(mPrimitiveFields.mTranslationZ, translationZ);
// mMatrixOrPivotDirty not set, since matrix doesn't respect Z
}
- float getTranslationZ() const {
- return mPrimitiveFields.mTranslationZ;
- }
+ float getTranslationZ() const { return mPrimitiveFields.mTranslationZ; }
// Animation helper
- bool setX(float value) {
- return setTranslationX(value - getLeft());
- }
+ bool setX(float value) { return setTranslationX(value - getLeft()); }
// Animation helper
- float getX() const {
- return getLeft() + getTranslationX();
- }
+ float getX() const { return getLeft() + getTranslationX(); }
// Animation helper
- bool setY(float value) {
- return setTranslationY(value - getTop());
- }
+ bool setY(float value) { return setTranslationY(value - getTop()); }
// Animation helper
- float getY() const {
- return getTop() + getTranslationY();
- }
+ float getY() const { return getTop() + getTranslationY(); }
// Animation helper
- bool setZ(float value) {
- return setTranslationZ(value - getElevation());
- }
+ bool setZ(float value) { return setTranslationZ(value - getElevation()); }
- float getZ() const {
- return getElevation() + getTranslationZ();
- }
+ float getZ() const { return getElevation() + getTranslationZ(); }
bool setRotation(float rotation) {
return RP_SET_AND_DIRTY(mPrimitiveFields.mRotation, rotation);
}
- float getRotation() const {
- return mPrimitiveFields.mRotation;
- }
+ float getRotation() const { return mPrimitiveFields.mRotation; }
bool setRotationX(float rotationX) {
return RP_SET_AND_DIRTY(mPrimitiveFields.mRotationX, rotationX);
}
- float getRotationX() const {
- return mPrimitiveFields.mRotationX;
- }
+ float getRotationX() const { return mPrimitiveFields.mRotationX; }
bool setRotationY(float rotationY) {
return RP_SET_AND_DIRTY(mPrimitiveFields.mRotationY, rotationY);
}
- float getRotationY() const {
- return mPrimitiveFields.mRotationY;
- }
+ float getRotationY() const { return mPrimitiveFields.mRotationY; }
- bool setScaleX(float scaleX) {
- return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleX, scaleX);
- }
+ bool setScaleX(float scaleX) { return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleX, scaleX); }
- float getScaleX() const {
- return mPrimitiveFields.mScaleX;
- }
+ float getScaleX() const { return mPrimitiveFields.mScaleX; }
- bool setScaleY(float scaleY) {
- return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleY, scaleY);
- }
+ bool setScaleY(float scaleY) { return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleY, scaleY); }
- float getScaleY() const {
- return mPrimitiveFields.mScaleY;
- }
+ float getScaleY() const { return mPrimitiveFields.mScaleY; }
bool setPivotX(float pivotX) {
- if (RP_SET(mPrimitiveFields.mPivotX, pivotX)
- || !mPrimitiveFields.mPivotExplicitlySet) {
+ if (RP_SET(mPrimitiveFields.mPivotX, pivotX) || !mPrimitiveFields.mPivotExplicitlySet) {
mPrimitiveFields.mMatrixOrPivotDirty = true;
mPrimitiveFields.mPivotExplicitlySet = true;
return true;
@@ -373,13 +314,10 @@ public:
* so the value returned may be stale if the RenderProperties has been
* modified since the last call to updateMatrix()
*/
- float getPivotX() const {
- return mPrimitiveFields.mPivotX;
- }
+ float getPivotX() const { return mPrimitiveFields.mPivotX; }
bool setPivotY(float pivotY) {
- if (RP_SET(mPrimitiveFields.mPivotY, pivotY)
- || !mPrimitiveFields.mPivotExplicitlySet) {
+ if (RP_SET(mPrimitiveFields.mPivotY, pivotY) || !mPrimitiveFields.mPivotExplicitlySet) {
mPrimitiveFields.mMatrixOrPivotDirty = true;
mPrimitiveFields.mPivotExplicitlySet = true;
return true;
@@ -387,13 +325,9 @@ public:
return false;
}
- float getPivotY() const {
- return mPrimitiveFields.mPivotY;
- }
+ float getPivotY() const { return mPrimitiveFields.mPivotY; }
- bool isPivotExplicitlySet() const {
- return mPrimitiveFields.mPivotExplicitlySet;
- }
+ bool isPivotExplicitlySet() const { return mPrimitiveFields.mPivotExplicitlySet; }
bool setCameraDistance(float distance) {
if (distance != getCameraDistance()) {
@@ -420,9 +354,7 @@ public:
return false;
}
- int getLeft() const {
- return mPrimitiveFields.mLeft;
- }
+ int getLeft() const { return mPrimitiveFields.mLeft; }
bool setTop(int top) {
if (RP_SET(mPrimitiveFields.mTop, top)) {
@@ -435,9 +367,7 @@ public:
return false;
}
- int getTop() const {
- return mPrimitiveFields.mTop;
- }
+ int getTop() const { return mPrimitiveFields.mTop; }
bool setRight(int right) {
if (RP_SET(mPrimitiveFields.mRight, right)) {
@@ -450,9 +380,7 @@ public:
return false;
}
- int getRight() const {
- return mPrimitiveFields.mRight;
- }
+ int getRight() const { return mPrimitiveFields.mRight; }
bool setBottom(int bottom) {
if (RP_SET(mPrimitiveFields.mBottom, bottom)) {
@@ -465,9 +393,7 @@ public:
return false;
}
- int getBottom() const {
- return mPrimitiveFields.mBottom;
- }
+ int getBottom() const { return mPrimitiveFields.mBottom; }
bool setLeftTop(int left, int top) {
bool leftResult = setLeft(left);
@@ -476,8 +402,8 @@ public:
}
bool setLeftTopRightBottom(int left, int top, int right, int bottom) {
- if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop
- || right != mPrimitiveFields.mRight || bottom != mPrimitiveFields.mBottom) {
+ if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop ||
+ right != mPrimitiveFields.mRight || bottom != mPrimitiveFields.mBottom) {
mPrimitiveFields.mLeft = left;
mPrimitiveFields.mTop = top;
mPrimitiveFields.mRight = right;
@@ -510,17 +436,11 @@ public:
return false;
}
- int getWidth() const {
- return mPrimitiveFields.mWidth;
- }
+ int getWidth() const { return mPrimitiveFields.mWidth; }
- int getHeight() const {
- return mPrimitiveFields.mHeight;
- }
+ int getHeight() const { return mPrimitiveFields.mHeight; }
- const SkMatrix* getAnimationMatrix() const {
- return mAnimationMatrix;
- }
+ const SkMatrix* getAnimationMatrix() const { return mAnimationMatrix; }
bool hasTransformMatrix() const {
return getTransformMatrix() && !getTransformMatrix()->isIdentity();
@@ -536,17 +456,11 @@ public:
return mComputedFields.mTransformMatrix;
}
- int getClippingFlags() const {
- return mPrimitiveFields.mClippingFlags;
- }
+ int getClippingFlags() const { return mPrimitiveFields.mClippingFlags; }
- bool getClipToBounds() const {
- return mPrimitiveFields.mClippingFlags & CLIP_TO_BOUNDS;
- }
+ bool getClipToBounds() const { return mPrimitiveFields.mClippingFlags & CLIP_TO_BOUNDS; }
- const Rect& getClipBounds() const {
- return mPrimitiveFields.mClipBounds;
- }
+ const Rect& getClipBounds() const { return mPrimitiveFields.mClipBounds; }
void getClippingRectForFlags(uint32_t flags, Rect* outRect) const {
if (flags & CLIP_TO_BOUNDS) {
@@ -559,41 +473,25 @@ public:
}
}
- bool getHasOverlappingRendering() const {
- return mPrimitiveFields.mHasOverlappingRendering;
- }
+ bool getHasOverlappingRendering() const { return mPrimitiveFields.mHasOverlappingRendering; }
- const Outline& getOutline() const {
- return mPrimitiveFields.mOutline;
- }
+ const Outline& getOutline() const { return mPrimitiveFields.mOutline; }
- const RevealClip& getRevealClip() const {
- return mPrimitiveFields.mRevealClip;
- }
+ const RevealClip& getRevealClip() const { return mPrimitiveFields.mRevealClip; }
- bool getProjectBackwards() const {
- return mPrimitiveFields.mProjectBackwards;
- }
+ bool getProjectBackwards() const { return mPrimitiveFields.mProjectBackwards; }
void debugOutputProperties(std::ostream& output, const int level) const;
void updateMatrix();
- Outline& mutableOutline() {
- return mPrimitiveFields.mOutline;
- }
+ Outline& mutableOutline() { return mPrimitiveFields.mOutline; }
- RevealClip& mutableRevealClip() {
- return mPrimitiveFields.mRevealClip;
- }
+ RevealClip& mutableRevealClip() { return mPrimitiveFields.mRevealClip; }
- const LayerProperties& layerProperties() const {
- return mLayerProperties;
- }
+ const LayerProperties& layerProperties() const { return mLayerProperties; }
- LayerProperties& mutateLayerProperties() {
- return mLayerProperties;
- }
+ LayerProperties& mutateLayerProperties() { return mLayerProperties; }
// Returns true if damage calculations should be clipped to bounds
// TODO: Figure out something better for getZ(), as children should still be
@@ -605,24 +503,29 @@ public:
}
bool hasShadow() const {
- return getZ() > 0.0f
- && getOutline().getPath() != nullptr
- && getOutline().getAlpha() != 0.0f;
+ return getZ() > 0.0f && getOutline().getPath() != nullptr &&
+ getOutline().getAlpha() != 0.0f;
+ }
+
+ SkColor getShadowColor() const {
+ return mPrimitiveFields.mShadowColor;
+ }
+
+ bool setShadowColor(SkColor shadowColor) {
+ return RP_SET(mPrimitiveFields.mShadowColor, shadowColor);
}
bool fitsOnLayer() const {
const DeviceInfo* deviceInfo = DeviceInfo::get();
- return mPrimitiveFields.mWidth <= deviceInfo->maxTextureSize()
- && mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize();
+ return mPrimitiveFields.mWidth <= deviceInfo->maxTextureSize() &&
+ mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize();
}
bool promotedToLayer() const {
- return mLayerProperties.mType == LayerType::None
- && fitsOnLayer()
- && (mComputedFields.mNeedLayerForFunctors
- || (!MathUtils::isZero(mPrimitiveFields.mAlpha)
- && mPrimitiveFields.mAlpha < 1
- && mPrimitiveFields.mHasOverlappingRendering));
+ return mLayerProperties.mType == LayerType::None && fitsOnLayer() &&
+ (mComputedFields.mNeedLayerForFunctors ||
+ (!MathUtils::isZero(mPrimitiveFields.mAlpha) && mPrimitiveFields.mAlpha < 1 &&
+ mPrimitiveFields.mHasOverlappingRendering));
}
LayerType effectiveLayerType() const {
@@ -635,6 +538,7 @@ private:
int mLeft = 0, mTop = 0, mRight = 0, mBottom = 0;
int mWidth = 0, mHeight = 0;
int mClippingFlags = CLIP_TO_BOUNDS;
+ SkColor mShadowColor = SK_ColorBLACK;
float mAlpha = 1;
float mTranslationX = 0, mTranslationY = 0, mTranslationZ = 0;
float mElevation = 0;
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index b26e433cfa4c..d60b99469368 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -32,10 +32,10 @@ void ResourceCache::logCache() {
ALOGD("ResourceCache: cacheReport:");
for (size_t i = 0; i < mCache->size(); ++i) {
ResourceReference* ref = mCache->valueAt(i);
- ALOGD(" ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p",
- i, mCache->keyAt(i), mCache->valueAt(i));
- ALOGD(" ResourceCache: mCache(%zu): refCount, destroyed, type = %d, %d, %d",
- i, ref->refCount, ref->destroyed, ref->resourceType);
+ ALOGD(" ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p", i, mCache->keyAt(i),
+ mCache->valueAt(i));
+ ALOGD(" ResourceCache: mCache(%zu): refCount, destroyed, type = %d, %d, %d", i,
+ ref->refCount, ref->destroyed, ref->resourceType);
}
}
@@ -63,7 +63,7 @@ void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType)
}
void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) {
- incrementRefcount((void*) patchResource, kNinePatch);
+ incrementRefcount((void*)patchResource, kNinePatch);
}
void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) {
@@ -82,7 +82,7 @@ void ResourceCache::decrementRefcount(void* resource) {
}
void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) {
- decrementRefcount((void*) patchResource);
+ decrementRefcount((void*)patchResource);
}
void ResourceCache::decrementRefcountLocked(void* resource) {
@@ -99,7 +99,7 @@ void ResourceCache::decrementRefcountLocked(void* resource) {
}
void ResourceCache::decrementRefcountLocked(const Res_png_9patch* patchResource) {
- decrementRefcountLocked((void*) patchResource);
+ decrementRefcountLocked((void*)patchResource);
}
void ResourceCache::destructor(Res_png_9patch* resource) {
@@ -117,7 +117,7 @@ void ResourceCache::destructorLocked(Res_png_9patch* resource) {
} else {
// A Res_png_9patch is actually an array of byte that's larger
// than sizeof(Res_png_9patch). It must be freed as an array.
- delete[] (int8_t*) resource;
+ delete[](int8_t*) resource;
}
return;
}
@@ -136,20 +136,19 @@ void ResourceCache::deleteResourceReferenceLocked(const void* resource, Resource
switch (ref->resourceType) {
case kNinePatch: {
if (Caches::hasInstance()) {
- Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource);
+ Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*)resource);
} else {
// A Res_png_9patch is actually an array of byte that's larger
// than sizeof(Res_png_9patch). It must be freed as an array.
- int8_t* patch = (int8_t*) resource;
+ int8_t* patch = (int8_t*)resource;
delete[] patch;
}
- }
- break;
+ } break;
}
}
mCache->removeItem(resource);
delete ref;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index 3ac78642c7ee..fd3f9fd05d58 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -41,9 +41,10 @@ enum ResourceType {
class ResourceReference {
public:
-
explicit ResourceReference(ResourceType type) {
- refCount = 0; destroyed = false; resourceType = type;
+ refCount = 0;
+ destroyed = false;
+ resourceType = type;
}
int refCount;
@@ -51,14 +52,13 @@ public:
ResourceType resourceType;
};
-class ANDROID_API ResourceCache: public Singleton<ResourceCache> {
+class ANDROID_API ResourceCache : public Singleton<ResourceCache> {
ResourceCache();
~ResourceCache();
friend class Singleton<ResourceCache>;
public:
-
/**
* When using these two methods, make sure to only invoke the *Locked()
* variants of increment/decrementRefcount(), recyle() and destructor()
@@ -97,7 +97,7 @@ private:
KeyedVector<const void*, ResourceReference*>* mCache;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_RESOURCE_CACHE_H
+#endif // ANDROID_HWUI_RESOURCE_CACHE_H
diff --git a/libs/hwui/RevealClip.h b/libs/hwui/RevealClip.h
index 63821dddd369..a5678d48482a 100644
--- a/libs/hwui/RevealClip.h
+++ b/libs/hwui/RevealClip.h
@@ -25,11 +25,7 @@ namespace uirenderer {
class RevealClip {
public:
- RevealClip()
- : mShouldClip(false)
- , mX(0)
- , mY(0)
- , mRadius(0) {}
+ RevealClip() : mShouldClip(false), mX(0), mY(0), mRadius(0) {}
void set(bool shouldClip, float x, float y, float radius) {
mShouldClip = shouldClip;
@@ -43,13 +39,10 @@ public:
}
}
- bool willClip() const {
- return mShouldClip;
- }
+ bool willClip() const { return mShouldClip; }
void getBounds(Rect* outBounds) const {
- outBounds->set(mX - mRadius, mY - mRadius,
- mX + mRadius, mY + mRadius);
+ outBounds->set(mX - mRadius, mY - mRadius, mX + mRadius, mY + mRadius);
}
float getRadius() const { return mRadius; }
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index e94a70a9f80d..d0155ee473f7 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -16,8 +16,8 @@
#include <math.h>
#include <utils/Log.h>
-#include <utils/Trace.h>
#include <utils/MathUtils.h>
+#include <utils/Trace.h>
#include "AmbientShadow.h"
#include "Properties.h"
@@ -28,10 +28,10 @@
namespace android {
namespace uirenderer {
-void ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque,
- const Vector3* casterPolygon, int casterVertexCount,
- const Vector3& centroid3d, const Rect& casterBounds,
- const Rect& localClip, float maxZ, VertexBuffer& shadowVertexBuffer) {
+void ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque, const Vector3* casterPolygon,
+ int casterVertexCount, const Vector3& centroid3d,
+ const Rect& casterBounds, const Rect& localClip,
+ float maxZ, VertexBuffer& shadowVertexBuffer) {
ATRACE_CALL();
// A bunch of parameters to tweak the shadow.
@@ -53,32 +53,32 @@ void ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque,
return;
}
- AmbientShadow::createAmbientShadow(isCasterOpaque, casterPolygon,
- casterVertexCount, centroid3d, heightFactor, geomFactor,
- shadowVertexBuffer);
+ AmbientShadow::createAmbientShadow(isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
+ heightFactor, geomFactor, shadowVertexBuffer);
}
-void ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
- const Vector3* casterPolygon, int casterVertexCount, const Vector3& casterCentroid,
- const mat4& receiverTransform, const Vector3& lightCenter, int lightRadius,
- const Rect& casterBounds, const Rect& localClip, VertexBuffer& shadowVertexBuffer) {
+void ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque, const Vector3* casterPolygon,
+ int casterVertexCount, const Vector3& casterCentroid,
+ const mat4& receiverTransform,
+ const Vector3& lightCenter, int lightRadius,
+ const Rect& casterBounds, const Rect& localClip,
+ VertexBuffer& shadowVertexBuffer) {
ATRACE_CALL();
Vector3 adjustedLightCenter(lightCenter);
if (CC_UNLIKELY(Properties::overrideLightPosY > 0)) {
- adjustedLightCenter.y = - Properties::overrideLightPosY; // negated since this shifts up
+ adjustedLightCenter.y = -Properties::overrideLightPosY; // negated since this shifts up
}
if (CC_UNLIKELY(Properties::overrideLightPosZ > 0)) {
adjustedLightCenter.z = Properties::overrideLightPosZ;
}
#if DEBUG_SHADOW
- ALOGD("light center %f %f %f %d",
- adjustedLightCenter.x, adjustedLightCenter.y, adjustedLightCenter.z, lightRadius);
+ ALOGD("light center %f %f %f %d", adjustedLightCenter.x, adjustedLightCenter.y,
+ adjustedLightCenter.z, lightRadius);
#endif
- if (isnan(adjustedLightCenter.x)
- || isnan(adjustedLightCenter.y)
- || isnan(adjustedLightCenter.z)) {
+ if (isnan(adjustedLightCenter.x) || isnan(adjustedLightCenter.y) ||
+ isnan(adjustedLightCenter.z)) {
return;
}
@@ -95,7 +95,7 @@ void ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
// Now light and caster are both in local space, we will check whether
// the shadow is within the clip area.
Rect lightRect = Rect(adjustedLightCenter.x - lightRadius, adjustedLightCenter.y - lightRadius,
- adjustedLightCenter.x + lightRadius, adjustedLightCenter.y + lightRadius);
+ adjustedLightCenter.x + lightRadius, adjustedLightCenter.y + lightRadius);
lightRect.unionWith(localClip);
if (!lightRect.intersects(casterBounds)) {
#if DEBUG_SHADOW
@@ -104,13 +104,13 @@ void ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
return;
}
- SpotShadow::createSpotShadow(isCasterOpaque, adjustedLightCenter, lightRadius,
- casterPolygon, casterVertexCount, casterCentroid, shadowVertexBuffer);
+ SpotShadow::createSpotShadow(isCasterOpaque, adjustedLightCenter, lightRadius, casterPolygon,
+ casterVertexCount, casterCentroid, shadowVertexBuffer);
#if DEBUG_SHADOW
- if(shadowVertexBuffer.getVertexCount() <= 0) {
+ if (shadowVertexBuffer.getVertexCount() <= 0) {
ALOGD("Spot shadow generation failed %d", shadowVertexBuffer.getVertexCount());
- }
+ }
#endif
}
@@ -141,7 +141,7 @@ Vector2 ShadowTessellator::centroid2d(const Vector2* poly, int polyLength) {
Vector2 centroid = poly[0];
if (area != 0) {
centroid = (Vector2){static_cast<float>(sumx / (3 * area)),
- static_cast<float>(sumy / (3 * area))};
+ static_cast<float>(sumy / (3 * area))};
} else {
ALOGW("Area is 0 while computing centroid!");
}
@@ -161,8 +161,8 @@ Vector2 ShadowTessellator::calculateNormal(const Vector2& p1, const Vector2& p2)
return result;
}
-int ShadowTessellator::getExtraVertexNumber(const Vector2& vector1,
- const Vector2& vector2, float divisor) {
+int ShadowTessellator::getExtraVertexNumber(const Vector2& vector1, const Vector2& vector2,
+ float divisor) {
// When there is no distance difference, there is no need for extra vertices.
if (vector1.lengthSquared() == 0 || vector2.lengthSquared() == 0) {
return 0;
@@ -179,13 +179,13 @@ int ShadowTessellator::getExtraVertexNumber(const Vector2& vector1,
// TODO: Use look up table for the dotProduct to extraVerticesNumber
// computation, if needed.
float angle = acosf(dotProduct);
- return (int) floor(angle / divisor);
+ return (int)floor(angle / divisor);
}
void ShadowTessellator::checkOverflow(int used, int total, const char* bufferName) {
- LOG_ALWAYS_FATAL_IF(used > total, "Error: %s overflow!!! used %d, total %d",
- bufferName, used, total);
+ LOG_ALWAYS_FATAL_IF(used > total, "Error: %s overflow!!! used %d, total %d", bufferName, used,
+ total);
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index 2eaf187a1af1..79f46f9e9a06 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -68,27 +68,27 @@ class VertexBuffer;
class ShadowTessellator {
public:
- static void tessellateAmbientShadow(bool isCasterOpaque,
- const Vector3* casterPolygon, int casterVertexCount,
- const Vector3& centroid3d, const Rect& casterBounds,
- const Rect& localClip, float maxZ, VertexBuffer& shadowVertexBuffer);
+ static void tessellateAmbientShadow(bool isCasterOpaque, const Vector3* casterPolygon,
+ int casterVertexCount, const Vector3& centroid3d,
+ const Rect& casterBounds, const Rect& localClip, float maxZ,
+ VertexBuffer& shadowVertexBuffer);
- static void tessellateSpotShadow(bool isCasterOpaque,
- const Vector3* casterPolygon, int casterVertexCount, const Vector3& casterCentroid,
- const mat4& receiverTransform, const Vector3& lightCenter, int lightRadius,
- const Rect& casterBounds, const Rect& localClip, VertexBuffer& shadowVertexBuffer);
+ static void tessellateSpotShadow(bool isCasterOpaque, const Vector3* casterPolygon,
+ int casterVertexCount, const Vector3& casterCentroid,
+ const mat4& receiverTransform, const Vector3& lightCenter,
+ int lightRadius, const Rect& casterBounds,
+ const Rect& localClip, VertexBuffer& shadowVertexBuffer);
static Vector2 centroid2d(const Vector2* poly, int polyLength);
static Vector2 calculateNormal(const Vector2& p1, const Vector2& p2);
- static int getExtraVertexNumber(const Vector2& vector1, const Vector2& vector2,
- float divisor);
+ static int getExtraVertexNumber(const Vector2& vector1, const Vector2& vector2, float divisor);
static void checkOverflow(int used, int total, const char* bufferName);
-}; // ShadowTessellator
+}; // ShadowTessellator
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_SHADOW_TESSELLATOR_H
+#endif // ANDROID_HWUI_SHADOW_TESSELLATOR_H
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 1f5f733188de..508869a0cbdd 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -26,9 +26,9 @@
#include <SkCanvasStateUtils.h>
#include <SkColorFilter.h>
#include <SkColorSpaceXformCanvas.h>
-#include <SkDrawable.h>
#include <SkDeque.h>
#include <SkDrawFilter.h>
+#include <SkDrawable.h>
#include <SkGraphics.h>
#include <SkImage.h>
#include <SkImagePriv.h>
@@ -60,8 +60,9 @@ SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) {
mCanvasOwned =
std::unique_ptr<SkCanvas>(new SkCanvas(bitmap, SkCanvas::ColorBehavior::kLegacy));
if (cs.get() == nullptr || cs->isSRGB()) {
- if(!uirenderer::Properties::isSkiaEnabled()) {
- mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), SkColorSpace::MakeSRGB());
+ if (!uirenderer::Properties::isSkiaEnabled()) {
+ mCanvasWrapper =
+ SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), SkColorSpace::MakeSRGB());
mCanvas = mCanvasWrapper.get();
} else {
mCanvas = mCanvasOwned.get();
@@ -98,8 +99,7 @@ void SkiaCanvas::setBitmap(const SkBitmap& bitmap) {
std::unique_ptr<SkCanvas> newCanvasWrapper;
if (cs.get() != nullptr && !cs->isSRGB()) {
newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), std::move(cs));
- }
- else if(!uirenderer::Properties::isSkiaEnabled()) {
+ } else if (!uirenderer::Properties::isSkiaEnabled()) {
newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), SkColorSpace::MakeSRGB());
}
@@ -155,7 +155,7 @@ void SkiaCanvas::restore() {
}
bool preserveMatrix = !(rec->saveFlags & SaveFlags::Matrix);
- bool preserveClip = !(rec->saveFlags & SaveFlags::Clip);
+ bool preserveClip = !(rec->saveFlags & SaveFlags::Clip);
SkMatrix savedMatrix;
if (preserveMatrix) {
@@ -197,16 +197,16 @@ static inline SkCanvas::SaveLayerFlags layerFlags(SaveFlags::Flags flags) {
return layerFlags;
}
-int SkiaCanvas::saveLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, SaveFlags::Flags flags) {
+int SkiaCanvas::saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
+ SaveFlags::Flags flags) {
const SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
const SkCanvas::SaveLayerRec rec(&bounds, paint, layerFlags(flags));
return mCanvas->saveLayer(rec);
}
-int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom,
- int alpha, SaveFlags::Flags flags) {
+int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
+ SaveFlags::Flags flags) {
if (static_cast<unsigned>(alpha) < 0xFF) {
SkPaint alphaPaint;
alphaPaint.setAlpha(alpha);
@@ -218,24 +218,24 @@ int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom,
class SkiaCanvas::Clip {
public:
Clip(const SkRect& rect, SkClipOp op, const SkMatrix& m)
- : mType(Type::Rect), mOp(op), mMatrix(m), mRRect(SkRRect::MakeRect(rect)) {}
+ : mType(Type::Rect), mOp(op), mMatrix(m), mRRect(SkRRect::MakeRect(rect)) {}
Clip(const SkRRect& rrect, SkClipOp op, const SkMatrix& m)
- : mType(Type::RRect), mOp(op), mMatrix(m), mRRect(rrect) {}
+ : mType(Type::RRect), mOp(op), mMatrix(m), mRRect(rrect) {}
Clip(const SkPath& path, SkClipOp op, const SkMatrix& m)
- : mType(Type::Path), mOp(op), mMatrix(m), mPath(&path) {}
+ : mType(Type::Path), mOp(op), mMatrix(m), mPath(&path) {}
void apply(SkCanvas* canvas) const {
canvas->setMatrix(mMatrix);
switch (mType) {
- case Type::Rect:
- canvas->clipRect(mRRect.rect(), mOp);
- break;
- case Type::RRect:
- canvas->clipRRect(mRRect, mOp);
- break;
- case Type::Path:
- canvas->clipPath(*mPath.get(), mOp);
- break;
+ case Type::Rect:
+ canvas->clipRect(mRRect.rect(), mOp);
+ break;
+ case Type::RRect:
+ canvas->clipRRect(mRRect, mOp);
+ break;
+ case Type::Path:
+ canvas->clipPath(*mPath.get(), mOp);
+ break;
}
}
@@ -246,19 +246,17 @@ private:
Path,
};
- Type mType;
- SkClipOp mOp;
- SkMatrix mMatrix;
+ Type mType;
+ SkClipOp mOp;
+ SkMatrix mMatrix;
// These are logically a union (tracked separately due to non-POD path).
SkTLazy<SkPath> mPath;
- SkRRect mRRect;
+ SkRRect mRRect;
};
const SkiaCanvas::SaveRec* SkiaCanvas::currentSaveRec() const {
- const SaveRec* rec = mSaveStack
- ? static_cast<const SaveRec*>(mSaveStack->back())
- : nullptr;
+ const SaveRec* rec = mSaveStack ? static_cast<const SaveRec*>(mSaveStack->back()) : nullptr;
int currentSaveCount = mCanvas->getSaveCount();
SkASSERT(!rec || currentSaveCount >= rec->saveCount);
@@ -436,10 +434,9 @@ SkCanvasState* SkiaCanvas::captureCanvasState() const {
// translate & scale transforms, and a simple rectangular clip.
// (This also avoids significant wasted time in calling
// SkCanvasStateUtils::CaptureCanvasState when the clip is complex).
- if (!canvas->isClipRect() ||
- (canvas->getTotalMatrix().getType() &
- ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask))) {
- return nullptr;
+ if (!canvas->isClipRect() || (canvas->getTotalMatrix().getType() &
+ ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask))) {
+ return nullptr;
}
return SkCanvasStateUtils::CaptureCanvasState(canvas);
@@ -465,7 +462,7 @@ void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint
SkCanvas::PointMode mode) {
if (CC_UNLIKELY(count < 2 || paint.nothingToDraw())) return;
// convert the floats into SkPoints
- count >>= 1; // now it is the number of points
+ count >>= 1; // now it is the number of points
std::unique_ptr<SkPoint[]> pts(new SkPoint[count]);
for (int i = 0; i < count; i++) {
pts[i].set(points[0], points[1]);
@@ -474,7 +471,6 @@ void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint
mCanvas->drawPoints(mode, count, pts.get(), paint);
}
-
void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) {
mCanvas->drawPoint(x, y, paint);
}
@@ -493,11 +489,9 @@ void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint)
this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode);
}
-void SkiaCanvas::drawRect(float left, float top, float right, float bottom,
- const SkPaint& paint) {
+void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
mCanvas->drawRect({left, top, right, bottom}, paint);
-
}
void SkiaCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
@@ -505,8 +499,8 @@ void SkiaCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
mCanvas->drawRegion(region, paint);
}
-void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom,
- float rx, float ry, const SkPaint& paint) {
+void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
+ const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
mCanvas->drawRoundRect(rect, rx, ry, paint);
@@ -523,11 +517,15 @@ void SkiaCanvas::drawOval(float left, float top, float right, float bottom, cons
mCanvas->drawOval(oval, paint);
}
-void SkiaCanvas::drawArc(float left, float top, float right, float bottom,
- float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
+void SkiaCanvas::drawArc(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle, bool useCenter, const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
- mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint);
+ if (fabs(sweepAngle) >= 360.0f) {
+ mCanvas->drawOval(arc, paint);
+ } else {
+ mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint);
+ }
}
void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
@@ -547,7 +545,7 @@ void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, cons
// ----------------------------------------------------------------------------
const SkPaint* SkiaCanvas::addFilter(const SkPaint* origPaint, SkPaint* tmpPaint,
- sk_sp<SkColorFilter> colorSpaceFilter) {
+ sk_sp<SkColorFilter> colorSpaceFilter) {
/* We don't apply the colorSpace filter if this canvas is already wrapped with
* a SkColorSpaceXformCanvas since it already takes care of converting the
* contents of the bitmap into the appropriate colorspace. The mCanvasWrapper
@@ -560,8 +558,8 @@ const SkPaint* SkiaCanvas::addFilter(const SkPaint* origPaint, SkPaint* tmpPaint
}
if (tmpPaint->getColorFilter()) {
- tmpPaint->setColorFilter(SkColorFilter::MakeComposeFilter(
- tmpPaint->refColorFilter(), colorSpaceFilter));
+ tmpPaint->setColorFilter(
+ SkColorFilter::MakeComposeFilter(tmpPaint->refColorFilter(), colorSpaceFilter));
LOG_ALWAYS_FATAL_IF(!tmpPaint->getColorFilter());
} else {
tmpPaint->setColorFilter(colorSpaceFilter);
@@ -590,9 +588,9 @@ void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPain
mCanvas->drawImage(image, 0, 0, addFilter(paint, &tmpPaint, colorFilter));
}
-void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
- float srcRight, float srcBottom, float dstLeft, float dstTop,
- float dstRight, float dstBottom, const SkPaint* paint) {
+void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
+ float srcBottom, float dstLeft, float dstTop, float dstRight,
+ float dstBottom, const SkPaint* paint) {
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
@@ -600,11 +598,11 @@ void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
sk_sp<SkColorFilter> colorFilter;
sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
mCanvas->drawImageRect(image, srcRect, dstRect, addFilter(paint, &tmpPaint, colorFilter),
- SkCanvas::kFast_SrcRectConstraint);
+ SkCanvas::kFast_SrcRectConstraint);
}
void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
- const float* vertices, const int* colors, const SkPaint* paint) {
+ const float* vertices, const int* colors, const SkPaint* paint) {
const int ptCount = (meshWidth + 1) * (meshHeight + 1);
const int indexCount = meshWidth * meshHeight * 6;
uint32_t flags = SkVertices::kHasTexCoords_BuilderFlag;
@@ -668,7 +666,7 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
SkASSERT(indexPtr - indices == indexCount);
}
- // double-check that we have legal indices
+// double-check that we have legal indices
#ifdef SK_DEBUG
{
for (int i = 0; i < indexCount; i++) {
@@ -685,8 +683,9 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
sk_sp<SkColorFilter> colorFilter;
sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
- sk_sp<SkShader> shader = image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
- if(colorFilter) {
+ sk_sp<SkShader> shader =
+ image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ if (colorFilter) {
shader = shader->makeWithColorFilter(colorFilter);
}
tmpPaint.setShader(shader);
@@ -694,9 +693,9 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate, tmpPaint);
}
-void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk,
- float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
-
+void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft,
+ float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) {
SkCanvas::Lattice lattice;
NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
@@ -731,8 +730,8 @@ void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
// ----------------------------------------------------------------------------
void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x,
- float y, float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
- float totalAdvance) {
+ float y, float boundsLeft, float boundsTop, float boundsRight,
+ float boundsBottom, float totalAdvance) {
if (count <= 0 || paint.nothingToDraw()) return;
// Set align to left for drawing, as we don't want individual
// glyphs centered or right-aligned; the offset above takes
@@ -740,8 +739,8 @@ void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& p
SkPaint paintCopy(paint);
paintCopy.setTextAlign(SkPaint::kLeft_Align);
- SkRect bounds = SkRect::MakeLTRB(boundsLeft + x, boundsTop + y,
- boundsRight + x, boundsBottom + y);
+ SkRect bounds =
+ SkRect::MakeLTRB(boundsLeft + x, boundsTop + y, boundsRight + x, boundsBottom + y);
SkTextBlobBuilder builder;
const SkTextBlobBuilder::RunBuffer& buffer = builder.allocRunPos(paintCopy, count, &bounds);
@@ -753,7 +752,8 @@ void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& p
}
void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
- const SkPaint& paint, const SkPath& path, size_t start, size_t end) {
+ const SkPaint& paint, const SkPath& path, size_t start,
+ size_t end) {
const int N = end - start;
SkAutoSTMalloc<1024, uint8_t> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform)));
SkRSXform* xform = (SkRSXform*)storage.get();
@@ -773,8 +773,8 @@ void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset,
}
xform[i - start].fSCos = tan.x();
xform[i - start].fSSin = tan.y();
- xform[i - start].fTx = pos.x() - tan.y() * y;
- xform[i - start].fTy = pos.y() + tan.x() * y;
+ xform[i - start].fTx = pos.x() - tan.y() * y;
+ xform[i - start].fTy = pos.y() + tan.x() * y;
}
this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paint);
@@ -785,17 +785,24 @@ void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset,
// ----------------------------------------------------------------------------
void SkiaCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
- uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
- uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
- uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) {
+ uirenderer::CanvasPropertyPrimitive* top,
+ uirenderer::CanvasPropertyPrimitive* right,
+ uirenderer::CanvasPropertyPrimitive* bottom,
+ uirenderer::CanvasPropertyPrimitive* rx,
+ uirenderer::CanvasPropertyPrimitive* ry,
+ uirenderer::CanvasPropertyPaint* paint) {
sk_sp<uirenderer::skiapipeline::AnimatedRoundRect> drawable(
- new uirenderer::skiapipeline::AnimatedRoundRect(left, top, right, bottom, rx, ry, paint));
+ new uirenderer::skiapipeline::AnimatedRoundRect(left, top, right, bottom, rx, ry,
+ paint));
mCanvas->drawDrawable(drawable.get());
}
-void SkiaCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y,
- uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint) {
- sk_sp<uirenderer::skiapipeline::AnimatedCircle> drawable(new uirenderer::skiapipeline::AnimatedCircle(x, y, radius, paint));
+void SkiaCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x,
+ uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint) {
+ sk_sp<uirenderer::skiapipeline::AnimatedCircle> drawable(
+ new uirenderer::skiapipeline::AnimatedCircle(x, y, radius, paint));
mCanvas->drawDrawable(drawable.get());
}
@@ -812,8 +819,8 @@ void SkiaCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
}
void SkiaCanvas::callDrawGLFunction(Functor* functor,
- uirenderer::GlFunctorLifecycleListener* listener) {
+ uirenderer::GlFunctorLifecycleListener* listener) {
LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw GL Content");
}
-} // namespace android
+} // namespace android
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index e17f835031bb..99e676a6fb1e 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -15,11 +15,11 @@
*/
#pragma once
-#include "hwui/Canvas.h"
#include "CanvasProperty.h"
#include "DeferredLayerUpdater.h"
#include "RenderNode.h"
#include "VectorDrawable.h"
+#include "hwui/Canvas.h"
#include <SkCanvas.h>
#include <SkTLazy.h>
@@ -42,12 +42,10 @@ public:
virtual ~SkiaCanvas();
- virtual SkCanvas* asSkCanvas() override {
- return mCanvas;
- }
+ virtual SkCanvas* asSkCanvas() override { return mCanvas; }
virtual void resetRecording(int width, int height,
- uirenderer::RenderNode* renderNode) override {
+ uirenderer::RenderNode* renderNode) override {
LOG_ALWAYS_FATAL("SkiaCanvas cannot be reset as a recording canvas");
}
@@ -70,10 +68,10 @@ public:
virtual void restore() override;
virtual void restoreToCount(int saveCount) override;
- virtual int saveLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, SaveFlags::Flags flags) override;
- virtual int saveLayerAlpha(float left, float top, float right, float bottom,
- int alpha, SaveFlags::Flags flags) override;
+ virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
+ SaveFlags::Flags flags) override;
+ virtual int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
+ SaveFlags::Flags flags) override;
virtual void getMatrix(SkMatrix* outMatrix) const override;
virtual void setMatrix(const SkMatrix& matrix) override;
@@ -86,8 +84,7 @@ public:
virtual bool getClipBounds(SkRect* outRect) const override;
virtual bool quickRejectRect(float left, float top, float right, float bottom) const override;
virtual bool quickRejectPath(const SkPath& path) const override;
- virtual bool clipRect(float left, float top, float right, float bottom,
- SkClipOp op) override;
+ virtual bool clipRect(float left, float top, float right, float bottom, SkClipOp op) override;
virtual bool clipPath(const SkPath* path, SkClipOp op) override;
virtual SkDrawFilter* getDrawFilter() override;
@@ -101,47 +98,52 @@ public:
virtual void drawPoint(float x, float y, const SkPaint& paint) override;
virtual void drawPoints(const float* points, int count, const SkPaint& paint) override;
virtual void drawLine(float startX, float startY, float stopX, float stopY,
- const SkPaint& paint) override;
+ const SkPaint& paint) override;
virtual void drawLines(const float* points, int count, const SkPaint& paint) override;
virtual void drawRect(float left, float top, float right, float bottom,
- const SkPaint& paint) override;
+ const SkPaint& paint) override;
virtual void drawRegion(const SkRegion& region, const SkPaint& paint) override;
- virtual void drawRoundRect(float left, float top, float right, float bottom,
- float rx, float ry, const SkPaint& paint) override;
+ virtual void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
+ const SkPaint& paint) override;
virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override;
virtual void drawOval(float left, float top, float right, float bottom,
- const SkPaint& paint) override;
- virtual void drawArc(float left, float top, float right, float bottom,
- float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) override;
+ const SkPaint& paint) override;
+ virtual void drawArc(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle, bool useCenter, const SkPaint& paint) override;
virtual void drawPath(const SkPath& path, const SkPaint& paint) override;
virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint) override;
virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) override;
virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) override;
- virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
- float srcRight, float srcBottom, float dstLeft, float dstTop,
- float dstRight, float dstBottom, const SkPaint* paint) override;
+ virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
+ float srcBottom, float dstLeft, float dstTop, float dstRight,
+ float dstBottom, const SkPaint* paint) override;
virtual void drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
- const float* vertices, const int* colors, const SkPaint* paint) override;
- virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk,
- float dstLeft, float dstTop, float dstRight, float dstBottom,
- const SkPaint* paint) override;
+ const float* vertices, const int* colors,
+ const SkPaint* paint) override;
+ virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
+ float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) override;
- virtual bool drawTextAbsolutePos() const override { return true; }
+ virtual bool drawTextAbsolutePos() const override { return true; }
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
- uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
- uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
- uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) override;
+ uirenderer::CanvasPropertyPrimitive* top,
+ uirenderer::CanvasPropertyPrimitive* right,
+ uirenderer::CanvasPropertyPrimitive* bottom,
+ uirenderer::CanvasPropertyPrimitive* rx,
+ uirenderer::CanvasPropertyPrimitive* ry,
+ uirenderer::CanvasPropertyPaint* paint) override;
virtual void drawCircle(uirenderer::CanvasPropertyPrimitive* x,
- uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius,
- uirenderer::CanvasPropertyPaint* paint) override;
+ uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint) override;
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override;
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;
virtual void callDrawGLFunction(Functor* functor,
- uirenderer::GlFunctorLifecycleListener* listener) override;
+ uirenderer::GlFunctorLifecycleListener* listener) override;
protected:
SkiaCanvas();
@@ -149,40 +151,39 @@ protected:
void drawDrawable(SkDrawable* drawable) { mCanvas->drawDrawable(drawable); }
virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x,
- float y, float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
- float totalAdvance) override;
+ float y, float boundsLeft, float boundsTop, float boundsRight,
+ float boundsBottom, float totalAdvance) override;
virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
- const SkPaint& paint, const SkPath& path, size_t start, size_t end) override;
+ const SkPaint& paint, const SkPath& path, size_t start,
+ size_t end) override;
private:
struct SaveRec {
- int saveCount;
+ int saveCount;
SaveFlags::Flags saveFlags;
- size_t clipIndex;
+ size_t clipIndex;
};
const SaveRec* currentSaveRec() const;
void recordPartialSave(SaveFlags::Flags flags);
- template<typename T>
+ template <typename T>
void recordClip(const T&, SkClipOp);
void applyPersistentClips(size_t clipStartIndex);
- void drawPoints(const float* points, int count, const SkPaint& paint,
- SkCanvas::PointMode mode);
+ void drawPoints(const float* points, int count, const SkPaint& paint, SkCanvas::PointMode mode);
const SkPaint* addFilter(const SkPaint* origPaint, SkPaint* tmpPaint,
- sk_sp<SkColorFilter> colorSpaceFilter);
+ sk_sp<SkColorFilter> colorSpaceFilter);
class Clip;
- std::unique_ptr<SkCanvas> mCanvasWrapper; // might own a wrapper on the canvas
- std::unique_ptr<SkCanvas> mCanvasOwned; // might own a canvas we allocated
- SkCanvas* mCanvas; // we do NOT own this canvas, it must survive us
- // unless it is the same as mCanvasOwned.get()
- std::unique_ptr<SkDeque> mSaveStack; // lazily allocated, tracks partial saves.
- std::vector<Clip> mClipStack; // tracks persistent clips.
+ std::unique_ptr<SkCanvas> mCanvasWrapper; // might own a wrapper on the canvas
+ std::unique_ptr<SkCanvas> mCanvasOwned; // might own a canvas we allocated
+ SkCanvas* mCanvas; // we do NOT own this canvas, it must survive us
+ // unless it is the same as mCanvasOwned.get()
+ std::unique_ptr<SkDeque> mSaveStack; // lazily allocated, tracks partial saves.
+ std::vector<Clip> mClipStack; // tracks persistent clips.
};
-} // namespace android
-
+} // namespace android
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index ddddefac74b9..06e2d6c00ef5 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -20,18 +20,18 @@
#include <log/log.h>
-#include "hwui/Bitmap.h"
#include <SkLatticeIter.h>
-#include <SkPatchUtils.h>
#include <SkPaint.h>
+#include <SkPatchUtils.h>
#include <SkPath.h>
#include <SkPixelRef.h>
-#include <SkRect.h>
#include <SkRRect.h>
#include <SkRSXform.h>
+#include <SkRect.h>
#include <SkSurface.h>
#include <SkTextBlobRunIterator.h>
#include <SkVertices.h>
+#include "hwui/Bitmap.h"
namespace android {
namespace uirenderer {
@@ -46,13 +46,13 @@ void SkiaCanvasProxy::onDrawPaint(const SkPaint& paint) {
}
void SkiaCanvasProxy::onDrawPoints(PointMode pointMode, size_t count, const SkPoint pts[],
- const SkPaint& paint) {
+ const SkPaint& paint) {
if (!pts || count == 0) {
return;
}
// convert the SkPoints into floats
- static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
+ static_assert(sizeof(SkPoint) == sizeof(float) * 2, "SkPoint is no longer two floats");
const size_t floatCount = count << 1;
const float* floatArray = &pts[0].fX;
@@ -72,7 +72,7 @@ void SkiaCanvasProxy::onDrawPoints(PointMode pointMode, size_t count, const SkPo
SkPath path;
for (size_t i = 0; i < count - 1; i++) {
path.moveTo(pts[i]);
- path.lineTo(pts[i+1]);
+ path.lineTo(pts[i + 1]);
this->drawPath(path, strokedPaint);
path.rewind();
}
@@ -95,8 +95,8 @@ void SkiaCanvasProxy::onDrawRRect(const SkRRect& roundRect, const SkPaint& paint
if (!roundRect.isComplex()) {
const SkRect& rect = roundRect.rect();
SkVector radii = roundRect.getSimpleRadii();
- mCanvas->drawRoundRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- radii.fX, radii.fY, paint);
+ mCanvas->drawRoundRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, radii.fX, radii.fY,
+ paint);
} else {
SkPath path;
path.addRRect(roundRect);
@@ -106,8 +106,8 @@ void SkiaCanvasProxy::onDrawRRect(const SkRRect& roundRect, const SkPaint& paint
void SkiaCanvasProxy::onDrawArc(const SkRect& rect, SkScalar startAngle, SkScalar sweepAngle,
bool useCenter, const SkPaint& paint) {
- mCanvas->drawArc(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- startAngle, sweepAngle, useCenter, paint);
+ mCanvas->drawArc(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, startAngle, sweepAngle,
+ useCenter, paint);
}
void SkiaCanvasProxy::onDrawPath(const SkPath& path, const SkPaint& paint) {
@@ -115,41 +115,38 @@ void SkiaCanvasProxy::onDrawPath(const SkPath& path, const SkPaint& paint) {
}
void SkiaCanvasProxy::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
- const SkPaint* paint) {
+ const SkPaint* paint) {
sk_sp<Bitmap> hwuiBitmap = Bitmap::createFrom(bitmap.info(), *bitmap.pixelRef());
// HWUI doesn't support extractSubset(), so convert any subsetted bitmap into
// a drawBitmapRect(); pass through an un-subsetted bitmap.
if (hwuiBitmap && bitmap.dimensions() != hwuiBitmap->info().dimensions()) {
SkIPoint origin = bitmap.pixelRefOrigin();
- mCanvas->drawBitmap(*hwuiBitmap, origin.fX, origin.fY,
- origin.fX + bitmap.dimensions().width(),
- origin.fY + bitmap.dimensions().height(),
- left, top,
- left + bitmap.dimensions().width(),
- top + bitmap.dimensions().height(),
- paint);
+ mCanvas->drawBitmap(
+ *hwuiBitmap, origin.fX, origin.fY, origin.fX + bitmap.dimensions().width(),
+ origin.fY + bitmap.dimensions().height(), left, top,
+ left + bitmap.dimensions().width(), top + bitmap.dimensions().height(), paint);
} else {
mCanvas->drawBitmap(*hwuiBitmap, left, top, paint);
}
}
void SkiaCanvasProxy::onDrawBitmapRect(const SkBitmap& skBitmap, const SkRect* srcPtr,
- const SkRect& dst, const SkPaint* paint, SrcRectConstraint) {
+ const SkRect& dst, const SkPaint* paint, SrcRectConstraint) {
SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(skBitmap.width(), skBitmap.height());
// TODO: if bitmap is a subset, do we need to add pixelRefOrigin to src?
- Bitmap* bitmap = reinterpret_cast<Bitmap*>(skBitmap.pixelRef());
- mCanvas->drawBitmap(*bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
- dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
+ Bitmap* bitmap = reinterpret_cast<Bitmap*>(skBitmap.pixelRef());
+ mCanvas->drawBitmap(*bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom, dst.fLeft, dst.fTop,
+ dst.fRight, dst.fBottom, paint);
}
void SkiaCanvasProxy::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
- const SkRect& dst, const SkPaint*) {
- //TODO make nine-patch drawing a method on Canvas.h
+ const SkRect& dst, const SkPaint*) {
+ // TODO make nine-patch drawing a method on Canvas.h
SkDEBUGFAIL("SkiaCanvasProxy::onDrawBitmapNine is not yet supported");
}
void SkiaCanvasProxy::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,
- const SkPaint* paint) {
+ const SkPaint* paint) {
SkBitmap skiaBitmap;
SkPixmap pixmap;
if (image->peekPixels(&pixmap) && skiaBitmap.installPixels(pixmap)) {
@@ -158,24 +155,24 @@ void SkiaCanvasProxy::onDrawImage(const SkImage* image, SkScalar left, SkScalar
}
void SkiaCanvasProxy::onDrawImageRect(const SkImage* image, const SkRect* srcPtr, const SkRect& dst,
- const SkPaint* paint, SrcRectConstraint constraint) {
+ const SkPaint* paint, SrcRectConstraint constraint) {
SkBitmap skiaBitmap;
SkPixmap pixmap;
if (image->peekPixels(&pixmap) && skiaBitmap.installPixels(pixmap)) {
sk_sp<Bitmap> bitmap = Bitmap::createFrom(skiaBitmap.info(), *skiaBitmap.pixelRef());
SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(image->width(), image->height());
- mCanvas->drawBitmap(*bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
- dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
+ mCanvas->drawBitmap(*bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom, dst.fLeft,
+ dst.fTop, dst.fRight, dst.fBottom, paint);
}
}
void SkiaCanvasProxy::onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
- const SkPaint*) {
+ const SkPaint*) {
SkDEBUGFAIL("SkiaCanvasProxy::onDrawImageNine is not yet supported");
}
void SkiaCanvasProxy::onDrawImageLattice(const SkImage* image, const Lattice& lattice,
- const SkRect& dst, const SkPaint* paint) {
+ const SkRect& dst, const SkPaint* paint) {
SkLatticeIter iter(lattice, dst);
SkRect srcR, dstR;
while (iter.next(&srcR, &dstR)) {
@@ -184,7 +181,7 @@ void SkiaCanvasProxy::onDrawImageLattice(const SkImage* image, const Lattice& la
}
void SkiaCanvasProxy::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
- const SkPaint& paint) {
+ const SkPaint& paint) {
if (mFilterHwuiCalls) {
return;
}
@@ -214,7 +211,8 @@ static inline SaveFlags::Flags saveFlags(SkCanvas::SaveLayerFlags layerFlags) {
return saveFlags;
}
-SkCanvas::SaveLayerStrategy SkiaCanvasProxy::getSaveLayerStrategy(const SaveLayerRec& saveLayerRec) {
+SkCanvas::SaveLayerStrategy SkiaCanvasProxy::getSaveLayerStrategy(
+ const SaveLayerRec& saveLayerRec) {
SkRect rect;
if (saveLayerRec.fBounds) {
rect = *saveLayerRec.fBounds;
@@ -239,7 +237,7 @@ void SkiaCanvasProxy::didSetMatrix(const SkMatrix& matrix) {
}
void SkiaCanvasProxy::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
- const SkPaint& paint) {
+ const SkPaint& paint) {
SkPath path;
path.addRRect(outer);
path.addRRect(inner);
@@ -259,7 +257,7 @@ public:
glyphIDs = (uint16_t*)text;
count = byteLength >> 1;
} else {
- // ensure space for one glyph per ID given UTF8 encoding.
+ // ensure space for one glyph per ID given UTF8 encoding.
storage.reset(new uint16_t[byteLength]);
glyphIDs = storage.get();
count = paint.textToGlyphs(text, byteLength, storage.get());
@@ -270,12 +268,13 @@ public:
SkPaint paint;
uint16_t* glyphIDs;
int count;
+
private:
std::unique_ptr<uint16_t[]> storage;
};
void SkiaCanvasProxy::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
- const SkPaint& origPaint) {
+ const SkPaint& origPaint) {
// convert to glyphIDs if necessary
GlyphIDConverter glyphs(text, byteLength, origPaint);
@@ -309,14 +308,14 @@ void SkiaCanvasProxy::onDrawText(const void* text, size_t byteLength, SkScalar x
int xBaseline = 0;
int yBaseline = 0;
if (mCanvas->drawTextAbsolutePos()) {
- bounds.offset(x,y);
+ bounds.offset(x, y);
xBaseline = x;
yBaseline = y;
}
- static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
- auto glyphFunc = [&] (uint16_t* text, float* positions) {
- memcpy(text, glyphs.glyphIDs, glyphs.count*sizeof(uint16_t));
+ static_assert(sizeof(SkPoint) == sizeof(float) * 2, "SkPoint is no longer two floats");
+ auto glyphFunc = [&](uint16_t* text, float* positions) {
+ memcpy(text, glyphs.glyphIDs, glyphs.count * sizeof(uint16_t));
size_t posIndex = 0;
// setup the first glyph position
positions[posIndex++] = xBaseline;
@@ -326,24 +325,24 @@ void SkiaCanvasProxy::onDrawText(const void* text, size_t byteLength, SkScalar x
float yPosition = yBaseline;
for (int i = 1; i < glyphs.count; i++) {
positions[posIndex++] = xBaseline;
- yPosition += glyphWidths[i-1];
+ yPosition += glyphWidths[i - 1];
positions[posIndex++] = yPosition;
}
} else {
float xPosition = xBaseline;
for (int i = 1; i < glyphs.count; i++) {
- xPosition += glyphWidths[i-1];
+ xPosition += glyphWidths[i - 1];
positions[posIndex++] = xPosition;
positions[posIndex++] = yBaseline;
}
}
};
mCanvas->drawGlyphs(glyphFunc, glyphs.count, glyphs.paint, x, y, bounds.fLeft, bounds.fTop,
- bounds.fRight, bounds.fBottom, 0);
+ bounds.fRight, bounds.fBottom, 0);
}
void SkiaCanvasProxy::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
- const SkPaint& origPaint) {
+ const SkPaint& origPaint) {
// convert to glyphIDs if necessary
GlyphIDConverter glyphs(text, byteLength, origPaint);
@@ -369,11 +368,11 @@ void SkiaCanvasProxy::onDrawPosText(const void* text, size_t byteLength, const S
bounds.join(glyphBounds);
}
- static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
- auto glyphFunc = [&] (uint16_t* text, float* positions) {
- memcpy(text, glyphs.glyphIDs, glyphs.count*sizeof(uint16_t));
+ static_assert(sizeof(SkPoint) == sizeof(float) * 2, "SkPoint is no longer two floats");
+ auto glyphFunc = [&](uint16_t* text, float* positions) {
+ memcpy(text, glyphs.glyphIDs, glyphs.count * sizeof(uint16_t));
if (mCanvas->drawTextAbsolutePos()) {
- memcpy(positions, pos, 2*glyphs.count*sizeof(float));
+ memcpy(positions, pos, 2 * glyphs.count * sizeof(float));
} else {
for (int i = 0, posIndex = 0; i < glyphs.count; i++) {
positions[posIndex++] = pos[i].fX - x;
@@ -382,11 +381,11 @@ void SkiaCanvasProxy::onDrawPosText(const void* text, size_t byteLength, const S
}
};
mCanvas->drawGlyphs(glyphFunc, glyphs.count, glyphs.paint, x, y, bounds.fLeft, bounds.fTop,
- bounds.fRight, bounds.fBottom, 0);
+ bounds.fRight, bounds.fBottom, 0);
}
void SkiaCanvasProxy::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
- SkScalar constY, const SkPaint& paint) {
+ SkScalar constY, const SkPaint& paint) {
const size_t pointCount = byteLength >> 1;
std::unique_ptr<SkPoint[]> pts(new SkPoint[pointCount]);
for (size_t i = 0; i < pointCount; i++) {
@@ -396,13 +395,14 @@ void SkiaCanvasProxy::onDrawPosTextH(const void* text, size_t byteLength, const
}
void SkiaCanvasProxy::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
- const SkMatrix* matrix, const SkPaint& origPaint) {
+ const SkMatrix* matrix, const SkPaint& origPaint) {
SkDEBUGFAIL("SkiaCanvasProxy::onDrawTextOnPath is not supported");
}
void SkiaCanvasProxy::onDrawTextRSXform(const void* text, size_t byteLength,
- const SkRSXform xform[], const SkRect* cullRect, const SkPaint& paint) {
- GlyphIDConverter glyphs(text, byteLength, paint); // Just get count
+ const SkRSXform xform[], const SkRect* cullRect,
+ const SkPaint& paint) {
+ GlyphIDConverter glyphs(text, byteLength, paint); // Just get count
SkMatrix localM, currM, origM;
mCanvas->getMatrix(&currM);
origM = currM;
@@ -410,55 +410,56 @@ void SkiaCanvasProxy::onDrawTextRSXform(const void* text, size_t byteLength,
localM.setRSXform(*xform++);
currM.setConcat(origM, localM);
mCanvas->setMatrix(currM);
- this->onDrawText((char*)text + (byteLength / glyphs.count * i),
- byteLength / glyphs.count, 0, 0, paint);
+ this->onDrawText((char*)text + (byteLength / glyphs.count * i), byteLength / glyphs.count,
+ 0, 0, paint);
}
mCanvas->setMatrix(origM);
}
-
void SkiaCanvasProxy::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
- const SkPaint& paint) {
+ const SkPaint& paint) {
SkPaint runPaint = paint;
- SkTextBlobRunIterator it(blob);
- for (;!it.done(); it.next()) {
- size_t textLen = it.glyphCount() * sizeof(uint16_t);
- const SkPoint& offset = it.offset();
- // applyFontToPaint() always overwrites the exact same attributes,
- // so it is safe to not re-seed the paint for this reason.
- it.applyFontToPaint(&runPaint);
-
- switch (it.positioning()) {
- case SkTextBlob::kDefault_Positioning:
- this->drawText(it.glyphs(), textLen, x + offset.x(), y + offset.y(), runPaint);
- break;
- case SkTextBlob::kHorizontal_Positioning: {
- std::unique_ptr<SkPoint[]> pts(new SkPoint[it.glyphCount()]);
- for (size_t i = 0; i < it.glyphCount(); i++) {
- pts[i].set(x + offset.x() + it.pos()[i], y + offset.y());
- }
- this->drawPosText(it.glyphs(), textLen, pts.get(), runPaint);
- break;
- }
- case SkTextBlob::kFull_Positioning: {
- std::unique_ptr<SkPoint[]> pts(new SkPoint[it.glyphCount()]);
- for (size_t i = 0; i < it.glyphCount(); i++) {
- const size_t xIndex = i*2;
- const size_t yIndex = xIndex + 1;
- pts[i].set(x + offset.x() + it.pos()[xIndex], y + offset.y() + it.pos()[yIndex]);
- }
- this->drawPosText(it.glyphs(), textLen, pts.get(), runPaint);
- break;
- }
- default:
- SK_ABORT("unhandled positioning mode");
- }
- }
+ SkTextBlobRunIterator it(blob);
+ for (; !it.done(); it.next()) {
+ size_t textLen = it.glyphCount() * sizeof(uint16_t);
+ const SkPoint& offset = it.offset();
+ // applyFontToPaint() always overwrites the exact same attributes,
+ // so it is safe to not re-seed the paint for this reason.
+ it.applyFontToPaint(&runPaint);
+
+ switch (it.positioning()) {
+ case SkTextBlob::kDefault_Positioning:
+ this->drawText(it.glyphs(), textLen, x + offset.x(), y + offset.y(), runPaint);
+ break;
+ case SkTextBlob::kHorizontal_Positioning: {
+ std::unique_ptr<SkPoint[]> pts(new SkPoint[it.glyphCount()]);
+ for (size_t i = 0; i < it.glyphCount(); i++) {
+ pts[i].set(x + offset.x() + it.pos()[i], y + offset.y());
+ }
+ this->drawPosText(it.glyphs(), textLen, pts.get(), runPaint);
+ break;
+ }
+ case SkTextBlob::kFull_Positioning: {
+ std::unique_ptr<SkPoint[]> pts(new SkPoint[it.glyphCount()]);
+ for (size_t i = 0; i < it.glyphCount(); i++) {
+ const size_t xIndex = i * 2;
+ const size_t yIndex = xIndex + 1;
+ pts[i].set(x + offset.x() + it.pos()[xIndex],
+ y + offset.y() + it.pos()[yIndex]);
+ }
+ this->drawPosText(it.glyphs(), textLen, pts.get(), runPaint);
+ break;
+ }
+ default:
+ SK_ABORT("unhandled positioning mode");
+ }
+ }
}
void SkiaCanvasProxy::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
- const SkPoint texCoords[4], SkBlendMode bmode, const SkPaint& paint) {
+ const SkPoint texCoords[4], SkBlendMode bmode,
+ const SkPaint& paint) {
if (mFilterHwuiCalls) {
return;
}
@@ -466,9 +467,9 @@ void SkiaCanvasProxy::onDrawPatch(const SkPoint cubics[12], const SkColor colors
mCanvas->getMatrix(&matrix);
SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, &matrix);
- mCanvas->drawVertices(SkPatchUtils::MakeVertices(cubics, colors, texCoords,
- lod.width(), lod.height()).get(),
- bmode, paint);
+ mCanvas->drawVertices(
+ SkPatchUtils::MakeVertices(cubics, colors, texCoords, lod.width(), lod.height()).get(),
+ bmode, paint);
}
void SkiaCanvasProxy::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle) {
@@ -485,5 +486,5 @@ void SkiaCanvasProxy::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle)
mCanvas->clipPath(&path, op);
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
index d11a779b3600..360d5a08b974 100644
--- a/libs/hwui/SkiaCanvasProxy.h
+++ b/libs/hwui/SkiaCanvasProxy.h
@@ -17,8 +17,8 @@
#ifndef SkiaCanvasProxy_DEFINED
#define SkiaCanvasProxy_DEFINED
-#include <cutils/compiler.h>
#include <SkCanvas.h>
+#include <cutils/compiler.h>
#include "hwui/Canvas.h"
@@ -43,7 +43,6 @@ public:
virtual ~SkiaCanvasProxy() {}
protected:
-
virtual sk_sp<SkSurface> onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override;
virtual void willSave() override;
@@ -66,15 +65,15 @@ protected:
const SkPaint*) override;
virtual void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst,
const SkPaint* paint, SrcRectConstraint) override;
- virtual void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
- const SkRect& dst, const SkPaint*) override;
+ virtual void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
+ const SkPaint*) override;
virtual void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*);
virtual void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*,
- SrcRectConstraint);
+ SrcRectConstraint);
virtual void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
- const SkPaint*);
+ const SkPaint*);
virtual void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
- const SkPaint*);
+ const SkPaint*);
virtual void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
@@ -107,7 +106,7 @@ private:
typedef SkCanvas INHERITED;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // SkiaCanvasProxy_DEFINED
+#endif // SkiaCanvasProxy_DEFINED
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 5c5378bf22ad..df746554f306 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -39,11 +39,11 @@ static constexpr GLenum gTileModes[] = {
};
static_assert(gTileModes[SkShader::kClamp_TileMode] == GL_CLAMP_TO_EDGE,
- "SkShader TileModes have changed");
+ "SkShader TileModes have changed");
static_assert(gTileModes[SkShader::kRepeat_TileMode] == GL_REPEAT,
- "SkShader TileModes have changed");
+ "SkShader TileModes have changed");
static_assert(gTileModes[SkShader::kMirror_TileMode] == GL_MIRRORED_REPEAT,
- "SkShader TileModes have changed");
+ "SkShader TileModes have changed");
/**
* This function does not work for n == 0.
@@ -70,7 +70,7 @@ static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, G
* @param modelViewMatrix Model view matrix, as supplied by the OpenGLRenderer.
*/
static void computeScreenSpaceMatrix(mat4& screenSpace, const SkMatrix& unitMatrix,
- const SkMatrix& localMatrix, const mat4& modelViewMatrix) {
+ const SkMatrix& localMatrix, const mat4& modelViewMatrix) {
mat4 shaderMatrix;
// uses implicit construction
shaderMatrix.loadInverse(localMatrix);
@@ -95,7 +95,7 @@ static void toLinearUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) {
}
static void toCircularUnitMatrix(const float x, const float y, const float radius,
- SkMatrix* matrix) {
+ SkMatrix* matrix) {
const float inv = 1.0f / radius;
matrix->setTranslate(-x, -y);
matrix->postScale(inv, inv);
@@ -118,8 +118,8 @@ static bool isSimpleGradient(const SkShader::GradientInfo& gradInfo) {
///////////////////////////////////////////////////////////////////////////////
bool tryStoreGradient(Caches& caches, const SkShader& shader, const Matrix4 modelViewMatrix,
- GLuint* textureUnit, ProgramDescription* description,
- SkiaShaderData::GradientShaderData* outData) {
+ GLuint* textureUnit, ProgramDescription* description,
+ SkiaShaderData::GradientShaderData* outData) {
SkShader::GradientInfo gradInfo;
gradInfo.fColorCount = 0;
gradInfo.fColors = nullptr;
@@ -135,8 +135,8 @@ bool tryStoreGradient(Caches& caches, const SkShader& shader, const Matrix4 mode
case SkShader::kRadial_GradientType:
description->gradientType = ProgramDescription::kGradientCircular;
- toCircularUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY,
- gradInfo.fRadius[0], &unitMatrix);
+ toCircularUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, gradInfo.fRadius[0],
+ &unitMatrix);
break;
case SkShader::kSweep_GradientType:
description->gradientType = ProgramDescription::kGradientSweep;
@@ -150,8 +150,8 @@ bool tryStoreGradient(Caches& caches, const SkShader& shader, const Matrix4 mode
description->hasGradient = true;
description->isSimpleGradient = isSimpleGradient(gradInfo);
- computeScreenSpaceMatrix(outData->screenSpace, unitMatrix,
- shader.getLocalMatrix(), modelViewMatrix);
+ computeScreenSpaceMatrix(outData->screenSpace, unitMatrix, shader.getLocalMatrix(),
+ modelViewMatrix);
// re-query shader to get full color / offset data
std::unique_ptr<SkColor[]> colorStorage(new SkColor[gradInfo.fColorCount]);
@@ -164,7 +164,7 @@ bool tryStoreGradient(Caches& caches, const SkShader& shader, const Matrix4 mode
outData->gradientSampler = (*textureUnit)++;
#ifndef SK_SCALAR_IS_FLOAT
- #error Need to convert gradInfo.fColorOffsets to float!
+#error Need to convert gradInfo.fColorOffsets to float!
#endif
outData->gradientTexture = caches.gradientCache.get(
gradInfo.fColors, gradInfo.fColorOffsets, gradInfo.fColorCount);
@@ -181,8 +181,7 @@ bool tryStoreGradient(Caches& caches, const SkShader& shader, const Matrix4 mode
}
void applyGradient(Caches& caches, const SkiaShaderData::GradientShaderData& data,
- const GLsizei width, const GLsizei height) {
-
+ const GLsizei width, const GLsizei height) {
if (CC_UNLIKELY(data.gradientTexture)) {
caches.textureState().activateTexture(data.gradientSampler);
bindTexture(&caches, data.gradientTexture, data.wrapST, data.wrapST);
@@ -193,13 +192,13 @@ void applyGradient(Caches& caches, const SkiaShaderData::GradientShaderData& dat
}
glUniform2f(caches.program().getUniform("screenSize"), 1.0f / width, 1.0f / height);
- glUniformMatrix4fv(caches.program().getUniform("screenSpace"), 1,
- GL_FALSE, &data.screenSpace.data[0]);
+ glUniformMatrix4fv(caches.program().getUniform("screenSpace"), 1, GL_FALSE,
+ &data.screenSpace.data[0]);
}
bool tryStoreBitmap(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix,
- GLuint* textureUnit, ProgramDescription* description,
- SkiaShaderData::BitmapShaderData* outData) {
+ GLuint* textureUnit, ProgramDescription* description,
+ SkiaShaderData::BitmapShaderData* outData) {
SkBitmap bitmap;
SkShader::TileMode xy[2];
if (!shader.isABitmap(&bitmap, nullptr, xy)) {
@@ -225,9 +224,9 @@ bool tryStoreBitmap(Caches& caches, const SkShader& shader, const Matrix4& model
description->hasTranslucentConversion = texture->blend;
description->isShaderBitmapExternal = hwuiBitmap->isHardware();
// gralloc doesn't support non-clamp modes
- if (hwuiBitmap->isHardware() || (!caches.extensions().hasNPot()
- && (!isPowerOfTwo(width) || !isPowerOfTwo(height))
- && (xy[0] != SkShader::kClamp_TileMode || xy[1] != SkShader::kClamp_TileMode))) {
+ if (hwuiBitmap->isHardware() ||
+ (!caches.extensions().hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) &&
+ (xy[0] != SkShader::kClamp_TileMode || xy[1] != SkShader::kClamp_TileMode))) {
// need non-clamp mode, but it's not supported for this draw,
// so enable custom shader logic to mimic
description->useShaderBasedWrap = true;
@@ -242,7 +241,7 @@ bool tryStoreBitmap(Caches& caches, const SkShader& shader, const Matrix4& model
}
computeScreenSpaceMatrix(outData->textureTransform, SkMatrix::I(), shader.getLocalMatrix(),
- modelViewMatrix);
+ modelViewMatrix);
outData->textureDimension[0] = 1.0f / width;
outData->textureDimension[1] = 1.0f / height;
@@ -256,7 +255,7 @@ void applyBitmap(Caches& caches, const SkiaShaderData::BitmapShaderData& data) {
glUniform1i(caches.program().getUniform("bitmapSampler"), data.bitmapSampler);
glUniformMatrix4fv(caches.program().getUniform("textureTransform"), 1, GL_FALSE,
- &data.textureTransform.data[0]);
+ &data.textureTransform.data[0]);
glUniform2fv(caches.program().getUniform("textureDimension"), 1, &data.textureDimension[0]);
}
@@ -283,20 +282,19 @@ SkiaShaderType getComposeSubType(const SkShader& shader) {
}
void storeCompose(Caches& caches, const SkShader& bitmapShader, const SkShader& gradientShader,
- const Matrix4& modelViewMatrix, GLuint* textureUnit,
- ProgramDescription* description, SkiaShaderData* outData) {
- LOG_ALWAYS_FATAL_IF(!tryStoreBitmap(caches, bitmapShader, modelViewMatrix,
- textureUnit, description, &outData->bitmapData),
- "failed storing bitmap shader data");
- LOG_ALWAYS_FATAL_IF(!tryStoreGradient(caches, gradientShader, modelViewMatrix,
- textureUnit, description, &outData->gradientData),
- "failing storing gradient shader data");
+ const Matrix4& modelViewMatrix, GLuint* textureUnit,
+ ProgramDescription* description, SkiaShaderData* outData) {
+ LOG_ALWAYS_FATAL_IF(!tryStoreBitmap(caches, bitmapShader, modelViewMatrix, textureUnit,
+ description, &outData->bitmapData),
+ "failed storing bitmap shader data");
+ LOG_ALWAYS_FATAL_IF(!tryStoreGradient(caches, gradientShader, modelViewMatrix, textureUnit,
+ description, &outData->gradientData),
+ "failing storing gradient shader data");
}
bool tryStoreCompose(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix,
- GLuint* textureUnit, ProgramDescription* description,
- SkiaShaderData* outData) {
-
+ GLuint* textureUnit, ProgramDescription* description,
+ SkiaShaderData* outData) {
SkShader::ComposeRec rec;
if (!shader.asACompose(&rec)) return false;
@@ -311,34 +309,33 @@ bool tryStoreCompose(Caches& caches, const SkShader& shader, const Matrix4& mode
computeScreenSpaceMatrix(transform, SkMatrix::I(), shader.getLocalMatrix(), modelViewMatrix);
if (shaderAType == kBitmap_SkiaShaderType) {
description->isBitmapFirst = true;
- storeCompose(caches, *rec.fShaderA, *rec.fShaderB,
- transform, textureUnit, description, outData);
+ storeCompose(caches, *rec.fShaderA, *rec.fShaderB, transform, textureUnit, description,
+ outData);
} else {
description->isBitmapFirst = false;
- storeCompose(caches, *rec.fShaderB, *rec.fShaderA,
- transform, textureUnit, description, outData);
+ storeCompose(caches, *rec.fShaderB, *rec.fShaderA, transform, textureUnit, description,
+ outData);
}
description->shadersMode = rec.fBlendMode;
return true;
}
void SkiaShader::store(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix,
- GLuint* textureUnit, ProgramDescription* description,
- SkiaShaderData* outData) {
- if (tryStoreGradient(caches, shader, modelViewMatrix,
- textureUnit, description, &outData->gradientData)) {
+ GLuint* textureUnit, ProgramDescription* description,
+ SkiaShaderData* outData) {
+ if (tryStoreGradient(caches, shader, modelViewMatrix, textureUnit, description,
+ &outData->gradientData)) {
outData->skiaShaderType = kGradient_SkiaShaderType;
return;
}
- if (tryStoreBitmap(caches, shader, modelViewMatrix,
- textureUnit, description, &outData->bitmapData)) {
+ if (tryStoreBitmap(caches, shader, modelViewMatrix, textureUnit, description,
+ &outData->bitmapData)) {
outData->skiaShaderType = kBitmap_SkiaShaderType;
return;
}
- if (tryStoreCompose(caches, shader, modelViewMatrix,
- textureUnit, description, outData)) {
+ if (tryStoreCompose(caches, shader, modelViewMatrix, textureUnit, description, outData)) {
outData->skiaShaderType = kCompose_SkiaShaderType;
return;
}
@@ -347,8 +344,8 @@ void SkiaShader::store(Caches& caches, const SkShader& shader, const Matrix4& mo
outData->skiaShaderType = kNone_SkiaShaderType;
}
-void SkiaShader::apply(Caches& caches, const SkiaShaderData& data,
- const GLsizei width, const GLsizei height) {
+void SkiaShader::apply(Caches& caches, const SkiaShaderData& data, const GLsizei width,
+ const GLsizei height) {
if (!data.skiaShaderType) return;
if (data.skiaShaderType & kGradient_SkiaShaderType) {
@@ -359,5 +356,5 @@ void SkiaShader::apply(Caches& caches, const SkiaShaderData& data,
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index ab578d540774..e8e92bdc1d76 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -74,13 +74,13 @@ struct SkiaShaderData {
class SkiaShader {
public:
static void store(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix,
- GLuint* textureUnit, ProgramDescription* description,
- SkiaShaderData* outData);
- static void apply(Caches& caches, const SkiaShaderData& data,
- const GLsizei width, const GLsizei height);
+ GLuint* textureUnit, ProgramDescription* description,
+ SkiaShaderData* outData);
+ static void apply(Caches& caches, const SkiaShaderData& data, const GLsizei width,
+ const GLsizei height);
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_SKIA_SHADER_H
+#endif // ANDROID_HWUI_SKIA_SHADER_H
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 9d719bd1e997..f1a1bef7c94e 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -113,8 +113,8 @@ void Snapshot::resetClip(float left, float top, float right, float bottom) {
// Clipping round rect
///////////////////////////////////////////////////////////////////////////////
-void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds,
- float radius, bool highPriority) {
+void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, float radius,
+ bool highPriority) {
if (bounds.isEmpty()) {
mClipArea->setEmpty();
return;
@@ -135,7 +135,7 @@ void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& boun
state->matrix.loadInverse(roundRectDrawingMatrix);
// compute area under rounded corners - only draws overlapping these rects need to be clipped
- for (int i = 0 ; i < 4; i++) {
+ for (int i = 0; i < 4; i++) {
state->dangerRects[i] = bounds;
}
state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius;
@@ -170,15 +170,16 @@ static Snapshot* getClipRoot(Snapshot* target) {
}
const ClipBase* Snapshot::serializeIntersectedClip(LinearAllocator& allocator,
- const ClipBase* recordedClip, const Matrix4& recordedClipTransform) {
+ const ClipBase* recordedClip,
+ const Matrix4& recordedClipTransform) {
auto target = this;
if (CC_UNLIKELY(recordedClip && recordedClip->intersectWithRoot)) {
// Clip must be intersected with root, instead of current clip.
target = getClipRoot(this);
}
- return target->mClipArea->serializeIntersectedClip(allocator,
- recordedClip, recordedClipTransform);
+ return target->mClipArea->serializeIntersectedClip(allocator, recordedClip,
+ recordedClipTransform);
}
void Snapshot::applyClip(const ClipBase* recordedClip, const Matrix4& transform) {
@@ -194,15 +195,15 @@ void Snapshot::applyClip(const ClipBase* recordedClip, const Matrix4& transform)
///////////////////////////////////////////////////////////////////////////////
void Snapshot::dump() const {
- ALOGD("Snapshot %p, flags %x, prev %p, height %d, hasComplexClip %d",
- this, flags, previous, getViewportHeight(), !mClipArea->isSimple());
+ ALOGD("Snapshot %p, flags %x, prev %p, height %d, hasComplexClip %d", this, flags, previous,
+ getViewportHeight(), !mClipArea->isSimple());
const Rect& clipRect(mClipArea->getClipRect());
- ALOGD(" ClipRect %.1f %.1f %.1f %.1f, clip simple %d",
- clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, mClipArea->isSimple());
+ ALOGD(" ClipRect %.1f %.1f %.1f %.1f, clip simple %d", clipRect.left, clipRect.top,
+ clipRect.right, clipRect.bottom, mClipArea->isSimple());
ALOGD(" Transform (at %p):", transform);
transform->dump();
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 8cd90a68a9bb..655f819ca41b 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -19,9 +19,9 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#include <ui/Region.h>
#include <utils/LinearAllocator.h>
#include <utils/RefBase.h>
-#include <ui/Region.h>
#include <SkClipOp.h>
#include <SkRegion.h>
@@ -50,10 +50,8 @@ public:
}
bool areaRequiresRoundRectClip(const Rect& rect) const {
- return rect.intersects(dangerRects[0])
- || rect.intersects(dangerRects[1])
- || rect.intersects(dangerRects[2])
- || rect.intersects(dangerRects[3]);
+ return rect.intersects(dangerRects[0]) || rect.intersects(dangerRects[1]) ||
+ rect.intersects(dangerRects[2]) || rect.intersects(dangerRects[3]);
}
bool highPriority;
@@ -74,7 +72,6 @@ public:
*/
class Snapshot {
public:
-
Snapshot();
Snapshot(Snapshot* s, int saveFlags);
@@ -147,8 +144,9 @@ public:
const ClipArea& getClipArea() const { return *mClipArea; }
ClipArea& mutateClipArea() { return *mClipArea; }
- WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip(LinearAllocator& allocator,
- const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
+ WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip(
+ LinearAllocator& allocator, const ClipBase* recordedClip,
+ const Matrix4& recordedClipTransform);
void applyClip(const ClipBase* clip, const Matrix4& transform);
/**
@@ -173,8 +171,8 @@ public:
*
* If the current round rect clip is high priority, the incoming clip is ignored.
*/
- void setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds,
- float radius, bool highPriority);
+ void setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, float radius,
+ bool highPriority);
/**
* Sets (and replaces) the current projection mask
@@ -275,7 +273,7 @@ private:
ViewportData mViewportData;
Vector3 mRelativeLightCenter;
-}; // class Snapshot
+}; // class Snapshot
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index 7b0a1bc3e93e..e371ac8da1e5 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -37,7 +37,7 @@
// For the whole polygon, the sum of all the deltas b/t normals is 2 * M_PI,
// therefore, the maximum number of extra vertices will be twice bigger.
-#define SPOT_MAX_EXTRA_CORNER_VERTEX_NUMBER (2 * SPOT_EXTRA_CORNER_VERTEX_PER_PI)
+#define SPOT_MAX_EXTRA_CORNER_VERTEX_NUMBER (2 * SPOT_EXTRA_CORNER_VERTEX_PER_PI)
// For each RADIANS_DIVISOR, we would allocate one more vertex b/t the normals.
#define SPOT_CORNER_RADIANS_DIVISOR (M_PI / SPOT_EXTRA_CORNER_VERTEX_PER_PI)
@@ -52,10 +52,10 @@
#include "VertexBuffer.h"
#include "utils/MathUtils.h"
-#include <algorithm>
#include <math.h>
#include <stdlib.h>
#include <utils/Log.h>
+#include <algorithm>
// TODO: After we settle down the new algorithm, we can remove the old one and
// its utility functions.
@@ -115,14 +115,14 @@ static float angle(const Vector2& point, const Vector2& center) {
* @param p2 The second point defining the line segment
* @return The distance along the ray if it intersects with the line segment, negative if otherwise
*/
-static float rayIntersectPoints(const Vector2& rayOrigin, float dx, float dy,
- const Vector2& p1, const Vector2& p2) {
+static float rayIntersectPoints(const Vector2& rayOrigin, float dx, float dy, const Vector2& p1,
+ const Vector2& p2) {
// The math below is derived from solving this formula, basically the
// intersection point should stay on both the ray and the edge of (p1, p2).
// solve([p1x+t*(p2x-p1x)=dx*t2+px,p1y+t*(p2y-p1y)=dy*t2+py],[t,t2]);
float divisor = (dx * (p1.y - p2.y) + dy * p2.x - dy * p1.x);
- if (divisor == 0) return -1.0f; // error, invalid divisor
+ if (divisor == 0) return -1.0f; // error, invalid divisor
#if DEBUG_SHADOW
float interpVal = (dx * (p1.y - rayOrigin.y) + dy * rayOrigin.x - dy * p1.x) / divisor;
@@ -132,9 +132,10 @@ static float rayIntersectPoints(const Vector2& rayOrigin, float dx, float dy,
#endif
float distance = (p1.x * (rayOrigin.y - p2.y) + p2.x * (p1.y - rayOrigin.y) +
- rayOrigin.x * (p2.y - p1.y)) / divisor;
+ rayOrigin.x * (p2.y - p1.y)) /
+ divisor;
- return distance; // may be negative in error cases
+ return distance; // may be negative in error cases
}
/**
@@ -144,9 +145,7 @@ static float rayIntersectPoints(const Vector2& rayOrigin, float dx, float dy,
* @param pointsLength the number of vertices of the polygon.
*/
void SpotShadow::xsort(Vector2* points, int pointsLength) {
- auto cmp = [](const Vector2& a, const Vector2& b) -> bool {
- return a.x < b.x;
- };
+ auto cmp = [](const Vector2& a, const Vector2& b) -> bool { return a.x < b.x; };
std::sort(points, points + pointsLength, cmp);
}
@@ -171,10 +170,9 @@ int SpotShadow::hull(Vector2* points, int pointsLength, Vector2* retPoly) {
lUpper[lUpperSize] = points[i];
lUpperSize++;
- while (lUpperSize > 2 && !ccw(
- lUpper[lUpperSize - 3].x, lUpper[lUpperSize - 3].y,
- lUpper[lUpperSize - 2].x, lUpper[lUpperSize - 2].y,
- lUpper[lUpperSize - 1].x, lUpper[lUpperSize - 1].y)) {
+ while (lUpperSize > 2 &&
+ !ccw(lUpper[lUpperSize - 3].x, lUpper[lUpperSize - 3].y, lUpper[lUpperSize - 2].x,
+ lUpper[lUpperSize - 2].y, lUpper[lUpperSize - 1].x, lUpper[lUpperSize - 1].y)) {
// Remove the middle point of the three last
lUpper[lUpperSize - 2].x = lUpper[lUpperSize - 1].x;
lUpper[lUpperSize - 2].y = lUpper[lUpperSize - 1].y;
@@ -192,10 +190,9 @@ int SpotShadow::hull(Vector2* points, int pointsLength, Vector2* retPoly) {
lLower[lLowerSize] = points[i];
lLowerSize++;
- while (lLowerSize > 2 && !ccw(
- lLower[lLowerSize - 3].x, lLower[lLowerSize - 3].y,
- lLower[lLowerSize - 2].x, lLower[lLowerSize - 2].y,
- lLower[lLowerSize - 1].x, lLower[lLowerSize - 1].y)) {
+ while (lLowerSize > 2 &&
+ !ccw(lLower[lLowerSize - 3].x, lLower[lLowerSize - 3].y, lLower[lLowerSize - 2].x,
+ lLower[lLowerSize - 2].y, lLower[lLowerSize - 1].x, lLower[lLowerSize - 1].y)) {
// Remove the middle point of the three last
lLower[lLowerSize - 2] = lLower[lLowerSize - 1];
lLowerSize--;
@@ -223,8 +220,7 @@ int SpotShadow::hull(Vector2* points, int pointsLength, Vector2* retPoly) {
*
* @return true if a right hand turn
*/
-bool SpotShadow::ccw(float ax, float ay, float bx, float by,
- float cx, float cy) {
+bool SpotShadow::ccw(float ax, float ay, float bx, float by, float cx, float cy) {
return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax) > EPSILON;
}
@@ -251,8 +247,7 @@ void SpotShadow::swap(Vector2* points, int i, int j) {
/**
* quick sort implementation about the center.
*/
-void SpotShadow::quicksortCirc(Vector2* points, int low, int high,
- const Vector2& center) {
+void SpotShadow::quicksortCirc(Vector2* points, int low, int high, const Vector2& center) {
int i = low, j = high;
int p = low + (high - low) / 2;
float pivot = angle(points[p], center);
@@ -281,8 +276,7 @@ void SpotShadow::quicksortCirc(Vector2* points, int low, int high,
* @param poly the polygon
* @return true if the testPoint is inside the poly.
*/
-bool SpotShadow::testPointInsidePolygon(const Vector2 testPoint,
- const Vector2* poly, int len) {
+bool SpotShadow::testPointInsidePolygon(const Vector2 testPoint, const Vector2* poly, int len) {
bool c = false;
float testx = testPoint.x;
float testy = testPoint.y;
@@ -292,9 +286,8 @@ bool SpotShadow::testPointInsidePolygon(const Vector2 testPoint,
float endX = poly[i].x;
float endY = poly[i].y;
- if (((endY > testy) != (startY > testy))
- && (testx < (startX - endX) * (testy - endY)
- / (startY - endY) + endX)) {
+ if (((endY > testy) != (startY > testy)) &&
+ (testx < (startX - endX) * (testy - endY) / (startY - endY) + endX)) {
c = !c;
}
}
@@ -326,8 +319,8 @@ void SpotShadow::reverse(Vector2* polygon, int len) {
* @param size the light size.
* @param ret result polygon.
*/
-void SpotShadow::computeLightPolygon(int points, const Vector3& lightCenter,
- float size, Vector3* ret) {
+void SpotShadow::computeLightPolygon(int points, const Vector3& lightCenter, float size,
+ Vector3* ret) {
// TODO: Caching all the sin / cos values and store them in a look up table.
for (int i = 0; i < points; i++) {
float angle = 2 * i * M_PI / points;
@@ -346,8 +339,8 @@ void SpotShadow::computeLightPolygon(int points, const Vector3& lightCenter,
*
* @return float The ratio of (polygon.z / light.z - polygon.z)
*/
-float SpotShadow::projectCasterToOutline(Vector2& outline,
- const Vector3& lightCenter, const Vector3& polyVertex) {
+float SpotShadow::projectCasterToOutline(Vector2& outline, const Vector3& lightCenter,
+ const Vector3& polyVertex) {
float lightToPolyZ = lightCenter.z - polyVertex.z;
float ratioZ = CASTER_Z_CAP_RATIO;
if (lightToPolyZ != 0) {
@@ -372,9 +365,9 @@ float SpotShadow::projectCasterToOutline(Vector2& outline,
* @param shadowTriangleStrip return an (x,y,alpha) triangle strip representing the shadow. Return
* empty strip if error.
*/
-void SpotShadow::createSpotShadow(bool isCasterOpaque, const Vector3& lightCenter,
- float lightSize, const Vector3* poly, int polyLength, const Vector3& polyCentroid,
- VertexBuffer& shadowTriangleStrip) {
+void SpotShadow::createSpotShadow(bool isCasterOpaque, const Vector3& lightCenter, float lightSize,
+ const Vector3* poly, int polyLength, const Vector3& polyCentroid,
+ VertexBuffer& shadowTriangleStrip) {
if (CC_UNLIKELY(lightCenter.z <= 0)) {
ALOGW("Relative Light Z is not positive. No spot shadow!");
return;
@@ -403,21 +396,18 @@ void SpotShadow::createSpotShadow(bool isCasterOpaque, const Vector3& lightCente
// Compute the last outline vertex to make sure we can get the normal and outline
// in one single loop.
- projectCasterToOutline(outlineData[polyLength - 1].position, lightCenter,
- poly[polyLength - 1]);
+ projectCasterToOutline(outlineData[polyLength - 1].position, lightCenter, poly[polyLength - 1]);
// Take the outline's polygon, calculate the normal for each outline edge.
int currentNormalIndex = polyLength - 1;
int nextNormalIndex = 0;
for (int i = 0; i < polyLength; i++) {
- float ratioZ = projectCasterToOutline(outlineData[i].position,
- lightCenter, poly[i]);
+ float ratioZ = projectCasterToOutline(outlineData[i].position, lightCenter, poly[i]);
outlineData[i].radius = ratioZ * lightSize;
outlineData[currentNormalIndex].normal = ShadowTessellator::calculateNormal(
- outlineData[currentNormalIndex].position,
- outlineData[nextNormalIndex].position);
+ outlineData[currentNormalIndex].position, outlineData[nextNormalIndex].position);
currentNormalIndex = (currentNormalIndex + 1) % polyLength;
nextNormalIndex++;
}
@@ -489,11 +479,9 @@ void SpotShadow::createSpotShadow(bool isCasterOpaque, const Vector3& lightCente
(previousNormal * (currentCornerSliceNumber - k) + currentNormal * k) /
currentCornerSliceNumber;
avgNormal.normalize();
- penumbra[penumbraIndex++] = outlineData[i].position +
- avgNormal * outlineData[i].radius;
+ penumbra[penumbraIndex++] = outlineData[i].position + avgNormal * outlineData[i].radius;
}
-
// Compute the umbra by the intersection from the outline's centroid!
//
// (V) ------------------------------------
@@ -547,7 +535,7 @@ void SpotShadow::createSpotShadow(bool isCasterOpaque, const Vector3& lightCente
#endif
for (int i = 0; i < polyLength; i++) {
umbra[i] = outlineData[i].position * FAKE_UMBRA_SIZE_RATIO +
- outlineCentroid * (1 - FAKE_UMBRA_SIZE_RATIO);
+ outlineCentroid * (1 - FAKE_UMBRA_SIZE_RATIO);
}
shadowStrengthScale = 1.0 / minRaitoVI;
}
@@ -556,7 +544,8 @@ void SpotShadow::createSpotShadow(bool isCasterOpaque, const Vector3& lightCente
int umbraLength = polyLength;
#if DEBUG_SHADOW
- ALOGD("penumbraLength is %d , allocatedPenumbraLength %d", penumbraLength, allocatedPenumbraLength);
+ ALOGD("penumbraLength is %d , allocatedPenumbraLength %d", penumbraLength,
+ allocatedPenumbraLength);
dumpPolygon(poly, polyLength, "input poly");
dumpPolygon(penumbra, penumbraLength, "penumbra");
dumpPolygon(umbra, umbraLength, "umbra");
@@ -573,10 +562,9 @@ void SpotShadow::createSpotShadow(bool isCasterOpaque, const Vector3& lightCente
int finalUmbraLength = hull(umbra, umbraLength, finalUmbra);
int finalPenumbraLength = hull(penumbra, penumbraLength, finalPenumbra);
- generateTriangleStrip(isCasterOpaque, shadowStrengthScale, finalPenumbra,
- finalPenumbraLength, finalUmbra, finalUmbraLength, poly, polyLength,
- shadowTriangleStrip, outlineCentroid);
-
+ generateTriangleStrip(isCasterOpaque, shadowStrengthScale, finalPenumbra, finalPenumbraLength,
+ finalUmbra, finalUmbraLength, poly, polyLength, shadowTriangleStrip,
+ outlineCentroid);
}
/**
@@ -632,7 +620,7 @@ inline int getClosestUmbraIndex(const Vector2& pivot, const Vector2* polygon, in
break;
}
}
- if(resultIndex == -1) {
+ if (resultIndex == -1) {
ALOGE("resultIndex is -1, the polygon must be invalid!");
resultIndex = 0;
}
@@ -651,7 +639,7 @@ inline bool sameDirections(bool isPositiveCross, float a, float b) {
// Find the right polygon edge to shoot the ray at.
inline int findPolyIndex(bool isPositiveCross, int startPolyIndex, const Vector2& umbraDir,
- const Vector2* polyToCentroid, int polyLength) {
+ const Vector2* polyToCentroid, int polyLength) {
// Make sure we loop with a bound.
for (int i = 0; i < polyLength; i++) {
int currentIndex = (i + startPolyIndex) % polyLength;
@@ -662,7 +650,7 @@ inline int findPolyIndex(bool isPositiveCross, int startPolyIndex, const Vector2
float umbraCrossNext = umbraDir.cross(nextToCentroid);
if (sameDirections(isPositiveCross, currentCrossUmbra, umbraCrossNext)) {
#if DEBUG_SHADOW
- ALOGD("findPolyIndex loop %d times , index %d", i, currentIndex );
+ ALOGD("findPolyIndex loop %d times , index %d", i, currentIndex);
#endif
return currentIndex;
}
@@ -674,12 +662,13 @@ inline int findPolyIndex(bool isPositiveCross, int startPolyIndex, const Vector2
// Generate the index pair for penumbra / umbra vertices, and more penumbra vertices
// if needed.
inline void genNewPenumbraAndPairWithUmbra(const Vector2* penumbra, int penumbraLength,
- const Vector2* umbra, int umbraLength, Vector2* newPenumbra, int& newPenumbraIndex,
- IndexPair* verticesPair, int& verticesPairIndex) {
+ const Vector2* umbra, int umbraLength,
+ Vector2* newPenumbra, int& newPenumbraIndex,
+ IndexPair* verticesPair, int& verticesPairIndex) {
// In order to keep everything in just one loop, we need to pre-compute the
// closest umbra vertex for the last penumbra vertex.
- int previousClosestUmbraIndex = getClosestUmbraIndex(penumbra[penumbraLength - 1],
- umbra, umbraLength);
+ int previousClosestUmbraIndex =
+ getClosestUmbraIndex(penumbra[penumbraLength - 1], umbra, umbraLength);
for (int i = 0; i < penumbraLength; i++) {
const Vector2& currentPenumbraVertex = penumbra[i];
// For current penumbra vertex, starting from previousClosestUmbraIndex,
@@ -704,7 +693,8 @@ inline void genNewPenumbraAndPairWithUmbra(const Vector2* penumbra, int penumbra
}
if (indexDelta > 1) {
- // For those umbra don't have penumbra, generate new penumbra vertices by interpolation.
+ // For those umbra don't have penumbra, generate new penumbra vertices by
+ // interpolation.
//
// Assuming Pi for penumbra vertices, and Ui for umbra vertices.
// In the case like below P1 paired with U1 and P2 paired with U5.
@@ -756,7 +746,7 @@ inline void genNewPenumbraAndPairWithUmbra(const Vector2* penumbra, int penumbra
float weightForPreviousPenumbra = 1.0f - weightForCurrentPenumbra;
Vector2 interpolatedPenumbra = currentPenumbraVertex * weightForCurrentPenumbra +
- previousPenumbra * weightForPreviousPenumbra;
+ previousPenumbra * weightForPreviousPenumbra;
int skippedUmbraIndex = (previousClosestUmbraIndex + k + 1) % umbraLength;
verticesPair[verticesPairIndex].outerIndex = newPenumbraIndex;
@@ -775,8 +765,8 @@ inline void genNewPenumbraAndPairWithUmbra(const Vector2* penumbra, int penumbra
}
// Precompute all the polygon's vector, return true if the reference cross product is positive.
-inline bool genPolyToCentroid(const Vector2* poly2d, int polyLength,
- const Vector2& centroid, Vector2* polyToCentroid) {
+inline bool genPolyToCentroid(const Vector2* poly2d, int polyLength, const Vector2& centroid,
+ Vector2* polyToCentroid) {
for (int j = 0; j < polyLength; j++) {
polyToCentroid[j] = poly2d[j] - centroid;
// Normalize these vectors such that we can use epsilon comparison after
@@ -798,21 +788,22 @@ inline bool genPolyToCentroid(const Vector2* poly2d, int polyLength,
// If the ray hit the polygon first, then return the intersection point as the
// closer vertex.
inline Vector2 getCloserVertex(const Vector2& umbraVertex, const Vector2& centroid,
- const Vector2* poly2d, int polyLength, const Vector2* polyToCentroid,
- bool isPositiveCross, int& previousPolyIndex) {
+ const Vector2* poly2d, int polyLength, const Vector2* polyToCentroid,
+ bool isPositiveCross, int& previousPolyIndex) {
Vector2 umbraToCentroid = umbraVertex - centroid;
float distanceToUmbra = umbraToCentroid.length();
umbraToCentroid = umbraToCentroid / distanceToUmbra;
// previousPolyIndex is updated for each item such that we can minimize the
// looping inside findPolyIndex();
- previousPolyIndex = findPolyIndex(isPositiveCross, previousPolyIndex,
- umbraToCentroid, polyToCentroid, polyLength);
+ previousPolyIndex = findPolyIndex(isPositiveCross, previousPolyIndex, umbraToCentroid,
+ polyToCentroid, polyLength);
float dx = umbraToCentroid.x;
float dy = umbraToCentroid.y;
- float distanceToIntersectPoly = rayIntersectPoints(centroid, dx, dy,
- poly2d[previousPolyIndex], poly2d[(previousPolyIndex + 1) % polyLength]);
+ float distanceToIntersectPoly =
+ rayIntersectPoints(centroid, dx, dy, poly2d[previousPolyIndex],
+ poly2d[(previousPolyIndex + 1) % polyLength]);
if (distanceToIntersectPoly < 0) {
distanceToIntersectPoly = 0;
}
@@ -833,9 +824,9 @@ inline Vector2 getCloserVertex(const Vector2& umbraVertex, const Vector2& centro
* Generate a triangle strip given two convex polygon
**/
void SpotShadow::generateTriangleStrip(bool isCasterOpaque, float shadowStrengthScale,
- Vector2* penumbra, int penumbraLength, Vector2* umbra, int umbraLength,
- const Vector3* poly, int polyLength, VertexBuffer& shadowTriangleStrip,
- const Vector2& centroid) {
+ Vector2* penumbra, int penumbraLength, Vector2* umbra,
+ int umbraLength, const Vector3* poly, int polyLength,
+ VertexBuffer& shadowTriangleStrip, const Vector2& centroid) {
bool hasOccludedUmbraArea = false;
Vector2 poly2d[polyLength];
@@ -891,7 +882,7 @@ void SpotShadow::generateTriangleStrip(bool isCasterOpaque, float shadowStrength
// For each penumbra vertex, find its closet umbra vertex by comparing the
// neighbor umbra vertices.
genNewPenumbraAndPairWithUmbra(penumbra, penumbraLength, umbra, umbraLength, newPenumbra,
- newPenumbraIndex, verticesPair, verticesPairIndex);
+ newPenumbraIndex, verticesPair, verticesPairIndex);
ShadowTessellator::checkOverflow(verticesPairIndex, maxNewPenumbraLength, "Spot pair");
ShadowTessellator::checkOverflow(newPenumbraIndex, maxNewPenumbraLength, "Spot new penumbra");
#if DEBUG_SHADOW
@@ -915,17 +906,15 @@ void SpotShadow::generateTriangleStrip(bool isCasterOpaque, float shadowStrength
const int newPenumbraLength = newPenumbraIndex;
const int totalVertexCount = newPenumbraLength + umbraLength * 2;
const int totalIndexCount = 2 * umbraLength + 2 * verticesPairIndex + 6;
- AlphaVertex* shadowVertices =
- shadowTriangleStrip.alloc<AlphaVertex>(totalVertexCount);
- uint16_t* indexBuffer =
- shadowTriangleStrip.allocIndices<uint16_t>(totalIndexCount);
+ AlphaVertex* shadowVertices = shadowTriangleStrip.alloc<AlphaVertex>(totalVertexCount);
+ uint16_t* indexBuffer = shadowTriangleStrip.allocIndices<uint16_t>(totalIndexCount);
int vertexBufferIndex = 0;
int indexBufferIndex = 0;
// Fill the IB and VB for the penumbra area.
for (int i = 0; i < newPenumbraLength; i++) {
- AlphaVertex::set(&shadowVertices[vertexBufferIndex++], newPenumbra[i].x,
- newPenumbra[i].y, PENUMBRA_ALPHA);
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], newPenumbra[i].x, newPenumbra[i].y,
+ PENUMBRA_ALPHA);
}
// Since the umbra can be a faked one when the occluder is too high, the umbra should be lighter
// in this case.
@@ -933,7 +922,7 @@ void SpotShadow::generateTriangleStrip(bool isCasterOpaque, float shadowStrength
for (int i = 0; i < umbraLength; i++) {
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], umbra[i].x, umbra[i].y,
- scaledUmbraAlpha);
+ scaledUmbraAlpha);
}
for (int i = 0; i < verticesPairIndex; i++) {
@@ -966,21 +955,22 @@ void SpotShadow::generateTriangleStrip(bool isCasterOpaque, float shadowStrength
for (int i = 0; i < umbraLength; i++) {
// Shoot a ray from centroid to each umbra vertices and pick the one with
// shorter distance to the centroid, b/t the umbra vertex or the intersection point.
- Vector2 closerVertex = getCloserVertex(umbra[i], centroid, poly2d, polyLength,
- polyToCentroid, isPositiveCross, previousPolyIndex);
+ Vector2 closerVertex =
+ getCloserVertex(umbra[i], centroid, poly2d, polyLength, polyToCentroid,
+ isPositiveCross, previousPolyIndex);
// We already stored the umbra vertices, just need to add the occlued umbra's ones.
indexBuffer[indexBufferIndex++] = newPenumbraLength + i;
indexBuffer[indexBufferIndex++] = vertexBufferIndex;
- AlphaVertex::set(&shadowVertices[vertexBufferIndex++],
- closerVertex.x, closerVertex.y, scaledUmbraAlpha);
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], closerVertex.x, closerVertex.y,
+ scaledUmbraAlpha);
}
} else {
// If there is no occluded umbra at all, then draw the triangle fan
// starting from the centroid to all umbra vertices.
int lastCentroidIndex = vertexBufferIndex;
- AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid.x,
- centroid.y, scaledUmbraAlpha);
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid.x, centroid.y,
+ scaledUmbraAlpha);
for (int i = 0; i < umbraLength; i++) {
indexBuffer[indexBufferIndex++] = newPenumbraLength + i;
indexBuffer[indexBufferIndex++] = lastCentroidIndex;
@@ -1006,8 +996,7 @@ void SpotShadow::generateTriangleStrip(bool isCasterOpaque, float shadowStrength
/**
* Calculate the bounds for generating random test points.
*/
-void SpotShadow::updateBound(const Vector2 inVector, Vector2& lowerBound,
- Vector2& upperBound) {
+void SpotShadow::updateBound(const Vector2 inVector, Vector2& lowerBound, Vector2& upperBound) {
if (inVector.x < lowerBound.x) {
lowerBound.x = inVector.x;
}
@@ -1046,8 +1035,7 @@ void SpotShadow::dumpPolygon(const Vector3* poly, int polyLength, const char* po
/**
* Test whether the polygon is convex.
*/
-bool SpotShadow::testConvex(const Vector2* polygon, int polygonLength,
- const char* name) {
+bool SpotShadow::testConvex(const Vector2* polygon, int polygonLength, const char* name) {
bool isConvex = true;
for (int i = 0; i < polygonLength; i++) {
Vector2 start = polygon[i];
@@ -1055,13 +1043,13 @@ bool SpotShadow::testConvex(const Vector2* polygon, int polygonLength,
Vector2 end = polygon[(i + 2) % polygonLength];
float delta = (float(middle.x) - start.x) * (float(end.y) - start.y) -
- (float(middle.y) - start.y) * (float(end.x) - start.x);
+ (float(middle.y) - start.y) * (float(end.x) - start.x);
bool isCCWOrCoLinear = (delta >= EPSILON);
if (isCCWOrCoLinear) {
ALOGW("(Error Type 2): polygon (%s) is not a convex b/c start (x %f, y %f),"
- "middle (x %f, y %f) and end (x %f, y %f) , delta is %f !!!",
- name, start.x, start.y, middle.x, middle.y, end.x, end.y, delta);
+ "middle (x %f, y %f) and end (x %f, y %f) , delta is %f !!!",
+ name, start.x, start.y, middle.x, middle.y, end.x, end.y, delta);
isConvex = false;
break;
}
@@ -1074,9 +1062,9 @@ bool SpotShadow::testConvex(const Vector2* polygon, int polygonLength,
* Using Marte Carlo method, we generate a random point, and if it is inside the
* intersection, then it must be inside both source polygons.
*/
-void SpotShadow::testIntersection(const Vector2* poly1, int poly1Length,
- const Vector2* poly2, int poly2Length,
- const Vector2* intersection, int intersectionLength) {
+void SpotShadow::testIntersection(const Vector2* poly1, int poly1Length, const Vector2* poly2,
+ int poly2Length, const Vector2* intersection,
+ int intersectionLength) {
// Find the min and max of x and y.
Vector2 lowerBound = {FLT_MAX, FLT_MAX};
Vector2 upperBound = {-FLT_MAX, -FLT_MAX};
@@ -1102,15 +1090,15 @@ void SpotShadow::testIntersection(const Vector2* poly1, int poly1Length,
if (!testPointInsidePolygon(testPoint, poly1, poly1Length)) {
dumpPoly = true;
ALOGW("(Error Type 1): one point (%f, %f) in the intersection is"
- " not in the poly1",
- testPoint.x, testPoint.y);
+ " not in the poly1",
+ testPoint.x, testPoint.y);
}
if (!testPointInsidePolygon(testPoint, poly2, poly2Length)) {
dumpPoly = true;
ALOGW("(Error Type 1): one point (%f, %f) in the intersection is"
- " not in the poly2",
- testPoint.x, testPoint.y);
+ " not in the poly2",
+ testPoint.x, testPoint.y);
}
}
}
@@ -1128,5 +1116,5 @@ void SpotShadow::testIntersection(const Vector2* poly1, int poly1Length,
}
#endif
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/SpotShadow.h b/libs/hwui/SpotShadow.h
index 6108bb6bd585..8476be70318b 100644
--- a/libs/hwui/SpotShadow.h
+++ b/libs/hwui/SpotShadow.h
@@ -27,22 +27,22 @@ class VertexBuffer;
class SpotShadow {
public:
- static void createSpotShadow(bool isCasterOpaque, const Vector3& lightCenter,
- float lightSize, const Vector3* poly, int polyLength,
- const Vector3& polyCentroid, VertexBuffer& retstrips);
+ static void createSpotShadow(bool isCasterOpaque, const Vector3& lightCenter, float lightSize,
+ const Vector3* poly, int polyLength, const Vector3& polyCentroid,
+ VertexBuffer& retstrips);
private:
struct VertexAngleData;
- static float projectCasterToOutline(Vector2& outline,
- const Vector3& lightCenter, const Vector3& polyVertex);
+ static float projectCasterToOutline(Vector2& outline, const Vector3& lightCenter,
+ const Vector3& polyVertex);
- static void computeLightPolygon(int points, const Vector3& lightCenter,
- float size, Vector3* ret);
+ static void computeLightPolygon(int points, const Vector3& lightCenter, float size,
+ Vector3* ret);
static void smoothPolygon(int level, int rays, float* rayDist);
- static float rayIntersectPoly(const Vector2* poly, int polyLength,
- const Vector2& point, float dx, float dy);
+ static float rayIntersectPoly(const Vector2* poly, int polyLength, const Vector2& point,
+ float dx, float dy);
static void xsort(Vector2* points, int pointsLength);
static int hull(Vector2* points, int pointsLength, Vector2* retPoly);
@@ -57,23 +57,23 @@ private:
static void reverse(Vector2* polygon, int len);
static void generateTriangleStrip(bool isCasterOpaque, float shadowStrengthScale,
- Vector2* penumbra, int penumbraLength, Vector2* umbra, int umbraLength,
- const Vector3* poly, int polyLength, VertexBuffer& retstrips, const Vector2& centroid);
+ Vector2* penumbra, int penumbraLength, Vector2* umbra,
+ int umbraLength, const Vector3* poly, int polyLength,
+ VertexBuffer& retstrips, const Vector2& centroid);
#if DEBUG_SHADOW
- static bool testConvex(const Vector2* polygon, int polygonLength,
- const char* name);
- static void testIntersection(const Vector2* poly1, int poly1Length,
- const Vector2* poly2, int poly2Length,
- const Vector2* intersection, int intersectionLength);
- static void updateBound(const Vector2 inVector, Vector2& lowerBound, Vector2& upperBound );
+ static bool testConvex(const Vector2* polygon, int polygonLength, const char* name);
+ static void testIntersection(const Vector2* poly1, int poly1Length, const Vector2* poly2,
+ int poly2Length, const Vector2* intersection,
+ int intersectionLength);
+ static void updateBound(const Vector2 inVector, Vector2& lowerBound, Vector2& upperBound);
static void dumpPolygon(const Vector2* poly, int polyLength, const char* polyName);
static void dumpPolygon(const Vector3* poly, int polyLength, const char* polyName);
#endif
-}; // SpotShadow
+}; // SpotShadow
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_SPOT_SHADOW_H
+#endif // ANDROID_HWUI_SPOT_SHADOW_H
diff --git a/libs/hwui/SwapBehavior.h b/libs/hwui/SwapBehavior.h
index 4091670cabe8..3a176d7bfbcc 100644
--- a/libs/hwui/SwapBehavior.h
+++ b/libs/hwui/SwapBehavior.h
@@ -26,8 +26,8 @@ enum class SwapBehavior {
kSwap_discardBuffer,
};
-} // namespace renderthread
-} //namespace uirenderer
-} // namespace android
+} // namespace renderthread
+} // namespace uirenderer
+} // namespace android
-#endif //HWUI_SWAPBEHAVIOR_H
+#endif // HWUI_SWAPBEHAVIOR_H
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index 63bf7bc443e0..c7d93da718e7 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -45,7 +45,8 @@ TessellationCache::Description::Description()
memset(&shape, 0, sizeof(Shape));
}
-TessellationCache::Description::Description(Type type, const Matrix4& transform, const SkPaint& paint)
+TessellationCache::Description::Description(Type type, const Matrix4& transform,
+ const SkPaint& paint)
: type(type)
, aa(paint.isAntiAlias())
, cap(paint.getStrokeCap())
@@ -82,7 +83,7 @@ hash_t TessellationCache::Description::hash() const {
hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
hash = JenkinsHashMix(hash, android::hash_type(scaleX));
hash = JenkinsHashMix(hash, android::hash_type(scaleY));
- hash = JenkinsHashMixBytes(hash, (uint8_t*) &shape, sizeof(Shape));
+ hash = JenkinsHashMixBytes(hash, (uint8_t*)&shape, sizeof(Shape));
return JenkinsHashWhiten(hash);
}
@@ -94,25 +95,24 @@ void TessellationCache::Description::setupMatrixAndPaint(Matrix4* matrix, SkPain
paint->setStrokeWidth(strokeWidth);
}
-TessellationCache::ShadowDescription::ShadowDescription()
- : nodeKey(nullptr) {
+TessellationCache::ShadowDescription::ShadowDescription() : nodeKey(nullptr) {
memset(&matrixData, 0, sizeof(matrixData));
}
-TessellationCache::ShadowDescription::ShadowDescription(const SkPath* nodeKey, const Matrix4* drawTransform)
+TessellationCache::ShadowDescription::ShadowDescription(const SkPath* nodeKey,
+ const Matrix4* drawTransform)
: nodeKey(nodeKey) {
memcpy(&matrixData, drawTransform->data, sizeof(matrixData));
}
bool TessellationCache::ShadowDescription::operator==(
const TessellationCache::ShadowDescription& rhs) const {
- return nodeKey == rhs.nodeKey
- && memcmp(&matrixData, &rhs.matrixData, sizeof(matrixData)) == 0;
+ return nodeKey == rhs.nodeKey && memcmp(&matrixData, &rhs.matrixData, sizeof(matrixData)) == 0;
}
hash_t TessellationCache::ShadowDescription::hash() const {
- uint32_t hash = JenkinsHashMixBytes(0, (uint8_t*) &nodeKey, sizeof(const void*));
- hash = JenkinsHashMixBytes(hash, (uint8_t*) &matrixData, sizeof(matrixData));
+ uint32_t hash = JenkinsHashMixBytes(0, (uint8_t*)&nodeKey, sizeof(const void*));
+ hash = JenkinsHashMixBytes(hash, (uint8_t*)&matrixData, sizeof(matrixData));
return JenkinsHashWhiten(hash);
}
@@ -123,9 +123,7 @@ hash_t TessellationCache::ShadowDescription::hash() const {
class TessellationCache::TessellationTask : public Task<VertexBuffer*> {
public:
TessellationTask(Tessellator tessellator, const Description& description)
- : tessellator(tessellator)
- , description(description) {
- }
+ : tessellator(tessellator), description(description) {}
~TessellationTask() {}
@@ -135,8 +133,7 @@ public:
class TessellationCache::TessellationProcessor : public TaskProcessor<VertexBuffer*> {
public:
- explicit TessellationProcessor(Caches& caches)
- : TaskProcessor<VertexBuffer*>(&caches.tasks) {}
+ explicit TessellationProcessor(Caches& caches) : TaskProcessor<VertexBuffer*>(&caches.tasks) {}
~TessellationProcessor() {}
virtual void onProcess(const sp<Task<VertexBuffer*> >& task) override {
@@ -149,10 +146,7 @@ public:
class TessellationCache::Buffer {
public:
- explicit Buffer(const sp<Task<VertexBuffer*> >& task)
- : mTask(task)
- , mBuffer(nullptr) {
- }
+ explicit Buffer(const sp<Task<VertexBuffer*> >& task) : mTask(task), mBuffer(nullptr) {}
~Buffer() {
mTask.clear();
@@ -203,18 +197,15 @@ static void reverseVertexArray(Vertex* polygon, int len) {
}
}
-void tessellateShadows(
- const Matrix4* drawTransform, const Rect* localClip,
- bool isCasterOpaque, const SkPath* casterPerimeter,
- const Matrix4* casterTransformXY, const Matrix4* casterTransformZ,
- const Vector3& lightCenter, float lightRadius,
- VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer) {
-
+void tessellateShadows(const Matrix4* drawTransform, const Rect* localClip, bool isCasterOpaque,
+ const SkPath* casterPerimeter, const Matrix4* casterTransformXY,
+ const Matrix4* casterTransformZ, const Vector3& lightCenter,
+ float lightRadius, VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer) {
// tessellate caster outline into a 2d polygon
std::vector<Vertex> casterVertices2d;
const float casterRefinementThreshold = 2.0f;
- PathTessellator::approximatePathOutlineVertices(*casterPerimeter,
- casterRefinementThreshold, casterVertices2d);
+ PathTessellator::approximatePathOutlineVertices(*casterPerimeter, casterRefinementThreshold,
+ casterVertices2d);
// Shadow requires CCW for now. TODO: remove potential double-reverse
reverseVertexArray(&casterVertices2d.front(), casterVertices2d.size());
@@ -235,9 +226,8 @@ void tessellateShadows(
}
// map the centroid of the caster into 3d
- Vector2 centroid = ShadowTessellator::centroid2d(
- reinterpret_cast<const Vector2*>(&casterVertices2d.front()),
- casterVertexCount);
+ Vector2 centroid = ShadowTessellator::centroid2d(
+ reinterpret_cast<const Vector2*>(&casterVertices2d.front()), casterVertexCount);
Vector3 centroid3d = {centroid.x, centroid.y, 0};
mapPointFakeZ(centroid3d, casterTransformXY, casterTransformZ);
@@ -257,14 +247,13 @@ void tessellateShadows(
casterTransformXY->mapRect(casterBounds);
// actual tessellation of both shadows
- ShadowTessellator::tessellateAmbientShadow(
- isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
- casterBounds, *localClip, maxZ, ambientBuffer);
-
- ShadowTessellator::tessellateSpotShadow(
- isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
- *drawTransform, lightCenter, lightRadius, casterBounds, *localClip,
- spotBuffer);
+ ShadowTessellator::tessellateAmbientShadow(isCasterOpaque, casterPolygon, casterVertexCount,
+ centroid3d, casterBounds, *localClip, maxZ,
+ ambientBuffer);
+
+ ShadowTessellator::tessellateSpotShadow(isCasterOpaque, casterPolygon, casterVertexCount,
+ centroid3d, *drawTransform, lightCenter, lightRadius,
+ casterBounds, *localClip, spotBuffer);
}
class ShadowProcessor : public TaskProcessor<TessellationCache::vertexBuffer_pair_t> {
@@ -278,8 +267,8 @@ public:
ATRACE_NAME("shadow tessellation");
tessellateShadows(&t->drawTransform, &t->localClip, t->opaque, &t->casterPerimeter,
- &t->transformXY, &t->transformZ, t->lightCenter, t->lightRadius,
- t->ambientBuffer, t->spotBuffer);
+ &t->transformXY, &t->transformZ, t->lightCenter, t->lightRadius,
+ t->ambientBuffer, t->spotBuffer);
t->setResult(TessellationCache::vertexBuffer_pair_t(&t->ambientBuffer, &t->spotBuffer));
}
@@ -292,7 +281,8 @@ public:
TessellationCache::TessellationCache()
: mMaxSize(MB(1))
, mCache(LruCache<Description, Buffer*>::kUnlimitedCapacity)
- , mShadowCache(LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) {
+ , mShadowCache(
+ LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) {
mCache.setOnEntryRemovedListener(&mBufferRemovedListener);
mShadowCache.setOnEntryRemovedListener(&mBufferPairRemovedListener);
mDebugEnabled = Properties::debugLevel & kDebugCaches;
@@ -323,7 +313,6 @@ uint32_t TessellationCache::getMaxSize() {
// Caching
///////////////////////////////////////////////////////////////////////////////
-
void TessellationCache::trim() {
uint32_t size = getSize();
while (size > mMaxSize) {
@@ -343,7 +332,7 @@ void TessellationCache::clear() {
///////////////////////////////////////////////////////////////////////////////
void TessellationCache::BufferRemovedListener::operator()(Description& description,
- Buffer*& buffer) {
+ Buffer*& buffer) {
delete buffer;
}
@@ -352,32 +341,31 @@ void TessellationCache::BufferRemovedListener::operator()(Description& descripti
///////////////////////////////////////////////////////////////////////////////
void TessellationCache::precacheShadows(const Matrix4* drawTransform, const Rect& localClip,
- bool opaque, const SkPath* casterPerimeter,
- const Matrix4* transformXY, const Matrix4* transformZ,
- const Vector3& lightCenter, float lightRadius) {
+ bool opaque, const SkPath* casterPerimeter,
+ const Matrix4* transformXY, const Matrix4* transformZ,
+ const Vector3& lightCenter, float lightRadius) {
ShadowDescription key(casterPerimeter, drawTransform);
if (mShadowCache.get(key)) return;
- sp<ShadowTask> task = new ShadowTask(drawTransform, localClip, opaque,
- casterPerimeter, transformXY, transformZ, lightCenter, lightRadius);
+ sp<ShadowTask> task = new ShadowTask(drawTransform, localClip, opaque, casterPerimeter,
+ transformXY, transformZ, lightCenter, lightRadius);
if (mShadowProcessor == nullptr) {
mShadowProcessor = new ShadowProcessor(Caches::getInstance());
}
mShadowProcessor->add(task);
- task->incStrong(nullptr); // not using sp<>s, so manually ref while in the cache
+ task->incStrong(nullptr); // not using sp<>s, so manually ref while in the cache
mShadowCache.put(key, task.get());
}
sp<TessellationCache::ShadowTask> TessellationCache::getShadowTask(
- const Matrix4* drawTransform, const Rect& localClip,
- bool opaque, const SkPath* casterPerimeter,
- const Matrix4* transformXY, const Matrix4* transformZ,
+ const Matrix4* drawTransform, const Rect& localClip, bool opaque,
+ const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ,
const Vector3& lightCenter, float lightRadius) {
ShadowDescription key(casterPerimeter, drawTransform);
ShadowTask* task = static_cast<ShadowTask*>(mShadowCache.get(key));
if (!task) {
- precacheShadows(drawTransform, localClip, opaque, casterPerimeter,
- transformXY, transformZ, lightCenter, lightRadius);
+ precacheShadows(drawTransform, localClip, opaque, casterPerimeter, transformXY, transformZ,
+ lightCenter, lightRadius);
task = static_cast<ShadowTask*>(mShadowCache.get(key));
}
LOG_ALWAYS_FATAL_IF(task == nullptr, "shadow not precached");
@@ -388,8 +376,8 @@ sp<TessellationCache::ShadowTask> TessellationCache::getShadowTask(
// Tessellation precaching
///////////////////////////////////////////////////////////////////////////////
-TessellationCache::Buffer* TessellationCache::getOrCreateBuffer(
- const Description& entry, Tessellator tessellator) {
+TessellationCache::Buffer* TessellationCache::getOrCreateBuffer(const Description& entry,
+ Tessellator tessellator) {
Buffer* buffer = mCache.get(entry);
if (!buffer) {
// not cached, enqueue a task to fill the buffer
@@ -408,7 +396,7 @@ TessellationCache::Buffer* TessellationCache::getOrCreateBuffer(
}
static VertexBuffer* tessellatePath(const TessellationCache::Description& description,
- const SkPath& path) {
+ const SkPath& path) {
Matrix4 matrix;
SkPaint paint;
description.setupMatrixAndPaint(&matrix, &paint);
@@ -422,8 +410,8 @@ static VertexBuffer* tessellatePath(const TessellationCache::Description& descri
///////////////////////////////////////////////////////////////////////////////
static VertexBuffer* tessellateRoundRect(const TessellationCache::Description& description) {
- SkRect rect = SkRect::MakeWH(description.shape.roundRect.width,
- description.shape.roundRect.height);
+ SkRect rect =
+ SkRect::MakeWH(description.shape.roundRect.width, description.shape.roundRect.height);
float rx = description.shape.roundRect.rx;
float ry = description.shape.roundRect.ry;
if (description.style == SkPaint::kStrokeAndFill_Style) {
@@ -437,9 +425,9 @@ static VertexBuffer* tessellateRoundRect(const TessellationCache::Description& d
return tessellatePath(description, path);
}
-TessellationCache::Buffer* TessellationCache::getRoundRectBuffer(
- const Matrix4& transform, const SkPaint& paint,
- float width, float height, float rx, float ry) {
+TessellationCache::Buffer* TessellationCache::getRoundRectBuffer(const Matrix4& transform,
+ const SkPaint& paint, float width,
+ float height, float rx, float ry) {
Description entry(Description::Type::RoundRect, transform, paint);
entry.shape.roundRect.width = width;
entry.shape.roundRect.height = height;
@@ -448,9 +436,9 @@ TessellationCache::Buffer* TessellationCache::getRoundRectBuffer(
return getOrCreateBuffer(entry, &tessellateRoundRect);
}
const VertexBuffer* TessellationCache::getRoundRect(const Matrix4& transform, const SkPaint& paint,
- float width, float height, float rx, float ry) {
+ float width, float height, float rx, float ry) {
return getRoundRectBuffer(transform, paint, width, height, rx, ry)->getVertexBuffer();
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/TessellationCache.h b/libs/hwui/TessellationCache.h
index ccad1b7bd415..a0f0ed4653e0 100644
--- a/libs/hwui/TessellationCache.h
+++ b/libs/hwui/TessellationCache.h
@@ -90,17 +90,16 @@ public:
class ShadowTask : public Task<vertexBuffer_pair_t> {
public:
ShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
- const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ,
- const Vector3& lightCenter, float lightRadius)
- : drawTransform(*drawTransform)
- , localClip(localClip)
- , opaque(opaque)
- , casterPerimeter(*casterPerimeter)
- , transformXY(*transformXY)
- , transformZ(*transformZ)
- , lightCenter(lightCenter)
- , lightRadius(lightRadius) {
- }
+ const SkPath* casterPerimeter, const Matrix4* transformXY,
+ const Matrix4* transformZ, const Vector3& lightCenter, float lightRadius)
+ : drawTransform(*drawTransform)
+ , localClip(localClip)
+ , opaque(opaque)
+ , casterPerimeter(*casterPerimeter)
+ , transformXY(*transformXY)
+ , transformZ(*transformZ)
+ , lightCenter(lightCenter)
+ , lightRadius(lightRadius) {}
/* Note - we deep copy all task parameters, because *even though* pointers into Allocator
* controlled objects (like the SkPath and Matrix4s) should be safe for the entire frame,
@@ -153,17 +152,17 @@ public:
// TODO: precache/get for Oval, Lines, Points, etc.
- void precacheRoundRect(const Matrix4& transform, const SkPaint& paint,
- float width, float height, float rx, float ry) {
+ void precacheRoundRect(const Matrix4& transform, const SkPaint& paint, float width,
+ float height, float rx, float ry) {
getRoundRectBuffer(transform, paint, width, height, rx, ry);
}
- const VertexBuffer* getRoundRect(const Matrix4& transform, const SkPaint& paint,
- float width, float height, float rx, float ry);
+ const VertexBuffer* getRoundRect(const Matrix4& transform, const SkPaint& paint, float width,
+ float height, float rx, float ry);
- sp<ShadowTask> getShadowTask(const Matrix4* drawTransform, const Rect& localClip,
- bool opaque, const SkPath* casterPerimeter,
- const Matrix4* transformXY, const Matrix4* transformZ,
- const Vector3& lightCenter, float lightRadius);
+ sp<ShadowTask> getShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
+ const SkPath* casterPerimeter, const Matrix4* transformXY,
+ const Matrix4* transformZ, const Vector3& lightCenter,
+ float lightRadius);
private:
class Buffer;
@@ -172,15 +171,14 @@ private:
typedef VertexBuffer* (*Tessellator)(const Description&);
- void precacheShadows(const Matrix4* drawTransform, const Rect& localClip,
- bool opaque, const SkPath* casterPerimeter,
- const Matrix4* transformXY, const Matrix4* transformZ,
- const Vector3& lightCenter, float lightRadius);
+ void precacheShadows(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
+ const SkPath* casterPerimeter, const Matrix4* transformXY,
+ const Matrix4* transformZ, const Vector3& lightCenter, float lightRadius);
- Buffer* getRectBuffer(const Matrix4& transform, const SkPaint& paint,
- float width, float height);
- Buffer* getRoundRectBuffer(const Matrix4& transform, const SkPaint& paint,
- float width, float height, float rx, float ry);
+ Buffer* getRectBuffer(const Matrix4& transform, const SkPaint& paint, float width,
+ float height);
+ Buffer* getRoundRectBuffer(const Matrix4& transform, const SkPaint& paint, float width,
+ float height, float rx, float ry);
Buffer* getOrCreateBuffer(const Description& entry, Tessellator tessellator);
@@ -207,21 +205,21 @@ private:
// holds a pointer, and implicit strong ref to each shadow task of the frame
LruCache<ShadowDescription, Task<vertexBuffer_pair_t>*> mShadowCache;
- class BufferPairRemovedListener : public OnEntryRemoved<ShadowDescription, Task<vertexBuffer_pair_t>*> {
- void operator()(ShadowDescription& description, Task<vertexBuffer_pair_t>*& bufferPairTask) override {
+ class BufferPairRemovedListener
+ : public OnEntryRemoved<ShadowDescription, Task<vertexBuffer_pair_t>*> {
+ void operator()(ShadowDescription& description,
+ Task<vertexBuffer_pair_t>*& bufferPairTask) override {
bufferPairTask->decStrong(nullptr);
}
};
BufferPairRemovedListener mBufferPairRemovedListener;
-}; // class TessellationCache
+}; // class TessellationCache
-void tessellateShadows(
- const Matrix4* drawTransform, const Rect* localClip,
- bool isCasterOpaque, const SkPath* casterPerimeter,
- const Matrix4* casterTransformXY, const Matrix4* casterTransformZ,
- const Vector3& lightCenter, float lightRadius,
- VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer);
+void tessellateShadows(const Matrix4* drawTransform, const Rect* localClip, bool isCasterOpaque,
+ const SkPath* casterPerimeter, const Matrix4* casterTransformXY,
+ const Matrix4* casterTransformZ, const Vector3& lightCenter,
+ float lightRadius, VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer);
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index c521892c69df..c892ceb3e14d 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -19,8 +19,8 @@
#include "Caches.h"
#include "Debug.h"
#include "FontRenderer.h"
-#include "TextDropShadowCache.h"
#include "Properties.h"
+#include "TextDropShadowCache.h"
namespace android {
namespace uirenderer {
@@ -38,8 +38,7 @@ hash_t ShadowText::hash() const {
hash = JenkinsHashMix(hash, android::hash_type(italicStyle));
hash = JenkinsHashMix(hash, android::hash_type(scaleX));
if (glyphs) {
- hash = JenkinsHashMixShorts(
- hash, reinterpret_cast<const uint16_t*>(glyphs), glyphCount);
+ hash = JenkinsHashMixShorts(hash, reinterpret_cast<const uint16_t*>(glyphs), glyphCount);
}
if (positions) {
for (uint32_t i = 0; i < glyphCount * 2; i++) {
@@ -146,15 +145,15 @@ void TextDropShadowCache::clear() {
}
ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
- float radius, const float* positions) {
+ float radius, const float* positions) {
ShadowText entry(paint, radius, numGlyphs, glyphs, positions);
ShadowTexture* texture = mCache.get(entry);
if (!texture) {
SkPaint paintCopy(*paint);
paintCopy.setTextAlign(SkPaint::kLeft_Align);
- FontRenderer::DropShadow shadow = mRenderer->renderDropShadow(&paintCopy, glyphs, numGlyphs,
- radius, positions);
+ FontRenderer::DropShadow shadow =
+ mRenderer->renderDropShadow(&paintCopy, glyphs, numGlyphs, radius, positions);
if (!shadow.image) {
return nullptr;
@@ -174,14 +173,15 @@ ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const glyph_t* gly
if (size < mMaxSize) {
while (mSize + size > mMaxSize) {
LOG_ALWAYS_FATAL_IF(!mCache.removeOldest(),
- "Failed to remove oldest from cache. mSize = %"
- PRIu32 ", mCache.size() = %zu", mSize, mCache.size());
+ "Failed to remove oldest from cache. mSize = %" PRIu32
+ ", mCache.size() = %zu",
+ mSize, mCache.size());
}
}
// Textures are Alpha8
- texture->upload(GL_ALPHA, shadow.width, shadow.height,
- GL_ALPHA, GL_UNSIGNED_BYTE, shadow.image);
+ texture->upload(GL_ALPHA, shadow.width, shadow.height, GL_ALPHA, GL_UNSIGNED_BYTE,
+ shadow.image);
texture->setFilter(GL_LINEAR);
texture->setWrap(GL_CLAMP_TO_EDGE);
@@ -205,5 +205,5 @@ ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const glyph_t* gly
return texture;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h
index 13e87749029a..86a012970f17 100644
--- a/libs/hwui/TextDropShadowCache.h
+++ b/libs/hwui/TextDropShadowCache.h
@@ -24,8 +24,8 @@
#include <utils/LruCache.h>
#include <utils/String16.h>
-#include "font/Font.h"
#include "Texture.h"
+#include "font/Font.h"
namespace android {
namespace uirenderer {
@@ -34,13 +34,20 @@ class Caches;
class FontRenderer;
struct ShadowText {
- ShadowText(): glyphCount(0), radius(0.0f), textSize(0.0f), typeface(nullptr),
- flags(0), italicStyle(0.0f), scaleX(0), glyphs(nullptr), positions(nullptr) {
- }
+ ShadowText()
+ : glyphCount(0)
+ , radius(0.0f)
+ , textSize(0.0f)
+ , typeface(nullptr)
+ , flags(0)
+ , italicStyle(0.0f)
+ , scaleX(0)
+ , glyphs(nullptr)
+ , positions(nullptr) {}
// len is the number of bytes in text
ShadowText(const SkPaint* paint, float radius, uint32_t glyphCount, const glyph_t* srcGlyphs,
- const float* positions)
+ const float* positions)
: glyphCount(glyphCount)
, radius(radius)
, textSize(paint->getTextSize())
@@ -49,23 +56,17 @@ struct ShadowText {
, italicStyle(paint->getTextSkewX())
, scaleX(paint->getTextScaleX())
, glyphs(srcGlyphs)
- , positions(positions) {
- }
+ , positions(positions) {}
- ~ShadowText() {
- }
+ ~ShadowText() {}
hash_t hash() const;
static int compare(const ShadowText& lhs, const ShadowText& rhs);
- bool operator==(const ShadowText& other) const {
- return compare(*this, other) == 0;
- }
+ bool operator==(const ShadowText& other) const { return compare(*this, other) == 0; }
- bool operator!=(const ShadowText& other) const {
- return compare(*this, other) != 0;
- }
+ bool operator!=(const ShadowText& other) const { return compare(*this, other) != 0; }
void copyTextLocally() {
str.setTo(reinterpret_cast<const char16_t*>(glyphs), glyphCount);
@@ -91,7 +92,7 @@ struct ShadowText {
String16 str;
Vector<float> positionsCopy;
-}; // struct ShadowText
+}; // struct ShadowText
// Caching support
@@ -110,15 +111,14 @@ inline hash_t hash_type(const ShadowText& entry) {
/**
* Alpha texture used to represent a shadow.
*/
-struct ShadowTexture: public Texture {
- explicit ShadowTexture(Caches& caches): Texture(caches) {
- }
+struct ShadowTexture : public Texture {
+ explicit ShadowTexture(Caches& caches) : Texture(caches) {}
float left;
float top;
-}; // struct ShadowTexture
+}; // struct ShadowTexture
-class TextDropShadowCache: public OnEntryRemoved<ShadowText, ShadowTexture*> {
+class TextDropShadowCache : public OnEntryRemoved<ShadowText, ShadowTexture*> {
public:
TextDropShadowCache();
explicit TextDropShadowCache(uint32_t maxByteSize);
@@ -130,17 +130,15 @@ public:
*/
void operator()(ShadowText& text, ShadowTexture*& texture) override;
- ShadowTexture* get(const SkPaint* paint, const glyph_t* text,
- int numGlyphs, float radius, const float* positions);
+ ShadowTexture* get(const SkPaint* paint, const glyph_t* text, int numGlyphs, float radius,
+ const float* positions);
/**
* Clears the cache. This causes all textures to be deleted.
*/
void clear();
- void setFontRenderer(FontRenderer& fontRenderer) {
- mRenderer = &fontRenderer;
- }
+ void setFontRenderer(FontRenderer& fontRenderer) { mRenderer = &fontRenderer; }
/**
* Returns the maximum size of the cache in bytes.
@@ -158,9 +156,9 @@ private:
const uint32_t mMaxSize;
FontRenderer* mRenderer = nullptr;
bool mDebugEnabled;
-}; // class TextDropShadowCache
+}; // class TextDropShadowCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_TEXT_DROP_SHADOW_CACHE_H
+#endif // ANDROID_HWUI_TEXT_DROP_SHADOW_CACHE_H
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index b7c1e290370f..1e90eebe3bb8 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include "Caches.h"
#include "Texture.h"
+#include "Caches.h"
#include "utils/GLUtils.h"
#include "utils/MathUtils.h"
#include "utils/TraceUtils.h"
@@ -32,22 +32,22 @@ namespace uirenderer {
// Number of bytes used by a texture in the given format
static int bytesPerPixel(GLint glFormat) {
switch (glFormat) {
- // The wrapped-texture case, usually means a SurfaceTexture
- case 0:
- return 0;
- case GL_LUMINANCE:
- case GL_ALPHA:
- return 1;
- case GL_SRGB8:
- case GL_RGB:
- return 3;
- case GL_SRGB8_ALPHA8:
- case GL_RGBA:
- return 4;
- case GL_RGBA16F:
- return 8;
- default:
- LOG_ALWAYS_FATAL("UNKNOWN FORMAT 0x%x", glFormat);
+ // The wrapped-texture case, usually means a SurfaceTexture
+ case 0:
+ return 0;
+ case GL_LUMINANCE:
+ case GL_ALPHA:
+ return 1;
+ case GL_SRGB8:
+ case GL_RGB:
+ return 3;
+ case GL_SRGB8_ALPHA8:
+ case GL_RGBA:
+ return 4;
+ case GL_RGBA16F:
+ return 8;
+ default:
+ LOG_ALWAYS_FATAL("UNKNOWN FORMAT 0x%x", glFormat);
}
}
@@ -92,13 +92,10 @@ void Texture::deleteTexture() {
}
}
-bool Texture::updateLayout(uint32_t width, uint32_t height, GLint internalFormat,
- GLint format, GLenum target) {
- if (mWidth == width
- && mHeight == height
- && mFormat == format
- && mInternalFormat == internalFormat
- && mTarget == target) {
+bool Texture::updateLayout(uint32_t width, uint32_t height, GLint internalFormat, GLint format,
+ GLenum target) {
+ if (mWidth == width && mHeight == height && mFormat == format &&
+ mInternalFormat == internalFormat && mTarget == target) {
return false;
}
mWidth = width;
@@ -117,8 +114,8 @@ void Texture::resetCachedParams() {
mMagFilter = GL_LINEAR;
}
-void Texture::upload(GLint internalFormat, uint32_t width, uint32_t height,
- GLenum format, GLenum type, const void* pixels) {
+void Texture::upload(GLint internalFormat, uint32_t width, uint32_t height, GLenum format,
+ GLenum type, const void* pixels) {
GL_CHECKPOINT(MODERATE);
// We don't have color space information, we assume the data is gamma encoded
@@ -132,11 +129,9 @@ void Texture::upload(GLint internalFormat, uint32_t width, uint32_t height,
}
mCaches.textureState().bindTexture(GL_TEXTURE_2D, mId);
if (needsAlloc) {
- glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, mWidth, mHeight, 0,
- format, type, pixels);
+ glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, mWidth, mHeight, 0, format, type, pixels);
} else if (pixels) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, internalFormat, mWidth, mHeight, 0,
- format, type, pixels);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, internalFormat, mWidth, mHeight, 0, format, type, pixels);
}
GL_CHECKPOINT(MODERATE);
}
@@ -148,15 +143,15 @@ void Texture::uploadHardwareBitmapToTexture(GraphicBuffer* buffer) {
mEglImageHandle = EGL_NO_IMAGE_KHR;
}
mEglImageHandle = eglCreateImageKHR(eglDisplayHandle, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
- buffer->getNativeBuffer(), 0);
+ buffer->getNativeBuffer(), 0);
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, mEglImageHandle);
}
static void uploadToTexture(bool resize, GLint internalFormat, GLenum format, GLenum type,
- GLsizei stride, GLsizei bpp, GLsizei width, GLsizei height, const GLvoid * data) {
-
- const bool useStride = stride != width
- && Caches::getInstance().extensions().hasUnpackRowLength();
+ GLsizei stride, GLsizei bpp, GLsizei width, GLsizei height,
+ const GLvoid* data) {
+ const bool useStride =
+ stride != width && Caches::getInstance().extensions().hasUnpackRowLength();
if ((stride == width) || useStride) {
if (useStride) {
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
@@ -175,11 +170,11 @@ static void uploadToTexture(bool resize, GLint internalFormat, GLenum format, GL
// With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
// if the stride doesn't match the width
- GLvoid * temp = (GLvoid *) malloc(width * height * bpp);
+ GLvoid* temp = (GLvoid*)malloc(width * height * bpp);
if (!temp) return;
- uint8_t * pDst = (uint8_t *)temp;
- uint8_t * pSrc = (uint8_t *)data;
+ uint8_t* pDst = (uint8_t*)temp;
+ uint8_t* pSrc = (uint8_t*)data;
for (GLsizei i = 0; i < height; i++) {
memcpy(pDst, pSrc, width * bpp);
pDst += width * bpp;
@@ -196,69 +191,70 @@ static void uploadToTexture(bool resize, GLint internalFormat, GLenum format, GL
}
}
-void Texture::colorTypeToGlFormatAndType(const Caches& caches, SkColorType colorType,
- bool needSRGB, GLint* outInternalFormat, GLint* outFormat, GLint* outType) {
+void Texture::colorTypeToGlFormatAndType(const Caches& caches, SkColorType colorType, bool needSRGB,
+ GLint* outInternalFormat, GLint* outFormat,
+ GLint* outType) {
switch (colorType) {
- case kAlpha_8_SkColorType:
- *outFormat = GL_ALPHA;
- *outInternalFormat = GL_ALPHA;
- *outType = GL_UNSIGNED_BYTE;
- break;
- case kRGB_565_SkColorType:
- if (needSRGB) {
- // We would ideally use a GL_RGB/GL_SRGB8 texture but the
- // intermediate Skia bitmap needs to be ARGB_8888
- *outFormat = GL_RGBA;
- *outInternalFormat = caches.rgbaInternalFormat();
+ case kAlpha_8_SkColorType:
+ *outFormat = GL_ALPHA;
+ *outInternalFormat = GL_ALPHA;
*outType = GL_UNSIGNED_BYTE;
- } else {
- *outFormat = GL_RGB;
- *outInternalFormat = GL_RGB;
- *outType = GL_UNSIGNED_SHORT_5_6_5;
- }
- break;
- // ARGB_4444 is upconverted to RGBA_8888
- case kARGB_4444_SkColorType:
- case kN32_SkColorType:
- *outFormat = GL_RGBA;
- *outInternalFormat = caches.rgbaInternalFormat(needSRGB);
- *outType = GL_UNSIGNED_BYTE;
- break;
- case kGray_8_SkColorType:
- *outFormat = GL_LUMINANCE;
- *outInternalFormat = GL_LUMINANCE;
- *outType = GL_UNSIGNED_BYTE;
- break;
- case kRGBA_F16_SkColorType:
- if (caches.extensions().getMajorGlVersion() >= 3) {
- // This format is always linear
- *outFormat = GL_RGBA;
- *outInternalFormat = GL_RGBA16F;
- *outType = GL_HALF_FLOAT;
- } else {
+ break;
+ case kRGB_565_SkColorType:
+ if (needSRGB) {
+ // We would ideally use a GL_RGB/GL_SRGB8 texture but the
+ // intermediate Skia bitmap needs to be ARGB_8888
+ *outFormat = GL_RGBA;
+ *outInternalFormat = caches.rgbaInternalFormat();
+ *outType = GL_UNSIGNED_BYTE;
+ } else {
+ *outFormat = GL_RGB;
+ *outInternalFormat = GL_RGB;
+ *outType = GL_UNSIGNED_SHORT_5_6_5;
+ }
+ break;
+ // ARGB_4444 is upconverted to RGBA_8888
+ case kARGB_4444_SkColorType:
+ case kN32_SkColorType:
*outFormat = GL_RGBA;
- *outInternalFormat = caches.rgbaInternalFormat(true);
+ *outInternalFormat = caches.rgbaInternalFormat(needSRGB);
*outType = GL_UNSIGNED_BYTE;
- }
- break;
- default:
- LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", colorType);
- break;
+ break;
+ case kGray_8_SkColorType:
+ *outFormat = GL_LUMINANCE;
+ *outInternalFormat = GL_LUMINANCE;
+ *outType = GL_UNSIGNED_BYTE;
+ break;
+ case kRGBA_F16_SkColorType:
+ if (caches.extensions().getMajorGlVersion() >= 3) {
+ // This format is always linear
+ *outFormat = GL_RGBA;
+ *outInternalFormat = GL_RGBA16F;
+ *outType = GL_HALF_FLOAT;
+ } else {
+ *outFormat = GL_RGBA;
+ *outInternalFormat = caches.rgbaInternalFormat(true);
+ *outType = GL_UNSIGNED_BYTE;
+ }
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", colorType);
+ break;
}
}
SkBitmap Texture::uploadToN32(const SkBitmap& bitmap, bool hasLinearBlending,
- sk_sp<SkColorSpace> sRGB) {
+ sk_sp<SkColorSpace> sRGB) {
SkBitmap rgbaBitmap;
rgbaBitmap.allocPixels(SkImageInfo::MakeN32(bitmap.width(), bitmap.height(),
- bitmap.info().alphaType(), hasLinearBlending ? sRGB : nullptr));
+ bitmap.info().alphaType(),
+ hasLinearBlending ? sRGB : nullptr));
rgbaBitmap.eraseColor(0);
if (bitmap.colorType() == kRGBA_F16_SkColorType) {
// Drawing RGBA_F16 onto ARGB_8888 is not supported
- bitmap.readPixels(rgbaBitmap.info()
- .makeColorSpace(SkColorSpace::MakeSRGB()),
- rgbaBitmap.getPixels(), rgbaBitmap.rowBytes(), 0, 0);
+ bitmap.readPixels(rgbaBitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
+ rgbaBitmap.getPixels(), rgbaBitmap.rowBytes(), 0, 0);
} else {
SkCanvas canvas(rgbaBitmap);
canvas.drawBitmap(bitmap, 0.0f, 0.0f, nullptr);
@@ -268,12 +264,11 @@ SkBitmap Texture::uploadToN32(const SkBitmap& bitmap, bool hasLinearBlending,
}
bool Texture::hasUnsupportedColorType(const SkImageInfo& info, bool hasLinearBlending) {
- return info.colorType() == kARGB_4444_SkColorType
- || (info.colorType() == kRGB_565_SkColorType
- && hasLinearBlending
- && info.colorSpace()->isSRGB())
- || (info.colorType() == kRGBA_F16_SkColorType
- && Caches::getInstance().extensions().getMajorGlVersion() < 3);
+ return info.colorType() == kARGB_4444_SkColorType ||
+ (info.colorType() == kRGB_565_SkColorType && hasLinearBlending &&
+ info.colorSpace()->isSRGB()) ||
+ (info.colorType() == kRGBA_F16_SkColorType &&
+ Caches::getInstance().extensions().getMajorGlVersion() < 3);
}
void Texture::upload(Bitmap& bitmap) {
@@ -298,13 +293,13 @@ void Texture::upload(Bitmap& bitmap) {
bool needSRGB = transferFunctionCloseToSRGB(bitmap.info().colorSpace());
GLint internalFormat, format, type;
- colorTypeToGlFormatAndType(mCaches, bitmap.colorType(),
- needSRGB && hasLinearBlending, &internalFormat, &format, &type);
+ colorTypeToGlFormatAndType(mCaches, bitmap.colorType(), needSRGB && hasLinearBlending,
+ &internalFormat, &format, &type);
// Some devices don't support GL_RGBA16F, so we need to compare the color type
// and internal GL format to decide what to do with 16 bit bitmaps
- bool rgba16fNeedsConversion = bitmap.colorType() == kRGBA_F16_SkColorType
- && internalFormat != GL_RGBA16F;
+ bool rgba16fNeedsConversion =
+ bitmap.colorType() == kRGBA_F16_SkColorType && internalFormat != GL_RGBA16F;
// RGBA16F is always linear extended sRGB
if (internalFormat == GL_RGBA16F) {
@@ -330,16 +325,16 @@ void Texture::upload(Bitmap& bitmap) {
float data[16];
xyzMatrix.asColMajorf(data);
- ColorSpace::TransferParameters p =
- {fn.fG, fn.fA, fn.fB, fn.fC, fn.fD, fn.fE, fn.fF};
- ColorSpace src("Unnamed", mat4f((const float*) &data[0]).upperLeft(), p);
+ ColorSpace::TransferParameters p = {fn.fG, fn.fA, fn.fB, fn.fC,
+ fn.fD, fn.fE, fn.fF};
+ ColorSpace src("Unnamed", mat4f((const float*)&data[0]).upperLeft(), p);
mConnector.reset(new ColorSpaceConnector(src, ColorSpace::sRGB()));
// A non-sRGB color space might have a transfer function close enough to sRGB
// that we can save shader instructions by using an sRGB sampler
// This is only possible if we have hardware support for sRGB textures
- if (needSRGB && internalFormat == GL_RGBA
- && mCaches.extensions().hasSRGB() && !bitmap.isHardware()) {
+ if (needSRGB && internalFormat == GL_RGBA && mCaches.extensions().hasSRGB() &&
+ !bitmap.isHardware()) {
internalFormat = GL_SRGB8_ALPHA8;
}
}
@@ -360,13 +355,14 @@ void Texture::upload(Bitmap& bitmap) {
sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeSRGB();
SkBitmap rgbaBitmap = uploadToN32(skBitmap, hasLinearBlending, std::move(sRGB));
uploadToTexture(needsAlloc, internalFormat, format, type, rgbaBitmap.rowBytesAsPixels(),
- rgbaBitmap.bytesPerPixel(), rgbaBitmap.width(),
- rgbaBitmap.height(), rgbaBitmap.getPixels());
+ rgbaBitmap.bytesPerPixel(), rgbaBitmap.width(), rgbaBitmap.height(),
+ rgbaBitmap.getPixels());
} else if (bitmap.isHardware()) {
uploadHardwareBitmapToTexture(bitmap.graphicBuffer());
} else {
uploadToTexture(needsAlloc, internalFormat, format, type, bitmap.rowBytesAsPixels(),
- bitmap.info().bytesPerPixel(), bitmap.width(), bitmap.height(), bitmap.pixels());
+ bitmap.info().bytesPerPixel(), bitmap.width(), bitmap.height(),
+ bitmap.pixels());
}
if (canMipMap) {
@@ -382,8 +378,8 @@ void Texture::upload(Bitmap& bitmap) {
}
}
-void Texture::wrap(GLuint id, uint32_t width, uint32_t height,
- GLint internalFormat, GLint format, GLenum target) {
+void Texture::wrap(GLuint id, uint32_t width, uint32_t height, GLint internalFormat, GLint format,
+ GLenum target) {
mId = id;
mWidth = width;
mHeight = height;
@@ -399,8 +395,8 @@ TransferFunctionType Texture::getTransferFunctionType() const {
if (mConnector.get() != nullptr && mInternalFormat != GL_SRGB8_ALPHA8) {
const ColorSpace::TransferParameters& p = mConnector->getSource().getTransferParameters();
if (MathUtils::isZero(p.e) && MathUtils::isZero(p.f)) {
- if (MathUtils::areEqual(p.a, 1.0f) && MathUtils::isZero(p.b)
- && MathUtils::isZero(p.c) && MathUtils::isZero(p.d)) {
+ if (MathUtils::areEqual(p.a, 1.0f) && MathUtils::isZero(p.b) &&
+ MathUtils::isZero(p.c) && MathUtils::isZero(p.d)) {
if (MathUtils::areEqual(p.g, 1.0f)) {
return TransferFunctionType::None;
}
@@ -413,5 +409,5 @@ TransferFunctionType Texture::getTransferFunctionType() const {
return TransferFunctionType::None;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 7f742e604838..5b7e4e261f30 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -27,10 +27,10 @@
#include <ui/ColorSpace.h>
-#include <GLES2/gl2.h>
-#include <GLES3/gl3.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES3/gl3.h>
#include <SkBitmap.h>
namespace android {
@@ -48,32 +48,30 @@ class Layer;
*/
class Texture : public GpuMemoryTracker {
public:
- static SkBitmap uploadToN32(const SkBitmap& bitmap,
- bool hasLinearBlending, sk_sp<SkColorSpace> sRGB);
+ static SkBitmap uploadToN32(const SkBitmap& bitmap, bool hasLinearBlending,
+ sk_sp<SkColorSpace> sRGB);
static bool hasUnsupportedColorType(const SkImageInfo& info, bool hasLinearBlending);
static void colorTypeToGlFormatAndType(const Caches& caches, SkColorType colorType,
- bool needSRGB, GLint* outInternalFormat, GLint* outFormat, GLint* outType);
+ bool needSRGB, GLint* outInternalFormat,
+ GLint* outFormat, GLint* outType);
- explicit Texture(Caches& caches)
- : GpuMemoryTracker(GpuObjectType::Texture)
- , mCaches(caches)
- { }
+ explicit Texture(Caches& caches) : GpuMemoryTracker(GpuObjectType::Texture), mCaches(caches) {}
- virtual ~Texture() { }
+ virtual ~Texture() {}
inline void setWrap(GLenum wrap, bool bindTexture = false, bool force = false) {
setWrapST(wrap, wrap, bindTexture, force);
}
virtual void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false,
- bool force = false);
+ bool force = false);
inline void setFilter(GLenum filter, bool bindTexture = false, bool force = false) {
setFilterMinMag(filter, filter, bindTexture, force);
}
virtual void setFilterMinMag(GLenum min, GLenum mag, bool bindTexture = false,
- bool force = false);
+ bool force = false);
/**
* Convenience method to call glDeleteTextures() on this texture's id.
@@ -89,7 +87,7 @@ public:
*/
void resize(uint32_t width, uint32_t height, GLint internalFormat, GLint format) {
upload(internalFormat, width, height, format,
- internalFormat == GL_RGBA16F ? GL_HALF_FLOAT : GL_UNSIGNED_BYTE, nullptr);
+ internalFormat == GL_RGBA16F ? GL_HALF_FLOAT : GL_UNSIGNED_BYTE, nullptr);
}
/**
@@ -104,60 +102,42 @@ public:
/**
* Basically glTexImage2D/glTexSubImage2D.
*/
- void upload(GLint internalFormat, uint32_t width, uint32_t height,
- GLenum format, GLenum type, const void* pixels);
+ void upload(GLint internalFormat, uint32_t width, uint32_t height, GLenum format, GLenum type,
+ const void* pixels);
/**
* Wraps an existing texture.
*/
- void wrap(GLuint id, uint32_t width, uint32_t height, GLint internalFormat,
- GLint format, GLenum target);
+ void wrap(GLuint id, uint32_t width, uint32_t height, GLint internalFormat, GLint format,
+ GLenum target);
- GLuint id() const {
- return mId;
- }
+ GLuint id() const { return mId; }
- uint32_t width() const {
- return mWidth;
- }
+ uint32_t width() const { return mWidth; }
- uint32_t height() const {
- return mHeight;
- }
+ uint32_t height() const { return mHeight; }
- GLint format() const {
- return mFormat;
- }
+ GLint format() const { return mFormat; }
- GLint internalFormat() const {
- return mInternalFormat;
- }
+ GLint internalFormat() const { return mInternalFormat; }
- GLenum target() const {
- return mTarget;
- }
+ GLenum target() const { return mTarget; }
/**
* Returns nullptr if this texture does not require color space conversion
* to sRGB, or a valid pointer to a ColorSpaceConnector if a conversion
* is required.
*/
- constexpr const ColorSpaceConnector* getColorSpaceConnector() const {
- return mConnector.get();
- }
+ constexpr const ColorSpaceConnector* getColorSpaceConnector() const { return mConnector.get(); }
- constexpr bool hasColorSpaceConversion() const {
- return mConnector.get() != nullptr;
- }
+ constexpr bool hasColorSpaceConversion() const { return mConnector.get() != nullptr; }
TransferFunctionType getTransferFunctionType() const;
/**
* Returns true if this texture uses a linear encoding format.
*/
- constexpr bool isLinear() const {
- return mIsLinear;
- }
+ constexpr bool isLinear() const { return mIsLinear; }
/**
* Generation of the backing bitmap,
@@ -190,6 +170,7 @@ public:
* the current frame. This is reset at the start of a new frame.
*/
void* isInUse = nullptr;
+
private:
// TODO: Temporarily grant private access to GlLayer, remove once
// GlLayer can be de-tangled from being a dual-purpose render target
@@ -197,8 +178,8 @@ private:
friend class GlLayer;
// Returns true if the texture layout (size, format, etc.) changed, false if it was the same
- bool updateLayout(uint32_t width, uint32_t height, GLint internalFormat,
- GLint format, GLenum target);
+ bool updateLayout(uint32_t width, uint32_t height, GLint internalFormat, GLint format,
+ GLenum target);
void uploadHardwareBitmapToTexture(GraphicBuffer* buffer);
void resetCachedParams();
@@ -226,12 +207,11 @@ private:
Caches& mCaches;
std::unique_ptr<ColorSpaceConnector> mConnector;
-}; // struct Texture
+}; // struct Texture
class AutoTexture {
public:
- explicit AutoTexture(Texture* texture)
- : texture(texture) {}
+ explicit AutoTexture(Texture* texture) : texture(texture) {}
~AutoTexture() {
if (texture && texture->cleanup) {
texture->deleteTexture();
@@ -240,9 +220,9 @@ public:
}
Texture* const texture;
-}; // class AutoTexture
+}; // class AutoTexture
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_TEXTURE_H
+#endif // ANDROID_HWUI_TEXTURE_H
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 6fe3606a7576..9d365fb29ebe 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -19,12 +19,12 @@
#include <utils/Mutex.h>
#include "Caches.h"
+#include "DeviceInfo.h"
+#include "Properties.h"
#include "Texture.h"
#include "TextureCache.h"
-#include "Properties.h"
-#include "utils/TraceUtils.h"
#include "hwui/Bitmap.h"
-#include "DeviceInfo.h"
+#include "utils/TraceUtils.h"
namespace android {
namespace uirenderer {
@@ -36,7 +36,7 @@ namespace uirenderer {
TextureCache::TextureCache()
: mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity)
, mSize(0)
- , mMaxSize(DeviceInfo::multiplyByResolution(4 * 6)) // 6 screen-sized RGBA_8888 bitmaps
+ , mMaxSize(DeviceInfo::multiplyByResolution(4 * 6)) // 6 screen-sized RGBA_8888 bitmaps
, mFlushRate(.4f) {
mCache.setOnEntryRemovedListener(this);
mMaxTextureSize = DeviceInfo::get()->maxTextureSize();
@@ -67,8 +67,8 @@ void TextureCache::operator()(uint32_t&, Texture*& texture) {
// This will be called already locked
if (texture) {
mSize -= texture->bitmapSize;
- TEXTURE_LOGD("TextureCache::callback: name, removed size, mSize = %d, %d, %d",
- texture->id, texture->bitmapSize, mSize);
+ TEXTURE_LOGD("TextureCache::callback: name, removed size, mSize = %d, %d, %d", texture->id,
+ texture->bitmapSize, mSize);
if (mDebugEnabled) {
ALOGD("Texture deleted, size = %d", texture->bitmapSize);
}
@@ -92,19 +92,19 @@ void TextureCache::resetMarkInUse(void* ownerToken) {
bool TextureCache::canMakeTextureFromBitmap(Bitmap* bitmap) {
if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) {
- ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)",
- bitmap->width(), bitmap->height(), mMaxTextureSize, mMaxTextureSize);
+ ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)", bitmap->width(),
+ bitmap->height(), mMaxTextureSize, mMaxTextureSize);
return false;
}
return true;
}
Texture* TextureCache::createTexture(Bitmap* bitmap) {
- Texture* texture = new Texture(Caches::getInstance());
- texture->bitmapSize = bitmap->rowBytes() * bitmap->height();
- texture->generation = bitmap->getGenerationID();
- texture->upload(*bitmap);
- return texture;
+ Texture* texture = new Texture(Caches::getInstance());
+ texture->bitmapSize = bitmap->rowBytes() * bitmap->height();
+ texture->generation = bitmap->getGenerationID();
+ texture->upload(*bitmap);
+ return texture;
}
// Returns a prepared Texture* that either is already in the cache or can fit
@@ -113,9 +113,9 @@ Texture* TextureCache::getCachedTexture(Bitmap* bitmap) {
if (bitmap->isHardware()) {
auto textureIterator = mHardwareTextures.find(bitmap->getStableID());
if (textureIterator == mHardwareTextures.end()) {
- Texture* texture = createTexture(bitmap);
- mHardwareTextures.insert(std::make_pair(bitmap->getStableID(),
- std::unique_ptr<Texture>(texture)));
+ Texture* texture = createTexture(bitmap);
+ mHardwareTextures.insert(
+ std::make_pair(bitmap->getStableID(), std::unique_ptr<Texture>(texture)));
if (mDebugEnabled) {
ALOGD("Texture created for hw bitmap size = %d", texture->bitmapSize);
}
@@ -147,7 +147,7 @@ Texture* TextureCache::getCachedTexture(Bitmap* bitmap) {
texture = createTexture(bitmap);
mSize += size;
TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
- bitmap, texture->id, size, mSize);
+ bitmap, texture->id, size, mSize);
if (mDebugEnabled) {
ALOGD("Texture created, size = %d", size);
}
@@ -201,7 +201,7 @@ bool TextureCache::destroyTexture(uint32_t pixelRefStableID) {
void TextureCache::clear() {
mCache.clear();
- for(auto& iter: mHardwareTextures) {
+ for (auto& iter : mHardwareTextures) {
iter.second->deleteTexture();
}
mHardwareTextures.clear();
@@ -223,5 +223,5 @@ void TextureCache::flush() {
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 776ff8a03fd1..19e7bea99669 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -26,8 +26,8 @@
#include "Debug.h"
-#include <vector>
#include <unordered_map>
+#include <vector>
namespace android {
@@ -43,9 +43,9 @@ class Texture;
// Debug
#if DEBUG_TEXTURES
- #define TEXTURE_LOGD(...) ALOGD(__VA_ARGS__)
+#define TEXTURE_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define TEXTURE_LOGD(...)
+#define TEXTURE_LOGD(...)
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -136,9 +136,9 @@ private:
bool mDebugEnabled;
std::unordered_map<uint32_t, std::unique_ptr<Texture>> mHardwareTextures;
-}; // class TextureCache
+}; // class TextureCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_TEXTURE_CACHE_H
+#endif // ANDROID_HWUI_TEXTURE_CACHE_H
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index e39614b6a5ea..d7012697a91e 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -37,6 +37,7 @@ class RenderState;
class ErrorHandler {
public:
virtual void onError(const std::string& message) = 0;
+
protected:
~ErrorHandler() {}
};
@@ -48,6 +49,7 @@ public:
// is finished it is possible that the node was "resurrected" and has
// a non-zero parent count.
virtual void onMaybeRemovedFromTree(RenderNode* node) = 0;
+
protected:
virtual ~TreeObserver() {}
};
@@ -55,6 +57,7 @@ protected:
// This would be a struct, but we want to PREVENT_COPY_AND_ASSIGN
class TreeInfo {
PREVENT_COPY_AND_ASSIGN(TreeInfo);
+
public:
enum TraversalMode {
// The full monty - sync, push, run animators, etc... Used by DrawFrameTask
@@ -68,10 +71,7 @@ public:
};
TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext)
- : mode(mode)
- , prepareTextures(mode == MODE_FULL)
- , canvasContext(canvasContext)
- {}
+ : mode(mode), prepareTextures(mode == MODE_FULL), canvasContext(canvasContext) {}
TraversalMode mode;
// TODO: Remove this? Currently this is used to signal to stop preparing
diff --git a/libs/hwui/UvMapper.h b/libs/hwui/UvMapper.h
index 70428d2efd51..b495e3394bc9 100644
--- a/libs/hwui/UvMapper.h
+++ b/libs/hwui/UvMapper.h
@@ -33,15 +33,14 @@ public:
* Using this constructor is equivalent to not using any mapping at all.
* UV coordinates in the [0..1] range remain in the [0..1] range.
*/
- UvMapper(): mIdentity(true), mMinU(0.0f), mMaxU(1.0f), mMinV(0.0f), mMaxV(1.0f) {
- }
+ UvMapper() : mIdentity(true), mMinU(0.0f), mMaxU(1.0f), mMinV(0.0f), mMaxV(1.0f) {}
/**
* Creates a new mapper with the specified ranges for U and V coordinates.
* The parameter minU must be < maxU and minV must be < maxV.
*/
- UvMapper(float minU, float maxU, float minV, float maxV):
- mMinU(minU), mMaxU(maxU), mMinV(minV), mMaxV(maxV) {
+ UvMapper(float minU, float maxU, float minV, float maxV)
+ : mMinU(minU), mMaxU(maxU), mMinV(minV), mMaxV(maxV) {
checkIdentity();
}
@@ -49,9 +48,7 @@ public:
* Returns true if calling the map*() methods has no effect (that is,
* texture coordinates remain in the 0..1 range.)
*/
- bool isIdentity() const {
- return mIdentity;
- }
+ bool isIdentity() const { return mIdentity; }
/**
* Changes the U and V mapping ranges.
@@ -127,7 +124,7 @@ private:
float mMaxV;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_UV_MAPPER_H
+#endif // ANDROID_HWUI_UV_MAPPER_H
diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h
index 6367dbd7b660..d2c15ad872a5 100644
--- a/libs/hwui/Vector.h
+++ b/libs/hwui/Vector.h
@@ -32,13 +32,9 @@ struct Vector2 {
float x;
float y;
- float lengthSquared() const {
- return x * x + y * y;
- }
+ float lengthSquared() const { return x * x + y * y; }
- float length() const {
- return sqrt(x * x + y * y);
- }
+ float length() const { return sqrt(x * x + y * y); }
void operator+=(const Vector2& v) {
x += v.x;
@@ -70,21 +66,13 @@ struct Vector2 {
y *= s;
}
- Vector2 operator+(const Vector2& v) const {
- return (Vector2){x + v.x, y + v.y};
- }
+ Vector2 operator+(const Vector2& v) const { return (Vector2){x + v.x, y + v.y}; }
- Vector2 operator-(const Vector2& v) const {
- return (Vector2){x - v.x, y - v.y};
- }
+ Vector2 operator-(const Vector2& v) const { return (Vector2){x - v.x, y - v.y}; }
- Vector2 operator/(float s) const {
- return (Vector2){x / s, y / s};
- }
+ Vector2 operator/(float s) const { return (Vector2){x / s, y / s}; }
- Vector2 operator*(float s) const {
- return (Vector2){x * s, y * s};
- }
+ Vector2 operator*(float s) const { return (Vector2){x * s, y * s}; }
void normalize() {
float s = 1.0f / length();
@@ -98,18 +86,12 @@ struct Vector2 {
return v;
}
- float dot(const Vector2& v) const {
- return x * v.x + y * v.y;
- }
+ float dot(const Vector2& v) const { return x * v.x + y * v.y; }
- float cross(const Vector2& v) const {
- return x * v.y - y * v.x;
- }
+ float cross(const Vector2& v) const { return x * v.y - y * v.x; }
- void dump() {
- ALOGD("Vector2[%.2f, %.2f]", x, y);
- }
-}; // class Vector2
+ void dump() { ALOGD("Vector2[%.2f, %.2f]", x, y); }
+}; // class Vector2
// MUST BE A POD - this means no ctor or dtor!
class Vector3 {
@@ -118,29 +100,20 @@ public:
float y;
float z;
- Vector3 operator+(const Vector3& v) const {
- return (Vector3){x + v.x, y + v.y, z + v.z};
- }
+ Vector3 operator+(const Vector3& v) const { return (Vector3){x + v.x, y + v.y, z + v.z}; }
- Vector3 operator-(const Vector3& v) const {
- return (Vector3){x - v.x, y - v.y, z - v.z};
- }
+ Vector3 operator-(const Vector3& v) const { return (Vector3){x - v.x, y - v.y, z - v.z}; }
- Vector3 operator/(float s) const {
- return (Vector3){x / s, y / s, z / s};
- }
-
- Vector3 operator*(float s) const {
- return (Vector3){x * s, y * s, z * s};
- }
+ Vector3 operator/(float s) const { return (Vector3){x / s, y / s, z / s}; }
+ Vector3 operator*(float s) const { return (Vector3){x * s, y * s, z * s}; }
void dump(const char* label = "Vector3") const {
ALOGD("%s[%.2f, %.2f, %.2f]", label, x, y, z);
}
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_VECTOR_H
+#endif // ANDROID_HWUI_VECTOR_H
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 376371de80dc..ce00488c9728 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -16,11 +16,11 @@
#include "VectorDrawable.h"
+#include <utils/Log.h>
#include "PathParser.h"
#include "SkColorFilter.h"
#include "SkImageInfo.h"
#include "SkShader.h"
-#include <utils/Log.h>
#include "utils/Macros.h"
#include "utils/TraceUtils.h"
#include "utils/VectorDrawableUtils.h"
@@ -79,7 +79,7 @@ FullPath::FullPath(const FullPath& path) : Path(path) {
}
static void applyTrim(SkPath* outPath, const SkPath& inPath, float trimPathStart, float trimPathEnd,
- float trimPathOffset) {
+ float trimPathOffset) {
if (trimPathStart == 0.0f && trimPathEnd == 1.0f) {
*outPath = inPath;
return;
@@ -109,25 +109,25 @@ const SkPath& FullPath::getUpdatedPath(bool useStagingData, SkPath* tempStagingP
return mTrimmedSkPath;
}
Path::getUpdatedPath(useStagingData, tempStagingPath);
- SkPath *outPath;
+ SkPath* outPath;
if (useStagingData) {
SkPath inPath = *tempStagingPath;
applyTrim(tempStagingPath, inPath, mStagingProperties.getTrimPathStart(),
- mStagingProperties.getTrimPathEnd(), mStagingProperties.getTrimPathOffset());
+ mStagingProperties.getTrimPathEnd(), mStagingProperties.getTrimPathOffset());
outPath = tempStagingPath;
} else {
if (mProperties.getTrimPathStart() != 0.0f || mProperties.getTrimPathEnd() != 1.0f) {
mProperties.mTrimDirty = false;
applyTrim(&mTrimmedSkPath, mSkPath, mProperties.getTrimPathStart(),
- mProperties.getTrimPathEnd(), mProperties.getTrimPathOffset());
+ mProperties.getTrimPathEnd(), mProperties.getTrimPathOffset());
outPath = &mTrimmedSkPath;
} else {
outPath = &mSkPath;
}
}
const FullPathProperties& properties = useStagingData ? mStagingProperties : mProperties;
- bool setFillPath = properties.getFillGradient() != nullptr
- || properties.getFillColor() != SK_ColorTRANSPARENT;
+ bool setFillPath = properties.getFillGradient() != nullptr ||
+ properties.getFillColor() != SK_ColorTRANSPARENT;
if (setFillPath) {
SkPath::FillType ft = static_cast<SkPath::FillType>(properties.getFillType());
outPath->setFillType(ft);
@@ -138,11 +138,10 @@ const SkPath& FullPath::getUpdatedPath(bool useStagingData, SkPath* tempStagingP
void FullPath::dump() {
Path::dump();
ALOGD("stroke width, color, alpha: %f, %d, %f, fill color, alpha: %d, %f",
- mProperties.getStrokeWidth(), mProperties.getStrokeColor(), mProperties.getStrokeAlpha(),
- mProperties.getFillColor(), mProperties.getFillAlpha());
+ mProperties.getStrokeWidth(), mProperties.getStrokeColor(), mProperties.getStrokeAlpha(),
+ mProperties.getFillColor(), mProperties.getFillAlpha());
}
-
inline SkColor applyAlpha(SkColor color, float alpha) {
int alphaBytes = SkColorGetA(color);
return SkColorSetA(color, alphaBytes * alpha);
@@ -213,7 +212,7 @@ bool FullPath::FullPathProperties::copyProperties(int8_t* outProperties, int len
int propertyDataSize = sizeof(FullPathProperties::PrimitiveFields);
if (length != propertyDataSize) {
LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
- propertyDataSize, length);
+ propertyDataSize, length);
return false;
}
@@ -229,35 +228,37 @@ void FullPath::FullPathProperties::setColorPropertyValue(int propertyId, int32_t
} else if (currentProperty == Property::fillColor) {
setFillColor(value);
} else {
- LOG_ALWAYS_FATAL("Error setting color property on FullPath: No valid property"
- " with id: %d", propertyId);
+ LOG_ALWAYS_FATAL(
+ "Error setting color property on FullPath: No valid property"
+ " with id: %d",
+ propertyId);
}
}
void FullPath::FullPathProperties::setPropertyValue(int propertyId, float value) {
Property property = static_cast<Property>(propertyId);
switch (property) {
- case Property::strokeWidth:
- setStrokeWidth(value);
- break;
- case Property::strokeAlpha:
- setStrokeAlpha(value);
- break;
- case Property::fillAlpha:
- setFillAlpha(value);
- break;
- case Property::trimPathStart:
- setTrimPathStart(value);
- break;
- case Property::trimPathEnd:
- setTrimPathEnd(value);
- break;
- case Property::trimPathOffset:
- setTrimPathOffset(value);
- break;
- default:
- LOG_ALWAYS_FATAL("Invalid property id: %d for animation", propertyId);
- break;
+ case Property::strokeWidth:
+ setStrokeWidth(value);
+ break;
+ case Property::strokeAlpha:
+ setStrokeAlpha(value);
+ break;
+ case Property::fillAlpha:
+ setFillAlpha(value);
+ break;
+ case Property::trimPathStart:
+ setTrimPathStart(value);
+ break;
+ case Property::trimPathEnd:
+ setTrimPathEnd(value);
+ break;
+ case Property::trimPathOffset:
+ setTrimPathOffset(value);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Invalid property id: %d for animation", propertyId);
+ break;
}
}
@@ -288,7 +289,7 @@ void Group::draw(SkCanvas* outCanvas, bool useStagingData) {
void Group::dump() {
ALOGD("Group %s has %zu children: ", mName.c_str(), mChildren.size());
ALOGD("Group translateX, Y : %f, %f, scaleX, Y: %f, %f", mProperties.getTranslateX(),
- mProperties.getTranslateY(), mProperties.getScaleX(), mProperties.getScaleY());
+ mProperties.getTranslateY(), mProperties.getScaleX(), mProperties.getScaleY());
for (size_t i = 0; i < mChildren.size(); i++) {
mChildren[i]->dump();
}
@@ -315,7 +316,7 @@ void Group::getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& propertie
outMatrix->postScale(properties.getScaleX(), properties.getScaleY());
outMatrix->postRotate(properties.getRotation(), 0, 0);
outMatrix->postTranslate(properties.getTranslateX() + properties.getPivotX(),
- properties.getTranslateY() + properties.getPivotY());
+ properties.getTranslateY() + properties.getPivotY());
}
void Group::addChild(Node* child) {
@@ -329,7 +330,7 @@ bool Group::GroupProperties::copyProperties(float* outProperties, int length) co
int propertyCount = static_cast<int>(Property::count);
if (length != propertyCount) {
LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
- propertyCount, length);
+ propertyCount, length);
return false;
}
@@ -343,23 +344,23 @@ bool Group::GroupProperties::copyProperties(float* outProperties, int length) co
float Group::GroupProperties::getPropertyValue(int propertyId) const {
Property currentProperty = static_cast<Property>(propertyId);
switch (currentProperty) {
- case Property::rotate:
- return getRotation();
- case Property::pivotX:
- return getPivotX();
- case Property::pivotY:
- return getPivotY();
- case Property::scaleX:
- return getScaleX();
- case Property::scaleY:
- return getScaleY();
- case Property::translateX:
- return getTranslateX();
- case Property::translateY:
- return getTranslateY();
- default:
- LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
- return 0;
+ case Property::rotate:
+ return getRotation();
+ case Property::pivotX:
+ return getPivotX();
+ case Property::pivotY:
+ return getPivotY();
+ case Property::scaleX:
+ return getScaleX();
+ case Property::scaleY:
+ return getScaleY();
+ case Property::translateX:
+ return getTranslateX();
+ case Property::translateY:
+ return getTranslateY();
+ default:
+ LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
+ return 0;
}
}
@@ -367,29 +368,29 @@ float Group::GroupProperties::getPropertyValue(int propertyId) const {
void Group::GroupProperties::setPropertyValue(int propertyId, float value) {
Property currentProperty = static_cast<Property>(propertyId);
switch (currentProperty) {
- case Property::rotate:
- setRotation(value);
- break;
- case Property::pivotX:
- setPivotX(value);
- break;
- case Property::pivotY:
- setPivotY(value);
- break;
- case Property::scaleX:
- setScaleX(value);
- break;
- case Property::scaleY:
- setScaleY(value);
- break;
- case Property::translateX:
- setTranslateX(value);
- break;
- case Property::translateY:
- setTranslateY(value);
- break;
- default:
- LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
+ case Property::rotate:
+ setRotation(value);
+ break;
+ case Property::pivotX:
+ setPivotX(value);
+ break;
+ case Property::pivotY:
+ setPivotY(value);
+ break;
+ case Property::scaleX:
+ setScaleX(value);
+ break;
+ case Property::scaleY:
+ setScaleY(value);
+ break;
+ case Property::translateX:
+ setTranslateX(value);
+ break;
+ case Property::translateY:
+ setTranslateY(value);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
}
}
@@ -401,8 +402,8 @@ bool Group::GroupProperties::isValidProperty(int propertyId) {
return propertyId >= 0 && propertyId < static_cast<int>(Property::count);
}
-int Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
- const SkRect& bounds, bool needsMirroring, bool canReuseCache) {
+int Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter, const SkRect& bounds,
+ bool needsMirroring, bool canReuseCache) {
// The imageView can scale the canvas in different ways, in order to
// avoid blurry scaling, we have to draw into a bitmap with exact pixel
// size first. This bitmap size is determined by the bounds and the
@@ -417,8 +418,8 @@ int Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
canvasScaleX = fabs(canvasMatrix.getScaleX());
canvasScaleY = fabs(canvasMatrix.getScaleY());
}
- int scaledWidth = (int) (bounds.width() * canvasScaleX);
- int scaledHeight = (int) (bounds.height() * canvasScaleY);
+ int scaledWidth = (int)(bounds.width() * canvasScaleX);
+ int scaledHeight = (int)(bounds.height() * canvasScaleY);
scaledWidth = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledWidth);
scaledHeight = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledHeight);
@@ -449,8 +450,8 @@ int Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
}
void Tree::drawStaging(Canvas* outCanvas) {
- bool redrawNeeded = allocateBitmapIfNeeded(mStagingCache,
- mStagingProperties.getScaledWidth(), mStagingProperties.getScaledHeight());
+ bool redrawNeeded = allocateBitmapIfNeeded(mStagingCache, mStagingProperties.getScaledWidth(),
+ mStagingProperties.getScaledHeight());
// draw bitmap cache
if (redrawNeeded || mStagingCache.dirty) {
updateBitmapCache(*mStagingCache.bitmap, true);
@@ -459,10 +460,11 @@ void Tree::drawStaging(Canvas* outCanvas) {
SkPaint tmpPaint;
SkPaint* paint = updatePaint(&tmpPaint, &mStagingProperties);
- outCanvas->drawBitmap(*mStagingCache.bitmap, 0, 0,
- mStagingCache.bitmap->width(), mStagingCache.bitmap->height(),
- mStagingProperties.getBounds().left(), mStagingProperties.getBounds().top(),
- mStagingProperties.getBounds().right(), mStagingProperties.getBounds().bottom(), paint);
+ outCanvas->drawBitmap(*mStagingCache.bitmap, 0, 0, mStagingCache.bitmap->width(),
+ mStagingCache.bitmap->height(), mStagingProperties.getBounds().left(),
+ mStagingProperties.getBounds().top(),
+ mStagingProperties.getBounds().right(),
+ mStagingProperties.getBounds().bottom(), paint);
}
SkPaint* Tree::getPaint() {
@@ -484,7 +486,7 @@ SkPaint* Tree::updatePaint(SkPaint* outPaint, TreeProperties* prop) {
Bitmap& Tree::getBitmapUpdateIfDirty() {
bool redrawNeeded = allocateBitmapIfNeeded(mCache, mProperties.getScaledWidth(),
- mProperties.getScaledHeight());
+ mProperties.getScaledHeight());
if (redrawNeeded || mCache.dirty) {
updateBitmapCache(*mCache.bitmap, false);
mCache.dirty = false;
@@ -495,8 +497,8 @@ Bitmap& Tree::getBitmapUpdateIfDirty() {
void Tree::updateCache(sp<skiapipeline::VectorDrawableAtlas>& atlas, GrContext* context) {
SkRect dst;
sk_sp<SkSurface> surface = mCache.getSurface(&dst);
- bool canReuseSurface = surface && dst.width() >= mProperties.getScaledWidth()
- && dst.height() >= mProperties.getScaledHeight();
+ bool canReuseSurface = surface && dst.width() >= mProperties.getScaledWidth() &&
+ dst.height() >= mProperties.getScaledHeight();
if (!canReuseSurface) {
int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
@@ -506,7 +508,7 @@ void Tree::updateCache(sp<skiapipeline::VectorDrawableAtlas>& atlas, GrContext*
surface = atlasEntry.surface;
mCache.setAtlas(atlas, atlasEntry.key);
} else {
- //don't draw, if we failed to allocate an offscreen buffer
+ // don't draw, if we failed to allocate an offscreen buffer
mCache.clear();
surface.reset();
}
@@ -526,7 +528,7 @@ void Tree::updateCache(sp<skiapipeline::VectorDrawableAtlas>& atlas, GrContext*
}
void Tree::Cache::setAtlas(sp<skiapipeline::VectorDrawableAtlas> newAtlas,
- skiapipeline::AtlasKey newAtlasKey) {
+ skiapipeline::AtlasKey newAtlasKey) {
LOG_ALWAYS_FATAL_IF(newAtlasKey == INVALID_ATLAS_KEY);
clear();
mAtlas = newAtlas;
@@ -560,7 +562,8 @@ void Tree::draw(SkCanvas* canvas) {
sk_sp<SkSurface> vdSurface = mCache.getSurface(&src);
if (vdSurface) {
canvas->drawImageRect(vdSurface->makeImageSnapshot().get(), src,
- mutateProperties()->getBounds(), getPaint(), SkCanvas::kFast_SrcRectConstraint);
+ mutateProperties()->getBounds(), getPaint(),
+ SkCanvas::kFast_SrcRectConstraint);
} else {
// Handle the case when VectorDrawableAtlas has been destroyed, because of memory pressure.
// We render the VD into a temporary standalone buffer and mark the frame as dirty. Next
@@ -572,7 +575,8 @@ void Tree::draw(SkCanvas* canvas) {
int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight),
- mutateProperties()->getBounds(), getPaint(), SkCanvas::kFast_SrcRectConstraint);
+ mutateProperties()->getBounds(), getPaint(),
+ SkCanvas::kFast_SrcRectConstraint);
mCache.clear();
markDirty();
}
@@ -586,10 +590,10 @@ void Tree::updateBitmapCache(Bitmap& bitmap, bool useStagingData) {
ATRACE_FORMAT("VectorDrawable repaint %dx%d", cacheWidth, cacheHeight);
outCache.eraseColor(SK_ColorTRANSPARENT);
SkCanvas outCanvas(outCache);
- float viewportWidth = useStagingData ?
- mStagingProperties.getViewportWidth() : mProperties.getViewportWidth();
- float viewportHeight = useStagingData ?
- mStagingProperties.getViewportHeight() : mProperties.getViewportHeight();
+ float viewportWidth =
+ useStagingData ? mStagingProperties.getViewportWidth() : mProperties.getViewportWidth();
+ float viewportHeight = useStagingData ? mStagingProperties.getViewportHeight()
+ : mProperties.getViewportHeight();
float scaleX = cacheWidth / viewportWidth;
float scaleY = cacheHeight / viewportHeight;
outCanvas.scale(scaleX, scaleY);
@@ -622,7 +626,7 @@ void Tree::onPropertyChanged(TreeProperties* prop) {
}
}
-}; // namespace VectorDrawable
+}; // namespace VectorDrawable
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 4b80542ad0d0..7f7560958022 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -17,15 +17,15 @@
#ifndef ANDROID_HWUI_VPATH_H
#define ANDROID_HWUI_VPATH_H
-#include "hwui/Canvas.h"
+#include "DisplayList.h"
#include "hwui/Bitmap.h"
+#include "hwui/Canvas.h"
#include "renderthread/CacheManager.h"
-#include "DisplayList.h"
#include <SkBitmap.h>
+#include <SkCanvas.h>
#include <SkColor.h>
#include <SkColorFilter.h>
-#include <SkCanvas.h>
#include <SkMatrix.h>
#include <SkPaint.h>
#include <SkPath.h>
@@ -36,25 +36,35 @@
#include <cutils/compiler.h>
#include <stddef.h>
-#include <vector>
#include <string>
+#include <vector>
namespace android {
namespace uirenderer {
// Debug
#if DEBUG_VECTOR_DRAWABLE
- #define VECTOR_DRAWABLE_LOGD(...) ALOGD(__VA_ARGS__)
+#define VECTOR_DRAWABLE_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define VECTOR_DRAWABLE_LOGD(...)
+#define VECTOR_DRAWABLE_LOGD(...)
#endif
namespace VectorDrawable {
-#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
+#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) \
+ (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
#define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false)
-#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value));\
- onPropertyChanged(); retVal;})
-#define UPDATE_SKPROP(field, value) ({bool retVal = ((field) != (value)); if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); retVal;})
+#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) \
+ ({ \
+ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value)); \
+ onPropertyChanged(); \
+ retVal; \
+ })
+#define UPDATE_SKPROP(field, value) \
+ ({ \
+ bool retVal = ((field) != (value)); \
+ if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); \
+ retVal; \
+ })
/* A VectorDrawable is composed of a tree of nodes.
* Each node can be a group node, or a path.
@@ -85,12 +95,9 @@ class PropertyChangedListener {
public:
PropertyChangedListener(bool* dirty, bool* stagingDirty)
: mDirty(dirty), mStagingDirty(stagingDirty) {}
- void onPropertyChanged() {
- *mDirty = true;
- }
- void onStagingPropertyChanged() {
- *mStagingDirty = true;
- }
+ void onPropertyChanged() { *mDirty = true; }
+ void onStagingPropertyChanged() { *mStagingDirty = true; }
+
private:
bool* mDirty;
bool* mStagingDirty;
@@ -101,27 +108,23 @@ public:
class Properties {
public:
explicit Properties(Node* node) : mNode(node) {}
- inline void onPropertyChanged() {
- mNode->onPropertyChanged(this);
- }
+ inline void onPropertyChanged() { mNode->onPropertyChanged(this); }
+
private:
Node* mNode;
};
- Node(const Node& node) {
- mName = node.mName;
- }
+ Node(const Node& node) { mName = node.mName; }
Node() {}
virtual void draw(SkCanvas* outCanvas, bool useStagingData) = 0;
virtual void dump() = 0;
- void setName(const char* name) {
- mName = name;
- }
+ void setName(const char* name) { mName = name; }
virtual void setPropertyChangedListener(PropertyChangedListener* listener) {
mPropertyChangedListener = listener;
}
virtual void onPropertyChanged(Properties* properties) = 0;
- virtual ~Node(){}
+ virtual ~Node() {}
virtual void syncProperties() = 0;
+
protected:
std::string mName;
PropertyChangedListener* mPropertyChangedListener = nullptr;
@@ -134,8 +137,7 @@ public:
std::vector<size_t> verbSizes;
std::vector<float> points;
bool operator==(const Data& data) const {
- return verbs == data.verbs && verbSizes == data.verbSizes
- && points == data.points;
+ return verbs == data.verbs && verbSizes == data.verbSizes && points == data.points;
}
};
@@ -156,11 +158,9 @@ public:
}
mData = data;
onPropertyChanged();
-
- }
- const Data& getData() const {
- return mData;
}
+ const Data& getData() const { return mData; }
+
private:
Data mData;
};
@@ -177,7 +177,7 @@ public:
if (mPropertyChangedListener) {
mPropertyChangedListener->onStagingPropertyChanged();
}
- } else if (prop == &mProperties){
+ } else if (prop == &mProperties) {
mSkPathDirty = true;
if (mPropertyChangedListener) {
mPropertyChangedListener->onPropertyChanged();
@@ -203,7 +203,7 @@ private:
bool mStagingPropertiesDirty = true;
};
-class ANDROID_API FullPath: public Path {
+class ANDROID_API FullPath : public Path {
public:
class FullPathProperties : public Properties {
public:
@@ -234,87 +234,59 @@ public:
onPropertyChanged();
}
void setFillGradient(SkShader* gradient) {
- if(UPDATE_SKPROP(fillGradient, gradient)) {
+ if (UPDATE_SKPROP(fillGradient, gradient)) {
onPropertyChanged();
}
}
void setStrokeGradient(SkShader* gradient) {
- if(UPDATE_SKPROP(strokeGradient, gradient)) {
+ if (UPDATE_SKPROP(strokeGradient, gradient)) {
onPropertyChanged();
}
}
- SkShader* getFillGradient() const {
- return fillGradient;
- }
- SkShader* getStrokeGradient() const {
- return strokeGradient;
- }
- float getStrokeWidth() const{
- return mPrimitiveFields.strokeWidth;
- }
+ SkShader* getFillGradient() const { return fillGradient; }
+ SkShader* getStrokeGradient() const { return strokeGradient; }
+ float getStrokeWidth() const { return mPrimitiveFields.strokeWidth; }
void setStrokeWidth(float strokeWidth) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
}
- SkColor getStrokeColor() const{
- return mPrimitiveFields.strokeColor;
- }
+ SkColor getStrokeColor() const { return mPrimitiveFields.strokeColor; }
void setStrokeColor(SkColor strokeColor) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor);
}
- float getStrokeAlpha() const{
- return mPrimitiveFields.strokeAlpha;
- }
+ float getStrokeAlpha() const { return mPrimitiveFields.strokeAlpha; }
void setStrokeAlpha(float strokeAlpha) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha);
}
- SkColor getFillColor() const {
- return mPrimitiveFields.fillColor;
- }
+ SkColor getFillColor() const { return mPrimitiveFields.fillColor; }
void setFillColor(SkColor fillColor) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor);
}
- float getFillAlpha() const{
- return mPrimitiveFields.fillAlpha;
- }
+ float getFillAlpha() const { return mPrimitiveFields.fillAlpha; }
void setFillAlpha(float fillAlpha) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha);
}
- float getTrimPathStart() const{
- return mPrimitiveFields.trimPathStart;
- }
+ float getTrimPathStart() const { return mPrimitiveFields.trimPathStart; }
void setTrimPathStart(float trimPathStart) {
VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty);
}
- float getTrimPathEnd() const{
- return mPrimitiveFields.trimPathEnd;
- }
+ float getTrimPathEnd() const { return mPrimitiveFields.trimPathEnd; }
void setTrimPathEnd(float trimPathEnd) {
VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty);
}
- float getTrimPathOffset() const{
- return mPrimitiveFields.trimPathOffset;
- }
+ float getTrimPathOffset() const { return mPrimitiveFields.trimPathOffset; }
void setTrimPathOffset(float trimPathOffset) {
VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty);
}
- float getStrokeMiterLimit() const {
- return mPrimitiveFields.strokeMiterLimit;
- }
- float getStrokeLineCap() const {
- return mPrimitiveFields.strokeLineCap;
- }
- float getStrokeLineJoin() const {
- return mPrimitiveFields.strokeLineJoin;
- }
- float getFillType() const {
- return mPrimitiveFields.fillType;
- }
+ float getStrokeMiterLimit() const { return mPrimitiveFields.strokeMiterLimit; }
+ float getStrokeLineCap() const { return mPrimitiveFields.strokeLineCap; }
+ float getStrokeLineJoin() const { return mPrimitiveFields.strokeLineJoin; }
+ float getFillType() const { return mPrimitiveFields.fillType; }
bool copyProperties(int8_t* outProperties, int length) const;
void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
- SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
- float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
- int fillType) {
+ SkColor fillColor, float fillAlpha, float trimPathStart,
+ float trimPathEnd, float trimPathOffset, float strokeMiterLimit,
+ int strokeLineCap, int strokeLineJoin, int fillType) {
mPrimitiveFields.strokeWidth = strokeWidth;
mPrimitiveFields.strokeColor = strokeColor;
mPrimitiveFields.strokeAlpha = strokeAlpha;
@@ -334,6 +306,7 @@ public:
void setColorPropertyValue(int propertyId, int32_t value);
void setPropertyValue(int propertyId, float value);
bool mTrimDirty;
+
private:
enum class Property {
strokeWidth = 0,
@@ -356,7 +329,7 @@ public:
};
// Called from UI thread
- FullPath(const FullPath& path); // for cloning
+ FullPath(const FullPath& path); // for cloning
FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
FullPath() : Path() {}
void draw(SkCanvas* outCanvas, bool useStagingData) override;
@@ -384,18 +357,17 @@ public:
protected:
const SkPath& getUpdatedPath(bool useStagingData, SkPath* tempStagingPath) override;
-private:
+private:
FullPathProperties mProperties = FullPathProperties(this);
FullPathProperties mStagingProperties = FullPathProperties(this);
bool mStagingPropertiesDirty = true;
// Intermediate data for drawing, render thread only
SkPath mTrimmedSkPath;
-
};
-class ANDROID_API ClipPath: public Path {
+class ANDROID_API ClipPath : public Path {
public:
ClipPath(const ClipPath& path) : Path(path) {}
ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
@@ -403,7 +375,7 @@ public:
void draw(SkCanvas* outCanvas, bool useStagingData) override;
};
-class ANDROID_API Group: public Node {
+class ANDROID_API Group : public Node {
public:
class GroupProperties : public Properties {
public:
@@ -421,50 +393,26 @@ public:
mPrimitiveFields = prop.mPrimitiveFields;
onPropertyChanged();
}
- float getRotation() const {
- return mPrimitiveFields.rotate;
- }
- void setRotation(float rotation) {
- VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation);
- }
- float getPivotX() const {
- return mPrimitiveFields.pivotX;
- }
- void setPivotX(float pivotX) {
- VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX);
- }
- float getPivotY() const {
- return mPrimitiveFields.pivotY;
- }
- void setPivotY(float pivotY) {
- VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY);
- }
- float getScaleX() const {
- return mPrimitiveFields.scaleX;
- }
- void setScaleX(float scaleX) {
- VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX);
- }
- float getScaleY() const {
- return mPrimitiveFields.scaleY;
- }
- void setScaleY(float scaleY) {
- VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY);
- }
- float getTranslateX() const {
- return mPrimitiveFields.translateX;
- }
+ float getRotation() const { return mPrimitiveFields.rotate; }
+ void setRotation(float rotation) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation); }
+ float getPivotX() const { return mPrimitiveFields.pivotX; }
+ void setPivotX(float pivotX) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX); }
+ float getPivotY() const { return mPrimitiveFields.pivotY; }
+ void setPivotY(float pivotY) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY); }
+ float getScaleX() const { return mPrimitiveFields.scaleX; }
+ void setScaleX(float scaleX) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX); }
+ float getScaleY() const { return mPrimitiveFields.scaleY; }
+ void setScaleY(float scaleY) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY); }
+ float getTranslateX() const { return mPrimitiveFields.translateX; }
void setTranslateX(float translateX) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX);
}
- float getTranslateY() const {
- return mPrimitiveFields.translateY;
- }
+ float getTranslateY() const { return mPrimitiveFields.translateY; }
void setTranslateY(float translateY) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY);
}
- void updateProperties(float rotate, float pivotX, float pivotY,
- float scaleX, float scaleY, float translateX, float translateY) {
+ void updateProperties(float rotate, float pivotX, float pivotY, float scaleX, float scaleY,
+ float translateX, float translateY) {
mPrimitiveFields.rotate = rotate;
mPrimitiveFields.pivotX = pivotX;
mPrimitiveFields.pivotY = pivotY;
@@ -478,6 +426,7 @@ public:
float getPropertyValue(int propertyId) const;
bool copyProperties(float* outProperties, int length) const;
static bool isValidProperty(int propertyId);
+
private:
enum class Property {
rotate = 0,
@@ -498,7 +447,7 @@ public:
virtual void setPropertyChangedListener(PropertyChangedListener* listener) override {
Node::setPropertyChangedListener(listener);
for (auto& child : mChildren) {
- child->setPropertyChangedListener(listener);
+ child->setPropertyChangedListener(listener);
}
}
virtual void syncProperties() override;
@@ -531,7 +480,7 @@ private:
GroupProperties mProperties = GroupProperties(this);
GroupProperties mStagingProperties = GroupProperties(this);
bool mStagingPropertiesDirty = true;
- std::vector< std::unique_ptr<Node> > mChildren;
+ std::vector<std::unique_ptr<Node> > mChildren;
};
class ANDROID_API Tree : public VirtualLightRefBase {
@@ -547,27 +496,25 @@ public:
}
// Draws the VD onto a bitmap cache, then the bitmap cache will be rendered onto the input
// canvas. Returns the number of pixels needed for the bitmap cache.
- int draw(Canvas* outCanvas, SkColorFilter* colorFilter,
- const SkRect& bounds, bool needsMirroring, bool canReuseCache);
+ int draw(Canvas* outCanvas, SkColorFilter* colorFilter, const SkRect& bounds,
+ bool needsMirroring, bool canReuseCache);
void drawStaging(Canvas* canvas);
Bitmap& getBitmapUpdateIfDirty();
- void setAllowCaching(bool allowCaching) {
- mAllowCaching = allowCaching;
- }
+ void setAllowCaching(bool allowCaching) { mAllowCaching = allowCaching; }
SkPaint* getPaint();
void syncProperties() {
if (mStagingProperties.mNonAnimatablePropertiesDirty) {
- mCache.dirty |= (mProperties.mNonAnimatableProperties.viewportWidth
- != mStagingProperties.mNonAnimatableProperties.viewportWidth)
- || (mProperties.mNonAnimatableProperties.viewportHeight
- != mStagingProperties.mNonAnimatableProperties.viewportHeight)
- || (mProperties.mNonAnimatableProperties.scaledWidth
- != mStagingProperties.mNonAnimatableProperties.scaledWidth)
- || (mProperties.mNonAnimatableProperties.scaledHeight
- != mStagingProperties.mNonAnimatableProperties.scaledHeight)
- || (mProperties.mNonAnimatableProperties.bounds
- != mStagingProperties.mNonAnimatableProperties.bounds);
+ mCache.dirty |= (mProperties.mNonAnimatableProperties.viewportWidth !=
+ mStagingProperties.mNonAnimatableProperties.viewportWidth) ||
+ (mProperties.mNonAnimatableProperties.viewportHeight !=
+ mStagingProperties.mNonAnimatableProperties.viewportHeight) ||
+ (mProperties.mNonAnimatableProperties.scaledWidth !=
+ mStagingProperties.mNonAnimatableProperties.scaledWidth) ||
+ (mProperties.mNonAnimatableProperties.scaledHeight !=
+ mStagingProperties.mNonAnimatableProperties.scaledHeight) ||
+ (mProperties.mNonAnimatableProperties.bounds !=
+ mStagingProperties.mNonAnimatableProperties.bounds);
mProperties.syncNonAnimatableProperties(mStagingProperties);
mStagingProperties.mNonAnimatablePropertiesDirty = false;
}
@@ -593,9 +540,7 @@ public:
int scaledWidth = 0;
int scaledHeight = 0;
SkColorFilter* colorFilter = nullptr;
- ~NonAnimatableProperties() {
- SkSafeUnref(colorFilter);
- }
+ ~NonAnimatableProperties() { SkSafeUnref(colorFilter); }
} mNonAnimatableProperties;
bool mNonAnimatablePropertiesDirty = true;
@@ -606,14 +551,14 @@ public:
// Copy over the data that can only be changed in UI thread
if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) {
SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter,
- prop.mNonAnimatableProperties.colorFilter);
+ prop.mNonAnimatableProperties.colorFilter);
}
mNonAnimatableProperties = prop.mNonAnimatableProperties;
}
void setViewportSize(float width, float height) {
- if (mNonAnimatableProperties.viewportWidth != width
- || mNonAnimatableProperties.viewportHeight != height) {
+ if (mNonAnimatableProperties.viewportWidth != width ||
+ mNonAnimatableProperties.viewportHeight != height) {
mNonAnimatablePropertiesDirty = true;
mNonAnimatableProperties.viewportWidth = width;
mNonAnimatableProperties.viewportHeight = height;
@@ -632,12 +577,12 @@ public:
// If the requested size is bigger than what the bitmap was, then
// we increase the bitmap size to match. The width and height
// are bound by MAX_CACHED_BITMAP_SIZE.
- if (mNonAnimatableProperties.scaledWidth < width
- || mNonAnimatableProperties.scaledHeight < height) {
- mNonAnimatableProperties.scaledWidth = std::max(width,
- mNonAnimatableProperties.scaledWidth);
- mNonAnimatableProperties.scaledHeight = std::max(height,
- mNonAnimatableProperties.scaledHeight);
+ if (mNonAnimatableProperties.scaledWidth < width ||
+ mNonAnimatableProperties.scaledHeight < height) {
+ mNonAnimatableProperties.scaledWidth =
+ std::max(width, mNonAnimatableProperties.scaledWidth);
+ mNonAnimatableProperties.scaledHeight =
+ std::max(height, mNonAnimatableProperties.scaledHeight);
mNonAnimatablePropertiesDirty = true;
mTree->onPropertyChanged(this);
}
@@ -648,25 +593,13 @@ public:
mTree->onPropertyChanged(this);
}
}
- SkColorFilter* getColorFilter() const{
- return mNonAnimatableProperties.colorFilter;
- }
+ SkColorFilter* getColorFilter() const { return mNonAnimatableProperties.colorFilter; }
- float getViewportWidth() const {
- return mNonAnimatableProperties.viewportWidth;
- }
- float getViewportHeight() const {
- return mNonAnimatableProperties.viewportHeight;
- }
- float getScaledWidth() const {
- return mNonAnimatableProperties.scaledWidth;
- }
- float getScaledHeight() const {
- return mNonAnimatableProperties.scaledHeight;
- }
- void syncAnimatableProperties(const TreeProperties& prop) {
- mRootAlpha = prop.mRootAlpha;
- }
+ float getViewportWidth() const { return mNonAnimatableProperties.viewportWidth; }
+ float getViewportHeight() const { return mNonAnimatableProperties.viewportHeight; }
+ float getScaledWidth() const { return mNonAnimatableProperties.scaledWidth; }
+ float getScaledHeight() const { return mNonAnimatableProperties.scaledHeight; }
+ void syncAnimatableProperties(const TreeProperties& prop) { mRootAlpha = prop.mRootAlpha; }
bool setRootAlpha(float rootAlpha) {
if (rootAlpha != mRootAlpha) {
mAnimatablePropertiesDirty = true;
@@ -676,10 +609,8 @@ public:
}
return false;
}
- float getRootAlpha() const { return mRootAlpha;}
- const SkRect& getBounds() const {
- return mNonAnimatableProperties.bounds;
- }
+ float getRootAlpha() const { return mRootAlpha; }
+ const SkRect& getBounds() const { return mNonAnimatableProperties.bounds; }
Tree* mTree;
};
void onPropertyChanged(TreeProperties* prop);
@@ -713,8 +644,8 @@ public:
private:
class Cache {
public:
- sk_sp<Bitmap> bitmap; //used by HWUI pipeline and software
- //TODO: use surface instead of bitmap when drawing in software canvas
+ sk_sp<Bitmap> bitmap; // used by HWUI pipeline and software
+ // TODO: use surface instead of bitmap when drawing in software canvas
bool dirty = true;
// the rest of the code in Cache is used by Skia pipelines only
@@ -725,7 +656,7 @@ private:
* Stores a weak pointer to the atlas and a key.
*/
void setAtlas(sp<skiapipeline::VectorDrawableAtlas> atlas,
- skiapipeline::AtlasKey newAtlasKey);
+ skiapipeline::AtlasKey newAtlasKey);
/**
* Gets a surface and bounds from the atlas.
@@ -738,6 +669,7 @@ private:
* Releases atlas key from the atlas, which makes it available for reuse.
*/
void clear();
+
private:
wp<skiapipeline::VectorDrawableAtlas> mAtlas;
skiapipeline::AtlasKey mAtlasKey = INVALID_ATLAS_KEY;
@@ -764,16 +696,16 @@ private:
Cache mStagingCache;
Cache mCache;
- PropertyChangedListener mPropertyChangedListener
- = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
+ PropertyChangedListener mPropertyChangedListener =
+ PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
mutable bool mWillBeConsumed = false;
};
-} // namespace VectorDrawable
+} // namespace VectorDrawable
typedef VectorDrawable::Path::Data PathData;
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
-#endif // ANDROID_HWUI_VPATH_H
+#endif // ANDROID_HWUI_VPATH_H
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index db982ad0c8f4..186d0a88a33e 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -45,15 +45,13 @@ struct Vertex {
vertex->y = y;
}
- static inline void set(Vertex* vertex, Vector2 val) {
- set(vertex, val.x, val.y);
- }
+ static inline void set(Vertex* vertex, Vector2 val) { set(vertex, val.x, val.y); }
static inline void copyWithOffset(Vertex* vertex, const Vertex& src, float x, float y) {
set(vertex, src.x + x, src.y + y);
}
-}; // struct Vertex
+}; // struct Vertex
REQUIRE_COMPATIBLE_LAYOUT(Vertex);
@@ -65,14 +63,14 @@ struct TextureVertex {
float u, v;
static inline void set(TextureVertex* vertex, float x, float y, float u, float v) {
- *vertex = { x, y, u, v };
+ *vertex = {x, y, u, v};
}
static inline void setUV(TextureVertex* vertex, float u, float v) {
vertex[0].u = u;
vertex[0].v = v;
}
-}; // struct TextureVertex
+}; // struct TextureVertex
REQUIRE_COMPATIBLE_LAYOUT(TextureVertex);
@@ -83,15 +81,15 @@ REQUIRE_COMPATIBLE_LAYOUT(TextureVertex);
struct ColorTextureVertex {
float x, y;
float u, v;
- float r, g, b, a; // pre-multiplied linear
+ float r, g, b, a; // pre-multiplied linear
- static inline void set(ColorTextureVertex* vertex, float x, float y,
- float u, float v, uint32_t color) {
+ static inline void set(ColorTextureVertex* vertex, float x, float y, float u, float v,
+ uint32_t color) {
FloatColor c;
c.set(color);
- *vertex = { x, y, u, v, c.r, c.g, c.b, c.a };
+ *vertex = {x, y, u, v, c.r, c.g, c.b, c.a};
}
-}; // struct ColorTextureVertex
+}; // struct ColorTextureVertex
REQUIRE_COMPATIBLE_LAYOUT(ColorTextureVertex);
@@ -103,22 +101,20 @@ struct AlphaVertex {
float alpha;
static inline void set(AlphaVertex* vertex, float x, float y, float alpha) {
- *vertex = { x, y, alpha };
+ *vertex = {x, y, alpha};
}
- static inline void copyWithOffset(AlphaVertex* vertex, const AlphaVertex& src,
- float x, float y) {
+ static inline void copyWithOffset(AlphaVertex* vertex, const AlphaVertex& src, float x,
+ float y) {
AlphaVertex::set(vertex, src.x + x, src.y + y, src.alpha);
}
- static inline void setColor(AlphaVertex* vertex, float alpha) {
- vertex[0].alpha = alpha;
- }
-}; // struct AlphaVertex
+ static inline void setColor(AlphaVertex* vertex, float alpha) { vertex[0].alpha = alpha; }
+}; // struct AlphaVertex
REQUIRE_COMPATIBLE_LAYOUT(AlphaVertex);
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_VERTEX_H
+#endif // ANDROID_HWUI_VERTEX_H
diff --git a/libs/hwui/VertexBuffer.h b/libs/hwui/VertexBuffer.h
index bdb5b7b381bf..613cf4af64b2 100644
--- a/libs/hwui/VertexBuffer.h
+++ b/libs/hwui/VertexBuffer.h
@@ -41,8 +41,7 @@ public:
, mMeshFeatureFlags(kNone)
, mReallocBuffer(nullptr)
, mCleanupMethod(nullptr)
- , mCleanupIndexMethod(nullptr)
- {}
+ , mCleanupIndexMethod(nullptr) {}
~VertexBuffer() {
if (mCleanupMethod) mCleanupMethod(mBuffer);
@@ -128,10 +127,10 @@ public:
unsigned int getVertexCount() const { return mVertexCount; }
unsigned int getSize() const { return mByteCount; }
unsigned int getIndexCount() const { return mIndexCount; }
- void updateIndexCount(unsigned int newCount) {
+ void updateIndexCount(unsigned int newCount) {
mIndexCount = std::min(newCount, mAllocatedIndexCount);
}
- void updateVertexCount(unsigned int newCount) {
+ void updateVertexCount(unsigned int newCount) {
mVertexCount = std::min(newCount, mAllocatedVertexCount);
}
MeshFeatureFlags getMeshFeatureFlags() const { return mMeshFeatureFlags; }
@@ -153,7 +152,7 @@ public:
private:
template <class TYPE>
static void cleanup(void* buffer) {
- delete[] (TYPE*)buffer;
+ delete[](TYPE*) buffer;
}
Rect mBounds;
@@ -169,13 +168,13 @@ private:
MeshFeatureFlags mMeshFeatureFlags;
- void* mReallocBuffer; // used for multi-allocation
+ void* mReallocBuffer; // used for multi-allocation
void (*mCleanupMethod)(void*);
void (*mCleanupIndexMethod)(void*);
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_VERTEX_BUFFER_H
+#endif // ANDROID_HWUI_VERTEX_BUFFER_H
diff --git a/libs/hwui/VkLayer.cpp b/libs/hwui/VkLayer.cpp
index ef4784b3d65b..30fba7ae7d9b 100644
--- a/libs/hwui/VkLayer.cpp
+++ b/libs/hwui/VkLayer.cpp
@@ -36,5 +36,5 @@ void VkLayer::onVkContextDestroyed() {
mImage = nullptr;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/VkLayer.h b/libs/hwui/VkLayer.h
index 7e41ad1d0e9c..f23f4726017e 100644
--- a/libs/hwui/VkLayer.h
+++ b/libs/hwui/VkLayer.h
@@ -36,30 +36,20 @@ public:
virtual ~VkLayer() {}
- uint32_t getWidth() const override {
- return mWidth;
- }
+ uint32_t getWidth() const override { return mWidth; }
- uint32_t getHeight() const override {
- return mHeight;
- }
+ uint32_t getHeight() const override { return mHeight; }
void setSize(uint32_t width, uint32_t height) override {
mWidth = width;
mHeight = height;
}
- void setBlend(bool blend) override {
- mBlend = blend;
- }
+ void setBlend(bool blend) override { mBlend = blend; }
- bool isBlend() const override {
- return mBlend;
- }
+ bool isBlend() const override { return mBlend; }
- sk_sp<SkImage> getImage() {
- return mImage;
- }
+ sk_sp<SkImage> getImage() { return mImage; }
void updateTexture();
@@ -72,9 +62,9 @@ private:
int mHeight;
bool mBlend;
- sk_sp<SkImage> mImage;
+ sk_sp<SkImage> mImage;
-}; // struct VkLayer
+}; // struct VkLayer
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/debug/DefaultGlesDriver.cpp b/libs/hwui/debug/DefaultGlesDriver.cpp
index 4515ec1f25a5..46ab20081d17 100644
--- a/libs/hwui/debug/DefaultGlesDriver.cpp
+++ b/libs/hwui/debug/DefaultGlesDriver.cpp
@@ -35,6 +35,6 @@ namespace debug {
#undef CALL_GL_API
#undef CALL_GL_API_RETURN
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/DefaultGlesDriver.h b/libs/hwui/debug/DefaultGlesDriver.h
index 3eab97077004..8027ea284aaa 100644
--- a/libs/hwui/debug/DefaultGlesDriver.h
+++ b/libs/hwui/debug/DefaultGlesDriver.h
@@ -25,11 +25,10 @@ namespace debug {
class DefaultGlesDriver : public GlesDriver {
public:
#define GL_ENTRY(ret, api, ...) virtual ret api##_(__VA_ARGS__) override;
- #include "gles_decls.in"
+#include "gles_decls.in"
#undef GL_ENTRY
-
};
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/FatalBaseDriver.cpp b/libs/hwui/debug/FatalBaseDriver.cpp
index 4c38fac33521..ed0f8316d208 100644
--- a/libs/hwui/debug/FatalBaseDriver.cpp
+++ b/libs/hwui/debug/FatalBaseDriver.cpp
@@ -25,9 +25,9 @@ namespace debug {
// Generate the proxy
#define API_ENTRY(x) FatalBaseDriver::x##_
#define CALL_GL_API(x, ...) LOG_ALWAYS_FATAL("Not Implemented");
-#define CALL_GL_API_RETURN(x, ...) \
- LOG_ALWAYS_FATAL("Not Implemented"); \
- return static_cast<decltype(x(__VA_ARGS__))>(0);
+#define CALL_GL_API_RETURN(x, ...) \
+ LOG_ALWAYS_FATAL("Not Implemented"); \
+ return static_cast<decltype(x(__VA_ARGS__))>(0);
#include "gles_stubs.in"
@@ -35,6 +35,6 @@ namespace debug {
#undef CALL_GL_API
#undef CALL_GL_API_RETURN
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/FatalBaseDriver.h b/libs/hwui/debug/FatalBaseDriver.h
index 76c30e90bd39..45353d0568aa 100644
--- a/libs/hwui/debug/FatalBaseDriver.h
+++ b/libs/hwui/debug/FatalBaseDriver.h
@@ -28,10 +28,10 @@ namespace debug {
class FatalBaseDriver : public GlesDriver {
public:
#define GL_ENTRY(ret, api, ...) virtual ret api##_(__VA_ARGS__) override;
- #include "gles_decls.in"
+#include "gles_decls.in"
#undef GL_ENTRY
};
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/GlesDriver.cpp b/libs/hwui/debug/GlesDriver.cpp
index 97e8f3a81b74..98f06b0cb4f0 100644
--- a/libs/hwui/debug/GlesDriver.cpp
+++ b/libs/hwui/debug/GlesDriver.cpp
@@ -41,6 +41,6 @@ sk_sp<const GrGLInterface> GlesDriver::getSkiaInterface() {
return skiaInterface;
}
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/GlesDriver.h b/libs/hwui/debug/GlesDriver.h
index 3c36487f72cf..1c77c1a45b82 100644
--- a/libs/hwui/debug/GlesDriver.h
+++ b/libs/hwui/debug/GlesDriver.h
@@ -43,13 +43,13 @@ public:
virtual sk_sp<const GrGLInterface> getSkiaInterface();
#define GL_ENTRY(ret, api, ...) virtual ret api##_(__VA_ARGS__) = 0;
- #include "gles_decls.in"
+#include "gles_decls.in"
#undef GL_ENTRY
static GlesDriver* get();
static std::unique_ptr<GlesDriver> replace(std::unique_ptr<GlesDriver>&& driver);
};
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/GlesErrorCheckWrapper.cpp b/libs/hwui/debug/GlesErrorCheckWrapper.cpp
index 7ededaaa7fc2..8d11c1905da3 100644
--- a/libs/hwui/debug/GlesErrorCheckWrapper.cpp
+++ b/libs/hwui/debug/GlesErrorCheckWrapper.cpp
@@ -29,38 +29,39 @@ void GlesErrorCheckWrapper::assertNoErrors(const char* apicall) {
while ((status = mBase.glGetError_()) != GL_NO_ERROR) {
lastError = status;
switch (status) {
- case GL_INVALID_ENUM:
- ALOGE("GL error: GL_INVALID_ENUM");
- lastErrorName = "GL_INVALID_ENUM";
- break;
- case GL_INVALID_VALUE:
- ALOGE("GL error: GL_INVALID_VALUE");
- lastErrorName = "GL_INVALID_VALUE";
- break;
- case GL_INVALID_OPERATION:
- ALOGE("GL error: GL_INVALID_OPERATION");
- lastErrorName = "GL_INVALID_OPERATION";
- break;
- case GL_OUT_OF_MEMORY:
- ALOGE("GL error: Out of memory!");
- lastErrorName = "GL_OUT_OF_MEMORY";
- break;
- default:
- ALOGE("GL error: 0x%x", status);
- lastErrorName = "UNKNOWN";
+ case GL_INVALID_ENUM:
+ ALOGE("GL error: GL_INVALID_ENUM");
+ lastErrorName = "GL_INVALID_ENUM";
+ break;
+ case GL_INVALID_VALUE:
+ ALOGE("GL error: GL_INVALID_VALUE");
+ lastErrorName = "GL_INVALID_VALUE";
+ break;
+ case GL_INVALID_OPERATION:
+ ALOGE("GL error: GL_INVALID_OPERATION");
+ lastErrorName = "GL_INVALID_OPERATION";
+ break;
+ case GL_OUT_OF_MEMORY:
+ ALOGE("GL error: Out of memory!");
+ lastErrorName = "GL_OUT_OF_MEMORY";
+ break;
+ default:
+ ALOGE("GL error: 0x%x", status);
+ lastErrorName = "UNKNOWN";
}
}
- LOG_ALWAYS_FATAL_IF(lastError != GL_NO_ERROR,
- "%s error! %s (0x%x)", apicall, lastErrorName, lastError);
+ LOG_ALWAYS_FATAL_IF(lastError != GL_NO_ERROR, "%s error! %s (0x%x)", apicall, lastErrorName,
+ lastError);
}
#define API_ENTRY(x) GlesErrorCheckWrapper::x##_
-#define CALL_GL_API(x, ...) \
- mBase.x##_(__VA_ARGS__); assertNoErrors(#x)
+#define CALL_GL_API(x, ...) \
+ mBase.x##_(__VA_ARGS__); \
+ assertNoErrors(#x)
-#define CALL_GL_API_RETURN(x, ...) \
+#define CALL_GL_API_RETURN(x, ...) \
auto ret = mBase.x##_(__VA_ARGS__); \
- assertNoErrors(#x); \
+ assertNoErrors(#x); \
return ret
#include "gles_stubs.in"
@@ -69,6 +70,6 @@ void GlesErrorCheckWrapper::assertNoErrors(const char* apicall) {
#undef CALL_GL_API
#undef CALL_GL_API_RETURN
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/GlesErrorCheckWrapper.h b/libs/hwui/debug/GlesErrorCheckWrapper.h
index fd45fc0184a1..ee5cc1f46de8 100644
--- a/libs/hwui/debug/GlesErrorCheckWrapper.h
+++ b/libs/hwui/debug/GlesErrorCheckWrapper.h
@@ -27,7 +27,7 @@ public:
GlesErrorCheckWrapper(GlesDriver& base) : mBase(base) {}
#define GL_ENTRY(ret, api, ...) virtual ret api##_(__VA_ARGS__) override;
- #include "gles_decls.in"
+#include "gles_decls.in"
#undef GL_ENTRY
private:
@@ -36,6 +36,6 @@ private:
GlesDriver& mBase;
};
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/MockGlesDriver.h b/libs/hwui/debug/MockGlesDriver.h
index e0bfc5780b21..e48ca193d48f 100644
--- a/libs/hwui/debug/MockGlesDriver.h
+++ b/libs/hwui/debug/MockGlesDriver.h
@@ -27,10 +27,11 @@ namespace debug {
class MockGlesDriver : public FatalBaseDriver {
public:
MOCK_METHOD2(glBindBuffer_, void(GLenum target, GLuint buffer));
- MOCK_METHOD4(glBufferData_, void(GLenum target, GLsizeiptr size, const void *data, GLenum usage));
- MOCK_METHOD2(glGenBuffers_, void(GLsizei n, GLuint *buffers));
+ MOCK_METHOD4(glBufferData_,
+ void(GLenum target, GLsizeiptr size, const void* data, GLenum usage));
+ MOCK_METHOD2(glGenBuffers_, void(GLsizei n, GLuint* buffers));
};
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/NullGlesDriver.cpp b/libs/hwui/debug/NullGlesDriver.cpp
index 8fbe4bfe7033..212b24290e22 100644
--- a/libs/hwui/debug/NullGlesDriver.cpp
+++ b/libs/hwui/debug/NullGlesDriver.cpp
@@ -29,27 +29,27 @@ struct {
GLboolean scissorEnabled;
} gState;
-static void nullglGenCommon(GLsizei n, GLuint *buffers) {
+static void nullglGenCommon(GLsizei n, GLuint* buffers) {
static GLuint nextId = 0;
int i;
- for(i = 0; i < n; i++) {
+ for (i = 0; i < n; i++) {
buffers[i] = ++nextId;
}
}
-void NullGlesDriver::glGenBuffers_(GLsizei n, GLuint *buffers) {
+void NullGlesDriver::glGenBuffers_(GLsizei n, GLuint* buffers) {
nullglGenCommon(n, buffers);
}
-void NullGlesDriver::glGenFramebuffers_(GLsizei n, GLuint *framebuffers) {
+void NullGlesDriver::glGenFramebuffers_(GLsizei n, GLuint* framebuffers) {
nullglGenCommon(n, framebuffers);
}
-void NullGlesDriver::glGenRenderbuffers_(GLsizei n, GLuint *renderbuffers) {
+void NullGlesDriver::glGenRenderbuffers_(GLsizei n, GLuint* renderbuffers) {
nullglGenCommon(n, renderbuffers);
}
-void NullGlesDriver::glGenTextures_(GLsizei n, GLuint *textures) {
+void NullGlesDriver::glGenTextures_(GLsizei n, GLuint* textures) {
nullglGenCommon(n, textures);
}
@@ -63,35 +63,37 @@ GLuint NullGlesDriver::glCreateShader_(GLenum type) {
return ++nextShader;
}
-void NullGlesDriver::glGetProgramiv_(GLuint program, GLenum pname, GLint *params) {
+void NullGlesDriver::glGetProgramiv_(GLuint program, GLenum pname, GLint* params) {
switch (pname) {
- case GL_DELETE_STATUS:
- case GL_LINK_STATUS:
- case GL_VALIDATE_STATUS:
- *params = GL_TRUE;
- break;
- case GL_INFO_LOG_LENGTH:
- *params = 16;
- break;
+ case GL_DELETE_STATUS:
+ case GL_LINK_STATUS:
+ case GL_VALIDATE_STATUS:
+ *params = GL_TRUE;
+ break;
+ case GL_INFO_LOG_LENGTH:
+ *params = 16;
+ break;
}
}
-void NullGlesDriver::glGetProgramInfoLog_(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+void NullGlesDriver::glGetProgramInfoLog_(GLuint program, GLsizei bufSize, GLsizei* length,
+ GLchar* infoLog) {
*length = snprintf(infoLog, bufSize, "success");
if (*length >= bufSize) {
*length = bufSize - 1;
}
}
-void NullGlesDriver::glGetShaderiv_(GLuint shader, GLenum pname, GLint *params) {
+void NullGlesDriver::glGetShaderiv_(GLuint shader, GLenum pname, GLint* params) {
switch (pname) {
- case GL_COMPILE_STATUS:
- case GL_DELETE_STATUS:
- *params = GL_TRUE;
+ case GL_COMPILE_STATUS:
+ case GL_DELETE_STATUS:
+ *params = GL_TRUE;
}
}
-void NullGlesDriver::glGetShaderInfoLog_(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+void NullGlesDriver::glGetShaderInfoLog_(GLuint shader, GLsizei bufSize, GLsizei* length,
+ GLchar* infoLog) {
*length = snprintf(infoLog, bufSize, "success");
if (*length >= bufSize) {
*length = bufSize - 1;
@@ -100,9 +102,9 @@ void NullGlesDriver::glGetShaderInfoLog_(GLuint shader, GLsizei bufSize, GLsizei
void setBooleanState(GLenum cap, GLboolean value) {
switch (cap) {
- case GL_SCISSOR_TEST:
- gState.scissorEnabled = value;
- break;
+ case GL_SCISSOR_TEST:
+ gState.scissorEnabled = value;
+ break;
}
}
@@ -116,55 +118,55 @@ void NullGlesDriver::glDisable_(GLenum cap) {
GLboolean NullGlesDriver::glIsEnabled_(GLenum cap) {
switch (cap) {
- case GL_SCISSOR_TEST:
- return gState.scissorEnabled;
- default:
- return GL_FALSE;
+ case GL_SCISSOR_TEST:
+ return gState.scissorEnabled;
+ default:
+ return GL_FALSE;
}
}
-void NullGlesDriver::glGetIntegerv_(GLenum pname, GLint *data) {
+void NullGlesDriver::glGetIntegerv_(GLenum pname, GLint* data) {
switch (pname) {
- case GL_MAX_TEXTURE_SIZE:
- *data = 2048;
- break;
- case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
- *data = 4;
- break;
- default:
- *data = 0;
+ case GL_MAX_TEXTURE_SIZE:
+ *data = 2048;
+ break;
+ case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+ *data = 4;
+ break;
+ default:
+ *data = 0;
}
}
GLenum NullGlesDriver::glCheckFramebufferStatus_(GLenum target) {
switch (target) {
- case GL_FRAMEBUFFER:
- return GL_FRAMEBUFFER_COMPLETE;
- default:
- return 0; // error case
+ case GL_FRAMEBUFFER:
+ return GL_FRAMEBUFFER_COMPLETE;
+ default:
+ return 0; // error case
}
}
static const char* getString(GLenum name) {
switch (name) {
- case GL_VENDOR:
- return "android";
- case GL_RENDERER:
- return "null";
- case GL_VERSION:
- return "OpenGL ES 2.0 rev1";
- case GL_SHADING_LANGUAGE_VERSION:
- return "OpenGL ES GLSL ES 2.0 rev1";
- case GL_EXTENSIONS:
- default:
- return "";
+ case GL_VENDOR:
+ return "android";
+ case GL_RENDERER:
+ return "null";
+ case GL_VERSION:
+ return "OpenGL ES 2.0 rev1";
+ case GL_SHADING_LANGUAGE_VERSION:
+ return "OpenGL ES GLSL ES 2.0 rev1";
+ case GL_EXTENSIONS:
+ default:
+ return "";
}
}
const GLubyte* NullGlesDriver::glGetString_(GLenum name) {
- return (GLubyte*) getString(name);
+ return (GLubyte*)getString(name);
}
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/NullGlesDriver.h b/libs/hwui/debug/NullGlesDriver.h
index 37ca8f34f87b..1a27dbc35299 100644
--- a/libs/hwui/debug/NullGlesDriver.h
+++ b/libs/hwui/debug/NullGlesDriver.h
@@ -26,26 +26,28 @@ class NullGlesDriver : public FatalBaseDriver {
public:
virtual sk_sp<const GrGLInterface> getSkiaInterface() override;
- virtual void glGenBuffers_(GLsizei n, GLuint *buffers) override;
- virtual void glGenFramebuffers_(GLsizei n, GLuint *framebuffers) override;
- virtual void glGenRenderbuffers_(GLsizei n, GLuint *renderbuffers) override;
- virtual void glGenTextures_(GLsizei n, GLuint *textures) override;
+ virtual void glGenBuffers_(GLsizei n, GLuint* buffers) override;
+ virtual void glGenFramebuffers_(GLsizei n, GLuint* framebuffers) override;
+ virtual void glGenRenderbuffers_(GLsizei n, GLuint* renderbuffers) override;
+ virtual void glGenTextures_(GLsizei n, GLuint* textures) override;
virtual GLuint glCreateProgram_(void) override;
virtual GLuint glCreateShader_(GLenum type) override;
- virtual void glGetProgramiv_(GLuint program, GLenum pname, GLint *params) override;
- virtual void glGetProgramInfoLog_(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) override;
- virtual void glGetShaderiv_(GLuint shader, GLenum pname, GLint *params) override;
- virtual void glGetShaderInfoLog_(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) override;
+ virtual void glGetProgramiv_(GLuint program, GLenum pname, GLint* params) override;
+ virtual void glGetProgramInfoLog_(GLuint program, GLsizei bufSize, GLsizei* length,
+ GLchar* infoLog) override;
+ virtual void glGetShaderiv_(GLuint shader, GLenum pname, GLint* params) override;
+ virtual void glGetShaderInfoLog_(GLuint shader, GLsizei bufSize, GLsizei* length,
+ GLchar* infoLog) override;
virtual void glEnable_(GLenum cap) override;
virtual void glDisable_(GLenum cap) override;
virtual GLboolean glIsEnabled_(GLenum cap) override;
- virtual void glGetIntegerv_(GLenum pname, GLint *data) override;
+ virtual void glGetIntegerv_(GLenum pname, GLint* data) override;
virtual const GLubyte* glGetString_(GLenum name) override;
virtual GLenum glCheckFramebufferStatus_(GLenum target) override;
virtual void glActiveTexture_(GLenum texture) override {}
virtual void glAttachShader_(GLuint program, GLuint shader) override {}
- virtual void glBindAttribLocation_(GLuint program, GLuint index, const GLchar *name) override {}
+ virtual void glBindAttribLocation_(GLuint program, GLuint index, const GLchar* name) override {}
virtual void glBindBuffer_(GLenum target, GLuint buffer) override {}
virtual void glBindFramebuffer_(GLenum target, GLuint framebuffer) override {}
virtual void glBindRenderbuffer_(GLenum target, GLuint renderbuffer) override {}
@@ -54,116 +56,147 @@ public:
virtual void glBlendEquation_(GLenum mode) override {}
virtual void glBlendEquationSeparate_(GLenum modeRGB, GLenum modeAlpha) override {}
virtual void glBlendFunc_(GLenum sfactor, GLenum dfactor) override {}
- virtual void glBlendFuncSeparate_(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) override {}
- virtual void glBufferData_(GLenum target, GLsizeiptr size, const void *data, GLenum usage) override {}
- virtual void glBufferSubData_(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) override {}
+ virtual void glBlendFuncSeparate_(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha,
+ GLenum dfactorAlpha) override {}
+ virtual void glBufferData_(GLenum target, GLsizeiptr size, const void* data,
+ GLenum usage) override {}
+ virtual void glBufferSubData_(GLenum target, GLintptr offset, GLsizeiptr size,
+ const void* data) override {}
virtual void glClear_(GLbitfield mask) override {}
virtual void glClearColor_(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) override {}
virtual void glClearDepthf_(GLfloat d) override {}
virtual void glClearStencil_(GLint s) override {}
- virtual void glColorMask_(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) override {}
+ virtual void glColorMask_(GLboolean red, GLboolean green, GLboolean blue,
+ GLboolean alpha) override {}
virtual void glCompileShader_(GLuint shader) override {}
- virtual void glCompressedTexImage2D_(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) override {}
- virtual void glCompressedTexSubImage2D_(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) override {}
- virtual void glCopyTexImage2D_(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) override {}
- virtual void glCopyTexSubImage2D_(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) override {}
+ virtual void glCompressedTexImage2D_(GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLint border,
+ GLsizei imageSize, const void* data) override {}
+ virtual void glCompressedTexSubImage2D_(GLenum target, GLint level, GLint xoffset,
+ GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLsizei imageSize,
+ const void* data) override {}
+ virtual void glCopyTexImage2D_(GLenum target, GLint level, GLenum internalformat, GLint x,
+ GLint y, GLsizei width, GLsizei height, GLint border) override {}
+ virtual void glCopyTexSubImage2D_(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLint x, GLint y, GLsizei width, GLsizei height) override {}
virtual void glCullFace_(GLenum mode) override {}
- virtual void glDeleteBuffers_(GLsizei n, const GLuint *buffers) override {}
- virtual void glDeleteFramebuffers_(GLsizei n, const GLuint *framebuffers) override {}
+ virtual void glDeleteBuffers_(GLsizei n, const GLuint* buffers) override {}
+ virtual void glDeleteFramebuffers_(GLsizei n, const GLuint* framebuffers) override {}
virtual void glDeleteProgram_(GLuint program) override {}
- virtual void glDeleteRenderbuffers_(GLsizei n, const GLuint *renderbuffers) override {}
+ virtual void glDeleteRenderbuffers_(GLsizei n, const GLuint* renderbuffers) override {}
virtual void glDeleteShader_(GLuint shader) override {}
- virtual void glDeleteTextures_(GLsizei n, const GLuint *textures) override {}
+ virtual void glDeleteTextures_(GLsizei n, const GLuint* textures) override {}
virtual void glDepthFunc_(GLenum func) override {}
virtual void glDepthMask_(GLboolean flag) override {}
virtual void glDepthRangef_(GLfloat n, GLfloat f) override {}
virtual void glDetachShader_(GLuint program, GLuint shader) override {}
virtual void glDisableVertexAttribArray_(GLuint index) override {}
virtual void glDrawArrays_(GLenum mode, GLint first, GLsizei count) override {}
- virtual void glDrawElements_(GLenum mode, GLsizei count, GLenum type, const void *indices) override {}
+ virtual void glDrawElements_(GLenum mode, GLsizei count, GLenum type,
+ const void* indices) override {}
virtual void glEnableVertexAttribArray_(GLuint index) override {}
virtual void glFinish_(void) override {}
virtual void glFlush_(void) override {}
- virtual void glFramebufferRenderbuffer_(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) override {}
- virtual void glFramebufferTexture2D_(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) override {}
+ virtual void glFramebufferRenderbuffer_(GLenum target, GLenum attachment,
+ GLenum renderbuffertarget,
+ GLuint renderbuffer) override {}
+ virtual void glFramebufferTexture2D_(GLenum target, GLenum attachment, GLenum textarget,
+ GLuint texture, GLint level) override {}
virtual void glFrontFace_(GLenum mode) override {}
virtual void glGenerateMipmap_(GLenum target) override {}
- virtual GLint glGetAttribLocation_(GLuint program, const GLchar *name) override { return 1; }
+ virtual GLint glGetAttribLocation_(GLuint program, const GLchar* name) override { return 1; }
virtual GLenum glGetError_(void) override { return GL_NO_ERROR; }
- virtual GLint glGetUniformLocation_(GLuint program, const GLchar *name) override { return 2; }
+ virtual GLint glGetUniformLocation_(GLuint program, const GLchar* name) override { return 2; }
virtual void glHint_(GLenum target, GLenum mode) override {}
virtual void glLineWidth_(GLfloat width) override {}
virtual void glLinkProgram_(GLuint program) override {}
virtual void glPixelStorei_(GLenum pname, GLint param) override {}
virtual void glPolygonOffset_(GLfloat factor, GLfloat units) override {}
- virtual void glReadPixels_(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) override {}
+ virtual void glReadPixels_(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
+ GLenum type, void* pixels) override {}
virtual void glReleaseShaderCompiler_(void) override {}
- virtual void glRenderbufferStorage_(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) override {}
+ virtual void glRenderbufferStorage_(GLenum target, GLenum internalformat, GLsizei width,
+ GLsizei height) override {}
virtual void glSampleCoverage_(GLfloat value, GLboolean invert) override {}
virtual void glScissor_(GLint x, GLint y, GLsizei width, GLsizei height) override {}
- virtual void glShaderBinary_(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length) override {}
- virtual void glShaderSource_(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length) override {}
+ virtual void glShaderBinary_(GLsizei count, const GLuint* shaders, GLenum binaryformat,
+ const void* binary, GLsizei length) override {}
+ virtual void glShaderSource_(GLuint shader, GLsizei count, const GLchar* const* string,
+ const GLint* length) override {}
virtual void glStencilFunc_(GLenum func, GLint ref, GLuint mask) override {}
- virtual void glStencilFuncSeparate_(GLenum face, GLenum func, GLint ref, GLuint mask) override {}
+ virtual void glStencilFuncSeparate_(GLenum face, GLenum func, GLint ref, GLuint mask) override {
+ }
virtual void glStencilMask_(GLuint mask) override {}
virtual void glStencilMaskSeparate_(GLenum face, GLuint mask) override {}
virtual void glStencilOp_(GLenum fail, GLenum zfail, GLenum zpass) override {}
- virtual void glStencilOpSeparate_(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) override {}
- virtual void glTexImage2D_(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) override {}
+ virtual void glStencilOpSeparate_(GLenum face, GLenum sfail, GLenum dpfail,
+ GLenum dppass) override {}
+ virtual void glTexImage2D_(GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const void* pixels) override {}
virtual void glTexParameterf_(GLenum target, GLenum pname, GLfloat param) override {}
- virtual void glTexParameterfv_(GLenum target, GLenum pname, const GLfloat *params) override {}
+ virtual void glTexParameterfv_(GLenum target, GLenum pname, const GLfloat* params) override {}
virtual void glTexParameteri_(GLenum target, GLenum pname, GLint param) override {}
- virtual void glTexParameteriv_(GLenum target, GLenum pname, const GLint *params) override {}
- virtual void glTexSubImage2D_(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) override {}
+ virtual void glTexParameteriv_(GLenum target, GLenum pname, const GLint* params) override {}
+ virtual void glTexSubImage2D_(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height, GLenum format, GLenum type,
+ const void* pixels) override {}
virtual void glUniform1f_(GLint location, GLfloat v0) override {}
- virtual void glUniform1fv_(GLint location, GLsizei count, const GLfloat *value) override {}
+ virtual void glUniform1fv_(GLint location, GLsizei count, const GLfloat* value) override {}
virtual void glUniform1i_(GLint location, GLint v0) override {}
- virtual void glUniform1iv_(GLint location, GLsizei count, const GLint *value) override {}
+ virtual void glUniform1iv_(GLint location, GLsizei count, const GLint* value) override {}
virtual void glUniform2f_(GLint location, GLfloat v0, GLfloat v1) override {}
- virtual void glUniform2fv_(GLint location, GLsizei count, const GLfloat *value) override {}
+ virtual void glUniform2fv_(GLint location, GLsizei count, const GLfloat* value) override {}
virtual void glUniform2i_(GLint location, GLint v0, GLint v1) override {}
- virtual void glUniform2iv_(GLint location, GLsizei count, const GLint *value) override {}
+ virtual void glUniform2iv_(GLint location, GLsizei count, const GLint* value) override {}
virtual void glUniform3f_(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) override {}
- virtual void glUniform3fv_(GLint location, GLsizei count, const GLfloat *value) override {}
+ virtual void glUniform3fv_(GLint location, GLsizei count, const GLfloat* value) override {}
virtual void glUniform3i_(GLint location, GLint v0, GLint v1, GLint v2) override {}
- virtual void glUniform3iv_(GLint location, GLsizei count, const GLint *value) override {}
- virtual void glUniform4f_(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) override {}
- virtual void glUniform4fv_(GLint location, GLsizei count, const GLfloat *value) override {}
+ virtual void glUniform3iv_(GLint location, GLsizei count, const GLint* value) override {}
+ virtual void glUniform4f_(GLint location, GLfloat v0, GLfloat v1, GLfloat v2,
+ GLfloat v3) override {}
+ virtual void glUniform4fv_(GLint location, GLsizei count, const GLfloat* value) override {}
virtual void glUniform4i_(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) override {}
- virtual void glUniform4iv_(GLint location, GLsizei count, const GLint *value) override {}
- virtual void glUniformMatrix2fv_(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override {}
- virtual void glUniformMatrix3fv_(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override {}
- virtual void glUniformMatrix4fv_(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override {}
+ virtual void glUniform4iv_(GLint location, GLsizei count, const GLint* value) override {}
+ virtual void glUniformMatrix2fv_(GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) override {}
+ virtual void glUniformMatrix3fv_(GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) override {}
+ virtual void glUniformMatrix4fv_(GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) override {}
virtual void glUseProgram_(GLuint program) override {}
virtual void glValidateProgram_(GLuint program) override {}
virtual void glVertexAttrib1f_(GLuint index, GLfloat x) override {}
- virtual void glVertexAttrib1fv_(GLuint index, const GLfloat *v) override {}
+ virtual void glVertexAttrib1fv_(GLuint index, const GLfloat* v) override {}
virtual void glVertexAttrib2f_(GLuint index, GLfloat x, GLfloat y) override {}
- virtual void glVertexAttrib2fv_(GLuint index, const GLfloat *v) override {}
+ virtual void glVertexAttrib2fv_(GLuint index, const GLfloat* v) override {}
virtual void glVertexAttrib3f_(GLuint index, GLfloat x, GLfloat y, GLfloat z) override {}
- virtual void glVertexAttrib3fv_(GLuint index, const GLfloat *v) override {}
- virtual void glVertexAttrib4f_(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) override {}
- virtual void glVertexAttrib4fv_(GLuint index, const GLfloat *v) override {}
- virtual void glVertexAttribPointer_(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) override {}
+ virtual void glVertexAttrib3fv_(GLuint index, const GLfloat* v) override {}
+ virtual void glVertexAttrib4f_(GLuint index, GLfloat x, GLfloat y, GLfloat z,
+ GLfloat w) override {}
+ virtual void glVertexAttrib4fv_(GLuint index, const GLfloat* v) override {}
+ virtual void glVertexAttribPointer_(GLuint index, GLint size, GLenum type, GLboolean normalized,
+ GLsizei stride, const void* pointer) override {}
virtual void glViewport_(GLint x, GLint y, GLsizei width, GLsizei height) override {}
// gles2 ext
- virtual void glInsertEventMarkerEXT_(GLsizei length, const GLchar *marker) override {}
- virtual void glPushGroupMarkerEXT_(GLsizei length, const GLchar *marker) override {}
+ virtual void glInsertEventMarkerEXT_(GLsizei length, const GLchar* marker) override {}
+ virtual void glPushGroupMarkerEXT_(GLsizei length, const GLchar* marker) override {}
virtual void glPopGroupMarkerEXT_(void) override {}
- virtual void glDiscardFramebufferEXT_(GLenum target, GLsizei numAttachments, const GLenum *attachments) override {}
+ virtual void glDiscardFramebufferEXT_(GLenum target, GLsizei numAttachments,
+ const GLenum* attachments) override {}
virtual void glEGLImageTargetTexture2DOES_(GLenum target, GLeglImageOES image) override {}
// GLES3
- virtual void* glMapBufferRange_(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) override {
+ virtual void* glMapBufferRange_(GLenum target, GLintptr offset, GLsizeiptr length,
+ GLbitfield access) override {
return 0;
}
- virtual GLboolean glUnmapBuffer_(GLenum target) override {
- return GL_FALSE;
- }
+ virtual GLboolean glUnmapBuffer_(GLenum target) override { return GL_FALSE; }
};
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/ScopedReplaceDriver.h b/libs/hwui/debug/ScopedReplaceDriver.h
index 342c9d223727..110196fb2a01 100644
--- a/libs/hwui/debug/ScopedReplaceDriver.h
+++ b/libs/hwui/debug/ScopedReplaceDriver.h
@@ -33,14 +33,13 @@ public:
Driver& get() { return *mCurrentDriver; }
- ~ScopedReplaceDriver() {
- GlesDriver::replace(std::move(mOldDriver));
- }
+ ~ScopedReplaceDriver() { GlesDriver::replace(std::move(mOldDriver)); }
+
private:
std::unique_ptr<GlesDriver> mOldDriver;
Driver* mCurrentDriver;
};
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/gles_redefine.h b/libs/hwui/debug/gles_redefine.h
index 201f0a945209..49b506918372 100644
--- a/libs/hwui/debug/gles_redefine.h
+++ b/libs/hwui/debug/gles_redefine.h
@@ -212,7 +212,8 @@
#define glDrawElementsInstancedANGLE wrap_glDrawElementsInstancedANGLE
#define glDrawElementsInstancedBaseInstanceEXT wrap_glDrawElementsInstancedBaseInstanceEXT
#define glDrawElementsInstancedBaseVertex wrap_glDrawElementsInstancedBaseVertex
-#define glDrawElementsInstancedBaseVertexBaseInstanceEXT wrap_glDrawElementsInstancedBaseVertexBaseInstanceEXT
+#define glDrawElementsInstancedBaseVertexBaseInstanceEXT \
+ wrap_glDrawElementsInstancedBaseVertexBaseInstanceEXT
#define glDrawElementsInstancedBaseVertexEXT wrap_glDrawElementsInstancedBaseVertexEXT
#define glDrawElementsInstancedBaseVertexOES wrap_glDrawElementsInstancedBaseVertexOES
#define glDrawElementsInstancedEXT wrap_glDrawElementsInstancedEXT
diff --git a/libs/hwui/debug/nullegl.cpp b/libs/hwui/debug/nullegl.cpp
index 2ae71df5c22c..ca47f8fd22ef 100644
--- a/libs/hwui/debug/nullegl.cpp
+++ b/libs/hwui/debug/nullegl.cpp
@@ -21,8 +21,8 @@
#include <stdlib.h>
#include <string.h>
-static EGLDisplay gDisplay = (EGLDisplay) 1;
-static EGLSyncKHR gFence = (EGLSyncKHR) 1;
+static EGLDisplay gDisplay = (EGLDisplay)1;
+static EGLSyncKHR gFence = (EGLSyncKHR)1;
typedef struct {
EGLSurface surface;
@@ -43,8 +43,8 @@ static void makeThreadState() {
ThreadState* getThreadState() {
ThreadState* ptr;
pthread_once(&ThreadStateSetupOnce, makeThreadState);
- if ((ptr = (ThreadState*) pthread_getspecific(ThreadStateKey)) == NULL) {
- ptr = (ThreadState*) calloc(1, sizeof(ThreadState));
+ if ((ptr = (ThreadState*)pthread_getspecific(ThreadStateKey)) == NULL) {
+ ptr = (ThreadState*)calloc(1, sizeof(ThreadState));
ptr->context = EGL_NO_CONTEXT;
ptr->surface = EGL_NO_SURFACE;
pthread_setspecific(ThreadStateKey, ptr);
@@ -60,7 +60,7 @@ EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) {
return gDisplay;
}
-EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) {
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) {
return EGL_TRUE;
}
@@ -68,30 +68,27 @@ EGLBoolean eglTerminate(EGLDisplay dpy) {
return EGL_TRUE;
}
-const char * eglQueryString(EGLDisplay dpy, EGLint name) {
+const char* eglQueryString(EGLDisplay dpy, EGLint name) {
if (name == EGL_EXTENSIONS) {
return "EGL_KHR_swap_buffers_with_damage";
}
return "";
}
-EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
- EGLConfig *configs, EGLint config_size,
- EGLint *num_config) {
+EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs,
+ EGLint config_size, EGLint* num_config) {
memset(configs, 9, sizeof(EGLConfig) * config_size);
*num_config = config_size;
return EGL_TRUE;
}
-EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
- EGLNativeWindowType win,
- const EGLint *attrib_list) {
- return (EGLSurface) malloc(sizeof(void*));
+EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win,
+ const EGLint* attrib_list) {
+ return (EGLSurface)malloc(sizeof(void*));
}
-EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
- const EGLint *attrib_list) {
- return (EGLSurface) malloc(sizeof(void*));
+EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list) {
+ return (EGLSurface)malloc(sizeof(void*));
}
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) {
@@ -99,8 +96,7 @@ EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) {
return EGL_TRUE;
}
-EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface,
- EGLint attribute, EGLint *value) {
+EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint* value) {
*value = 1000;
return EGL_TRUE;
}
@@ -109,8 +105,7 @@ EGLBoolean eglReleaseThread(void) {
return EGL_TRUE;
}
-EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface,
- EGLint attribute, EGLint value) {
+EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) {
return EGL_TRUE;
}
@@ -118,18 +113,16 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) {
return EGL_TRUE;
}
-EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
- EGLContext share_context,
- const EGLint *attrib_list) {
- return (EGLContext) malloc(sizeof(void*));
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context,
+ const EGLint* attrib_list) {
+ return (EGLContext)malloc(sizeof(void*));
}
EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) {
free(ctx);
return EGL_TRUE;
}
-EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
- EGLSurface read, EGLContext ctx) {
+EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
ThreadState* state = getThreadState();
state->surface = draw;
state->context = ctx;
@@ -152,15 +145,17 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
return EGL_TRUE;
}
-EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint rectCount) {
+EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface surface, EGLint* rects,
+ EGLint rectCount) {
return EGL_TRUE;
}
-EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) {
- return (EGLImageKHR) malloc(sizeof(EGLImageKHR));
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
+ EGLClientBuffer buffer, const EGLint* attrib_list) {
+ return (EGLImageKHR)malloc(sizeof(EGLImageKHR));
}
-EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) {
+EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint* attrib_list) {
return gFence;
}
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index 73beba9297c4..5dd8bb8119e9 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -16,12 +16,12 @@
#include <SkGlyph.h>
-#include "CacheTexture.h"
-#include "FontUtil.h"
#include "../Caches.h"
#include "../Debug.h"
#include "../Extensions.h"
#include "../PixelBuffer.h"
+#include "CacheTexture.h"
+#include "FontUtil.h"
namespace android {
namespace uirenderer {
@@ -37,9 +37,8 @@ namespace uirenderer {
*/
CacheBlock* CacheBlock::insertBlock(CacheBlock* head, CacheBlock* newBlock) {
#if DEBUG_FONT_RENDERER
- ALOGD("insertBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
- newBlock, newBlock->mX, newBlock->mY,
- newBlock->mWidth, newBlock->mHeight);
+ ALOGD("insertBlock: this, x, y, w, h = %p, %d, %d, %d, %d", newBlock, newBlock->mX,
+ newBlock->mY, newBlock->mWidth, newBlock->mHeight);
#endif
CacheBlock* currBlock = head;
@@ -81,9 +80,8 @@ CacheBlock* CacheBlock::insertBlock(CacheBlock* head, CacheBlock* newBlock) {
CacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock* blockToRemove) {
#if DEBUG_FONT_RENDERER
- ALOGD("removeBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
- blockToRemove, blockToRemove->mX, blockToRemove->mY,
- blockToRemove->mWidth, blockToRemove->mHeight);
+ ALOGD("removeBlock: this, x, y, w, h = %p, %d, %d, %d, %d", blockToRemove, blockToRemove->mX,
+ blockToRemove->mY, blockToRemove->mWidth, blockToRemove->mHeight);
#endif
CacheBlock* newHead = head;
@@ -93,7 +91,7 @@ CacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock* blockToRemove)
if (prevBlock) {
// If this doesn't hold, we have a use-after-free below.
LOG_ALWAYS_FATAL_IF(head == blockToRemove,
- "removeBlock: head should not have a previous block");
+ "removeBlock: head should not have a previous block");
prevBlock->mNext = nextBlock;
} else {
newHead = nextBlock;
@@ -121,8 +119,9 @@ CacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint3
, mCaches(Caches::getInstance()) {
mTexture.blend = true;
- mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
- getWidth() - TEXTURE_BORDER_SIZE, getHeight() - TEXTURE_BORDER_SIZE);
+ mCacheBlocks =
+ new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
+ getWidth() - TEXTURE_BORDER_SIZE, getHeight() - TEXTURE_BORDER_SIZE);
// OpenGL ES 3.0+ lets us specify the row length for unpack operations such
// as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
@@ -150,8 +149,9 @@ void CacheTexture::reset() {
void CacheTexture::init() {
// reset, then create a new remainder space to start again
reset();
- mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
- getWidth() - TEXTURE_BORDER_SIZE, getHeight() - TEXTURE_BORDER_SIZE);
+ mCacheBlocks =
+ new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
+ getWidth() - TEXTURE_BORDER_SIZE, getHeight() - TEXTURE_BORDER_SIZE);
}
void CacheTexture::releaseMesh() {
@@ -233,7 +233,7 @@ bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_
if (mFormat != GL_ALPHA) {
#if DEBUG_FONT_RENDERER
ALOGD("fitBitmap: texture format %x is inappropriate for monochromatic glyphs",
- mFormat);
+ mFormat);
#endif
return false;
}
@@ -272,8 +272,8 @@ bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_
// it's the remainder space (mY == 0) or there's only enough height for this one glyph
// or it's within ROUNDING_SIZE of the block width
if (roundedUpW <= cacheBlock->mWidth && glyphH <= cacheBlock->mHeight &&
- (cacheBlock->mY == TEXTURE_BORDER_SIZE ||
- (cacheBlock->mWidth - roundedUpW < CACHE_BLOCK_ROUNDING_SIZE))) {
+ (cacheBlock->mY == TEXTURE_BORDER_SIZE ||
+ (cacheBlock->mWidth - roundedUpW < CACHE_BLOCK_ROUNDING_SIZE))) {
if (cacheBlock->mHeight - glyphH < glyphH) {
// Only enough space for this glyph - don't bother rounding up the width
roundedUpW = glyphW;
@@ -292,12 +292,13 @@ bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_
if (getHeight() - glyphH >= glyphH) {
// There's enough height left over to create a new CacheBlock
- CacheBlock* newBlock = new CacheBlock(oldX, glyphH + TEXTURE_BORDER_SIZE,
- roundedUpW, getHeight() - glyphH - TEXTURE_BORDER_SIZE);
+ CacheBlock* newBlock =
+ new CacheBlock(oldX, glyphH + TEXTURE_BORDER_SIZE, roundedUpW,
+ getHeight() - glyphH - TEXTURE_BORDER_SIZE);
#if DEBUG_FONT_RENDERER
ALOGD("fitBitmap: Created new block: this, x, y, w, h = %p, %d, %d, %d, %d",
- newBlock, newBlock->mX, newBlock->mY,
- newBlock->mWidth, newBlock->mHeight);
+ newBlock, newBlock->mX, newBlock->mY, newBlock->mWidth,
+ newBlock->mHeight);
#endif
mCacheBlocks = CacheBlock::insertBlock(mCacheBlocks, newBlock);
}
@@ -307,8 +308,8 @@ bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_
cacheBlock->mHeight -= glyphH;
#if DEBUG_FONT_RENDERER
ALOGD("fitBitmap: Added to existing block: this, x, y, w, h = %p, %d, %d, %d, %d",
- cacheBlock, cacheBlock->mX, cacheBlock->mY,
- cacheBlock->mWidth, cacheBlock->mHeight);
+ cacheBlock, cacheBlock->mX, cacheBlock->mY, cacheBlock->mWidth,
+ cacheBlock->mHeight);
#endif
}
@@ -319,7 +320,7 @@ bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_
mDirty = true;
const Rect r(*retOriginX - TEXTURE_BORDER_SIZE, *retOriginY - TEXTURE_BORDER_SIZE,
- *retOriginX + glyphW, *retOriginY + glyphH);
+ *retOriginX + glyphW, *retOriginY + glyphH);
mDirtyRect.unionWith(r);
mNumGlyphs++;
@@ -350,5 +351,5 @@ uint32_t CacheTexture::calculateFreeMemory() const {
return free;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
index 6750a8ae11cf..654378eeb47e 100644
--- a/libs/hwui/font/CacheTexture.h
+++ b/libs/hwui/font/CacheTexture.h
@@ -26,7 +26,6 @@
#include <SkGlyph.h>
#include <utils/Log.h>
-
namespace android {
namespace uirenderer {
@@ -53,9 +52,8 @@ struct CacheBlock {
CacheBlock* mNext;
CacheBlock* mPrev;
- CacheBlock(uint16_t x, uint16_t y, uint16_t width, uint16_t height):
- mX(x), mY(y), mWidth(width), mHeight(height), mNext(nullptr), mPrev(nullptr) {
- }
+ CacheBlock(uint16_t x, uint16_t y, uint16_t width, uint16_t height)
+ : mX(x), mY(y), mWidth(width), mHeight(height), mNext(nullptr), mPrev(nullptr) {}
static CacheBlock* insertBlock(CacheBlock* head, CacheBlock* newBlock);
static CacheBlock* removeBlock(CacheBlock* head, CacheBlock* blockToRemove);
@@ -63,9 +61,8 @@ struct CacheBlock {
void output() {
CacheBlock* currBlock = this;
while (currBlock) {
- ALOGD("Block: this, x, y, w, h = %p, %d, %d, %d, %d",
- currBlock, currBlock->mX, currBlock->mY,
- currBlock->mWidth, currBlock->mHeight);
+ ALOGD("Block: this, x, y, w, h = %p, %d, %d, %d, %d", currBlock, currBlock->mX,
+ currBlock->mY, currBlock->mWidth, currBlock->mHeight);
currBlock = currBlock->mNext;
}
}
@@ -91,29 +88,19 @@ public:
bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY);
- inline uint16_t getWidth() const {
- return mWidth;
- }
+ inline uint16_t getWidth() const { return mWidth; }
- inline uint16_t getHeight() const {
- return mHeight;
- }
+ inline uint16_t getHeight() const { return mHeight; }
- inline GLenum getFormat() const {
- return mFormat;
- }
+ inline GLenum getFormat() const { return mFormat; }
inline uint32_t getOffset(uint16_t x, uint16_t y) const {
return (y * getWidth() + x) * PixelBuffer::formatSize(mFormat);
}
- inline const Rect* getDirtyRect() const {
- return &mDirtyRect;
- }
+ inline const Rect* getDirtyRect() const { return &mDirtyRect; }
- inline PixelBuffer* getPixelBuffer() const {
- return mPixelBuffer;
- }
+ inline PixelBuffer* getPixelBuffer() const { return mPixelBuffer; }
Texture& getTexture() {
allocatePixelBuffer();
@@ -125,43 +112,28 @@ public:
return mTexture.id();
}
- inline bool isDirty() const {
- return mDirty;
- }
+ inline bool isDirty() const { return mDirty; }
- inline bool getLinearFiltering() const {
- return mLinearFiltering;
- }
+ inline bool getLinearFiltering() const { return mLinearFiltering; }
/**
* This method assumes that the proper texture unit is active.
*/
void setLinearFiltering(bool linearFiltering);
- inline uint16_t getGlyphCount() const {
- return mNumGlyphs;
- }
+ inline uint16_t getGlyphCount() const { return mNumGlyphs; }
- TextureVertex* mesh() const {
- return mMesh;
- }
+ TextureVertex* mesh() const { return mMesh; }
- uint32_t meshElementCount() const {
- return mCurrentQuad * 6;
- }
+ uint32_t meshElementCount() const { return mCurrentQuad * 6; }
- uint16_t* indices() const {
- return (uint16_t*) nullptr;
- }
+ uint16_t* indices() const { return (uint16_t*)nullptr; }
- void resetMesh() {
- mCurrentQuad = 0;
- }
+ void resetMesh() { mCurrentQuad = 0; }
- inline void addQuad(float x1, float y1, float u1, float v1,
- float x2, float y2, float u2, float v2,
- float x3, float y3, float u3, float v3,
- float x4, float y4, float u4, float v4) {
+ inline void addQuad(float x1, float y1, float u1, float v1, float x2, float y2, float u2,
+ float v2, float x3, float y3, float u3, float v3, float x4, float y4,
+ float u4, float v4) {
TextureVertex* mesh = mMesh + mCurrentQuad * 4;
TextureVertex::set(mesh++, x2, y2, u2, v2);
TextureVertex::set(mesh++, x3, y3, u3, v3);
@@ -170,13 +142,9 @@ public:
mCurrentQuad++;
}
- bool canDraw() const {
- return mCurrentQuad > 0;
- }
+ bool canDraw() const { return mCurrentQuad > 0; }
- bool endOfMesh() const {
- return mCurrentQuad == mMaxQuadCount;
- }
+ bool endOfMesh() const { return mCurrentQuad == mMaxQuadCount; }
uint32_t calculateFreeMemory() const;
@@ -199,7 +167,7 @@ private:
Rect mDirtyRect;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_CACHE_TEXTURE_H
+#endif // ANDROID_HWUI_CACHE_TEXTURE_H
diff --git a/libs/hwui/font/CachedGlyphInfo.h b/libs/hwui/font/CachedGlyphInfo.h
index 073d59bdea3f..93bb823db512 100644
--- a/libs/hwui/font/CachedGlyphInfo.h
+++ b/libs/hwui/font/CachedGlyphInfo.h
@@ -50,7 +50,7 @@ struct CachedGlyphInfo {
CacheTexture* mCacheTexture;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_CACHED_GLYPH_INFO_H
+#endif // ANDROID_HWUI_CACHED_GLYPH_INFO_H
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 24d497cb1860..41a24a809e89 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -19,17 +19,17 @@
#include <utils/JenkinsHash.h>
#include <utils/Trace.h>
-#include <SkSurfaceProps.h>
#include <SkGlyph.h>
#include <SkGlyphCache.h>
+#include <SkSurfaceProps.h>
#include <SkUtils.h>
-#include "FontUtil.h"
-#include "Font.h"
#include "../Debug.h"
#include "../FontRenderer.h"
#include "../PixelBuffer.h"
#include "../Properties.h"
+#include "Font.h"
+#include "FontUtil.h"
namespace android {
namespace uirenderer {
@@ -38,8 +38,8 @@ namespace uirenderer {
// Font
///////////////////////////////////////////////////////////////////////////////
-Font::Font(FontRenderer* state, const Font::FontDescription& desc) :
- mState(state), mDescription(desc) { }
+Font::Font(FontRenderer* state, const Font::FontDescription& desc)
+ : mState(state), mDescription(desc) {}
Font::FontDescription::FontDescription(const SkPaint* paint, const SkMatrix& rasterMatrix)
: mLookupTransform(rasterMatrix) {
@@ -82,7 +82,7 @@ hash_t Font::FontDescription::hash() const {
}
int Font::FontDescription::compare(const Font::FontDescription& lhs,
- const Font::FontDescription& rhs) {
+ const Font::FontDescription& rhs) {
int deltaInt = int(lhs.mFontId) - int(rhs.mFontId);
if (deltaInt != 0) return deltaInt;
@@ -110,15 +110,15 @@ int Font::FontDescription::compare(const Font::FontDescription& lhs,
deltaInt = int(lhs.mHinting) - int(rhs.mHinting);
if (deltaInt != 0) return deltaInt;
- if (lhs.mLookupTransform[SkMatrix::kMScaleX] <
- rhs.mLookupTransform[SkMatrix::kMScaleX]) return -1;
- if (lhs.mLookupTransform[SkMatrix::kMScaleX] >
- rhs.mLookupTransform[SkMatrix::kMScaleX]) return +1;
+ if (lhs.mLookupTransform[SkMatrix::kMScaleX] < rhs.mLookupTransform[SkMatrix::kMScaleX])
+ return -1;
+ if (lhs.mLookupTransform[SkMatrix::kMScaleX] > rhs.mLookupTransform[SkMatrix::kMScaleX])
+ return +1;
- if (lhs.mLookupTransform[SkMatrix::kMScaleY] <
- rhs.mLookupTransform[SkMatrix::kMScaleY]) return -1;
- if (lhs.mLookupTransform[SkMatrix::kMScaleY] >
- rhs.mLookupTransform[SkMatrix::kMScaleY]) return +1;
+ if (lhs.mLookupTransform[SkMatrix::kMScaleY] < rhs.mLookupTransform[SkMatrix::kMScaleY])
+ return -1;
+ if (lhs.mLookupTransform[SkMatrix::kMScaleY] > rhs.mLookupTransform[SkMatrix::kMScaleY])
+ return +1;
return 0;
}
@@ -132,10 +132,10 @@ void Font::invalidateTextureCache(CacheTexture* cacheTexture) {
}
}
-void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
- uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
- int width = (int) glyph->mBitmapWidth;
- int height = (int) glyph->mBitmapHeight;
+void Font::measureCachedGlyph(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap,
+ uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
+ int width = (int)glyph->mBitmapWidth;
+ int height = (int)glyph->mBitmapHeight;
int nPenX = x + glyph->mBitmapLeft;
int nPenY = y + glyph->mBitmapTop;
@@ -154,10 +154,10 @@ void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
}
}
-void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
- uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
- float width = (float) glyph->mBitmapWidth;
- float height = (float) glyph->mBitmapHeight;
+void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap, uint32_t bitmapW,
+ uint32_t bitmapH, Rect* bounds, const float* pos) {
+ float width = (float)glyph->mBitmapWidth;
+ float height = (float)glyph->mBitmapHeight;
float nPenX = x + glyph->mBitmapLeft;
float nPenY = y + glyph->mBitmapTop + height;
@@ -167,16 +167,16 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
float v1 = glyph->mBitmapMinV;
float v2 = glyph->mBitmapMaxV;
- mState->appendMeshQuad(nPenX, nPenY, u1, v2,
- nPenX + width, nPenY, u2, v2,
- nPenX + width, nPenY - height, u2, v1,
- nPenX, nPenY - height, u1, v1, glyph->mCacheTexture);
+ mState->appendMeshQuad(nPenX, nPenY, u1, v2, nPenX + width, nPenY, u2, v2, nPenX + width,
+ nPenY - height, u2, v1, nPenX, nPenY - height, u1, v1,
+ glyph->mCacheTexture);
}
-void Font::drawCachedGlyphTransformed(CachedGlyphInfo* glyph, int x, int y,
- uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
- float width = (float) glyph->mBitmapWidth;
- float height = (float) glyph->mBitmapHeight;
+void Font::drawCachedGlyphTransformed(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap,
+ uint32_t bitmapW, uint32_t bitmapH, Rect* bounds,
+ const float* pos) {
+ float width = (float)glyph->mBitmapWidth;
+ float height = (float)glyph->mBitmapHeight;
SkPoint p[4];
p[0].iset(glyph->mBitmapLeft, glyph->mBitmapTop + height);
@@ -196,15 +196,14 @@ void Font::drawCachedGlyphTransformed(CachedGlyphInfo* glyph, int x, int y,
float v1 = glyph->mBitmapMinV;
float v2 = glyph->mBitmapMaxV;
- mState->appendRotatedMeshQuad(
- p[0].x(), p[0].y(), u1, v2,
- p[1].x(), p[1].y(), u2, v2,
- p[2].x(), p[2].y(), u2, v1,
- p[3].x(), p[3].y(), u1, v1, glyph->mCacheTexture);
+ mState->appendRotatedMeshQuad(p[0].x(), p[0].y(), u1, v2, p[1].x(), p[1].y(), u2, v2, p[2].x(),
+ p[2].y(), u2, v1, p[3].x(), p[3].y(), u1, v1,
+ glyph->mCacheTexture);
}
void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap,
- uint32_t bitmapWidth, uint32_t bitmapHeight, Rect* bounds, const float* pos) {
+ uint32_t bitmapWidth, uint32_t bitmapHeight, Rect* bounds,
+ const float* pos) {
int dstX = x + glyph->mBitmapLeft;
int dstY = y + glyph->mBitmapTop;
@@ -221,12 +220,11 @@ void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, uint8_t*
const uint8_t* cacheBuffer = pixelBuffer->map();
for (uint32_t cacheY = startY, bitmapY = dstY * bitmapWidth; cacheY < endY;
- cacheY += srcStride, bitmapY += bitmapWidth) {
-
+ cacheY += srcStride, bitmapY += bitmapWidth) {
for (uint32_t i = 0; i < glyph->mBitmapWidth; ++i) {
uint8_t* dst = &(bitmap[bitmapY + dstX + i]);
- const uint8_t& src = cacheBuffer[
- cacheY + (glyph->mStartX + i)*formatSize + alpha_channel_offset];
+ const uint8_t& src =
+ cacheBuffer[cacheY + (glyph->mStartX + i) * formatSize + alpha_channel_offset];
// Add alpha values to a max of 255, full opacity. This is done to handle
// fonts/strings where glyphs overlap.
*dst = std::min(*dst + src, 255);
@@ -235,7 +233,7 @@ void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, uint8_t*
}
void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset,
- SkPathMeasure& measure, SkPoint* position, SkVector* tangent) {
+ SkPathMeasure& measure, SkPoint* position, SkVector* tangent) {
const float halfWidth = glyph->mBitmapWidth * 0.5f;
const float height = glyph->mBitmapHeight;
@@ -249,13 +247,13 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float
// Move along the tangent and offset by the normal
destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset,
- -tangent->fY * halfWidth + tangent->fX * vOffset);
+ -tangent->fY * halfWidth + tangent->fX * vOffset);
destination[1].set(tangent->fX * halfWidth - tangent->fY * vOffset,
- tangent->fY * halfWidth + tangent->fX * vOffset);
+ tangent->fY * halfWidth + tangent->fX * vOffset);
destination[2].set(destination[1].fX + tangent->fY * height,
- destination[1].fY - tangent->fX * height);
+ destination[1].fY - tangent->fX * height);
destination[3].set(destination[0].fX + tangent->fY * height,
- destination[0].fY - tangent->fX * height);
+ destination[0].fY - tangent->fX * height);
const float u1 = glyph->mBitmapMinU;
const float u2 = glyph->mBitmapMaxU;
@@ -263,14 +261,10 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float
const float v2 = glyph->mBitmapMaxV;
mState->appendRotatedMeshQuad(
- position->x() + destination[0].x(),
- position->y() + destination[0].y(), u1, v2,
- position->x() + destination[1].x(),
- position->y() + destination[1].y(), u2, v2,
- position->x() + destination[2].x(),
- position->y() + destination[2].y(), u2, v1,
- position->x() + destination[3].x(),
- position->y() + destination[3].y(), u1, v1,
+ position->x() + destination[0].x(), position->y() + destination[0].y(), u1, v2,
+ position->x() + destination[1].x(), position->y() + destination[1].y(), u2, v2,
+ position->x() + destination[2].x(), position->y() + destination[2].y(), u2, v1,
+ position->x() + destination[3].x(), position->y() + destination[3].y(), u1, v1,
glyph->mCacheTexture);
}
@@ -280,7 +274,8 @@ CachedGlyphInfo* Font::getCachedGlyph(const SkPaint* paint, glyph_t textUnit, bo
// Is the glyph still in texture cache?
if (!cachedGlyph->mIsValid) {
SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
- SkAutoGlyphCacheNoGamma autoCache(*paint, &surfaceProps, &mDescription.mLookupTransform);
+ SkAutoGlyphCacheNoGamma autoCache(*paint, &surfaceProps,
+ &mDescription.mLookupTransform);
const SkGlyph& skiaGlyph = GET_METRICS(autoCache.getCache(), textUnit);
updateGlyphCache(paint, skiaGlyph, autoCache.getCache(), cachedGlyph, precaching);
}
@@ -291,14 +286,13 @@ CachedGlyphInfo* Font::getCachedGlyph(const SkPaint* paint, glyph_t textUnit, bo
return cachedGlyph;
}
-void Font::render(const SkPaint* paint, const glyph_t* glyphs,
- int numGlyphs, int x, int y, const float* positions) {
- render(paint, glyphs, numGlyphs, x, y, FRAMEBUFFER, nullptr,
- 0, 0, nullptr, positions);
+void Font::render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, int x, int y,
+ const float* positions) {
+ render(paint, glyphs, numGlyphs, x, y, FRAMEBUFFER, nullptr, 0, 0, nullptr, positions);
}
-void Font::render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
- const SkPath* path, float hOffset, float vOffset) {
+void Font::render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, const SkPath* path,
+ float hOffset, float vOffset) {
if (numGlyphs == 0 || glyphs == nullptr) {
return;
}
@@ -345,8 +339,8 @@ void Font::render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
}
}
-void Font::measure(const SkPaint* paint, const glyph_t* glyphs,
- int numGlyphs, Rect *bounds, const float* positions) {
+void Font::measure(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, Rect* bounds,
+ const float* positions) {
if (bounds == nullptr) {
ALOGE("No return rectangle provided to measure text");
return;
@@ -374,21 +368,19 @@ void Font::precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs)
}
}
-void Font::render(const SkPaint* paint, const glyph_t* glyphs,
- int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
- uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) {
+void Font::render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, int x, int y,
+ RenderMode mode, uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH,
+ Rect* bounds, const float* positions) {
if (numGlyphs == 0 || glyphs == nullptr) {
return;
}
- static RenderGlyph gRenderGlyph[] = {
- &android::uirenderer::Font::drawCachedGlyph,
- &android::uirenderer::Font::drawCachedGlyphTransformed,
- &android::uirenderer::Font::drawCachedGlyphBitmap,
- &android::uirenderer::Font::drawCachedGlyphBitmap,
- &android::uirenderer::Font::measureCachedGlyph,
- &android::uirenderer::Font::measureCachedGlyph
- };
+ static RenderGlyph gRenderGlyph[] = {&android::uirenderer::Font::drawCachedGlyph,
+ &android::uirenderer::Font::drawCachedGlyphTransformed,
+ &android::uirenderer::Font::drawCachedGlyphBitmap,
+ &android::uirenderer::Font::drawCachedGlyphBitmap,
+ &android::uirenderer::Font::measureCachedGlyph,
+ &android::uirenderer::Font::measureCachedGlyph};
RenderGlyph render = gRenderGlyph[(mode << 1) + !mIdentityTransform];
int glyphsCount = 0;
@@ -406,13 +398,12 @@ void Font::render(const SkPaint* paint, const glyph_t* glyphs,
// If it's still not valid, we couldn't cache it, so we shouldn't
// draw garbage; also skip empty glyphs (spaces)
if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) {
- int penX = x + (int) roundf(positions[(glyphsCount << 1)]);
- int penY = y + (int) roundf(positions[(glyphsCount << 1) + 1]);
+ int penX = x + (int)roundf(positions[(glyphsCount << 1)]);
+ int penY = y + (int)roundf(positions[(glyphsCount << 1) + 1]);
#ifdef BUGREPORT_FONT_CACHE_USAGE
mState->historyTracker().glyphRendered(cachedGlyph, penX, penY);
#endif
- (*this.*render)(cachedGlyph, penX, penY,
- bitmap, bitmapW, bitmapH, bounds, positions);
+ (*this.*render)(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH, bounds, positions);
} else {
#ifdef BUGREPORT_FONT_CACHE_USAGE
mState->historyTracker().glyphRendered(cachedGlyph, -1, -1);
@@ -424,7 +415,7 @@ void Font::render(const SkPaint* paint, const glyph_t* glyphs,
}
void Font::updateGlyphCache(const SkPaint* paint, const SkGlyph& skiaGlyph,
- SkGlyphCache* skiaGlyphCache, CachedGlyphInfo* glyph, bool precaching) {
+ SkGlyphCache* skiaGlyphCache, CachedGlyphInfo* glyph, bool precaching) {
glyph->mAdvanceX = skiaGlyph.fAdvanceX;
glyph->mAdvanceY = skiaGlyph.fAdvanceY;
glyph->mBitmapLeft = skiaGlyph.fLeft;
@@ -458,10 +449,10 @@ void Font::updateGlyphCache(const SkPaint* paint, const SkGlyph& skiaGlyph,
uint32_t cacheWidth = glyph->mCacheTexture->getWidth();
uint32_t cacheHeight = glyph->mCacheTexture->getHeight();
- glyph->mBitmapMinU = startX / (float) cacheWidth;
- glyph->mBitmapMinV = startY / (float) cacheHeight;
- glyph->mBitmapMaxU = endX / (float) cacheWidth;
- glyph->mBitmapMaxV = endY / (float) cacheHeight;
+ glyph->mBitmapMinU = startX / (float)cacheWidth;
+ glyph->mBitmapMinV = startY / (float)cacheHeight;
+ glyph->mBitmapMaxU = endX / (float)cacheWidth;
+ glyph->mBitmapMaxV = endY / (float)cacheHeight;
mState->setTextureDirty();
}
@@ -495,5 +486,5 @@ Font* Font::create(FontRenderer* state, const SkPaint* paint, const SkMatrix& ma
return font;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/font/Font.h b/libs/hwui/font/Font.h
index 504dabb5bcc0..85221bc069f1 100644
--- a/libs/hwui/font/Font.h
+++ b/libs/hwui/font/Font.h
@@ -21,14 +21,14 @@
#include <utils/KeyedVector.h>
-#include <SkScalar.h>
#include <SkPaint.h>
#include <SkPathMeasure.h>
+#include <SkScalar.h>
#include <SkTypeface.h>
-#include "FontUtil.h"
-#include "../Rect.h"
#include "../Matrix.h"
+#include "../Rect.h"
+#include "FontUtil.h"
class SkGlyphCache;
@@ -49,9 +49,7 @@ class FontRenderer;
*/
class Font {
public:
- enum Style {
- kFakeBold = 1
- };
+ enum Style { kFakeBold = 1 };
struct FontDescription {
FontDescription(const SkPaint* paint, const SkMatrix& matrix);
@@ -60,13 +58,9 @@ public:
hash_t hash() const;
- bool operator==(const FontDescription& other) const {
- return compare(*this, other) == 0;
- }
+ bool operator==(const FontDescription& other) const { return compare(*this, other) == 0; }
- bool operator!=(const FontDescription& other) const {
- return compare(*this, other) != 0;
- }
+ bool operator!=(const FontDescription& other) const { return compare(*this, other) != 0; }
SkFontID mFontId;
float mFontSize;
@@ -83,15 +77,13 @@ public:
~Font();
- void render(const SkPaint* paint, const glyph_t* glyphs,
- int numGlyphs, int x, int y, const float* positions);
+ void render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, int x, int y,
+ const float* positions);
- void render(const SkPaint* paint, const glyph_t* glyphs,
- int numGlyphs, const SkPath* path, float hOffset, float vOffset);
+ void render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, const SkPath* path,
+ float hOffset, float vOffset);
- const Font::FontDescription& getDescription() const {
- return mDescription;
- }
+ const Font::FontDescription& getDescription() const { return mDescription; }
/**
* Creates a new font associated with the specified font state.
@@ -103,8 +95,8 @@ private:
Font(FontRenderer* state, const Font::FontDescription& desc);
- typedef void (Font::*RenderGlyph)(CachedGlyphInfo*, int, int, uint8_t*,
- uint32_t, uint32_t, Rect*, const float*);
+ typedef void (Font::*RenderGlyph)(CachedGlyphInfo*, int, int, uint8_t*, uint32_t, uint32_t,
+ Rect*, const float*);
enum RenderMode {
FRAMEBUFFER,
@@ -114,36 +106,33 @@ private:
void precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs);
- void render(const SkPaint* paint, const glyph_t* glyphs,
- int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
- uint32_t bitmapW, uint32_t bitmapH, Rect *bounds, const float* positions);
+ void render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, int x, int y,
+ RenderMode mode, uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds,
+ const float* positions);
- void measure(const SkPaint* paint, const glyph_t* glyphs,
- int numGlyphs, Rect *bounds, const float* positions);
+ void measure(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, Rect* bounds,
+ const float* positions);
void invalidateTextureCache(CacheTexture* cacheTexture = nullptr);
CachedGlyphInfo* cacheGlyph(const SkPaint* paint, glyph_t glyph, bool precaching);
void updateGlyphCache(const SkPaint* paint, const SkGlyph& skiaGlyph,
- SkGlyphCache* skiaGlyphCache, CachedGlyphInfo* glyph, bool precaching);
-
- void measureCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
- uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
- Rect* bounds, const float* pos);
- void drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
- uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
- Rect* bounds, const float* pos);
- void drawCachedGlyphTransformed(CachedGlyphInfo* glyph, int x, int y,
- uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
- Rect* bounds, const float* pos);
- void drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
- uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
- Rect* bounds, const float* pos);
+ SkGlyphCache* skiaGlyphCache, CachedGlyphInfo* glyph, bool precaching);
+
+ void measureCachedGlyph(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap, uint32_t bitmapW,
+ uint32_t bitmapH, Rect* bounds, const float* pos);
+ void drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap, uint32_t bitmapW,
+ uint32_t bitmapH, Rect* bounds, const float* pos);
+ void drawCachedGlyphTransformed(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap,
+ uint32_t bitmapW, uint32_t bitmapH, Rect* bounds,
+ const float* pos);
+ void drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap,
+ uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos);
void drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset,
- SkPathMeasure& measure, SkPoint* position, SkVector* tangent);
+ SkPathMeasure& measure, SkPoint* position, SkVector* tangent);
CachedGlyphInfo* getCachedGlyph(const SkPaint* paint, glyph_t textUnit,
- bool precaching = false);
+ bool precaching = false);
FontRenderer* mState;
FontDescription mDescription;
@@ -154,8 +143,7 @@ private:
bool mIdentityTransform;
};
-inline int strictly_order_type(const Font::FontDescription& lhs,
- const Font::FontDescription& rhs) {
+inline int strictly_order_type(const Font::FontDescription& lhs, const Font::FontDescription& rhs) {
return Font::FontDescription::compare(lhs, rhs) < 0;
}
@@ -167,7 +155,7 @@ inline hash_t hash_type(const Font::FontDescription& entry) {
return entry.hash();
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_FONT_H
+#endif // ANDROID_HWUI_FONT_H
diff --git a/libs/hwui/font/FontCacheHistoryTracker.cpp b/libs/hwui/font/FontCacheHistoryTracker.cpp
index a2bfb27535e5..5b61c494524a 100644
--- a/libs/hwui/font/FontCacheHistoryTracker.cpp
+++ b/libs/hwui/font/FontCacheHistoryTracker.cpp
@@ -16,15 +16,15 @@
#include "FontCacheHistoryTracker.h"
-#include "CachedGlyphInfo.h"
#include "CacheTexture.h"
+#include "CachedGlyphInfo.h"
namespace android {
namespace uirenderer {
void FontCacheHistoryTracker::dumpCachedGlyph(String8& log, const CachedGlyph& glyph) {
log.appendFormat("glyph (texture %p, position: (%d, %d), size: %dx%d, gen: %d)", glyph.texture,
- glyph.startX, glyph.startY, glyph.bitmapW, glyph.bitmapH, glyph.generation);
+ glyph.startX, glyph.startY, glyph.bitmapW, glyph.bitmapH, glyph.generation);
}
void FontCacheHistoryTracker::dumpRenderEntry(String8& log, const RenderEntry& entry) {
@@ -40,7 +40,7 @@ void FontCacheHistoryTracker::dumpRenderEntry(String8& log, const RenderEntry& e
void FontCacheHistoryTracker::dumpUploadEntry(String8& log, const CachedGlyph& glyph) {
if (glyph.bitmapW == 0 && glyph.bitmapH == 0) {
log.appendFormat(" cleared cachetexture %p in gen %d\n", glyph.texture,
- glyph.generation);
+ glyph.generation);
} else {
log.appendFormat(" uploaded ");
dumpCachedGlyph(log, glyph);
@@ -73,7 +73,7 @@ void FontCacheHistoryTracker::glyphRendered(CachedGlyphInfo* glyphInfo, int penX
}
void FontCacheHistoryTracker::glyphUploaded(CacheTexture* texture, uint32_t x, uint32_t y,
- uint16_t glyphW, uint16_t glyphH) {
+ uint16_t glyphW, uint16_t glyphH) {
CachedGlyph& glyph = mUploadHistory.next();
glyph.generation = generation;
glyph.texture = texture;
@@ -96,5 +96,5 @@ void FontCacheHistoryTracker::glyphsCleared(CacheTexture* texture) {
void FontCacheHistoryTracker::frameCompleted() {
generation++;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/font/FontCacheHistoryTracker.h b/libs/hwui/font/FontCacheHistoryTracker.h
index f1d9b9f10dc0..4b9ceccc09c9 100644
--- a/libs/hwui/font/FontCacheHistoryTracker.h
+++ b/libs/hwui/font/FontCacheHistoryTracker.h
@@ -35,6 +35,7 @@ public:
void frameCompleted();
void dump(String8& log) const;
+
private:
struct CachedGlyph {
void* texture;
@@ -60,5 +61,5 @@ private:
uint16_t generation = 0;
};
-}; // namespace uirenderer
-}; // namespace android \ No newline at end of file
+}; // namespace uirenderer
+}; // namespace android \ No newline at end of file
diff --git a/libs/hwui/font/FontUtil.h b/libs/hwui/font/FontUtil.h
index d4b4ff949f5a..596e153db6a9 100644
--- a/libs/hwui/font/FontUtil.h
+++ b/libs/hwui/font/FontUtil.h
@@ -26,11 +26,11 @@
///////////////////////////////////////////////////////////////////////////////
#ifdef TEXTURE_BORDER_SIZE
- #if TEXTURE_BORDER_SIZE != 1
- #error TEXTURE_BORDER_SIZE other than 1 is not currently supported
- #endif
+#if TEXTURE_BORDER_SIZE != 1
+#error TEXTURE_BORDER_SIZE other than 1 is not currently supported
+#endif
#else
- #define TEXTURE_BORDER_SIZE 1
+#define TEXTURE_BORDER_SIZE 1
#endif
#define CACHE_BLOCK_ROUNDING_SIZE 4
@@ -43,4 +43,4 @@ typedef uint16_t glyph_t;
// [-1, 1]. Result is an integral float.
#define AUTO_KERN(prev, next) static_cast<float>(((next) - (prev) + 32) >> 6)
-#endif // ANDROID_HWUI_FONT_UTIL_H
+#endif // ANDROID_HWUI_FONT_UTIL_H
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 0aeb7627233a..795ec5bd4f76 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -17,38 +17,37 @@
#include "Caches.h"
#include "renderthread/EglManager.h"
-#include "renderthread/RenderThread.h"
#include "renderthread/RenderProxy.h"
+#include "renderthread/RenderThread.h"
#include "utils/Color.h"
#include <sys/mman.h>
-#include <log/log.h>
#include <cutils/ashmem.h>
+#include <log/log.h>
-#include <private/gui/ComposerService.h>
#include <binder/IServiceManager.h>
+#include <private/gui/ComposerService.h>
#include <ui/PixelFormat.h>
#include <SkCanvas.h>
-#include <SkToSRGBColorFilter.h>
#include <SkImagePriv.h>
+#include <SkToSRGBColorFilter.h>
namespace android {
static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) {
int32_t rowBytes32 = SkToS32(rowBytes);
- int64_t bigSize = (int64_t) height * rowBytes32;
+ int64_t bigSize = (int64_t)height * rowBytes32;
if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) {
- return false; // allocation will be too large
+ return false; // allocation will be too large
}
*size = sk_64_asS32(bigSize);
return true;
}
-typedef sk_sp<Bitmap> (*AllocPixelRef)(size_t allocSize, const SkImageInfo& info,
- size_t rowBytes);
+typedef sk_sp<Bitmap> (*AllocPixelRef)(size_t allocSize, const SkImageInfo& info, size_t rowBytes);
static sk_sp<Bitmap> allocateBitmap(SkBitmap* bitmap, AllocPixelRef alloc) {
const SkImageInfo& info = bitmap->info();
@@ -74,7 +73,7 @@ static sk_sp<Bitmap> allocateBitmap(SkBitmap* bitmap, AllocPixelRef alloc) {
}
sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap) {
- return allocateBitmap(bitmap, &Bitmap::allocateAshmemBitmap);
+ return allocateBitmap(bitmap, &Bitmap::allocateAshmemBitmap);
}
static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
@@ -90,7 +89,7 @@ sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(SkBitmap& bitmap) {
}
sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap) {
- return allocateBitmap(bitmap, &android::allocateHeapBitmap);
+ return allocateBitmap(bitmap, &android::allocateHeapBitmap);
}
sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) {
@@ -102,8 +101,7 @@ sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) {
return android::allocateHeapBitmap(size, info, info.minRowBytes());
}
-sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info,
- size_t rowBytes) {
+sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
// Create new ashmem region with read/write priv
int fd = ashmem_create_region("bitmap", size);
if (fd < 0) {
@@ -125,25 +123,25 @@ sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info,
}
void FreePixelRef(void* addr, void* context) {
- auto pixelRef = (SkPixelRef*) context;
+ auto pixelRef = (SkPixelRef*)context;
pixelRef->unref();
}
sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) {
pixelRef.ref();
- return sk_sp<Bitmap>(new Bitmap((void*) pixelRef.pixels(), (void*) &pixelRef, FreePixelRef,
- info, pixelRef.rowBytes()));
+ return sk_sp<Bitmap>(new Bitmap((void*)pixelRef.pixels(), (void*)&pixelRef, FreePixelRef, info,
+ pixelRef.rowBytes()));
}
sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) {
PixelFormat format = graphicBuffer->getPixelFormat();
if (!graphicBuffer.get() ||
- (format != PIXEL_FORMAT_RGBA_8888 && format != PIXEL_FORMAT_RGBA_FP16)) {
+ (format != PIXEL_FORMAT_RGBA_8888 && format != PIXEL_FORMAT_RGBA_FP16)) {
return nullptr;
}
SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
- kRGBA_8888_SkColorType, kPremul_SkAlphaType,
- SkColorSpace::MakeSRGB());
+ kRGBA_8888_SkColorType, kPremul_SkAlphaType,
+ SkColorSpace::MakeSRGB());
return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
}
@@ -155,8 +153,8 @@ static SkImageInfo validateAlpha(const SkImageInfo& info) {
// Need to validate the alpha type to filter against the color type
// to prevent things like a non-opaque RGB565 bitmap
SkAlphaType alphaType;
- LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType(
- info.colorType(), info.alphaType(), &alphaType),
+ LOG_ALWAYS_FATAL_IF(
+ !SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &alphaType),
"Failed to validate alpha type!");
return info.makeAlphaType(alphaType);
}
@@ -173,28 +171,27 @@ void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes) {
}
Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes)
- : SkPixelRef(info.width(), info.height(), address, rowBytes)
- , mInfo(validateAlpha(info))
- , mPixelStorageType(PixelStorageType::Heap) {
+ : SkPixelRef(info.width(), info.height(), address, rowBytes)
+ , mInfo(validateAlpha(info))
+ , mPixelStorageType(PixelStorageType::Heap) {
mPixelStorage.heap.address = address;
mPixelStorage.heap.size = size;
}
-Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc,
- const SkImageInfo& info, size_t rowBytes)
- : SkPixelRef(info.width(), info.height(), address, rowBytes)
- , mInfo(validateAlpha(info))
- , mPixelStorageType(PixelStorageType::External) {
+Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info,
+ size_t rowBytes)
+ : SkPixelRef(info.width(), info.height(), address, rowBytes)
+ , mInfo(validateAlpha(info))
+ , mPixelStorageType(PixelStorageType::External) {
mPixelStorage.external.address = address;
mPixelStorage.external.context = context;
mPixelStorage.external.freeFunc = freeFunc;
}
-Bitmap::Bitmap(void* address, int fd, size_t mappedSize,
- const SkImageInfo& info, size_t rowBytes)
- : SkPixelRef(info.width(), info.height(), address, rowBytes)
- , mInfo(validateAlpha(info))
- , mPixelStorageType(PixelStorageType::Ashmem) {
+Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes)
+ : SkPixelRef(info.width(), info.height(), address, rowBytes)
+ , mInfo(validateAlpha(info))
+ , mPixelStorageType(PixelStorageType::Ashmem) {
mPixelStorage.ashmem.address = address;
mPixelStorage.ashmem.fd = fd;
mPixelStorage.ashmem.size = mappedSize;
@@ -207,32 +204,31 @@ Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info)
, mPixelStorageType(PixelStorageType::Hardware) {
mPixelStorage.hardware.buffer = buffer;
buffer->incStrong(buffer);
- setImmutable(); // HW bitmaps are always immutable
+ setImmutable(); // HW bitmaps are always immutable
if (uirenderer::Properties::isSkiaEnabled()) {
mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast<AHardwareBuffer*>(buffer),
- mInfo.alphaType(), mInfo.refColorSpace());
+ mInfo.alphaType(), mInfo.refColorSpace());
}
}
Bitmap::~Bitmap() {
switch (mPixelStorageType) {
- case PixelStorageType::External:
- mPixelStorage.external.freeFunc(mPixelStorage.external.address,
- mPixelStorage.external.context);
- break;
- case PixelStorageType::Ashmem:
- munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
- close(mPixelStorage.ashmem.fd);
- break;
- case PixelStorageType::Heap:
- free(mPixelStorage.heap.address);
- break;
- case PixelStorageType::Hardware:
- auto buffer = mPixelStorage.hardware.buffer;
- buffer->decStrong(buffer);
- mPixelStorage.hardware.buffer = nullptr;
- break;
-
+ case PixelStorageType::External:
+ mPixelStorage.external.freeFunc(mPixelStorage.external.address,
+ mPixelStorage.external.context);
+ break;
+ case PixelStorageType::Ashmem:
+ munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
+ close(mPixelStorage.ashmem.fd);
+ break;
+ case PixelStorageType::Heap:
+ free(mPixelStorage.heap.address);
+ break;
+ case PixelStorageType::Hardware:
+ auto buffer = mPixelStorage.hardware.buffer;
+ buffer->decStrong(buffer);
+ mPixelStorage.hardware.buffer = nullptr;
+ break;
}
android::uirenderer::renderthread::RenderProxy::onBitmapDestroyed(getStableID());
@@ -248,32 +244,32 @@ void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
void* Bitmap::getStorage() const {
switch (mPixelStorageType) {
- case PixelStorageType::External:
- return mPixelStorage.external.address;
- case PixelStorageType::Ashmem:
- return mPixelStorage.ashmem.address;
- case PixelStorageType::Heap:
- return mPixelStorage.heap.address;
- case PixelStorageType::Hardware:
- return nullptr;
+ case PixelStorageType::External:
+ return mPixelStorage.external.address;
+ case PixelStorageType::Ashmem:
+ return mPixelStorage.ashmem.address;
+ case PixelStorageType::Heap:
+ return mPixelStorage.heap.address;
+ case PixelStorageType::Hardware:
+ return nullptr;
}
}
int Bitmap::getAshmemFd() const {
switch (mPixelStorageType) {
- case PixelStorageType::Ashmem:
- return mPixelStorage.ashmem.fd;
- default:
- return -1;
+ case PixelStorageType::Ashmem:
+ return mPixelStorage.ashmem.fd;
+ default:
+ return -1;
}
}
size_t Bitmap::getAllocationByteCount() const {
switch (mPixelStorageType) {
- case PixelStorageType::Heap:
- return mPixelStorage.heap.size;
- default:
- return rowBytes() * height();
+ case PixelStorageType::Heap:
+ return mPixelStorage.heap.size;
+ default:
+ return rowBytes() * height();
}
}
@@ -294,7 +290,8 @@ void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
if (isHardware()) {
if (uirenderer::Properties::isSkiaEnabled()) {
outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(),
- info().colorType(), info().alphaType(), nullptr));
+ info().colorType(), info().alphaType(),
+ nullptr));
} else {
outBitmap->allocPixels(info());
}
@@ -330,11 +327,11 @@ sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) {
// TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
}
- if(uirenderer::Properties::isSkiaEnabled() && image->colorSpace() != nullptr
- && !image->colorSpace()->isSRGB()) {
+ if (uirenderer::Properties::isSkiaEnabled() && image->colorSpace() != nullptr &&
+ !image->colorSpace()->isSRGB()) {
*outputColorFilter = SkToSRGBColorFilter::Make(image->refColorSpace());
}
return image;
}
-} // namespace android
+} // namespace android
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index fc27af9fb4e7..a75276fc2d0e 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -19,11 +19,11 @@
#include <SkColorFilter.h>
#include <SkColorSpace.h>
#include <SkImage.h>
+#include <SkImage.h>
#include <SkImageInfo.h>
#include <SkPixelRef.h>
#include <cutils/compiler.h>
#include <ui/GraphicBuffer.h>
-#include <SkImage.h>
namespace android {
@@ -36,7 +36,7 @@ enum class PixelStorageType {
namespace uirenderer {
namespace renderthread {
- class RenderThread;
+class RenderThread;
}
}
@@ -53,17 +53,16 @@ public:
static sk_sp<Bitmap> allocateAshmemBitmap(SkBitmap* bitmap);
static sk_sp<Bitmap> allocateAshmemBitmap(size_t allocSize, const SkImageInfo& info,
- size_t rowBytes);
+ size_t rowBytes);
static sk_sp<Bitmap> createFrom(sp<GraphicBuffer> graphicBuffer);
static sk_sp<Bitmap> createFrom(const SkImageInfo&, SkPixelRef&);
Bitmap(void* address, size_t allocSize, const SkImageInfo& info, size_t rowBytes);
- Bitmap(void* address, void* context, FreeFunc freeFunc,
- const SkImageInfo& info, size_t rowBytes);
- Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info,
- size_t rowBytes);
+ Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info,
+ size_t rowBytes);
+ Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes);
Bitmap(GraphicBuffer* buffer, const SkImageInfo& info);
int rowBytesAsPixels() const {
@@ -85,15 +84,11 @@ public:
bool isOpaque() const { return mInfo.isOpaque(); }
SkColorType colorType() const { return mInfo.colorType(); }
- const SkImageInfo& info() const {
- return mInfo;
- }
+ const SkImageInfo& info() const { return mInfo; }
void getBounds(SkRect* bounds) const;
- bool isHardware() const {
- return mPixelStorageType == PixelStorageType::Hardware;
- }
+ bool isHardware() const { return mPixelStorageType == PixelStorageType::Hardware; }
GraphicBuffer* graphicBuffer();
@@ -109,6 +104,7 @@ public:
* buffer that has no colorspace defined).
*/
sk_sp<SkImage> makeImage(sk_sp<SkColorFilter>* outputColorFilter);
+
private:
virtual ~Bitmap();
void* getStorage() const;
@@ -139,7 +135,7 @@ private:
} hardware;
} mPixelStorage;
- sk_sp<SkImage> mImage; // Cache is used only for HW Bitmaps with Skia pipeline.
+ sk_sp<SkImage> mImage; // Cache is used only for HW Bitmaps with Skia pipeline.
};
-} //namespace android
+} // namespace android
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index 6f0579950e10..75e414e4b3e7 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -16,13 +16,13 @@
#include "Canvas.h"
-#include "RecordingCanvas.h"
-#include "RenderNode.h"
#include "MinikinUtils.h"
#include "Paint.h"
#include "Properties.h"
-#include "pipeline/skia/SkiaRecordingCanvas.h"
+#include "RecordingCanvas.h"
+#include "RenderNode.h"
#include "Typeface.h"
+#include "pipeline/skia/SkiaRecordingCanvas.h"
#include <SkDrawFilter.h>
@@ -36,7 +36,7 @@ Canvas* Canvas::create_recording_canvas(int width, int height, uirenderer::Rende
}
static inline void drawStroke(SkScalar left, SkScalar right, SkScalar top, SkScalar thickness,
- const SkPaint& paint, Canvas* canvas) {
+ const SkPaint& paint, Canvas* canvas) {
const SkScalar strokeWidth = fmax(thickness, 1.0f);
const SkScalar bottom = top + strokeWidth;
canvas->drawRect(left, top, right, bottom, paint);
@@ -91,20 +91,18 @@ static void simplifyPaint(int color, SkPaint* paint) {
class DrawTextFunctor {
public:
- DrawTextFunctor(const minikin::Layout& layout, Canvas* canvas,
- const SkPaint& paint, float x, float y, minikin::MinikinRect& bounds,
- float totalAdvance)
- : layout(layout)
- , canvas(canvas)
- , paint(paint)
- , x(x)
- , y(y)
- , bounds(bounds)
- , totalAdvance(totalAdvance) {
- }
+ DrawTextFunctor(const minikin::Layout& layout, Canvas* canvas, const SkPaint& paint, float x,
+ float y, minikin::MinikinRect& bounds, float totalAdvance)
+ : layout(layout)
+ , canvas(canvas)
+ , paint(paint)
+ , x(x)
+ , y(y)
+ , bounds(bounds)
+ , totalAdvance(totalAdvance) {}
void operator()(size_t start, size_t end) {
- auto glyphFunc = [&] (uint16_t* text, float* positions) {
+ auto glyphFunc = [&](uint16_t* text, float* positions) {
if (canvas->drawTextAbsolutePos()) {
for (size_t i = start, textIndex = 0, posIndex = 0; i < end; i++) {
text[textIndex++] = layout.getGlyphId(i);
@@ -133,20 +131,21 @@ public:
simplifyPaint(darken ? SK_ColorWHITE : SK_ColorBLACK, &outlinePaint);
outlinePaint.setStyle(SkPaint::kStrokeAndFill_Style);
canvas->drawGlyphs(glyphFunc, glyphCount, outlinePaint, x, y, bounds.mLeft, bounds.mTop,
- bounds.mRight, bounds.mBottom, totalAdvance);
+ bounds.mRight, bounds.mBottom, totalAdvance);
// inner
SkPaint innerPaint(paint);
simplifyPaint(darken ? SK_ColorBLACK : SK_ColorWHITE, &innerPaint);
innerPaint.setStyle(SkPaint::kFill_Style);
canvas->drawGlyphs(glyphFunc, glyphCount, innerPaint, x, y, bounds.mLeft, bounds.mTop,
- bounds.mRight, bounds.mBottom, totalAdvance);
+ bounds.mRight, bounds.mBottom, totalAdvance);
} else {
// standard draw path
canvas->drawGlyphs(glyphFunc, glyphCount, paint, x, y, bounds.mLeft, bounds.mTop,
- bounds.mRight, bounds.mBottom, totalAdvance);
+ bounds.mRight, bounds.mBottom, totalAdvance);
}
}
+
private:
const minikin::Layout& layout;
Canvas* canvas;
@@ -157,14 +156,14 @@ private:
float totalAdvance;
};
-void Canvas::drawText(const uint16_t* text, int start, int count, int contextCount,
- float x, float y, minikin::Bidi bidiFlags, const Paint& origPaint,
- const Typeface* typeface) {
+void Canvas::drawText(const uint16_t* text, int start, int count, int contextCount, float x,
+ float y, minikin::Bidi bidiFlags, const Paint& origPaint,
+ const Typeface* typeface) {
// minikin may modify the original paint
Paint paint(origPaint);
- minikin::Layout layout = MinikinUtils::doLayout(
- &paint, bidiFlags, typeface, text, start, count, contextCount);
+ minikin::Layout layout =
+ MinikinUtils::doLayout(&paint, bidiFlags, typeface, text, start, count, contextCount);
x += MinikinUtils::xOffsetForTextAlign(&paint, layout);
@@ -186,18 +185,18 @@ void Canvas::drawText(const uint16_t* text, int start, int count, int contextCou
class DrawTextOnPathFunctor {
public:
DrawTextOnPathFunctor(const minikin::Layout& layout, Canvas* canvas, float hOffset,
- float vOffset, const Paint& paint, const SkPath& path)
- : layout(layout)
- , canvas(canvas)
- , hOffset(hOffset)
- , vOffset(vOffset)
- , paint(paint)
- , path(path) {
- }
+ float vOffset, const Paint& paint, const SkPath& path)
+ : layout(layout)
+ , canvas(canvas)
+ , hOffset(hOffset)
+ , vOffset(vOffset)
+ , paint(paint)
+ , path(path) {}
void operator()(size_t start, size_t end) {
canvas->drawLayoutOnPath(layout, hOffset, vOffset, paint, path, start, end);
}
+
private:
const minikin::Layout& layout;
Canvas* canvas;
@@ -208,11 +207,11 @@ private:
};
void Canvas::drawTextOnPath(const uint16_t* text, int count, minikin::Bidi bidiFlags,
- const SkPath& path, float hOffset, float vOffset, const Paint& paint,
- const Typeface* typeface) {
+ const SkPath& path, float hOffset, float vOffset, const Paint& paint,
+ const Typeface* typeface) {
Paint paintCopy(paint);
- minikin::Layout layout = MinikinUtils::doLayout(
- &paintCopy, bidiFlags, typeface, text, 0, count, count);
+ minikin::Layout layout =
+ MinikinUtils::doLayout(&paintCopy, bidiFlags, typeface, text, 0, count, count);
hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path);
// Set align to left for drawing, as we don't want individual
@@ -224,4 +223,4 @@ void Canvas::drawTextOnPath(const uint16_t* text, int count, minikin::Bidi bidiF
MinikinUtils::forFontRun(layout, &paintCopy, f);
}
-} // namespace android
+} // namespace android
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 0a1bae7c99d9..e682a2e226b7 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -19,10 +19,10 @@
#include <cutils/compiler.h>
#include <utils/Functor.h>
+#include <androidfw/ResourceTypes.h>
#include "GlFunctorLifecycleListener.h"
#include "Properties.h"
#include "utils/Macros.h"
-#include <androidfw/ResourceTypes.h>
#include <SkBitmap.h>
#include <SkCanvas.h>
@@ -32,35 +32,35 @@ class SkCanvasState;
class SkVertices;
namespace minikin {
- class Layout;
- enum class Bidi : uint8_t;
+class Layout;
+enum class Bidi : uint8_t;
}
namespace android {
namespace uirenderer {
- class CanvasPropertyPaint;
- class CanvasPropertyPrimitive;
- class DeferredLayerUpdater;
- class DisplayList;
- class RenderNode;
+class CanvasPropertyPaint;
+class CanvasPropertyPrimitive;
+class DeferredLayerUpdater;
+class DisplayList;
+class RenderNode;
}
namespace SaveFlags {
// These must match the corresponding Canvas API constants.
enum {
- Matrix = 0x01,
- Clip = 0x02,
+ Matrix = 0x01,
+ Clip = 0x02,
HasAlphaLayer = 0x04,
- ClipToLayer = 0x10,
+ ClipToLayer = 0x10,
// Helper constant
- MatrixClip = Matrix | Clip,
+ MatrixClip = Matrix | Clip,
};
typedef uint32_t Flags;
-} // namespace SaveFlags
+} // namespace SaveFlags
namespace uirenderer {
class SkiaCanvasProxy;
@@ -78,7 +78,7 @@ struct Typeface;
class ANDROID_API Canvas {
public:
- virtual ~Canvas() {};
+ virtual ~Canvas(){};
static Canvas* create_canvas(const SkBitmap& bitmap);
@@ -97,8 +97,8 @@ public:
determined based on Properties::getRenderPipelineType().
*
*/
- static WARN_UNUSED_RESULT Canvas* create_recording_canvas(int width, int height,
- uirenderer::RenderNode* renderNode = nullptr);
+ static WARN_UNUSED_RESULT Canvas* create_recording_canvas(
+ int width, int height, uirenderer::RenderNode* renderNode = nullptr);
/**
* Create a new Canvas object which delegates to an SkCanvas.
@@ -126,40 +126,43 @@ public:
*/
virtual SkCanvas* asSkCanvas() = 0;
-
virtual void setBitmap(const SkBitmap& bitmap) = 0;
virtual bool isOpaque() = 0;
virtual int width() = 0;
virtual int height() = 0;
-// ----------------------------------------------------------------------------
-// View System operations (not exposed in public Canvas API)
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // View System operations (not exposed in public Canvas API)
+ // ----------------------------------------------------------------------------
virtual void resetRecording(int width, int height,
- uirenderer::RenderNode* renderNode = nullptr) = 0;
+ uirenderer::RenderNode* renderNode = nullptr) = 0;
virtual uirenderer::DisplayList* finishRecording() = 0;
virtual void insertReorderBarrier(bool enableReorder) = 0;
bool isHighContrastText() const { return uirenderer::Properties::enableHighContrastText; }
virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
- uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
- uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
- uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) = 0;
+ uirenderer::CanvasPropertyPrimitive* top,
+ uirenderer::CanvasPropertyPrimitive* right,
+ uirenderer::CanvasPropertyPrimitive* bottom,
+ uirenderer::CanvasPropertyPrimitive* rx,
+ uirenderer::CanvasPropertyPrimitive* ry,
+ uirenderer::CanvasPropertyPaint* paint) = 0;
virtual void drawCircle(uirenderer::CanvasPropertyPrimitive* x,
- uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius,
- uirenderer::CanvasPropertyPaint* paint) = 0;
+ uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint) = 0;
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0;
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0;
virtual void callDrawGLFunction(Functor* functor,
- uirenderer::GlFunctorLifecycleListener* listener) = 0;
+ uirenderer::GlFunctorLifecycleListener* listener) = 0;
-// ----------------------------------------------------------------------------
-// Canvas state operations
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // Canvas state operations
+ // ----------------------------------------------------------------------------
// Save (layer)
virtual int getSaveCount() const = 0;
@@ -167,10 +170,10 @@ public:
virtual void restore() = 0;
virtual void restoreToCount(int saveCount) = 0;
- virtual int saveLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, SaveFlags::Flags flags) = 0;
- virtual int saveLayerAlpha(float left, float top, float right, float bottom,
- int alpha, SaveFlags::Flags flags) = 0;
+ virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
+ SaveFlags::Flags flags) = 0;
+ virtual int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
+ SaveFlags::Flags flags) = 0;
// Matrix
virtual void getMatrix(SkMatrix* outMatrix) const = 0;
@@ -187,8 +190,7 @@ public:
virtual bool quickRejectRect(float left, float top, float right, float bottom) const = 0;
virtual bool quickRejectPath(const SkPath& path) const = 0;
- virtual bool clipRect(float left, float top, float right, float bottom,
- SkClipOp op) = 0;
+ virtual bool clipRect(float left, float top, float right, float bottom, SkClipOp op) = 0;
virtual bool clipPath(const SkPath* path, SkClipOp op) = 0;
// filters
@@ -198,9 +200,9 @@ public:
// WebView only
virtual SkCanvasState* captureCanvasState() const { return nullptr; }
-// ----------------------------------------------------------------------------
-// Canvas draw operations
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // Canvas draw operations
+ // ----------------------------------------------------------------------------
virtual void drawColor(int color, SkBlendMode mode) = 0;
virtual void drawPaint(const SkPaint& paint) = 0;
@@ -208,34 +210,32 @@ public:
virtual void drawPoint(float x, float y, const SkPaint& paint) = 0;
virtual void drawPoints(const float* points, int floatCount, const SkPaint& paint) = 0;
virtual void drawLine(float startX, float startY, float stopX, float stopY,
- const SkPaint& paint) = 0;
+ const SkPaint& paint) = 0;
virtual void drawLines(const float* points, int floatCount, const SkPaint& paint) = 0;
virtual void drawRect(float left, float top, float right, float bottom,
- const SkPaint& paint) = 0;
+ const SkPaint& paint) = 0;
virtual void drawRegion(const SkRegion& region, const SkPaint& paint) = 0;
- virtual void drawRoundRect(float left, float top, float right, float bottom,
- float rx, float ry, const SkPaint& paint) = 0;
+ virtual void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
+ const SkPaint& paint) = 0;
virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) = 0;
virtual void drawOval(float left, float top, float right, float bottom,
- const SkPaint& paint) = 0;
- virtual void drawArc(float left, float top, float right, float bottom,
- float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) = 0;
+ const SkPaint& paint) = 0;
+ virtual void drawArc(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle, bool useCenter, const SkPaint& paint) = 0;
virtual void drawPath(const SkPath& path, const SkPaint& paint) = 0;
virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint) = 0;
// Bitmap-based
- virtual void drawBitmap(Bitmap& bitmap, float left, float top,
- const SkPaint* paint) = 0;
- virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix,
- const SkPaint* paint) = 0;
- virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
- float srcRight, float srcBottom, float dstLeft, float dstTop,
- float dstRight, float dstBottom, const SkPaint* paint) = 0;
+ virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) = 0;
+ virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) = 0;
+ virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
+ float srcBottom, float dstLeft, float dstTop, float dstRight,
+ float dstBottom, const SkPaint* paint) = 0;
virtual void drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
- const float* vertices, const int* colors, const SkPaint* paint) = 0;
- virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk,
- float dstLeft, float dstTop, float dstRight, float dstBottom,
- const SkPaint* paint) = 0;
+ const float* vertices, const int* colors, const SkPaint* paint) = 0;
+ virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
+ float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) = 0;
/**
* Specifies if the positions passed to ::drawText are absolute or relative
@@ -255,13 +255,12 @@ public:
* Converts utf16 text to glyphs, calculating position and boundary,
* and delegating the final draw to virtual drawGlyphs method.
*/
- void drawText(const uint16_t* text, int start, int count, int contextCount,
- float x, float y, minikin::Bidi bidiFlags, const Paint& origPaint,
- const Typeface* typeface);
+ void drawText(const uint16_t* text, int start, int count, int contextCount, float x, float y,
+ minikin::Bidi bidiFlags, const Paint& origPaint, const Typeface* typeface);
void drawTextOnPath(const uint16_t* text, int count, minikin::Bidi bidiFlags,
- const SkPath& path, float hOffset, float vOffset, const Paint& paint,
- const Typeface* typeface);
+ const SkPath& path, float hOffset, float vOffset, const Paint& paint,
+ const Typeface* typeface);
protected:
void drawTextDecorations(float x, float y, float length, const SkPaint& paint);
@@ -272,13 +271,14 @@ protected:
* totalAdvance: used to define width of text decorations (underlines, strikethroughs).
*/
virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x,
- float y, float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
- float totalAdvance) = 0;
+ float y, float boundsLeft, float boundsTop, float boundsRight,
+ float boundsBottom, float totalAdvance) = 0;
virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
- const SkPaint& paint, const SkPath& path, size_t start, size_t end) = 0;
+ const SkPaint& paint, const SkPath& path, size_t start,
+ size_t end) = 0;
friend class DrawTextFunctor;
friend class DrawTextOnPathFunctor;
friend class uirenderer::SkiaCanvasProxy;
};
-}; // namespace android
+}; // namespace android
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index a5b4c42d68d2..5d33860bab6b 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -16,37 +16,41 @@
#include "MinikinSkia.h"
-#include <log/log.h>
#include <SkFontDescriptor.h>
#include <SkFontMgr.h>
#include <SkPaint.h>
#include <SkTypeface.h>
+#include <log/log.h>
namespace android {
MinikinFontSkia::MinikinFontSkia(sk_sp<SkTypeface> typeface, const void* fontData, size_t fontSize,
- int ttcIndex, const std::vector<minikin::FontVariation>& axes) :
- minikin::MinikinFont(typeface->uniqueID()), mTypeface(std::move(typeface)), mFontData(fontData),
- mFontSize(fontSize), mTtcIndex(ttcIndex), mAxes(axes) {
-}
+ int ttcIndex, const std::vector<minikin::FontVariation>& axes)
+ : minikin::MinikinFont(typeface->uniqueID())
+ , mTypeface(std::move(typeface))
+ , mFontData(fontData)
+ , mFontSize(fontSize)
+ , mTtcIndex(ttcIndex)
+ , mAxes(axes) {}
static void MinikinFontSkia_SetSkiaPaint(const minikin::MinikinFont* font, SkPaint* skPaint,
- const minikin::MinikinPaint& paint) {
+ const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) {
skPaint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
skPaint->setTextSize(paint.size);
skPaint->setTextScaleX(paint.scaleX);
skPaint->setTextSkewX(paint.skewX);
MinikinFontSkia::unpackPaintFlags(skPaint, paint.paintFlags);
// Apply font fakery on top of user-supplied flags.
- MinikinFontSkia::populateSkPaint(skPaint, font, paint.fakery);
+ MinikinFontSkia::populateSkPaint(skPaint, font, fakery);
}
-float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id,
- const minikin::MinikinPaint &paint) const {
+float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id, const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const {
SkPaint skPaint;
uint16_t glyph16 = glyph_id;
SkScalar skWidth;
- MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
+ MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint, fakery);
skPaint.getTextWidths(&glyph16, sizeof(glyph16), &skWidth, NULL);
#ifdef VERBOSE
ALOGD("width for typeface %d glyph %d = %f", mTypeface->uniqueID(), glyph_id, skWidth);
@@ -55,11 +59,12 @@ float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id,
}
void MinikinFontSkia::GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id,
- const minikin::MinikinPaint& paint) const {
+ const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const {
SkPaint skPaint;
uint16_t glyph16 = glyph_id;
SkRect skBounds;
- MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
+ MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint, fakery);
skPaint.getTextWidths(&glyph16, sizeof(glyph16), NULL, &skBounds);
bounds->mLeft = skBounds.fLeft;
bounds->mTop = skBounds.fTop;
@@ -68,9 +73,10 @@ void MinikinFontSkia::GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id,
}
void MinikinFontSkia::GetFontExtent(minikin::MinikinExtent* extent,
- const minikin::MinikinPaint& paint) const {
+ const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const {
SkPaint skPaint;
- MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
+ MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint, fakery);
SkPaint::FontMetrics metrics;
skPaint.getFontMetrics(&metrics);
extent->ascent = metrics.fAscent;
@@ -78,7 +84,7 @@ void MinikinFontSkia::GetFontExtent(minikin::MinikinExtent* extent,
extent->line_gap = metrics.fLeading;
}
-SkTypeface *MinikinFontSkia::GetSkTypeface() const {
+SkTypeface* MinikinFontSkia::GetSkTypeface() const {
return mTypeface.get();
}
@@ -122,7 +128,7 @@ std::shared_ptr<minikin::MinikinFont> MinikinFontSkia::createFontWithVariation(
sk_sp<SkTypeface> face(fm->makeFromStream(std::move(stream), params));
return std::make_shared<MinikinFontSkia>(std::move(face), mFontData, mFontSize, ttcIndex,
- variations);
+ variations);
}
uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) {
@@ -130,9 +136,9 @@ uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) {
SkPaint::Hinting hinting = paint->getHinting();
// select only flags that might affect text layout
flags &= (SkPaint::kAntiAlias_Flag | SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag |
- SkPaint::kSubpixelText_Flag | SkPaint::kDevKernText_Flag |
- SkPaint::kEmbeddedBitmapText_Flag | SkPaint::kAutoHinting_Flag |
- SkPaint::kVerticalText_Flag);
+ SkPaint::kSubpixelText_Flag | SkPaint::kDevKernText_Flag |
+ SkPaint::kEmbeddedBitmapText_Flag | SkPaint::kAutoHinting_Flag |
+ SkPaint::kVerticalText_Flag);
flags |= (hinting << 16);
return flags;
}
@@ -143,12 +149,11 @@ void MinikinFontSkia::unpackPaintFlags(SkPaint* paint, uint32_t paintFlags) {
}
void MinikinFontSkia::populateSkPaint(SkPaint* paint, const MinikinFont* font,
- minikin::FontFakery fakery) {
+ minikin::FontFakery fakery) {
paint->setTypeface(reinterpret_cast<const MinikinFontSkia*>(font)->RefSkTypeface());
paint->setFakeBoldText(paint->isFakeBoldText() || fakery.isFakeBold());
if (fakery.isFakeItalic()) {
paint->setTextSkewX(paint->getTextSkewX() - 0.25f);
}
}
-
}
diff --git a/libs/hwui/hwui/MinikinSkia.h b/libs/hwui/hwui/MinikinSkia.h
index a19f4a769444..d1565986304f 100644
--- a/libs/hwui/hwui/MinikinSkia.h
+++ b/libs/hwui/hwui/MinikinSkia.h
@@ -17,9 +17,9 @@
#ifndef _ANDROID_GRAPHICS_MINIKIN_SKIA_H_
#define _ANDROID_GRAPHICS_MINIKIN_SKIA_H_
+#include <SkRefCnt.h>
#include <cutils/compiler.h>
#include <minikin/MinikinFont.h>
-#include <SkRefCnt.h>
class SkPaint;
class SkTypeface;
@@ -29,16 +29,17 @@ namespace android {
class ANDROID_API MinikinFontSkia : public minikin::MinikinFont {
public:
explicit MinikinFontSkia(sk_sp<SkTypeface> typeface, const void* fontData, size_t fontSize,
- int ttcIndex, const std::vector<minikin::FontVariation>& axes);
+ int ttcIndex, const std::vector<minikin::FontVariation>& axes);
- float GetHorizontalAdvance(uint32_t glyph_id,
- const minikin::MinikinPaint &paint) const;
+ float GetHorizontalAdvance(uint32_t glyph_id, const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const override;
void GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id,
- const minikin::MinikinPaint &paint) const;
+ const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const override;
- void GetFontExtent(minikin::MinikinExtent* extent,
- const minikin::MinikinPaint &paint) const;
+ void GetFontExtent(minikin::MinikinExtent* extent, const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const override;
SkTypeface* GetSkTypeface() const;
sk_sp<SkTypeface> RefSkTypeface() const;
@@ -56,7 +57,8 @@ public:
// set typeface and fake bold/italic parameters
static void populateSkPaint(SkPaint* paint, const minikin::MinikinFont* font,
- minikin::FontFakery fakery);
+ minikin::FontFakery fakery);
+
private:
sk_sp<SkTypeface> mTypeface;
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index 814d2cf84b49..90fe0b74dcec 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -26,50 +26,50 @@
namespace android {
-minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* minikinPaint,
- const Paint* paint, const Typeface* typeface) {
+minikin::MinikinPaint MinikinUtils::prepareMinikinPaint(const Paint* paint,
+ const Typeface* typeface) {
const Typeface* resolvedFace = Typeface::resolveDefault(typeface);
minikin::FontStyle resolved = resolvedFace->fStyle;
- /* Prepare minikin FontStyle */
- minikin::FontVariant minikinVariant = (paint->getFontVariant() == minikin::VARIANT_ELEGANT) ?
- minikin::VARIANT_ELEGANT : minikin::VARIANT_COMPACT;
- const uint32_t langListId = paint->getMinikinLangListId();
- minikin::FontStyle minikinStyle(langListId, minikinVariant, resolved.getWeight(),
- resolved.getItalic());
+ const minikin::FontVariant minikinVariant =
+ (paint->getFontVariant() == minikin::FontVariant::ELEGANT)
+ ? minikin::FontVariant::ELEGANT
+ : minikin::FontVariant::COMPACT;
+ minikin::MinikinPaint minikinPaint;
/* Prepare minikin Paint */
- minikinPaint->size = paint->isLinearText() ?
- paint->getTextSize() : static_cast<int>(paint->getTextSize());
- minikinPaint->scaleX = paint->getTextScaleX();
- minikinPaint->skewX = paint->getTextSkewX();
- minikinPaint->letterSpacing = paint->getLetterSpacing();
- minikinPaint->wordSpacing = paint->getWordSpacing();
- minikinPaint->paintFlags = MinikinFontSkia::packPaintFlags(paint);
- minikinPaint->fontFeatureSettings = paint->getFontFeatureSettings();
- minikinPaint->hyphenEdit = minikin::HyphenEdit(paint->getHyphenEdit());
- return minikinStyle;
+ minikinPaint.size =
+ paint->isLinearText() ? paint->getTextSize() : static_cast<int>(paint->getTextSize());
+ minikinPaint.scaleX = paint->getTextScaleX();
+ minikinPaint.skewX = paint->getTextSkewX();
+ minikinPaint.letterSpacing = paint->getLetterSpacing();
+ minikinPaint.wordSpacing = paint->getWordSpacing();
+ minikinPaint.paintFlags = MinikinFontSkia::packPaintFlags(paint);
+ minikinPaint.localeListId = paint->getMinikinLocaleListId();
+ minikinPaint.fontStyle = minikin::FontStyle(minikinVariant, resolved.weight, resolved.slant);
+ minikinPaint.fontFeatureSettings = paint->getFontFeatureSettings();
+ minikinPaint.hyphenEdit = minikin::HyphenEdit(paint->getHyphenEdit());
+ return minikinPaint;
}
minikin::Layout MinikinUtils::doLayout(const Paint* paint, minikin::Bidi bidiFlags,
- const Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize) {
- minikin::MinikinPaint minikinPaint;
- minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, paint, typeface);
+ const Typeface* typeface, const uint16_t* buf, size_t start,
+ size_t count, size_t bufSize) {
+ minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
minikin::Layout layout;
- layout.doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint,
- Typeface::resolveDefault(typeface)->fFontCollection);
+ layout.doLayout(buf, start, count, bufSize, bidiFlags, minikinPaint,
+ Typeface::resolveDefault(typeface)->fFontCollection);
return layout;
}
float MinikinUtils::measureText(const Paint* paint, minikin::Bidi bidiFlags,
- const Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize,
- float *advances) {
- minikin::MinikinPaint minikinPaint;
- minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, paint, typeface);
+ const Typeface* typeface, const uint16_t* buf, size_t start,
+ size_t count, size_t bufSize, float* advances) {
+ minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
const Typeface* resolvedTypeface = Typeface::resolveDefault(typeface);
- return minikin::Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinStyle,
- minikinPaint, resolvedTypeface->fFontCollection, advances, nullptr /* extent */,
- nullptr /* overhangs */);
+ return minikin::Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinPaint,
+ resolvedTypeface->fFontCollection, advances,
+ nullptr /* extent */, nullptr /* overhangs */);
}
bool MinikinUtils::hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs) {
@@ -92,7 +92,7 @@ float MinikinUtils::xOffsetForTextAlign(Paint* paint, const minikin::Layout& lay
}
float MinikinUtils::hOffsetForTextAlign(Paint* paint, const minikin::Layout& layout,
- const SkPath& path) {
+ const SkPath& path) {
float align = 0;
switch (paint->getTextAlign()) {
case Paint::kCenter_Align:
@@ -107,5 +107,4 @@ float MinikinUtils::hOffsetForTextAlign(Paint* paint, const minikin::Layout& lay
SkPathMeasure measure(path, false);
return align * (layout.getAdvance() - measure.getLength());
}
-
-}
+} // namespace android
diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h
index 2e8aa58682a2..7036cbee79f9 100644
--- a/libs/hwui/hwui/MinikinUtils.h
+++ b/libs/hwui/hwui/MinikinUtils.h
@@ -19,39 +19,40 @@
* Paint and so on.
**/
- // TODO: does this really need to be separate from MinikinSkia?
+// TODO: does this really need to be separate from MinikinSkia?
#ifndef _ANDROID_GRAPHICS_MINIKIN_UTILS_H_
#define _ANDROID_GRAPHICS_MINIKIN_UTILS_H_
#include <cutils/compiler.h>
#include <minikin/Layout.h>
-#include "Paint.h"
#include "MinikinSkia.h"
+#include "Paint.h"
#include "Typeface.h"
namespace android {
class MinikinUtils {
public:
- ANDROID_API static minikin::FontStyle prepareMinikinPaint(minikin::MinikinPaint* minikinPaint,
- const Paint* paint, const Typeface* typeface);
+ ANDROID_API static minikin::MinikinPaint prepareMinikinPaint(const Paint* paint,
+ const Typeface* typeface);
ANDROID_API static minikin::Layout doLayout(const Paint* paint, minikin::Bidi bidiFlags,
- const Typeface* typeface, const uint16_t* buf, size_t start, size_t count,
- size_t bufSize);
+ const Typeface* typeface, const uint16_t* buf,
+ size_t start, size_t count, size_t bufSize);
ANDROID_API static float measureText(const Paint* paint, minikin::Bidi bidiFlags,
- const Typeface* typeface, const uint16_t* buf, size_t start, size_t count,
- size_t bufSize, float *advances);
+ const Typeface* typeface, const uint16_t* buf,
+ size_t start, size_t count, size_t bufSize,
+ float* advances);
ANDROID_API static bool hasVariationSelector(const Typeface* typeface, uint32_t codepoint,
- uint32_t vs);
+ uint32_t vs);
ANDROID_API static float xOffsetForTextAlign(Paint* paint, const minikin::Layout& layout);
ANDROID_API static float hOffsetForTextAlign(Paint* paint, const minikin::Layout& layout,
- const SkPath& path);
+ const SkPath& path);
// f is a functor of type void f(size_t start, size_t end);
template <typename F>
ANDROID_API static void forFontRun(const minikin::Layout& layout, Paint* paint, F& f) {
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index f3779fddb620..76beb119b6da 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -32,8 +32,8 @@ class ANDROID_API Paint : public SkPaint {
public:
// Default values for underlined and strikethrough text,
// as defined by Skia in SkTextFormatParams.h.
- constexpr static float kStdStrikeThru_Offset = (-6.0f / 21.0f);
- constexpr static float kStdUnderline_Offset = (1.0f / 9.0f);
+ constexpr static float kStdStrikeThru_Offset = (-6.0f / 21.0f);
+ constexpr static float kStdUnderline_Offset = (1.0f / 9.0f);
constexpr static float kStdUnderline_Thickness = (1.0f / 18.0f);
constexpr static float kStdUnderline_Top =
@@ -51,79 +51,54 @@ public:
Paint& operator=(const Paint& other);
friend bool operator==(const Paint& a, const Paint& b);
- friend bool operator!=(const Paint& a, const Paint& b) {
- return !(a == b);
- }
+ friend bool operator!=(const Paint& a, const Paint& b) { return !(a == b); }
- void setLetterSpacing(float letterSpacing) {
- mLetterSpacing = letterSpacing;
- }
+ void setLetterSpacing(float letterSpacing) { mLetterSpacing = letterSpacing; }
- float getLetterSpacing() const {
- return mLetterSpacing;
- }
+ float getLetterSpacing() const { return mLetterSpacing; }
- void setWordSpacing(float wordSpacing) {
- mWordSpacing = wordSpacing;
- }
+ void setWordSpacing(float wordSpacing) { mWordSpacing = wordSpacing; }
- float getWordSpacing() const {
- return mWordSpacing;
- }
+ float getWordSpacing() const { return mWordSpacing; }
void setFontFeatureSettings(const std::string& fontFeatureSettings) {
mFontFeatureSettings = fontFeatureSettings;
}
- std::string getFontFeatureSettings() const {
- return mFontFeatureSettings;
- }
+ std::string getFontFeatureSettings() const { return mFontFeatureSettings; }
- void setMinikinLangListId(uint32_t minikinLangListId) {
- mMinikinLangListId = minikinLangListId;
+ void setMinikinLocaleListId(uint32_t minikinLocaleListId) {
+ mMinikinLocaleListId = minikinLocaleListId;
}
- uint32_t getMinikinLangListId() const {
- return mMinikinLangListId;
- }
+ uint32_t getMinikinLocaleListId() const { return mMinikinLocaleListId; }
- void setFontVariant(minikin::FontVariant variant) {
- mFontVariant = variant;
- }
+ void setFontVariant(minikin::FontVariant variant) { mFontVariant = variant; }
- minikin::FontVariant getFontVariant() const {
- return mFontVariant;
- }
+ minikin::FontVariant getFontVariant() const { return mFontVariant; }
- void setHyphenEdit(uint32_t hyphen) {
- mHyphenEdit = hyphen;
- }
+ void setHyphenEdit(uint32_t hyphen) { mHyphenEdit = hyphen; }
- uint32_t getHyphenEdit() const {
- return mHyphenEdit;
- }
+ uint32_t getHyphenEdit() const { return mHyphenEdit; }
- void setAndroidTypeface(Typeface* typeface) {
- mTypeface = typeface;
- }
+ void setAndroidTypeface(Typeface* typeface) { mTypeface = typeface; }
- const Typeface* getAndroidTypeface() const {
- return mTypeface;
- }
+ const Typeface* getAndroidTypeface() const { return mTypeface; }
private:
float mLetterSpacing = 0;
float mWordSpacing = 0;
std::string mFontFeatureSettings;
- uint32_t mMinikinLangListId;
+ uint32_t mMinikinLocaleListId;
minikin::FontVariant mFontVariant;
uint32_t mHyphenEdit = 0;
- // The native Typeface object has the same lifetime of the Java Typeface object. The Java Paint
- // object holds a strong reference to the Java Typeface object. Thus, following pointer can
- // never be a dangling pointer. Note that nullptr is valid: it means the default typeface.
+ // The native Typeface object has the same lifetime of the Java Typeface
+ // object. The Java Paint object holds a strong reference to the Java Typeface
+ // object. Thus, following pointer can never be a dangling pointer. Note that
+ // nullptr is valid: it means the default typeface.
const Typeface* mTypeface = nullptr;
};
} // namespace android
-#endif // ANDROID_GRAPHICS_PAINT_H_
+#endif // ANDROID_GRAPHICS_PAINT_H_
diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp
index a5c2087490aa..94492c52f365 100644
--- a/libs/hwui/hwui/PaintImpl.cpp
+++ b/libs/hwui/hwui/PaintImpl.cpp
@@ -18,33 +18,40 @@
namespace android {
-Paint::Paint() :
- SkPaint(), mLetterSpacing(0), mWordSpacing(0), mFontFeatureSettings(),
- mMinikinLangListId(0), mFontVariant(minikin::VARIANT_DEFAULT) {
-}
+Paint::Paint()
+ : SkPaint()
+ , mLetterSpacing(0)
+ , mWordSpacing(0)
+ , mFontFeatureSettings()
+ , mMinikinLocaleListId(0)
+ , mFontVariant(minikin::FontVariant::DEFAULT) {}
-Paint::Paint(const Paint& paint) : SkPaint(paint),
- mLetterSpacing(paint.mLetterSpacing), mWordSpacing(paint.mWordSpacing),
- mFontFeatureSettings(paint.mFontFeatureSettings),
- mMinikinLangListId(paint.mMinikinLangListId), mFontVariant(paint.mFontVariant),
- mHyphenEdit(paint.mHyphenEdit),
- mTypeface(paint.mTypeface) {
-}
+Paint::Paint(const Paint& paint)
+ : SkPaint(paint)
+ , mLetterSpacing(paint.mLetterSpacing)
+ , mWordSpacing(paint.mWordSpacing)
+ , mFontFeatureSettings(paint.mFontFeatureSettings)
+ , mMinikinLocaleListId(paint.mMinikinLocaleListId)
+ , mFontVariant(paint.mFontVariant)
+ , mHyphenEdit(paint.mHyphenEdit)
+ , mTypeface(paint.mTypeface) {}
-Paint::Paint(const SkPaint& paint) : SkPaint(paint),
- mLetterSpacing(0), mWordSpacing(0), mFontFeatureSettings(), mMinikinLangListId(0),
- mFontVariant(minikin::VARIANT_DEFAULT) {
-}
+Paint::Paint(const SkPaint& paint)
+ : SkPaint(paint)
+ , mLetterSpacing(0)
+ , mWordSpacing(0)
+ , mFontFeatureSettings()
+ , mMinikinLocaleListId(0)
+ , mFontVariant(minikin::FontVariant::DEFAULT) {}
-Paint::~Paint() {
-}
+Paint::~Paint() {}
Paint& Paint::operator=(const Paint& other) {
SkPaint::operator=(other);
mLetterSpacing = other.mLetterSpacing;
mWordSpacing = other.mWordSpacing;
mFontFeatureSettings = other.mFontFeatureSettings;
- mMinikinLangListId = other.mMinikinLangListId;
+ mMinikinLocaleListId = other.mMinikinLocaleListId;
mFontVariant = other.mFontVariant;
mHyphenEdit = other.mHyphenEdit;
mTypeface = other.mTypeface;
@@ -52,14 +59,10 @@ Paint& Paint::operator=(const Paint& other) {
}
bool operator==(const Paint& a, const Paint& b) {
- return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b)
- && a.mLetterSpacing == b.mLetterSpacing
- && a.mWordSpacing == b.mWordSpacing
- && a.mFontFeatureSettings == b.mFontFeatureSettings
- && a.mMinikinLangListId == b.mMinikinLangListId
- && a.mFontVariant == b.mFontVariant
- && a.mHyphenEdit == b.mHyphenEdit
- && a.mTypeface == b.mTypeface;
-}
-
+ return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b) &&
+ a.mLetterSpacing == b.mLetterSpacing && a.mWordSpacing == b.mWordSpacing &&
+ a.mFontFeatureSettings == b.mFontFeatureSettings &&
+ a.mMinikinLocaleListId == b.mMinikinLocaleListId && a.mFontVariant == b.mFontVariant &&
+ a.mHyphenEdit == b.mHyphenEdit && a.mTypeface == b.mTypeface;
}
+} // namespace android
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index 7cc0871c841a..e527adc08fd7 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -16,15 +16,15 @@
#include "Typeface.h"
-#include <pthread.h>
#include <fcntl.h> // For tests.
-#include <sys/stat.h> // For tests.
+#include <pthread.h>
#include <sys/mman.h> // For tests.
+#include <sys/stat.h> // For tests.
#include "MinikinSkia.h"
-#include "SkTypeface.h"
#include "SkPaint.h"
#include "SkStream.h" // Fot tests.
+#include "SkTypeface.h"
#include <minikin/FontCollection.h>
#include <minikin/FontFamily.h>
@@ -44,9 +44,8 @@ static Typeface::Style computeAPIStyle(int weight, bool italic) {
}
static minikin::FontStyle computeMinikinStyle(int weight, bool italic) {
- // TODO: Better to use raw base weight value for font selection instead of dividing by 100.
- const int minikinWeight = uirenderer::MathUtils::clamp((weight + 50) / 100, 1, 10);
- return minikin::FontStyle(minikinWeight, italic);
+ return minikin::FontStyle(uirenderer::MathUtils::clamp(weight, 1, 1000),
+ static_cast<minikin::FontSlant>(italic));
}
// Resolve the relative weight from the baseWeight and target style.
@@ -90,8 +89,8 @@ Typeface* Typeface::createAbsolute(Typeface* base, int weight, bool italic) {
return result;
}
-Typeface* Typeface::createFromTypefaceWithVariation(Typeface* src,
- const std::vector<minikin::FontVariation>& variations) {
+Typeface* Typeface::createFromTypefaceWithVariation(
+ Typeface* src, const std::vector<minikin::FontVariation>& variations) {
const Typeface* resolvedFace = Typeface::resolveDefault(src);
Typeface* result = new Typeface();
if (result != nullptr) {
@@ -123,9 +122,8 @@ Typeface* Typeface::createWithDifferentBaseWeight(Typeface* src, int weight) {
return result;
}
-Typeface* Typeface::createFromFamilies(
- std::vector<std::shared_ptr<minikin::FontFamily>>&& families,
- int weight, int italic) {
+Typeface* Typeface::createFromFamilies(std::vector<std::shared_ptr<minikin::FontFamily>>&& families,
+ int weight, int italic) {
Typeface* result = new Typeface;
result->fFontCollection.reset(new minikin::FontCollection(families));
@@ -135,7 +133,7 @@ Typeface* Typeface::createFromFamilies(
const minikin::FontStyle defaultStyle;
const minikin::MinikinFont* mf =
- families.empty() ? nullptr : families[0]->getClosestMatch(defaultStyle).font;
+ families.empty() ? nullptr : families[0]->getClosestMatch(defaultStyle).font;
if (mf != nullptr) {
SkTypeface* skTypeface = reinterpret_cast<const MinikinFontSkia*>(mf)->GetSkTypeface();
const SkFontStyle& style = skTypeface->fontStyle();
@@ -151,7 +149,7 @@ Typeface* Typeface::createFromFamilies(
weight = weightFromFont;
}
if (italic == RESOLVE_BY_FONT_TABLE) {
- italic = italicFromFont? 1 : 0;
+ italic = italicFromFont ? 1 : 0;
}
}
@@ -185,7 +183,7 @@ void Typeface::setRobotoTypefaceForTest() {
std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
std::shared_ptr<minikin::FontFamily> family = std::make_shared<minikin::FontFamily>(
- std::vector<minikin::Font>({ minikin::Font(std::move(font), minikin::FontStyle()) }));
+ std::vector<minikin::Font>({minikin::Font(std::move(font), minikin::FontStyle())}));
std::shared_ptr<minikin::FontCollection> collection =
std::make_shared<minikin::FontCollection>(std::move(family));
@@ -193,9 +191,8 @@ void Typeface::setRobotoTypefaceForTest() {
hwTypeface->fFontCollection = collection;
hwTypeface->fAPIStyle = Typeface::kNormal;
hwTypeface->fBaseWeight = SkFontStyle::kNormal_Weight;
- hwTypeface->fStyle = minikin::FontStyle(4 /* weight */, false /* italic */);
+ hwTypeface->fStyle = minikin::FontStyle();
Typeface::setDefault(hwTypeface);
}
-
-}
+} // namespace android
diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
index d90114d38a94..ef8d8f4ee4f3 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
#ifndef _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
#define _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
@@ -22,8 +21,8 @@
#include <cutils/compiler.h>
#include <minikin/FontCollection.h>
-#include <vector>
#include <memory>
+#include <vector>
namespace android {
@@ -32,19 +31,14 @@ namespace android {
constexpr int RESOLVE_BY_FONT_TABLE = -1;
struct ANDROID_API Typeface {
- public:
+public:
std::shared_ptr<minikin::FontCollection> fFontCollection;
// resolved style actually used for rendering
minikin::FontStyle fStyle;
// style used in the API
- enum Style : uint8_t {
- kNormal = 0,
- kBold = 0x01,
- kItalic = 0x02,
- kBoldItalic = 0x03
- };
+ enum Style : uint8_t { kNormal = 0, kBold = 0x01, kItalic = 0x02, kBoldItalic = 0x03 };
Style fAPIStyle;
static const Typeface* resolveDefault(const Typeface* src);
@@ -77,23 +71,21 @@ struct ANDROID_API Typeface {
static Typeface* createRelative(Typeface* src, Style desiredStyle);
static Typeface* createAbsolute(Typeface* base, int weight, bool italic);
- static Typeface* createFromTypefaceWithVariation(Typeface* src,
- const std::vector<minikin::FontVariation>& variations);
+ static Typeface* createFromTypefaceWithVariation(
+ Typeface* src, const std::vector<minikin::FontVariation>& variations);
static Typeface* createFromFamilies(
- std::vector<std::shared_ptr<minikin::FontFamily>>&& families,
- int weight, int italic);
+ std::vector<std::shared_ptr<minikin::FontFamily>>&& families, int weight, int italic);
static void setDefault(const Typeface* face);
// Sets roboto font as the default typeface for testing purpose.
static void setRobotoTypefaceForTest();
- private:
+
+private:
// base weight in CSS-style units, 1..1000
int fBaseWeight;
-
};
-
}
#endif // _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
diff --git a/libs/hwui/pipeline/skia/AnimatedDrawables.h b/libs/hwui/pipeline/skia/AnimatedDrawables.h
index 44c494f77231..efef6de2a9e1 100644
--- a/libs/hwui/pipeline/skia/AnimatedDrawables.h
+++ b/libs/hwui/pipeline/skia/AnimatedDrawables.h
@@ -16,10 +16,10 @@
#pragma once
-#include "CanvasProperty.h"
-#include <utils/RefBase.h>
#include <SkCanvas.h>
#include <SkDrawable.h>
+#include <utils/RefBase.h>
+#include "CanvasProperty.h"
namespace android {
namespace uirenderer {
@@ -28,16 +28,12 @@ namespace skiapipeline {
class AnimatedRoundRect : public SkDrawable {
public:
AnimatedRoundRect(uirenderer::CanvasPropertyPrimitive* left,
- uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
- uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
- uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* p)
- : mLeft(left)
- , mTop(top)
- , mRight(right)
- , mBottom(bottom)
- , mRx(rx)
- , mRy(ry)
- , mPaint(p) {}
+ uirenderer::CanvasPropertyPrimitive* top,
+ uirenderer::CanvasPropertyPrimitive* right,
+ uirenderer::CanvasPropertyPrimitive* bottom,
+ uirenderer::CanvasPropertyPrimitive* rx,
+ uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* p)
+ : mLeft(left), mTop(top), mRight(right), mBottom(bottom), mRx(rx), mRy(ry), mPaint(p) {}
protected:
virtual SkRect onGetBounds() override {
@@ -61,11 +57,9 @@ private:
class AnimatedCircle : public SkDrawable {
public:
AnimatedCircle(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y,
- uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint)
- : mX(x)
- , mY(y)
- , mRadius(radius)
- , mPaint(paint) {}
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint)
+ : mX(x), mY(y), mRadius(radius), mPaint(paint) {}
protected:
virtual SkRect onGetBounds() override {
@@ -85,6 +79,6 @@ private:
sp<uirenderer::CanvasPropertyPaint> mPaint;
};
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/DumpOpsCanvas.h b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
index 34fb04ccad55..1f83d1a201b0 100644
--- a/libs/hwui/pipeline/skia/DumpOpsCanvas.h
+++ b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
@@ -16,6 +16,7 @@
#pragma once
+#include "RenderNode.h"
#include "SkiaDisplayList.h"
namespace android {
@@ -32,8 +33,7 @@ public:
: mOutput(output)
, mLevel(level)
, mDisplayList(displayList)
- , mIdent((level + 1) * 2, ' ') {
- }
+ , mIdent((level + 1) * 2, ' ') {}
protected:
void onClipRect(const SkRect& rect, SkClipOp, ClipEdgeStyle) override {
@@ -52,9 +52,7 @@ protected:
mOutput << mIdent << "clipRegion" << std::endl;
}
- void onDrawPaint(const SkPaint&) override {
- mOutput << mIdent << "drawPaint" << std::endl;
- }
+ void onDrawPaint(const SkPaint&) override { mOutput << mIdent << "drawPaint" << std::endl; }
void onDrawPath(const SkPath&, const SkPaint&) override {
mOutput << mIdent << "drawPath" << std::endl;
@@ -92,22 +90,21 @@ protected:
mOutput << mIdent << "drawPosText" << std::endl;
}
- void onDrawPosTextH(const void*, size_t, const SkScalar[], SkScalar,
- const SkPaint&) override {
+ void onDrawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&) override {
mOutput << mIdent << "drawPosTextH" << std::endl;
}
void onDrawTextOnPath(const void*, size_t, const SkPath&, const SkMatrix*,
- const SkPaint&) override {
+ const SkPaint&) override {
mOutput << mIdent << "drawTextOnPath" << std::endl;
}
void onDrawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*,
- const SkPaint&) override {
+ const SkPaint&) override {
mOutput << mIdent << "drawTextRSXform" << std::endl;
}
- void onDrawTextBlob(const SkTextBlob*, SkScalar,SkScalar, const SkPaint&) override {
+ void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override {
mOutput << mIdent << "drawTextBlob" << std::endl;
}
@@ -116,17 +113,17 @@ protected:
}
void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
- const SkPaint*) override {
+ const SkPaint*) override {
mOutput << mIdent << "drawImageNine" << std::endl;
}
void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*,
- SrcRectConstraint) override {
+ SrcRectConstraint) override {
mOutput << mIdent << "drawImageRect" << std::endl;
}
void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
- const SkPaint*) override {
+ const SkPaint*) override {
mOutput << mIdent << "drawImageLattice" << std::endl;
}
@@ -157,21 +154,21 @@ protected:
private:
RenderNodeDrawable* getRenderNodeDrawable(SkDrawable* drawable) {
- for (auto& child : mDisplayList.mChildNodes) {
+ for (auto& child : mDisplayList.mChildNodes) {
if (drawable == &child) {
return &child;
}
- }
- return nullptr;
+ }
+ return nullptr;
}
GLFunctorDrawable* getGLFunctorDrawable(SkDrawable* drawable) {
- for (auto& child : mDisplayList.mChildFunctors) {
+ for (auto& child : mDisplayList.mChildFunctors) {
if (drawable == &child) {
return &child;
}
- }
- return nullptr;
+ }
+ return nullptr;
}
std::ostream& mOutput;
@@ -180,6 +177,6 @@ private:
std::string mIdent;
};
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index fcd72afe4fb9..145e3c485cbc 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -15,19 +15,19 @@
*/
#include "GLFunctorDrawable.h"
+#include <GrContext.h>
+#include <private/hwui/DrawGlInfo.h>
#include "GlFunctorLifecycleListener.h"
#include "RenderNode.h"
#include "SkAndroidFrameworkUtils.h"
#include "SkClipStack.h"
-#include <private/hwui/DrawGlInfo.h>
-#include <GrContext.h>
namespace android {
namespace uirenderer {
namespace skiapipeline {
GLFunctorDrawable::~GLFunctorDrawable() {
- if(mListener.get() != nullptr) {
+ if (mListener.get() != nullptr) {
mListener->onGlFunctorReleased(mFunctor);
}
}
@@ -73,7 +73,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
bool clearStencilAfterFunctor = false;
- //apply a simple clip with a scissor or a complex clip with a stencil
+ // apply a simple clip with a scissor or a complex clip with a stencil
SkRegion clipRegion;
canvas->temporary_internal_getRgnClip(&clipRegion);
if (CC_UNLIKELY(clipRegion.isComplex())) {
@@ -106,7 +106,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
(*mFunctor)(DrawGlInfo::kModeDraw, &info);
if (clearStencilAfterFunctor) {
- //clear stencil buffer as it may be used by Skia
+ // clear stencil buffer as it may be used by Skia
glDisable(GL_SCISSOR_TEST);
glDisable(GL_STENCIL_TEST);
glStencilMask(0x1);
@@ -115,8 +115,8 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
}
canvas->getGrContext()->resetContext();
- }
+}
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.h b/libs/hwui/pipeline/skia/GLFunctorDrawable.h
index 012c948be9b3..af57d7d33c2c 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.h
@@ -19,8 +19,8 @@
#include <SkCanvas.h>
#include <SkDrawable.h>
-#include <utils/RefBase.h>
#include <utils/Functor.h>
+#include <utils/RefBase.h>
namespace android {
namespace uirenderer {
@@ -36,24 +36,21 @@ namespace skiapipeline {
class GLFunctorDrawable : public SkDrawable {
public:
GLFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas)
- : mFunctor(functor)
- , mListener(listener)
- , mBounds(canvas->getLocalClipBounds())
- {}
+ : mFunctor(functor), mListener(listener), mBounds(canvas->getLocalClipBounds()) {}
virtual ~GLFunctorDrawable();
void syncFunctor() const;
- protected:
+protected:
virtual SkRect onGetBounds() override { return mBounds; }
virtual void onDraw(SkCanvas* canvas) override;
- private:
- Functor* mFunctor;
- sp<GlFunctorLifecycleListener> mListener;
- const SkRect mBounds;
+private:
+ Functor* mFunctor;
+ sp<GlFunctorLifecycleListener> mListener;
+ const SkRect mBounds;
};
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index def04e11d5d8..d9584db2df9d 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include "GlLayer.h"
#include "LayerDrawable.h"
+#include "GlLayer.h"
#include "VkLayer.h"
#include "GrBackendSurface.h"
@@ -51,9 +51,9 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer
externalTexture.fTarget = glLayer->getRenderTarget();
externalTexture.fID = glLayer->getTextureId();
GrBackendTexture backendTexture(layerWidth, layerHeight, kRGBA_8888_GrPixelConfig,
- externalTexture);
+ externalTexture);
layerImage = SkImage::MakeFromTexture(context, backendTexture, kTopLeft_GrSurfaceOrigin,
- kPremul_SkAlphaType, nullptr);
+ kPremul_SkAlphaType, nullptr);
} else {
SkASSERT(layer->getApi() == Layer::Api::Vulkan);
VkLayer* vkLayer = static_cast<VkLayer*>(layer);
@@ -64,12 +64,12 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer
if (layerImage) {
SkMatrix textureMatrix;
layer->getTexTransform().copyTo(textureMatrix);
- //TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed
+ // TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed
// use bottom left origin and remove flipV and invert transformations.
SkMatrix flipV;
flipV.setAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
textureMatrix.preConcat(flipV);
- textureMatrix.preScale(1.0f/layerWidth, 1.0f/layerHeight);
+ textureMatrix.preScale(1.0f / layerWidth, 1.0f / layerHeight);
textureMatrix.postScale(layerWidth, layerHeight);
SkMatrix textureMatrixInv;
if (!textureMatrix.invert(&textureMatrixInv)) {
@@ -98,6 +98,6 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer
return layerImage;
}
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h
index d34d8e07c133..345038769306 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.h
+++ b/libs/hwui/pipeline/skia/LayerDrawable.h
@@ -29,21 +29,21 @@ namespace skiapipeline {
* Draws a layer backed by an OpenGL texture into a SkCanvas.
*/
class LayerDrawable : public SkDrawable {
- public:
- explicit LayerDrawable(DeferredLayerUpdater* layerUpdater)
- : mLayerUpdater(layerUpdater) {}
+public:
+ explicit LayerDrawable(DeferredLayerUpdater* layerUpdater) : mLayerUpdater(layerUpdater) {}
static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer);
- protected:
- virtual SkRect onGetBounds() override {
- return SkRect::MakeWH(mLayerUpdater->getWidth(), mLayerUpdater->getHeight());
- }
- virtual void onDraw(SkCanvas* canvas) override;
+
+protected:
+ virtual SkRect onGetBounds() override {
+ return SkRect::MakeWH(mLayerUpdater->getWidth(), mLayerUpdater->getHeight());
+ }
+ virtual void onDraw(SkCanvas* canvas) override;
private:
sp<DeferredLayerUpdater> mLayerUpdater;
};
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index ca93925c3c04..46d4ae77694e 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -15,33 +15,34 @@
*/
#include "RenderNodeDrawable.h"
+#include <SkPaintFilterCanvas.h>
#include "RenderNode.h"
#include "SkiaDisplayList.h"
#include "SkiaPipeline.h"
#include "utils/TraceUtils.h"
-#include <SkPaintFilterCanvas.h>
namespace android {
namespace uirenderer {
namespace skiapipeline {
-void RenderNodeDrawable::drawBackwardsProjectedNodes(SkCanvas* canvas, const SkiaDisplayList& displayList,
- int nestLevel) {
+void RenderNodeDrawable::drawBackwardsProjectedNodes(SkCanvas* canvas,
+ const SkiaDisplayList& displayList,
+ int nestLevel) {
LOG_ALWAYS_FATAL_IF(0 == nestLevel && !displayList.mProjectionReceiver);
for (auto& child : displayList.mChildNodes) {
const RenderProperties& childProperties = child.getNodeProperties();
- //immediate children cannot be projected on their parent
+ // immediate children cannot be projected on their parent
if (childProperties.getProjectBackwards() && nestLevel > 0) {
SkAutoCanvasRestore acr2(canvas, true);
- //Apply recorded matrix, which is a total matrix saved at recording time to avoid
- //replaying all DL commands.
+ // Apply recorded matrix, which is a total matrix saved at recording time to avoid
+ // replaying all DL commands.
canvas->concat(child.getRecordedMatrix());
child.drawContent(canvas);
}
- //skip walking sub-nodes if current display list contains a receiver with exception of
- //level 0, which is a known receiver
+ // skip walking sub-nodes if current display list contains a receiver with exception of
+ // level 0, which is a known receiver
if (0 == nestLevel || !displayList.containsProjectionReceiver()) {
SkAutoCanvasRestore acr(canvas, true);
SkMatrix nodeMatrix;
@@ -51,9 +52,9 @@ void RenderNodeDrawable::drawBackwardsProjectedNodes(SkCanvas* canvas, const Ski
hwuiMatrix.copyTo(nodeMatrix);
canvas->concat(nodeMatrix);
SkiaDisplayList* childDisplayList = static_cast<SkiaDisplayList*>(
- (const_cast<DisplayList*>(childNode->getDisplayList())));
+ (const_cast<DisplayList*>(childNode->getDisplayList())));
if (childDisplayList) {
- drawBackwardsProjectedNodes(canvas, *childDisplayList, nestLevel+1);
+ drawBackwardsProjectedNodes(canvas, *childDisplayList, nestLevel + 1);
}
}
}
@@ -92,8 +93,8 @@ const RenderProperties& RenderNodeDrawable::getNodeProperties() const {
}
void RenderNodeDrawable::onDraw(SkCanvas* canvas) {
- //negative and positive Z order are drawn out of order, if this render node drawable is in
- //a reordering section
+ // negative and positive Z order are drawn out of order, if this render node drawable is in
+ // a reordering section
if ((!mInReorderingSection) || MathUtils::isZero(mRenderNode->properties().getZ())) {
this->forceDraw(canvas);
}
@@ -118,13 +119,13 @@ void RenderNodeDrawable::forceDraw(SkCanvas* canvas) {
SkAutoCanvasRestore acr(canvas, true);
const RenderProperties& properties = this->getNodeProperties();
- //pass this outline to the children that may clip backward projected nodes
- displayList->mProjectedOutline = displayList->containsProjectionReceiver()
- ? &properties.getOutline() : nullptr;
+ // pass this outline to the children that may clip backward projected nodes
+ displayList->mProjectedOutline =
+ displayList->containsProjectionReceiver() ? &properties.getOutline() : nullptr;
if (!properties.getProjectBackwards()) {
drawContent(canvas);
if (mProjectedDisplayList) {
- acr.restore(); //draw projected children using parent matrix
+ acr.restore(); // draw projected children using parent matrix
LOG_ALWAYS_FATAL_IF(!mProjectedDisplayList->mProjectedOutline);
const bool shouldClip = mProjectedDisplayList->mProjectedOutline->getPath();
SkAutoCanvasRestore acr2(canvas, shouldClip);
@@ -138,12 +139,10 @@ void RenderNodeDrawable::forceDraw(SkCanvas* canvas) {
displayList->mProjectedOutline = nullptr;
}
-static bool layerNeedsPaint(const LayerProperties& properties,
- float alphaMultiplier, SkPaint* paint) {
- if (alphaMultiplier < 1.0f
- || properties.alpha() < 255
- || properties.xferMode() != SkBlendMode::kSrcOver
- || properties.colorFilter() != nullptr) {
+static bool layerNeedsPaint(const LayerProperties& properties, float alphaMultiplier,
+ SkPaint* paint) {
+ if (alphaMultiplier < 1.0f || properties.alpha() < 255 ||
+ properties.xferMode() != SkBlendMode::kSrcOver || properties.colorFilter() != nullptr) {
paint->setAlpha(properties.alpha() * alphaMultiplier);
paint->setBlendMode(properties.xferMode());
paint->setColorFilter(sk_ref_sp(properties.colorFilter()));
@@ -155,13 +154,14 @@ static bool layerNeedsPaint(const LayerProperties& properties,
class AlphaFilterCanvas : public SkPaintFilterCanvas {
public:
AlphaFilterCanvas(SkCanvas* canvas, float alpha) : SkPaintFilterCanvas(canvas), mAlpha(alpha) {}
+
protected:
bool onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type t) const override {
SkTLazy<SkPaint> defaultPaint;
if (!*paint) {
paint->init(*defaultPaint.init());
}
- paint->writable()->setAlpha((uint8_t)(*paint)->getAlpha()*mAlpha);
+ paint->writable()->setAlpha((uint8_t)(*paint)->getAlpha() * mAlpha);
return true;
}
void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
@@ -169,6 +169,7 @@ protected:
// get their alpha applied. THe default SkPaintFilterCanvas::onDrawDrawable does not unroll.
drawable->draw(this, matrix);
}
+
private:
float mAlpha;
};
@@ -189,7 +190,7 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
displayList->mProjectedReceiverParentMatrix = canvas->getTotalMatrix();
}
- //TODO should we let the bound of the drawable do this for us?
+ // TODO should we let the bound of the drawable do this for us?
const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
bool quickRejected = properties.getClipToBounds() && canvas->quickReject(bounds);
if (!quickRejected) {
@@ -221,7 +222,7 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
}
}
- // composing a software layer with alpha
+ // composing a software layer with alpha
} else if (properties.effectiveLayerType() == LayerType::Software) {
SkPaint paint;
bool needsLayer = layerNeedsPaint(layerProperties, alphaMultiplier, &paint);
@@ -246,7 +247,7 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
}
void RenderNodeDrawable::setViewProperties(const RenderProperties& properties, SkCanvas* canvas,
- float* alphaMultiplier) {
+ float* alphaMultiplier) {
if (properties.getLeft() != 0 || properties.getTop() != 0) {
canvas->translate(properties.getLeft(), properties.getTop());
}
@@ -266,7 +267,7 @@ void RenderNodeDrawable::setViewProperties(const RenderProperties& properties, S
int clipFlags = properties.getClippingFlags();
if (properties.getAlpha() < 1) {
if (isLayer) {
- clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
+ clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
}
if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering())) {
*alphaMultiplier = properties.getAlpha();
@@ -275,18 +276,18 @@ void RenderNodeDrawable::setViewProperties(const RenderProperties& properties, S
Rect layerBounds(0, 0, properties.getWidth(), properties.getHeight());
if (clipFlags) {
properties.getClippingRectForFlags(clipFlags, &layerBounds);
- clipFlags = 0; // all clipping done by savelayer
+ clipFlags = 0; // all clipping done by savelayer
}
- SkRect bounds = SkRect::MakeLTRB(layerBounds.left, layerBounds.top,
- layerBounds.right, layerBounds.bottom);
- canvas->saveLayerAlpha(&bounds, (int) (properties.getAlpha() * 255));
+ SkRect bounds = SkRect::MakeLTRB(layerBounds.left, layerBounds.top, layerBounds.right,
+ layerBounds.bottom);
+ canvas->saveLayerAlpha(&bounds, (int)(properties.getAlpha() * 255));
}
if (CC_UNLIKELY(ATRACE_ENABLED() && properties.promotedToLayer())) {
// pretend alpha always causes savelayer to warn about
// performance problem affecting old versions
ATRACE_FORMAT("alpha caused saveLayer %dx%d", properties.getWidth(),
- properties.getHeight());
+ properties.getHeight());
}
}
@@ -312,6 +313,6 @@ void RenderNodeDrawable::setViewProperties(const RenderProperties& properties, S
}
}
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.h b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
index 3eed6476c994..ef21cd8a29b5 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.h
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
@@ -47,7 +47,7 @@ public:
* layer into the canvas.
*/
explicit RenderNodeDrawable(RenderNode* node, SkCanvas* canvas, bool composeLayer = true,
- bool inReorderingSection = false)
+ bool inReorderingSection = false)
: mRenderNode(node)
, mRecordedTransform(canvas->getTotalMatrix())
, mComposeLayer(composeLayer)
@@ -113,13 +113,13 @@ private:
* @param nestLevel should be always 0. Used to track how far we are from the receiver.
*/
void drawBackwardsProjectedNodes(SkCanvas* canvas, const SkiaDisplayList& displayList,
- int nestLevel = 0);
+ int nestLevel = 0);
/**
* Applies the rendering properties of a view onto a SkCanvas.
*/
static void setViewProperties(const RenderProperties& properties, SkCanvas* canvas,
- float* alphaMultiplier);
+ float* alphaMultiplier);
/**
* Stores transform on the canvas at time of recording and is used for
@@ -150,6 +150,6 @@ private:
SkiaDisplayList* mProjectedDisplayList = nullptr;
};
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
index c8207bc70dd4..7b59ccf3eec7 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
@@ -30,26 +30,24 @@ namespace uirenderer {
namespace skiapipeline {
StartReorderBarrierDrawable::StartReorderBarrierDrawable(SkiaDisplayList* data)
- : mEndChildIndex(0)
- , mBeginChildIndex(data->mChildNodes.size())
- , mDisplayList(data) {
-}
+ : mEndChildIndex(0), mBeginChildIndex(data->mChildNodes.size()), mDisplayList(data) {}
void StartReorderBarrierDrawable::onDraw(SkCanvas* canvas) {
if (mChildren.empty()) {
- //mChildren is allocated and initialized only the first time onDraw is called and cached for
- //subsequent calls
+ // mChildren is allocated and initialized only the first time onDraw is called and cached
+ // for
+ // subsequent calls
mChildren.reserve(mEndChildIndex - mBeginChildIndex + 1);
for (int i = mBeginChildIndex; i <= mEndChildIndex; i++) {
mChildren.push_back(const_cast<RenderNodeDrawable*>(&mDisplayList->mChildNodes[i]));
}
}
std::stable_sort(mChildren.begin(), mChildren.end(),
- [](RenderNodeDrawable* a, RenderNodeDrawable* b) {
- const float aZValue = a->getNodeProperties().getZ();
- const float bZValue = b->getNodeProperties().getZ();
- return aZValue < bZValue;
- });
+ [](RenderNodeDrawable* a, RenderNodeDrawable* b) {
+ const float aZValue = a->getNodeProperties().getZ();
+ const float bZValue = b->getNodeProperties().getZ();
+ return aZValue < bZValue;
+ });
size_t drawIndex = 0;
const size_t endIndex = mChildren.size();
@@ -57,7 +55,7 @@ void StartReorderBarrierDrawable::onDraw(SkCanvas* canvas) {
RenderNodeDrawable* childNode = mChildren[drawIndex];
SkASSERT(childNode);
const float casterZ = childNode->getNodeProperties().getZ();
- if (casterZ >= -NON_ZERO_EPSILON) { //draw only children with negative Z
+ if (casterZ >= -NON_ZERO_EPSILON) { // draw only children with negative Z
return;
}
childNode->forceDraw(canvas);
@@ -85,8 +83,9 @@ void EndReorderBarrierDrawable::onDraw(SkCanvas* canvas) {
size_t drawIndex = 0;
const size_t endIndex = zChildren.size();
- while (drawIndex < endIndex //draw only children with positive Z
- && zChildren[drawIndex]->getNodeProperties().getZ() <= NON_ZERO_EPSILON) drawIndex++;
+ while (drawIndex < endIndex // draw only children with positive Z
+ && zChildren[drawIndex]->getNodeProperties().getZ() <= NON_ZERO_EPSILON)
+ drawIndex++;
size_t shadowIndex = drawIndex;
float lastCasterZ = 0.0f;
@@ -98,7 +97,7 @@ void EndReorderBarrierDrawable::onDraw(SkCanvas* canvas) {
// OR if its caster's Z value is similar to the previous potential caster
if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) {
this->drawShadow(canvas, zChildren[shadowIndex]);
- lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
+ lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
shadowIndex++;
continue;
}
@@ -116,23 +115,21 @@ void EndReorderBarrierDrawable::onDraw(SkCanvas* canvas) {
void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* caster) {
const RenderProperties& casterProperties = caster->getNodeProperties();
- if (casterProperties.getAlpha() <= 0.0f
- || casterProperties.getOutline().getAlpha() <= 0.0f
- || !casterProperties.getOutline().getPath()
- || casterProperties.getScaleX() == 0
- || casterProperties.getScaleY() == 0) {
+ if (casterProperties.getAlpha() <= 0.0f || casterProperties.getOutline().getAlpha() <= 0.0f ||
+ !casterProperties.getOutline().getPath() || casterProperties.getScaleX() == 0 ||
+ casterProperties.getScaleY() == 0) {
// no shadow to draw
return;
}
- const SkScalar casterAlpha = casterProperties.getAlpha()
- * casterProperties.getOutline().getAlpha();
+ const SkScalar casterAlpha =
+ casterProperties.getAlpha() * casterProperties.getOutline().getAlpha();
if (casterAlpha <= 0.0f) {
return;
}
- float ambientAlpha = (SkiaPipeline::getAmbientShadowAlpha()/255.f)*casterAlpha;
- float spotAlpha = (SkiaPipeline::getSpotShadowAlpha()/255.f)*casterAlpha;
+ float ambientAlpha = (SkiaPipeline::getAmbientShadowAlpha() / 255.f) * casterAlpha;
+ float spotAlpha = (SkiaPipeline::getSpotShadowAlpha() / 255.f) * casterAlpha;
const RevealClip& revealClip = casterProperties.getRevealClip();
const SkPath* revealClipPath = revealClip.getPath();
@@ -172,7 +169,7 @@ void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable*
}
// intersect the shadow-casting path with the reveal, if present
- SkPath tmpPath; // holds temporary SkPath to store the result of intersections
+ SkPath tmpPath; // holds temporary SkPath to store the result of intersections
if (revealClipPath) {
Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, &tmpPath);
tmpPath.setIsVolatile(true);
@@ -190,11 +187,12 @@ void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable*
} else {
zParams = SkPoint3::Make(0, 0, casterProperties.getZ());
}
- SkShadowUtils::DrawShadow(canvas, *casterPath, zParams, skiaLightPos,
- SkiaPipeline::getLightRadius(), ambientAlpha, spotAlpha, SK_ColorBLACK,
- casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0);
+ SkShadowUtils::DrawShadow(
+ canvas, *casterPath, zParams, skiaLightPos, SkiaPipeline::getLightRadius(),
+ ambientAlpha, spotAlpha, casterProperties.getShadowColor(),
+ casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0);
}
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
index 9f00d23ae985..3c48d3604864 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
@@ -41,9 +41,7 @@ public:
explicit StartReorderBarrierDrawable(SkiaDisplayList* data);
protected:
- virtual SkRect onGetBounds() override {
- return SkRect::MakeLargest();
- }
+ virtual SkRect onGetBounds() override { return SkRect::MakeLargest(); }
virtual void onDraw(SkCanvas* canvas) override;
private:
@@ -65,16 +63,16 @@ private:
class EndReorderBarrierDrawable : public SkDrawable {
public:
explicit EndReorderBarrierDrawable(StartReorderBarrierDrawable* startBarrier);
+
protected:
- virtual SkRect onGetBounds() override {
- return SkRect::MakeLargest();
- }
+ virtual SkRect onGetBounds() override { return SkRect::MakeLargest(); }
virtual void onDraw(SkCanvas* canvas) override;
+
private:
void drawShadow(SkCanvas* canvas, RenderNodeDrawable* caster);
StartReorderBarrierDrawable* mStartBarrier;
};
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp
new file mode 100644
index 000000000000..87edd6968847
--- /dev/null
+++ b/libs/hwui/pipeline/skia/ShaderCache.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ShaderCache.h"
+#include <algorithm>
+#include <log/log.h>
+#include <thread>
+#include "FileBlobCache.h"
+#include "utils/TraceUtils.h"
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+// Cache size limits.
+static const size_t maxKeySize = 1024;
+static const size_t maxValueSize = 64 * 1024;
+static const size_t maxTotalSize = 512 * 1024;
+
+ShaderCache::ShaderCache() {
+ // There is an "incomplete FileBlobCache type" compilation error, if ctor is moved to header.
+}
+
+ShaderCache ShaderCache::sCache;
+
+ShaderCache& ShaderCache::get() {
+ return sCache;
+}
+
+void ShaderCache::initShaderDiskCache() {
+ ATRACE_NAME("initShaderDiskCache");
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mFilename.length() > 0) {
+ mBlobCache.reset(new FileBlobCache(maxKeySize, maxValueSize, maxTotalSize, mFilename));
+ mInitialized = true;
+ }
+}
+
+void ShaderCache::setFilename(const char* filename) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mFilename = filename;
+}
+
+BlobCache* ShaderCache::getBlobCacheLocked() {
+ LOG_ALWAYS_FATAL_IF(!mInitialized, "ShaderCache has not been initialized");
+ return mBlobCache.get();
+}
+
+sk_sp<SkData> ShaderCache::load(const SkData& key) {
+ ATRACE_NAME("ShaderCache::load");
+ size_t keySize = key.size();
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mInitialized) {
+ ALOGE("ShaderCache::load not initialized");
+ return nullptr;
+ }
+
+ // mObservedBlobValueSize is reasonably big to avoid memory reallocation
+ // Allocate a buffer with malloc. SkData takes ownership of that allocation and will call free.
+ void* valueBuffer = malloc(mObservedBlobValueSize);
+ if (!valueBuffer) {
+ return nullptr;
+ }
+ BlobCache* bc = getBlobCacheLocked();
+ size_t valueSize = bc->get(key.data(), keySize, valueBuffer, mObservedBlobValueSize);
+ int maxTries = 3;
+ while (valueSize > mObservedBlobValueSize && maxTries > 0) {
+ mObservedBlobValueSize = std::min(valueSize, maxValueSize);
+ valueBuffer = realloc(valueBuffer, mObservedBlobValueSize);
+ if (!valueBuffer) {
+ return nullptr;
+ }
+ valueSize = bc->get(key.data(), keySize, valueBuffer, mObservedBlobValueSize);
+ maxTries--;
+ }
+ if (!valueSize) {
+ free(valueBuffer);
+ return nullptr;
+ }
+ if (valueSize > mObservedBlobValueSize) {
+ ALOGE("ShaderCache::load value size is too big %d", (int) valueSize);
+ free(valueBuffer);
+ return nullptr;
+ }
+ return SkData::MakeFromMalloc(valueBuffer, valueSize);
+}
+
+void ShaderCache::store(const SkData& key, const SkData& data) {
+ ATRACE_NAME("ShaderCache::store");
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (!mInitialized) {
+ ALOGE("ShaderCache::store not initialized");
+ return;
+ }
+
+ size_t valueSize = data.size();
+ size_t keySize = key.size();
+ if (keySize == 0 || valueSize == 0 || valueSize >= maxValueSize) {
+ ALOGW("ShaderCache::store: sizes %d %d not allowed", (int)keySize, (int)valueSize);
+ return;
+ }
+
+ const void* value = data.data();
+
+ BlobCache* bc = getBlobCacheLocked();
+ bc->set(key.data(), keySize, value, valueSize);
+
+ if (!mSavePending && mDeferredSaveDelay > 0) {
+ mSavePending = true;
+ std::thread deferredSaveThread([this]() {
+ sleep(mDeferredSaveDelay);
+ std::lock_guard<std::mutex> lock(mMutex);
+ ATRACE_NAME("ShaderCache::saveToDisk");
+ if (mInitialized && mBlobCache) {
+ mBlobCache->writeToFile();
+ }
+ mSavePending = false;
+ });
+ deferredSaveThread.detach();
+ }
+}
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h
new file mode 100644
index 000000000000..27473d67bd1a
--- /dev/null
+++ b/libs/hwui/pipeline/skia/ShaderCache.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cutils/compiler.h>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <vector>
+#include <GrContextOptions.h>
+
+namespace android {
+
+class BlobCache;
+class FileBlobCache;
+
+namespace uirenderer {
+namespace skiapipeline {
+
+class ShaderCache : public GrContextOptions::PersistentCache {
+public:
+ /**
+ * "get" returns a pointer to the singleton ShaderCache object. This
+ * singleton object will never be destroyed.
+ */
+ ANDROID_API static ShaderCache& get();
+
+ /**
+ * "initShaderDiskCache" loads the serialized cache contents from disk and puts the ShaderCache
+ * into an initialized state, such that it is able to insert and retrieve entries from the
+ * cache. This should be called when HWUI pipeline is initialized. When not in the initialized
+ * state the load and store methods will return without performing any cache operations.
+ */
+ virtual void initShaderDiskCache();
+
+ /**
+ * "setFilename" sets the name of the file that should be used to store
+ * cache contents from one program invocation to another. This function does not perform any
+ * disk operation and it should be invoked before "initShaderCache".
+ */
+ virtual void setFilename(const char* filename);
+
+ /**
+ * "load" attempts to retrieve the value blob associated with a given key
+ * blob from cache. This will be called by Skia, when it needs to compile a new SKSL shader.
+ */
+ sk_sp<SkData> load(const SkData& key) override;
+
+ /**
+ * "store" attempts to insert a new key/value blob pair into the cache.
+ * This will be called by Skia after it compiled a new SKSL shader
+ */
+ void store(const SkData& key, const SkData& data) override;
+
+private:
+ // Creation and (the lack of) destruction is handled internally.
+ ShaderCache();
+
+ // Copying is disallowed.
+ ShaderCache(const ShaderCache&) = delete;
+ void operator=(const ShaderCache&) = delete;
+
+ /**
+ * "getBlobCacheLocked" returns the BlobCache object being used to store the
+ * key/value blob pairs. If the BlobCache object has not yet been created,
+ * this will do so, loading the serialized cache contents from disk if
+ * possible.
+ */
+ BlobCache* getBlobCacheLocked();
+
+ /**
+ * "mInitialized" indicates whether the ShaderCache is in the initialized
+ * state. It is initialized to false at construction time, and gets set to
+ * true when initialize is called.
+ * When in this state, the cache behaves as normal. When not,
+ * the load and store methods will return without performing any cache
+ * operations.
+ */
+ bool mInitialized = false;
+
+ /**
+ * "mBlobCache" is the cache in which the key/value blob pairs are stored. It
+ * is initially NULL, and will be initialized by getBlobCacheLocked the
+ * first time it's needed.
+ * The blob cache contains the Android build number. We treat version mismatches as an empty
+ * cache (logic implemented in BlobCache::unflatten).
+ */
+ std::unique_ptr<FileBlobCache> mBlobCache;
+
+ /**
+ * "mFilename" is the name of the file for storing cache contents in between
+ * program invocations. It is initialized to an empty string at
+ * construction time, and can be set with the setCacheFilename method. An
+ * empty string indicates that the cache should not be saved to or restored
+ * from disk.
+ */
+ std::string mFilename;
+
+ /**
+ * "mSavePending" indicates whether or not a deferred save operation is
+ * pending. Each time a key/value pair is inserted into the cache via
+ * load, a deferred save is initiated if one is not already pending.
+ * This will wait some amount of time and then trigger a save of the cache
+ * contents to disk.
+ */
+ bool mSavePending = false;
+
+ /**
+ * "mObservedBlobValueSize" is the maximum value size observed by the cache reading function.
+ */
+ size_t mObservedBlobValueSize = 20*1024;
+
+ /**
+ * The time in seconds to wait before saving newly inserted cache entries.
+ */
+ unsigned int mDeferredSaveDelay = 4;
+
+ /**
+ * "mMutex" is the mutex used to prevent concurrent access to the member
+ * variables. It must be locked whenever the member variables are accessed.
+ */
+ mutable std::mutex mMutex;
+
+ /**
+ * "sCache" is the singleton ShaderCache object.
+ */
+ static ShaderCache sCache;
+
+ friend class ShaderCacheTestUtils; //used for unit testing
+};
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index 3ddc09fbeca1..cb10901c4ccf 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -16,14 +16,13 @@
#include "SkiaDisplayList.h"
-#include "renderthread/CanvasContext.h"
-#include "VectorDrawable.h"
#include "DumpOpsCanvas.h"
#include "SkiaPipeline.h"
+#include "VectorDrawable.h"
+#include "renderthread/CanvasContext.h"
#include <SkImagePriv.h>
-
namespace android {
namespace uirenderer {
namespace skiapipeline {
@@ -49,8 +48,8 @@ void SkiaDisplayList::updateChildren(std::function<void(RenderNode*)> updateFn)
}
}
-bool SkiaDisplayList::prepareListAndChildren(TreeObserver& observer, TreeInfo& info,
- bool functorsNeedLayer,
+bool SkiaDisplayList::prepareListAndChildren(
+ TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) {
// If the prepare tree is triggered by the UI thread and no previous call to
// pinImages has failed then we must pin all mutable images in the GPU cache
@@ -64,7 +63,7 @@ bool SkiaDisplayList::prepareListAndChildren(TreeObserver& observer, TreeInfo& i
}
bool hasBackwardProjectedNodesHere = false;
- bool hasBackwardProjectedNodesSubtree= false;
+ bool hasBackwardProjectedNodesSubtree = false;
for (auto& child : mChildNodes) {
hasBackwardProjectedNodesHere |= child.getNodeProperties().getProjectBackwards();
@@ -78,14 +77,15 @@ bool SkiaDisplayList::prepareListAndChildren(TreeObserver& observer, TreeInfo& i
info.damageAccumulator->popTransform();
}
- //The purpose of next block of code is to reset projected display list if there are no
- //backward projected nodes. This speeds up drawing, by avoiding an extra walk of the tree
+ // The purpose of next block of code is to reset projected display list if there are no
+ // backward projected nodes. This speeds up drawing, by avoiding an extra walk of the tree
if (mProjectionReceiver) {
- mProjectionReceiver->setProjectedDisplayList(hasBackwardProjectedNodesSubtree ? this : nullptr);
+ mProjectionReceiver->setProjectedDisplayList(hasBackwardProjectedNodesSubtree ? this
+ : nullptr);
info.hasBackwardProjectedNodes = hasBackwardProjectedNodesHere;
} else {
- info.hasBackwardProjectedNodes = hasBackwardProjectedNodesSubtree
- || hasBackwardProjectedNodesHere;
+ info.hasBackwardProjectedNodes =
+ hasBackwardProjectedNodesSubtree || hasBackwardProjectedNodesHere;
}
bool isDirty = false;
@@ -94,7 +94,8 @@ bool SkiaDisplayList::prepareListAndChildren(TreeObserver& observer, TreeInfo& i
if (vectorDrawable->isDirty()) {
isDirty = true;
static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline())
- ->getVectorDrawables()->push_back(vectorDrawable);
+ ->getVectorDrawables()
+ ->push_back(vectorDrawable);
}
vectorDrawable->setPropertyChangeWillBeConsumed(true);
}
@@ -121,6 +122,6 @@ void SkiaDisplayList::output(std::ostream& output, uint32_t level) {
mDisplayList.draw(&canvas);
}
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index 66375d13826c..6883d33291ec 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -20,9 +20,9 @@
#include "GLFunctorDrawable.h"
#include "RenderNodeDrawable.h"
-#include <deque>
#include <SkLiteDL.h>
#include <SkLiteRecorder.h>
+#include <deque>
namespace android {
namespace uirenderer {
@@ -62,7 +62,7 @@ public:
* need to monitor that they don't extend beyond the lifetime of the class
* that creates them. Allocator dtor invokes all SkDrawable dtors.
*/
- template<class T, typename... Params>
+ template <class T, typename... Params>
SkDrawable* allocateDrawable(Params&&... params) {
return allocator.create<T>(std::forward<Params>(params)...);
}
@@ -113,7 +113,8 @@ public:
* to subclass from DisplayList
*/
- bool prepareListAndChildren(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
+ bool prepareListAndChildren(
+ TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) override;
/**
@@ -145,24 +146,25 @@ public:
std::vector<VectorDrawableRoot*> mVectorDrawables;
SkLiteDL mDisplayList;
- //mProjectionReceiver points to a child node (stored in mChildNodes) that is as a projection
- //receiver. It is set at record time and used at both prepare and draw tree traversals to
- //make sure backward projected nodes are found and drawn immediately after mProjectionReceiver.
+ // mProjectionReceiver points to a child node (stored in mChildNodes) that is as a projection
+ // receiver. It is set at record time and used at both prepare and draw tree traversals to
+ // make sure backward projected nodes are found and drawn immediately after mProjectionReceiver.
RenderNodeDrawable* mProjectionReceiver = nullptr;
- //mProjectedOutline is valid only when render node tree is traversed during the draw pass.
- //Render nodes that have a child receiver node, will store a pointer to their outline in
- //mProjectedOutline. Child receiver node will apply the clip before any backward projected
- //node is drawn.
+ // mProjectedOutline is valid only when render node tree is traversed during the draw pass.
+ // Render nodes that have a child receiver node, will store a pointer to their outline in
+ // mProjectedOutline. Child receiver node will apply the clip before any backward projected
+ // node is drawn.
const Outline* mProjectedOutline = nullptr;
- //mProjectedReceiverParentMatrix is valid when render node tree is traversed during the draw
- //pass. Render nodes that have a child receiver node, will store their matrix in
- //mProjectedReceiverParentMatrix. Child receiver node will set the matrix and then clip with the
- //outline of their parent.
+ // mProjectedReceiverParentMatrix is valid when render node tree is traversed during the draw
+ // pass. Render nodes that have a child receiver node, will store their matrix in
+ // mProjectedReceiverParentMatrix. Child receiver node will set the matrix and then clip with
+ // the
+ // outline of their parent.
SkMatrix mProjectedReceiverParentMatrix;
};
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/SkiaLayer.h b/libs/hwui/pipeline/skia/SkiaLayer.h
index 904d57e073ca..82e6914e8b7f 100644
--- a/libs/hwui/pipeline/skia/SkiaLayer.h
+++ b/libs/hwui/pipeline/skia/SkiaLayer.h
@@ -26,14 +26,12 @@ namespace skiapipeline {
/**
* An offscreen rendering target used to contain the contents a RenderNode.
*/
-struct SkiaLayer
-{
+struct SkiaLayer {
sk_sp<SkSurface> layerSurface;
Matrix4 inverseTransformInWindow;
bool hasRenderedSinceRepaint = false;
};
-
} /* namespace skiapipeline */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index abba70e4bdd5..365d7403e046 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -16,15 +16,15 @@
#include "SkiaOpenGLPipeline.h"
-#include "hwui/Bitmap.h"
#include "DeferredLayerUpdater.h"
#include "GlLayer.h"
#include "LayerDrawable.h"
-#include "renderthread/EglManager.h"
-#include "renderthread/Frame.h"
-#include "renderstate/RenderState.h"
#include "SkiaPipeline.h"
#include "SkiaProfileRenderer.h"
+#include "hwui/Bitmap.h"
+#include "renderstate/RenderState.h"
+#include "renderthread/EglManager.h"
+#include "renderthread/Frame.h"
#include "utils/TraceUtils.h"
#include <GrBackendSurface.h>
@@ -39,9 +39,7 @@ namespace uirenderer {
namespace skiapipeline {
SkiaOpenGLPipeline::SkiaOpenGLPipeline(RenderThread& thread)
- : SkiaPipeline(thread)
- , mEglManager(thread.eglManager()) {
-}
+ : SkiaPipeline(thread), mEglManager(thread.eglManager()) {}
MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() {
// TODO: Figure out why this workaround is needed, see b/13913604
@@ -55,19 +53,17 @@ MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() {
Frame SkiaOpenGLPipeline::getFrame() {
LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
- "drawRenderNode called on a context with no surface!");
+ "drawRenderNode called on a context with no surface!");
return mEglManager.beginFrame(mEglSurface);
}
-bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty,
- const SkRect& dirty,
- const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo,
- const std::vector<sp<RenderNode>>& renderNodes,
- FrameInfoVisualizer* profiler) {
-
+bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
+ const FrameBuilder::LightGeometry& lightGeometry,
+ LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
+ bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector<sp<RenderNode>>& renderNodes,
+ FrameInfoVisualizer* profiler) {
mEglManager.damageFrame(frame, dirty);
// setup surface for fbo0
@@ -77,7 +73,7 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty,
wideColorGamut ? kRGBA_half_GrPixelConfig : kRGBA_8888_GrPixelConfig;
GrBackendRenderTarget backendRT(frame.width(), frame.height(), 0, STENCIL_BUFFER_SIZE,
- pixelConfig, fboInfo);
+ pixelConfig, fboInfo);
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
@@ -86,13 +82,13 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty,
mRenderThread.getGrContext(), backendRT, kBottomLeft_GrSurfaceOrigin, nullptr, &props));
SkiaPipeline::updateLighting(lightGeometry, lightInfo);
- renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut,
- contentDrawBounds, surface);
+ renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut, contentDrawBounds,
+ surface);
layerUpdateQueue->clear();
// Draw visual debugging features
- if (CC_UNLIKELY(Properties::showDirtyRegions
- || ProfileType::None != Properties::getProfileType())) {
+ if (CC_UNLIKELY(Properties::showDirtyRegions ||
+ ProfileType::None != Properties::getProfileType())) {
SkCanvas* profileCanvas = surface->getCanvas();
SkiaProfileRenderer profileRenderer(profileCanvas);
profiler->draw(profileRenderer);
@@ -107,9 +103,8 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty,
return true;
}
-bool SkiaOpenGLPipeline::swapBuffers(const Frame& frame, bool drew,
- const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) {
-
+bool SkiaOpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
+ FrameInfo* currentFrameInfo, bool* requireSwap) {
GL_CHECKPOINT(LOW);
// Even if we decided to cancel the frame, from the perspective of jank
@@ -140,7 +135,7 @@ bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBi
* then reading from the intermediate buffer into the bitmap.
*/
sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
- SkBudgeted::kYes, bitmap->info());
+ SkBudgeted::kYes, bitmap->info());
Layer* layer = deferredLayer->backingLayer();
if (LayerDrawable::DrawLayer(mRenderThread.getGrContext(), tmpSurface->getCanvas(), layer)) {
@@ -155,9 +150,9 @@ bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBi
}
static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
- GlLayer* layer = new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha,
- mode, blend);
+ SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ GlLayer* layer =
+ new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
layer->generateTexture();
return layer;
}
@@ -174,8 +169,7 @@ void SkiaOpenGLPipeline::onStop() {
}
bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
- ColorMode colorMode) {
-
+ ColorMode colorMode) {
if (mEglSurface != EGL_NO_SURFACE) {
mEglManager.destroySurface(mEglSurface);
mEglSurface = EGL_NO_SURFACE;
@@ -221,8 +215,7 @@ void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* func
class AutoEglFence {
public:
- AutoEglFence(EGLDisplay display)
- : mDisplay(display) {
+ AutoEglFence(EGLDisplay display) : mDisplay(display) {
fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
}
@@ -233,17 +226,17 @@ public:
}
EGLSyncKHR fence = EGL_NO_SYNC_KHR;
+
private:
EGLDisplay mDisplay = EGL_NO_DISPLAY;
};
class AutoEglImage {
public:
- AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer)
- : mDisplay(display) {
- EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
- image = eglCreateImageKHR(display, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
+ AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) {
+ EGLint imageAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+ image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer,
+ imageAttrs);
}
~AutoEglImage() {
@@ -253,6 +246,7 @@ public:
}
EGLImageKHR image = EGL_NO_IMAGE_KHR;
+
private:
EGLDisplay mDisplay = EGL_NO_DISPLAY;
};
@@ -264,16 +258,14 @@ public:
glBindTexture(GL_TEXTURE_2D, mTexture);
}
- ~AutoSkiaGlTexture() {
- glDeleteTextures(1, &mTexture);
- }
+ ~AutoSkiaGlTexture() { glDeleteTextures(1, &mTexture); }
private:
GLuint mTexture = 0;
};
sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
- SkBitmap& skBitmap) {
+ SkBitmap& skBitmap) {
renderThread.eglManager().initialize();
sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext());
@@ -282,67 +274,67 @@ sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr
GLint format, type;
bool isSupported = false;
- //TODO: add support for linear blending (when ANDROID_ENABLE_LINEAR_BLENDING is defined)
+ // TODO: add support for linear blending (when ANDROID_ENABLE_LINEAR_BLENDING is defined)
switch (info.colorType()) {
- case kRGBA_8888_SkColorType:
- isSupported = true;
- // ARGB_4444 is upconverted to RGBA_8888
- case kARGB_4444_SkColorType:
- pixelFormat = PIXEL_FORMAT_RGBA_8888;
- format = GL_RGBA;
- type = GL_UNSIGNED_BYTE;
- break;
- case kRGBA_F16_SkColorType:
- isSupported = grContext->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig);
- if (isSupported) {
- type = GL_HALF_FLOAT;
- pixelFormat = PIXEL_FORMAT_RGBA_FP16;
- } else {
+ case kRGBA_8888_SkColorType:
+ isSupported = true;
+ // ARGB_4444 is upconverted to RGBA_8888
+ case kARGB_4444_SkColorType:
+ pixelFormat = PIXEL_FORMAT_RGBA_8888;
+ format = GL_RGBA;
type = GL_UNSIGNED_BYTE;
+ break;
+ case kRGBA_F16_SkColorType:
+ isSupported = grContext->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig);
+ if (isSupported) {
+ type = GL_HALF_FLOAT;
+ pixelFormat = PIXEL_FORMAT_RGBA_FP16;
+ } else {
+ type = GL_UNSIGNED_BYTE;
+ pixelFormat = PIXEL_FORMAT_RGBA_8888;
+ }
+ format = GL_RGBA;
+ break;
+ case kRGB_565_SkColorType:
+ isSupported = true;
+ pixelFormat = PIXEL_FORMAT_RGB_565;
+ format = GL_RGB;
+ type = GL_UNSIGNED_SHORT_5_6_5;
+ break;
+ case kGray_8_SkColorType:
+ isSupported = true;
pixelFormat = PIXEL_FORMAT_RGBA_8888;
- }
- format = GL_RGBA;
- break;
- case kRGB_565_SkColorType:
- isSupported = true;
- pixelFormat = PIXEL_FORMAT_RGB_565;
- format = GL_RGB;
- type = GL_UNSIGNED_SHORT_5_6_5;
- break;
- case kGray_8_SkColorType:
- isSupported = true;
- pixelFormat = PIXEL_FORMAT_RGBA_8888;
- format = GL_LUMINANCE;
- type = GL_UNSIGNED_BYTE;
- break;
- default:
- ALOGW("unable to create hardware bitmap of colortype: %d", info.colorType());
- return nullptr;
+ format = GL_LUMINANCE;
+ type = GL_UNSIGNED_BYTE;
+ break;
+ default:
+ ALOGW("unable to create hardware bitmap of colortype: %d", info.colorType());
+ return nullptr;
}
-
SkBitmap bitmap;
if (isSupported) {
bitmap = skBitmap;
} else {
- bitmap.allocPixels(SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(),
- nullptr));
+ bitmap.allocPixels(
+ SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(), nullptr));
bitmap.eraseColor(0);
if (info.colorType() == kRGBA_F16_SkColorType) {
// Drawing RGBA_F16 onto ARGB_8888 is not supported
skBitmap.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
- bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
+ bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
} else {
SkCanvas canvas(bitmap);
canvas.drawBitmap(skBitmap, 0.0f, 0.0f, nullptr);
}
}
- sp<GraphicBuffer> buffer = new GraphicBuffer(info.width(), info.height(), pixelFormat,
- GraphicBuffer::USAGE_HW_TEXTURE |
- GraphicBuffer::USAGE_SW_WRITE_NEVER |
- GraphicBuffer::USAGE_SW_READ_NEVER,
- std::string("Bitmap::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) + "]");
+ sp<GraphicBuffer> buffer = new GraphicBuffer(
+ info.width(), info.height(), pixelFormat,
+ GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
+ GraphicBuffer::USAGE_SW_READ_NEVER,
+ std::string("Bitmap::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) +
+ "]");
status_t error = buffer->initCheck();
if (error < 0) {
@@ -350,18 +342,17 @@ sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr
return nullptr;
}
- //upload the bitmap into a texture
+ // upload the bitmap into a texture
EGLDisplay display = eglGetCurrentDisplay();
- LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY,
- "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
- uirenderer::renderthread::EglManager::eglErrorString());
+ LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
+ uirenderer::renderthread::EglManager::eglErrorString());
// We use an EGLImage to access the content of the GraphicBuffer
// The EGL image is later bound to a 2D texture
- EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer->getNativeBuffer();
+ EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer->getNativeBuffer();
AutoEglImage autoImage(display, clientBuffer);
if (autoImage.image == EGL_NO_IMAGE_KHR) {
ALOGW("Could not create EGL image, err =%s",
- uirenderer::renderthread::EglManager::eglErrorString());
+ uirenderer::renderthread::EglManager::eglErrorString());
return nullptr;
}
AutoSkiaGlTexture glTexture;
@@ -372,7 +363,7 @@ sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr
// But asynchronous in sense that driver may upload texture onto hardware buffer when we first
// use it in drawing
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, info.width(), info.height(), format, type,
- bitmap.getPixels());
+ bitmap.getPixels());
GL_CHECKPOINT(MODERATE);
// The fence is used to wait for the texture upload to finish
@@ -386,7 +377,7 @@ sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr
// The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
// pipeline flush (similar to what a glFlush() would do.)
EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence,
- EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
+ EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError());
return nullptr;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index aa29c8e3babc..5e013b6697a7 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -33,25 +33,24 @@ public:
renderthread::MakeCurrentResult makeCurrent() override;
renderthread::Frame getFrame() override;
bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo,
- const std::vector< sp<RenderNode> >& renderNodes,
- FrameInfoVisualizer* profiler) override;
+ const FrameBuilder::LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
+ const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector<sp<RenderNode> >& renderNodes,
+ FrameInfoVisualizer* profiler) override;
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) override;
+ FrameInfo* currentFrameInfo, bool* requireSwap) override;
bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
DeferredLayerUpdater* createTextureLayer() override;
bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior,
- renderthread::ColorMode colorMode) override;
+ renderthread::ColorMode colorMode) override;
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;
static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread,
- SkBitmap& skBitmap);
+ SkBitmap& skBitmap);
private:
renderthread::EglManager& mEglManager;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index 049018cc321c..288d0395370c 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -16,16 +16,16 @@
#include "SkiaOpenGLReadback.h"
-#include "DeviceInfo.h"
-#include "Matrix.h"
-#include "Properties.h"
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GrBackendSurface.h>
#include <SkCanvas.h>
#include <SkSurface.h>
-#include <GrBackendSurface.h>
#include <gl/GrGLInterface.h>
#include <gl/GrGLTypes.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
+#include "DeviceInfo.h"
+#include "Matrix.h"
+#include "Properties.h"
using namespace android::uirenderer::renderthread;
@@ -34,8 +34,8 @@ namespace uirenderer {
namespace skiapipeline {
CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
- int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) {
-
+ int imgWidth, int imgHeight, const Rect& srcRect,
+ SkBitmap* bitmap) {
GLuint sourceTexId;
glGenTextures(1, &sourceTexId);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId);
@@ -46,7 +46,7 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4
sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
LOG_ALWAYS_FATAL_IF(!glInterface.get());
grContext.reset(GrContext::Create(GrBackend::kOpenGL_GrBackend,
- (GrBackendContext)glInterface.get()));
+ (GrBackendContext)glInterface.get()));
} else {
grContext->resetContext();
}
@@ -57,23 +57,17 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4
GrPixelConfig pixelConfig;
switch (bitmap->colorType()) {
- case kRGBA_F16_SkColorType:
- pixelConfig = kRGBA_half_GrPixelConfig;
- break;
- case kN32_SkColorType:
- default:
- pixelConfig = kRGBA_8888_GrPixelConfig;
- break;
+ case kRGBA_F16_SkColorType:
+ pixelConfig = kRGBA_half_GrPixelConfig;
+ break;
+ case kN32_SkColorType:
+ default:
+ pixelConfig = kRGBA_8888_GrPixelConfig;
+ break;
}
- /* Ideally, we would call grContext->caps()->isConfigRenderable(...). We
- * currently can't do that since some devices (i.e. SwiftShader) supports all
- * the appropriate half float extensions, but only allow the buffer to be read
- * back as full floats. We can relax this extension if Skia implements support
- * for reading back float buffers (skbug.com/6945).
- */
if (pixelConfig == kRGBA_half_GrPixelConfig &&
- !DeviceInfo::get()->extensions().hasRenderableFloatTextures()) {
+ !grContext->caps()->isConfigRenderable(kRGBA_half_GrPixelConfig, false)) {
ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
return CopyResult::DestinationInvalid;
}
@@ -82,7 +76,7 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4
CopyResult copyResult = CopyResult::UnknownError;
sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), backendTexture,
- kTopLeft_GrSurfaceOrigin));
+ kTopLeft_GrSurfaceOrigin));
if (image) {
int displayedWidth = imgWidth, displayedHeight = imgHeight;
// If this is a 90 or 270 degree rotation we need to swap width/height to get the device
@@ -100,12 +94,12 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4
if (srcNotEmpty) {
SkMatrix textureMatrixInv;
imgTransform.copyTo(textureMatrixInv);
- //TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed
+ // TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed
// use bottom left origin and remove flipV and invert transformations.
SkMatrix flipV;
flipV.setAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
textureMatrixInv.preConcat(flipV);
- textureMatrixInv.preScale(1.0f/displayedWidth, 1.0f/displayedHeight);
+ textureMatrixInv.preScale(1.0f / displayedWidth, 1.0f / displayedHeight);
textureMatrixInv.postScale(imgWidth, imgHeight);
SkMatrix textureMatrix;
if (!textureMatrixInv.invert(&textureMatrix)) {
@@ -117,20 +111,20 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4
// we render in an offscreen buffer to scale and to avoid an issue b/62262733
// with reading incorrect data from EGLImage backed SkImage (likely a driver bug)
- sk_sp<SkSurface> scaledSurface = SkSurface::MakeRenderTarget(
- grContext.get(), SkBudgeted::kYes, bitmap->info());
+ sk_sp<SkSurface> scaledSurface =
+ SkSurface::MakeRenderTarget(grContext.get(), SkBudgeted::kYes, bitmap->info());
SkPaint paint;
paint.setBlendMode(SkBlendMode::kSrc);
// Apply a filter, which is matching OpenGL pipeline readback behaviour. Filter usage
// is codified by tests using golden images like DecodeAccuracyTest.
- if (skiaSrcRect.width() != bitmap->width()
- || skiaSrcRect.height() != bitmap->height()) {
- //TODO: apply filter always, but check if tests will be fine
+ if (skiaSrcRect.width() != bitmap->width() ||
+ skiaSrcRect.height() != bitmap->height()) {
+ // TODO: apply filter always, but check if tests will be fine
paint.setFilterQuality(kLow_SkFilterQuality);
}
scaledSurface->getCanvas()->concat(textureMatrix);
scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, skiaDestRect, &paint,
- SkCanvas::kFast_SrcRectConstraint);
+ SkCanvas::kFast_SrcRectConstraint);
image = scaledSurface->makeImageSnapshot();
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h
index d914409628d0..cc9fb3b0a5e0 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h
@@ -25,9 +25,11 @@ namespace skiapipeline {
class SkiaOpenGLReadback : public OpenGLReadback {
public:
SkiaOpenGLReadback(renderthread::RenderThread& thread) : OpenGLReadback(thread) {}
+
protected:
virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
- int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) override;
+ int imgWidth, int imgHeight, const Rect& srcRect,
+ SkBitmap* bitmap) override;
};
} /* namespace skiapipeline */
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index a092cd569dfa..d5fe7f4fa6aa 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -16,7 +16,6 @@
#include "SkiaPipeline.h"
-#include "utils/TraceUtils.h"
#include <SkImageEncoder.h>
#include <SkImagePriv.h>
#include <SkOverdrawCanvas.h>
@@ -26,6 +25,7 @@
#include <SkPixelSerializer.h>
#include <SkStream.h>
#include "VectorDrawable.h"
+#include "utils/TraceUtils.h"
#include <unistd.h>
@@ -35,13 +35,13 @@ namespace android {
namespace uirenderer {
namespace skiapipeline {
-float SkiaPipeline::mLightRadius = 0;
+float SkiaPipeline::mLightRadius = 0;
uint8_t SkiaPipeline::mAmbientShadowAlpha = 0;
uint8_t SkiaPipeline::mSpotShadowAlpha = 0;
Vector3 SkiaPipeline::mLightCenter = {FLT_MIN, FLT_MIN, FLT_MIN};
-SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) {
+SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) {
mVectorDrawables.reserve(30);
}
@@ -82,8 +82,8 @@ void SkiaPipeline::onPrepareTree() {
}
void SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo) {
+ LayerUpdateQueue* layerUpdateQueue, bool opaque,
+ bool wideColorGamut, const BakedOpRenderer::LightInfo& lightInfo) {
updateLighting(lightGeometry, lightInfo);
ATRACE_NAME("draw layers");
renderVectorDrawableCache();
@@ -91,8 +91,8 @@ void SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry
layerUpdateQueue->clear();
}
-void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers,
- bool opaque, bool wideColorGamut) {
+void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque,
+ bool wideColorGamut) {
sk_sp<GrContext> cachedContext;
// Render all layers that need to be updated, in order.
@@ -129,7 +129,8 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers,
return;
}
- ATRACE_FORMAT("drawLayer [%s] %.1f x %.1f", layerNode->getName(), bounds.width(), bounds.height());
+ ATRACE_FORMAT("drawLayer [%s] %.1f x %.1f", layerNode->getName(), bounds.width(),
+ bounds.height());
layerNode->getSkiaLayer()->hasRenderedSinceRepaint = false;
layerCanvas->clear(SK_ColorTRANSPARENT);
@@ -158,22 +159,21 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers,
}
}
-bool SkiaPipeline::createOrUpdateLayer(RenderNode* node,
- const DamageAccumulator& damageAccumulator, bool wideColorGamut) {
+bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
+ bool wideColorGamut) {
SkSurface* layer = node->getLayerSurface();
if (!layer || layer->width() != node->getWidth() || layer->height() != node->getHeight()) {
SkImageInfo info;
if (wideColorGamut) {
info = SkImageInfo::Make(node->getWidth(), node->getHeight(), kRGBA_F16_SkColorType,
- kPremul_SkAlphaType);
+ kPremul_SkAlphaType);
} else {
info = SkImageInfo::MakeN32Premul(node->getWidth(), node->getHeight());
}
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
SkASSERT(mRenderThread.getGrContext() != nullptr);
- node->setLayerSurface(
- SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
- info, 0, &props));
+ node->setLayerSurface(SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
+ SkBudgeted::kYes, info, 0, &props));
if (node->getLayerSurface()) {
// update the transform in window of the layer to reset its origin wrt light source
// position
@@ -211,8 +211,8 @@ public:
SkData* onEncode(const SkPixmap& pixmap) override {
SkDynamicMemoryWStream buf;
return SkEncodeImage(&buf, pixmap, SkEncodedImageFormat::kPNG, 100)
- ? buf.detachAsData().release()
- : nullptr;
+ ? buf.detachAsData().release()
+ : nullptr;
}
};
@@ -245,7 +245,7 @@ public:
TaskProcessor<bool>::add(task);
}
- virtual void onProcess(const sp<Task<bool> >& task) override {
+ virtual void onProcess(const sp<Task<bool>>& task) override {
SavePictureTask* t = static_cast<SavePictureTask*>(task.get());
if (0 == access(t->filename.c_str(), F_OK)) {
@@ -257,8 +257,8 @@ public:
if (stream.isValid()) {
stream.write(t->data->data(), t->data->size());
stream.flush();
- SkDebugf("SKP Captured Drawing Output (%d bytes) for frame. %s",
- stream.bytesWritten(), t->filename.c_str());
+ SkDebugf("SKP Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(),
+ t->filename.c_str());
}
task->setResult(true);
@@ -271,8 +271,8 @@ SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface) {
char prop[PROPERTY_VALUE_MAX] = {'\0'};
if (!recordingPicture) {
property_get(PROPERTY_CAPTURE_SKP_FILENAME, prop, "0");
- recordingPicture = prop[0] != '0'
- && mCapturedFile != prop; //ensure we capture only once per filename
+ recordingPicture = prop[0] != '0' &&
+ mCapturedFile != prop; // ensure we capture only once per filename
if (recordingPicture) {
mCapturedFile = prop;
mCaptureSequence = property_get_int32(PROPERTY_CAPTURE_SKP_FRAMES, 1);
@@ -281,7 +281,7 @@ SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface) {
if (recordingPicture) {
mRecorder.reset(new SkPictureRecorder());
return mRecorder->beginRecording(surface->width(), surface->height(), nullptr,
- SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
+ SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
}
}
return surface->getCanvas();
@@ -296,7 +296,7 @@ void SkiaPipeline::endCapture(SkSurface* surface) {
PngPixelSerializer serializer;
picture->serialize(&stream, &serializer);
- //offload saving to file in a different thread
+ // offload saving to file in a different thread
if (!mSavePictureProcessor.get()) {
TaskManager* taskManager = getTaskManager();
mSavePictureProcessor = new SavePictureProcessor(
@@ -305,8 +305,9 @@ void SkiaPipeline::endCapture(SkSurface* surface) {
if (1 == mCaptureSequence) {
mSavePictureProcessor->savePicture(stream.detachAsData(), mCapturedFile);
} else {
- mSavePictureProcessor->savePicture(stream.detachAsData(),
- mCapturedFile + "_" + std::to_string(mCaptureSequence));
+ mSavePictureProcessor->savePicture(
+ stream.detachAsData(),
+ mCapturedFile + "_" + std::to_string(mCaptureSequence));
}
mCaptureSequence--;
}
@@ -315,9 +316,9 @@ void SkiaPipeline::endCapture(SkSurface* surface) {
}
void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
- const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut,
- const Rect &contentDrawBounds, sk_sp<SkSurface> surface) {
-
+ const std::vector<sp<RenderNode>>& nodes, bool opaque,
+ bool wideColorGamut, const Rect& contentDrawBounds,
+ sk_sp<SkSurface> surface) {
renderVectorDrawableCache();
// draw all layers up front
@@ -343,14 +344,14 @@ void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& cli
namespace {
static Rect nodeBounds(RenderNode& node) {
auto& props = node.properties();
- return Rect(props.getLeft(), props.getTop(),
- props.getRight(), props.getBottom());
+ return Rect(props.getLeft(), props.getTop(), props.getRight(), props.getBottom());
}
}
void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
- const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut,
- const Rect &contentDrawBounds, SkCanvas* canvas) {
+ const std::vector<sp<RenderNode>>& nodes, bool opaque,
+ bool wideColorGamut, const Rect& contentDrawBounds,
+ SkCanvas* canvas) {
SkAutoCanvasRestore saver(canvas, true);
canvas->androidFramework_setDeviceClipRestriction(clip.roundOut());
@@ -364,15 +365,18 @@ void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect&
root.draw(canvas);
}
} else if (0 == nodes.size()) {
- //nothing to draw
+ // nothing to draw
} else {
// It there are multiple render nodes, they are laid out as follows:
// #0 - backdrop (content + caption)
// #1 - content (local bounds are at (0,0), will be translated and clipped to backdrop)
// #2 - additional overlay nodes
- // Usually the backdrop cannot be seen since it will be entirely covered by the content. While
- // resizing however it might become partially visible. The following render loop will crop the
- // backdrop against the content and draw the remaining part of it. It will then draw the content
+ // Usually the backdrop cannot be seen since it will be entirely covered by the content.
+ // While
+ // resizing however it might become partially visible. The following render loop will crop
+ // the
+ // backdrop against the content and draw the remaining part of it. It will then draw the
+ // content
// cropped to the backdrop (since that indicates a shrinking of the window).
//
// Additional nodes will be drawn on top with no particular clipping semantics.
@@ -384,29 +388,31 @@ void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect&
// Backdrop bounds in render target space
const Rect backdrop = nodeBounds(*nodes[0]);
- // Bounds that content will fill in render target space (note content node bounds may be bigger)
+ // Bounds that content will fill in render target space (note content node bounds may be
+ // bigger)
Rect content(contentDrawBounds.getWidth(), contentDrawBounds.getHeight());
content.translate(backdrop.left, backdrop.top);
if (!content.contains(backdrop) && !nodes[0]->nothingToDraw()) {
// Content doesn't entirely overlap backdrop, so fill around content (right/bottom)
// Note: in the future, if content doesn't snap to backdrop's left/top, this may need to
- // also fill left/top. Currently, both 2up and freeform position content at the top/left of
+ // also fill left/top. Currently, both 2up and freeform position content at the top/left
+ // of
// the backdrop, so this isn't necessary.
RenderNodeDrawable backdropNode(nodes[0].get(), canvas);
if (content.right < backdrop.right) {
// draw backdrop to right side of content
SkAutoCanvasRestore acr(canvas, true);
- canvas->clipRect(SkRect::MakeLTRB(content.right, backdrop.top,
- backdrop.right, backdrop.bottom));
+ canvas->clipRect(SkRect::MakeLTRB(content.right, backdrop.top, backdrop.right,
+ backdrop.bottom));
backdropNode.draw(canvas);
}
if (content.bottom < backdrop.bottom) {
// draw backdrop to bottom of content
// Note: bottom fill uses content left/right, to avoid overdrawing left/right fill
SkAutoCanvasRestore acr(canvas, true);
- canvas->clipRect(SkRect::MakeLTRB(content.left, content.bottom,
- content.right, backdrop.bottom));
+ canvas->clipRect(SkRect::MakeLTRB(content.left, content.bottom, content.right,
+ backdrop.bottom));
backdropNode.draw(canvas);
}
}
@@ -419,8 +425,9 @@ void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect&
SkAutoCanvasRestore acr(canvas, true);
canvas->translate(dx, dy);
- const SkRect contentLocalClip = SkRect::MakeXYWH(contentDrawBounds.left,
- contentDrawBounds.top, backdrop.getWidth(), backdrop.getHeight());
+ const SkRect contentLocalClip =
+ SkRect::MakeXYWH(contentDrawBounds.left, contentDrawBounds.top,
+ backdrop.getWidth(), backdrop.getHeight());
canvas->clipRect(contentLocalClip);
contentNode.draw(canvas);
} else {
@@ -447,8 +454,8 @@ void SkiaPipeline::dumpResourceCacheUsage() const {
SkString log("Resource Cache Usage:\n");
log.appendf("%8d items out of %d maximum items\n", resources, maxResources);
- log.appendf("%8zu bytes (%.2f MB) out of %.2f MB maximum\n",
- bytes, bytes * (1.0f / (1024.0f * 1024.0f)), maxBytes * (1.0f / (1024.0f * 1024.0f)));
+ log.appendf("%8zu bytes (%.2f MB) out of %.2f MB maximum\n", bytes,
+ bytes * (1.0f / (1024.0f * 1024.0f)), maxBytes * (1.0f / (1024.0f * 1024.0f)));
ALOGD("%s", log.c_str());
}
@@ -461,13 +468,17 @@ void SkiaPipeline::dumpResourceCacheUsage() const {
// (2) Requires premul colors (instead of unpremul).
// (3) Requires RGBA colors (instead of BGRA).
static const uint32_t kOverdrawColors[2][6] = {
- { 0x00000000, 0x00000000, 0x2f2f0000, 0x2f002f00, 0x3f00003f, 0x7f00007f, },
- { 0x00000000, 0x00000000, 0x2f2f0000, 0x4f004f4f, 0x5f50335f, 0x7f00007f, },
+ {
+ 0x00000000, 0x00000000, 0x2f2f0000, 0x2f002f00, 0x3f00003f, 0x7f00007f,
+ },
+ {
+ 0x00000000, 0x00000000, 0x2f2f0000, 0x4f004f4f, 0x5f50335f, 0x7f00007f,
+ },
};
void SkiaPipeline::renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
- const std::vector<sp<RenderNode>>& nodes, const Rect &contentDrawBounds,
- sk_sp<SkSurface> surface) {
+ const std::vector<sp<RenderNode>>& nodes,
+ const Rect& contentDrawBounds, sk_sp<SkSurface> surface) {
// Set up the overdraw canvas.
SkImageInfo offscreenInfo = SkImageInfo::MakeA8(surface->width(), surface->height());
sk_sp<SkSurface> offscreen = surface->makeSurface(offscreenInfo);
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 67b18783cb53..27092270bb80 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -16,10 +16,10 @@
#pragma once
-#include "renderthread/CanvasContext.h"
+#include <SkSurface.h>
#include "FrameBuilder.h"
+#include "renderthread/CanvasContext.h"
#include "renderthread/IRenderPipeline.h"
-#include <SkSurface.h>
class SkPictureRecorder;
@@ -42,15 +42,15 @@ public:
void onPrepareTree() override;
void renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo) override;
+ LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo) override;
- bool createOrUpdateLayer(RenderNode* node,
- const DamageAccumulator& damageAccumulator, bool wideColorGamut) override;
+ bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
+ bool wideColorGamut) override;
void renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
- const std::vector< sp<RenderNode> >& nodes, bool opaque, bool wideColorGamut,
- const Rect &contentDrawBounds, sk_sp<SkSurface> surface);
+ const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut,
+ const Rect& contentDrawBounds, sk_sp<SkSurface> surface);
std::vector<VectorDrawableRoot*>* getVectorDrawables() { return &mVectorDrawables; }
@@ -86,7 +86,7 @@ public:
Vector3 adjustedLightCenter = mLightCenter;
if (CC_UNLIKELY(Properties::overrideLightPosY > 0)) {
// negated since this shifts up
- adjustedLightCenter.y = - Properties::overrideLightPosY;
+ adjustedLightCenter.y = -Properties::overrideLightPosY;
}
if (CC_UNLIKELY(Properties::overrideLightPosZ > 0)) {
adjustedLightCenter.z = Properties::overrideLightPosZ;
@@ -97,7 +97,7 @@ public:
}
static void updateLighting(const FrameBuilder::LightGeometry& lightGeometry,
- const BakedOpRenderer::LightInfo& lightInfo) {
+ const BakedOpRenderer::LightInfo& lightInfo) {
mLightRadius = lightGeometry.radius;
mAmbientShadowAlpha = lightInfo.ambientShadowAlpha;
mSpotShadowAlpha = lightInfo.spotShadowAlpha;
@@ -111,16 +111,16 @@ protected:
private:
void renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
- const std::vector< sp<RenderNode> >& nodes, bool opaque, bool wideColorGamut,
- const Rect &contentDrawBounds, SkCanvas* canvas);
+ const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut,
+ const Rect& contentDrawBounds, SkCanvas* canvas);
/**
* Debugging feature. Draws a semi-transparent overlay on each pixel, indicating
* how many times it has been drawn.
*/
void renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
- const std::vector< sp<RenderNode> >& nodes, const Rect &contentDrawBounds,
- sk_sp<SkSurface>);
+ const std::vector<sp<RenderNode>>& nodes, const Rect& contentDrawBounds,
+ sk_sp<SkSurface>);
/**
* Render mVectorDrawables into offscreen buffers.
@@ -137,7 +137,6 @@ private:
*/
std::vector<VectorDrawableRoot*> mVectorDrawables;
-
// Block of properties used only for debugging to record a SkPicture and save it in a file.
/**
* mCapturedFile is used to enforce we don't capture more than once for a given name (cause
diff --git a/libs/hwui/pipeline/skia/SkiaProfileRenderer.cpp b/libs/hwui/pipeline/skia/SkiaProfileRenderer.cpp
index d97fb372fe0c..492c39f1288c 100644
--- a/libs/hwui/pipeline/skia/SkiaProfileRenderer.cpp
+++ b/libs/hwui/pipeline/skia/SkiaProfileRenderer.cpp
@@ -20,7 +20,7 @@ namespace android {
namespace uirenderer {
void SkiaProfileRenderer::drawRect(float left, float top, float right, float bottom,
- const SkPaint& paint) {
+ const SkPaint& paint) {
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
mCanvas->drawRect(rect, paint);
}
@@ -28,7 +28,7 @@ void SkiaProfileRenderer::drawRect(float left, float top, float right, float bot
void SkiaProfileRenderer::drawRects(const float* rects, int count, const SkPaint& paint) {
for (int index = 0; index + 4 <= count; index += 4) {
SkRect rect = SkRect::MakeLTRB(rects[index + 0], rects[index + 1], rects[index + 2],
- rects[index + 3]);
+ rects[index + 3]);
mCanvas->drawRect(rect, paint);
}
}
diff --git a/libs/hwui/pipeline/skia/SkiaProfileRenderer.h b/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
index e6b7f8307379..5ae7d6b0b607 100644
--- a/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
+++ b/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
@@ -23,8 +23,7 @@ namespace uirenderer {
class SkiaProfileRenderer : public IProfileRenderer {
public:
- SkiaProfileRenderer(SkCanvas* canvas)
- : mCanvas(canvas) {}
+ SkiaProfileRenderer(SkCanvas* canvas) : mCanvas(canvas) {}
void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override;
void drawRects(const float* rects, int count, const SkPaint& paint) override;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 0bdf15333647..91b35c281b04 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -16,12 +16,12 @@
#include "SkiaRecordingCanvas.h"
+#include <SkImagePriv.h>
#include "Layer.h"
-#include "RenderNode.h"
#include "LayerDrawable.h"
#include "NinePatchUtils.h"
+#include "RenderNode.h"
#include "pipeline/skia/AnimatedDrawables.h"
-#include <SkImagePriv.h>
namespace android {
namespace uirenderer {
@@ -32,7 +32,7 @@ namespace skiapipeline {
// ----------------------------------------------------------------------------
void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, int width,
- int height) {
+ int height) {
mCurrentBarrier = nullptr;
SkASSERT(mDisplayList.get() == nullptr);
@@ -59,17 +59,21 @@ uirenderer::DisplayList* SkiaRecordingCanvas::finishRecording() {
// ----------------------------------------------------------------------------
void SkiaRecordingCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
- uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
- uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
- uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) {
+ uirenderer::CanvasPropertyPrimitive* top,
+ uirenderer::CanvasPropertyPrimitive* right,
+ uirenderer::CanvasPropertyPrimitive* bottom,
+ uirenderer::CanvasPropertyPrimitive* rx,
+ uirenderer::CanvasPropertyPrimitive* ry,
+ uirenderer::CanvasPropertyPaint* paint) {
// Destructor of drawables created with allocateDrawable, will be invoked by ~LinearAllocator.
- drawDrawable(mDisplayList->allocateDrawable<AnimatedRoundRect>(left, top, right, bottom,
- rx, ry, paint));
+ drawDrawable(mDisplayList->allocateDrawable<AnimatedRoundRect>(left, top, right, bottom, rx, ry,
+ paint));
}
void SkiaRecordingCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x,
- uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius,
- uirenderer::CanvasPropertyPaint* paint) {
+ uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint) {
drawDrawable(mDisplayList->allocateDrawable<AnimatedCircle>(x, y, radius, paint));
}
@@ -77,15 +81,14 @@ void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) {
if (nullptr != mCurrentBarrier) {
// finish off the existing chunk
SkDrawable* drawable =
- mDisplayList->allocateDrawable<EndReorderBarrierDrawable>(
- mCurrentBarrier);
+ mDisplayList->allocateDrawable<EndReorderBarrierDrawable>(mCurrentBarrier);
mCurrentBarrier = nullptr;
drawDrawable(drawable);
}
if (enableReorder) {
mCurrentBarrier = (StartReorderBarrierDrawable*)
- mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(
- mDisplayList.get());
+ mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(
+ mDisplayList.get());
drawDrawable(mCurrentBarrier);
}
}
@@ -113,25 +116,21 @@ void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
}
void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor,
- uirenderer::GlFunctorLifecycleListener* listener) {
+ uirenderer::GlFunctorLifecycleListener* listener) {
// Drawable dtor will be invoked when mChildFunctors deque is cleared.
mDisplayList->mChildFunctors.emplace_back(functor, listener, asSkCanvas());
drawDrawable(&mDisplayList->mChildFunctors.back());
}
class VectorDrawable : public SkDrawable {
- public:
+public:
VectorDrawable(VectorDrawableRoot* tree) : mRoot(tree) {}
- protected:
- virtual SkRect onGetBounds() override {
- return SkRect::MakeLargest();
- }
- virtual void onDraw(SkCanvas* canvas) override {
- mRoot->draw(canvas);
- }
+protected:
+ virtual SkRect onGetBounds() override { return SkRect::MakeLargest(); }
+ virtual void onDraw(SkCanvas* canvas) override { mRoot->draw(canvas); }
- private:
+private:
sp<VectorDrawableRoot> mRoot;
};
@@ -145,22 +144,25 @@ void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
// ----------------------------------------------------------------------------
inline static const SkPaint* bitmapPaint(const SkPaint* origPaint, SkPaint* tmpPaint,
- sk_sp<SkColorFilter> colorFilter) {
- if ((origPaint && origPaint->isAntiAlias()) || colorFilter) {
+ sk_sp<SkColorFilter> colorSpaceFilter) {
+ if ((origPaint && origPaint->isAntiAlias()) || colorSpaceFilter) {
if (origPaint) {
*tmpPaint = *origPaint;
}
- sk_sp<SkColorFilter> filter;
- if (colorFilter && tmpPaint->getColorFilter()) {
- filter = SkColorFilter::MakeComposeFilter(tmpPaint->refColorFilter(), colorFilter);
- LOG_ALWAYS_FATAL_IF(!filter);
- } else {
- filter = colorFilter;
+ if (colorSpaceFilter) {
+ if (tmpPaint->getColorFilter()) {
+ tmpPaint->setColorFilter(
+ SkColorFilter::MakeComposeFilter(tmpPaint->refColorFilter(), colorSpaceFilter));
+ } else {
+ tmpPaint->setColorFilter(colorSpaceFilter);
+ }
+ LOG_ALWAYS_FATAL_IF(!tmpPaint->getColorFilter());
}
+
+ // disabling AA on bitmap draws matches legacy HWUI behavior
tmpPaint->setAntiAlias(false);
- tmpPaint->setColorFilter(filter);
return tmpPaint;
} else {
return origPaint;
@@ -180,8 +182,7 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, cons
}
}
-void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix,
- const SkPaint* paint) {
+void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
SkAutoCanvasRestore acr(&mRecorder, true);
concat(matrix);
@@ -194,9 +195,9 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix,
}
}
-void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
- float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight,
- float dstBottom, const SkPaint* paint) {
+void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
+ float srcBottom, float dstLeft, float dstTop, float dstRight,
+ float dstBottom, const SkPaint* paint) {
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
@@ -204,15 +205,16 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop
sk_sp<SkColorFilter> colorFilter;
sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
mRecorder.drawImageRect(image, srcRect, dstRect, bitmapPaint(paint, &tmpPaint, colorFilter),
- SkCanvas::kFast_SrcRectConstraint);
- if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty()
- && !dstRect.isEmpty()) {
+ SkCanvas::kFast_SrcRectConstraint);
+ if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() &&
+ !dstRect.isEmpty()) {
mDisplayList->mMutableImages.push_back(image.get());
}
}
-void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk,
- float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
+void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft,
+ float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) {
SkCanvas::Lattice lattice;
NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
@@ -236,12 +238,12 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& ch
sk_sp<SkColorFilter> colorFilter;
sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
mRecorder.drawImageLattice(image.get(), lattice, dst,
- bitmapPaint(paint, &tmpPaint, colorFilter));
+ bitmapPaint(paint, &tmpPaint, colorFilter));
if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
mDisplayList->mMutableImages.push_back(image.get());
}
}
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 10829f87efb9..d35bbabb652f 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -15,10 +15,10 @@
*/
#pragma once
+#include <SkLiteRecorder.h>
+#include "ReorderBarrierDrawables.h"
#include "SkiaCanvas.h"
#include "SkiaDisplayList.h"
-#include "ReorderBarrierDrawables.h"
-#include <SkLiteRecorder.h>
namespace android {
namespace uirenderer {
@@ -29,7 +29,7 @@ namespace skiapipeline {
* SkLiteRecorder and a SkiaDisplayList.
*/
class SkiaRecordingCanvas : public SkiaCanvas {
- public:
+public:
explicit SkiaRecordingCanvas(uirenderer::RenderNode* renderNode, int width, int height) {
initDisplayList(renderNode, width, height);
}
@@ -39,31 +39,32 @@ class SkiaRecordingCanvas : public SkiaCanvas {
}
virtual void resetRecording(int width, int height,
- uirenderer::RenderNode* renderNode) override {
+ uirenderer::RenderNode* renderNode) override {
initDisplayList(renderNode, width, height);
}
virtual uirenderer::DisplayList* finishRecording() override;
- virtual void drawBitmap(Bitmap& bitmap, float left, float top,
- const SkPaint* paint) override;
- virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix,
- const SkPaint* paint) override;
- virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
- float srcRight, float srcBottom, float dstLeft, float dstTop,
- float dstRight, float dstBottom, const SkPaint* paint) override;
+ virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) override;
+ virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) override;
+ virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
+ float srcBottom, float dstLeft, float dstTop, float dstRight,
+ float dstBottom, const SkPaint* paint) override;
virtual void drawNinePatch(Bitmap& hwuiBitmap, const android::Res_png_9patch& chunk,
- float dstLeft, float dstTop, float dstRight, float dstBottom,
- const SkPaint* paint) override;
+ float dstLeft, float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) override;
virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
- uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
- uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
- uirenderer::CanvasPropertyPrimitive* ry,
- uirenderer::CanvasPropertyPaint* paint) override;
+ uirenderer::CanvasPropertyPrimitive* top,
+ uirenderer::CanvasPropertyPrimitive* right,
+ uirenderer::CanvasPropertyPrimitive* bottom,
+ uirenderer::CanvasPropertyPrimitive* rx,
+ uirenderer::CanvasPropertyPrimitive* ry,
+ uirenderer::CanvasPropertyPaint* paint) override;
virtual void drawCircle(uirenderer::CanvasPropertyPrimitive* x,
- uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius,
- uirenderer::CanvasPropertyPaint* paint) override;
+ uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint) override;
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
@@ -88,6 +89,6 @@ private:
void initDisplayList(uirenderer::RenderNode* renderNode, int width, int height);
};
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index e1ef71f7d3ab..653007482c0a 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -17,12 +17,12 @@
#include "SkiaVulkanPipeline.h"
#include "DeferredLayerUpdater.h"
-#include "renderthread/Frame.h"
#include "Readback.h"
-#include "renderstate/RenderState.h"
#include "SkiaPipeline.h"
#include "SkiaProfileRenderer.h"
#include "VkLayer.h"
+#include "renderstate/RenderState.h"
+#include "renderthread/Frame.h"
#include <SkSurface.h>
#include <SkTypes.h>
@@ -41,8 +41,7 @@ namespace uirenderer {
namespace skiapipeline {
SkiaVulkanPipeline::SkiaVulkanPipeline(renderthread::RenderThread& thread)
- : SkiaPipeline(thread)
- , mVkManager(thread.vulkanManager()) {}
+ : SkiaPipeline(thread), mVkManager(thread.vulkanManager()) {}
MakeCurrentResult SkiaVulkanPipeline::makeCurrent() {
return MakeCurrentResult::AlreadyCurrent;
@@ -50,7 +49,7 @@ MakeCurrentResult SkiaVulkanPipeline::makeCurrent() {
Frame SkiaVulkanPipeline::getFrame() {
LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr,
- "drawRenderNode called on a context with no surface!");
+ "drawRenderNode called on a context with no surface!");
SkSurface* backBuffer = mVkManager.getBackbufferSurface(mVkSurface);
if (backBuffer == nullptr) {
@@ -62,27 +61,25 @@ Frame SkiaVulkanPipeline::getFrame() {
return frame;
}
-bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty,
- const SkRect& dirty,
- const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo,
- const std::vector<sp<RenderNode>>& renderNodes,
- FrameInfoVisualizer* profiler) {
-
+bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
+ const FrameBuilder::LightGeometry& lightGeometry,
+ LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
+ bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector<sp<RenderNode>>& renderNodes,
+ FrameInfoVisualizer* profiler) {
sk_sp<SkSurface> backBuffer = mVkSurface->getBackBufferSurface();
if (backBuffer.get() == nullptr) {
return false;
}
SkiaPipeline::updateLighting(lightGeometry, lightInfo);
- renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut,
- contentDrawBounds, backBuffer);
+ renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut, contentDrawBounds,
+ backBuffer);
layerUpdateQueue->clear();
// Draw visual debugging features
- if (CC_UNLIKELY(Properties::showDirtyRegions
- || ProfileType::None != Properties::getProfileType())) {
+ if (CC_UNLIKELY(Properties::showDirtyRegions ||
+ ProfileType::None != Properties::getProfileType())) {
SkCanvas* profileCanvas = backBuffer->getCanvas();
SkiaProfileRenderer profileRenderer(profileCanvas);
profiler->draw(profileRenderer);
@@ -97,9 +94,8 @@ bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty,
return true;
}
-bool SkiaVulkanPipeline::swapBuffers(const Frame& frame, bool drew,
- const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) {
-
+bool SkiaVulkanPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
+ FrameInfo* currentFrameInfo, bool* requireSwap) {
*requireSwap = drew;
// Even if we decided to cancel the frame, from the perspective of jank
@@ -119,7 +115,7 @@ bool SkiaVulkanPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bi
}
static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
return new VkLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
}
@@ -129,11 +125,10 @@ DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::Vulkan);
}
-void SkiaVulkanPipeline::onStop() {
-}
+void SkiaVulkanPipeline::onStop() {}
bool SkiaVulkanPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
- ColorMode colorMode) {
+ ColorMode colorMode) {
if (mVkSurface) {
mVkManager.destroySurface(mVkSurface);
mVkSurface = nullptr;
@@ -162,16 +157,15 @@ void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* func
}
sk_sp<Bitmap> SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
- SkBitmap& skBitmap) {
- //TODO: implement this function for Vulkan pipeline
- //code below is a hack to avoid crashing because of missing HW Bitmap support
- sp<GraphicBuffer> buffer = new GraphicBuffer(skBitmap.info().width(), skBitmap.info().height(),
- PIXEL_FORMAT_RGBA_8888,
- GraphicBuffer::USAGE_HW_TEXTURE |
- GraphicBuffer::USAGE_SW_WRITE_NEVER |
- GraphicBuffer::USAGE_SW_READ_NEVER,
- std::string("SkiaVulkanPipeline::allocateHardwareBitmap pid [")
- + std::to_string(getpid()) + "]");
+ SkBitmap& skBitmap) {
+ // TODO: implement this function for Vulkan pipeline
+ // code below is a hack to avoid crashing because of missing HW Bitmap support
+ sp<GraphicBuffer> buffer = new GraphicBuffer(
+ skBitmap.info().width(), skBitmap.info().height(), PIXEL_FORMAT_RGBA_8888,
+ GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
+ GraphicBuffer::USAGE_SW_READ_NEVER,
+ std::string("SkiaVulkanPipeline::allocateHardwareBitmap pid [") +
+ std::to_string(getpid()) + "]");
status_t error = buffer->initCheck();
if (error < 0) {
ALOGW("SkiaVulkanPipeline::allocateHardwareBitmap() failed in GraphicBuffer.create()");
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 263206d97571..03b4c79f2beb 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -31,25 +31,24 @@ public:
renderthread::MakeCurrentResult makeCurrent() override;
renderthread::Frame getFrame() override;
bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo,
- const std::vector< sp<RenderNode> >& renderNodes,
- FrameInfoVisualizer* profiler) override;
+ const FrameBuilder::LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
+ const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector<sp<RenderNode> >& renderNodes,
+ FrameInfoVisualizer* profiler) override;
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) override;
+ FrameInfo* currentFrameInfo, bool* requireSwap) override;
bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
DeferredLayerUpdater* createTextureLayer() override;
bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior,
- renderthread::ColorMode colorMode) override;
+ renderthread::ColorMode colorMode) override;
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;
static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread,
- SkBitmap& skBitmap);
+ SkBitmap& skBitmap);
private:
renderthread::VulkanManager& mVkManager;
diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
index 9c9e17d600bf..8fb621d24866 100644
--- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
+++ b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
@@ -19,9 +19,9 @@
#include <GrRectanizer_pow2.h>
#include <SkCanvas.h>
#include <cmath>
-#include "utils/TraceUtils.h"
#include "renderthread/RenderProxy.h"
#include "renderthread/RenderThread.h"
+#include "utils/TraceUtils.h"
namespace android {
namespace uirenderer {
@@ -30,8 +30,7 @@ namespace skiapipeline {
VectorDrawableAtlas::VectorDrawableAtlas(size_t surfaceArea, StorageMode storageMode)
: mWidth((int)std::sqrt(surfaceArea))
, mHeight((int)std::sqrt(surfaceArea))
- , mStorageMode(storageMode) {
-}
+ , mStorageMode(storageMode) {}
void VectorDrawableAtlas::prepareForDraw(GrContext* context) {
if (StorageMode::allowSharedSurface == mStorageMode) {
@@ -55,8 +54,8 @@ void VectorDrawableAtlas::prepareForDraw(GrContext* context) {
#define MAX_UNUSED_RATIO 2.0f
bool VectorDrawableAtlas::isFragmented() {
- return mConsecutiveFailures > MAX_CONSECUTIVE_FAILURES
- && mPixelUsedByVDs*MAX_UNUSED_RATIO < mPixelAllocated;
+ return mConsecutiveFailures > MAX_CONSECUTIVE_FAILURES &&
+ mPixelUsedByVDs * MAX_UNUSED_RATIO < mPixelAllocated;
}
void VectorDrawableAtlas::repackIfNeeded(GrContext* context) {
@@ -69,9 +68,9 @@ void VectorDrawableAtlas::repackIfNeeded(GrContext* context) {
}
// compare to CacheEntry objects based on VD area.
-bool VectorDrawableAtlas::compareCacheEntry(const CacheEntry& first, const CacheEntry& second)
-{
- return first.VDrect.width()*first.VDrect.height() < second.VDrect.width()*second.VDrect.height();
+bool VectorDrawableAtlas::compareCacheEntry(const CacheEntry& first, const CacheEntry& second) {
+ return first.VDrect.width() * first.VDrect.height() <
+ second.VDrect.width() * second.VDrect.height();
}
void VectorDrawableAtlas::repack(GrContext* context) {
@@ -88,7 +87,7 @@ void VectorDrawableAtlas::repack(GrContext* context) {
mRectanizer = std::make_unique<GrRectanizerPow2>(mWidth, mHeight);
} else {
if (!mSurface) {
- return; //nothing to repack
+ return; // nothing to repack
}
mRectanizer.reset();
}
@@ -106,20 +105,20 @@ void VectorDrawableAtlas::repack(GrContext* context) {
for (CacheEntry& entry : mRects) {
SkRect currentVDRect = entry.VDrect;
- SkImage* sourceImage; //copy either from the atlas or from a standalone surface
+ SkImage* sourceImage; // copy either from the atlas or from a standalone surface
if (entry.surface) {
if (!fitInAtlas(currentVDRect.width(), currentVDRect.height())) {
- continue; //don't even try to repack huge VD
+ continue; // don't even try to repack huge VD
}
sourceImage = entry.surface->makeImageSnapshot().get();
} else {
sourceImage = sourceImageAtlas;
}
- size_t VDRectArea = currentVDRect.width()*currentVDRect.height();
+ size_t VDRectArea = currentVDRect.width() * currentVDRect.height();
SkIPoint16 pos;
if (canvas && mRectanizer->addRect(currentVDRect.width(), currentVDRect.height(), &pos)) {
- SkRect newRect = SkRect::MakeXYWH(pos.fX, pos.fY, currentVDRect.width(),
- currentVDRect.height());
+ SkRect newRect =
+ SkRect::MakeXYWH(pos.fX, pos.fY, currentVDRect.width(), currentVDRect.height());
canvas->drawImageRect(sourceImage, currentVDRect, newRect, nullptr);
entry.VDrect = newRect;
entry.rect = newRect;
@@ -134,8 +133,7 @@ void VectorDrawableAtlas::repack(GrContext* context) {
if (!entry.surface) {
// A rectangle moved from an atlas to a standalone surface.
mPixelUsedByVDs -= VDRectArea;
- SkRect newRect = SkRect::MakeWH(currentVDRect.width(),
- currentVDRect.height());
+ SkRect newRect = SkRect::MakeWH(currentVDRect.width(), currentVDRect.height());
entry.surface = createSurface(newRect.width(), newRect.height(), context);
auto tempCanvas = entry.surface->getCanvas();
tempCanvas->clear(SK_ColorTRANSPARENT);
@@ -158,7 +156,7 @@ AtlasEntry VectorDrawableAtlas::requestNewEntry(int width, int height, GrContext
}
if (mSurface) {
- const size_t area = width*height;
+ const size_t area = width * height;
// Use a rectanizer to allocate unused space from the atlas surface.
bool notTooBig = fitInAtlas(width, height);
@@ -243,10 +241,10 @@ void VectorDrawableAtlas::releaseEntry(AtlasKey atlasKey) {
// Store freed atlas rectangles in "mFreeRects" and try to reuse them later, when atlas
// is full.
SkRect& removedRect = entry->rect;
- size_t rectArea = removedRect.width()*removedRect.height();
+ size_t rectArea = removedRect.width() * removedRect.height();
mFreeRects.emplace(rectArea, removedRect);
SkRect& removedVDRect = entry->VDrect;
- size_t VDRectArea = removedVDRect.width()*removedVDRect.height();
+ size_t VDRectArea = removedVDRect.width() * removedVDRect.height();
mPixelUsedByVDs -= VDRectArea;
mConsecutiveFailures = 0;
}
@@ -272,8 +270,8 @@ sk_sp<SkSurface> VectorDrawableAtlas::createSurface(int width, int height, GrCon
SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType, colorSpace);
// This must have a top-left origin so that calls to surface->canvas->writePixels
// performs a basic texture upload instead of a more complex drawing operation
- return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0,
- kTopLeft_GrSurfaceOrigin, nullptr);
+ return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0, kTopLeft_GrSurfaceOrigin,
+ nullptr);
}
void VectorDrawableAtlas::setStorageMode(StorageMode mode) {
diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
index 0683b3915850..74e48cea2a87 100644
--- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
+++ b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
@@ -16,12 +16,12 @@
#pragma once
-#include <map>
#include <SkSurface.h>
#include <utils/FatVector.h>
#include <utils/RefBase.h>
#include <utils/Thread.h>
#include <list>
+#include <map>
class GrRectanizer;
@@ -55,18 +55,15 @@ struct AtlasEntry {
* When a VectorDrawable is deleted, it invokes VectorDrawableAtlas::releaseEntry, which is keeping
* track of free spaces and allow to reuse the surface for another VD.
*/
- //TODO: Check if not using atlas for AnimatedVD is more efficient.
- //TODO: For low memory situations, when there are no paint effects in VD, we may render without an
- //TODO: offscreen surface.
+// TODO: Check if not using atlas for AnimatedVD is more efficient.
+// TODO: For low memory situations, when there are no paint effects in VD, we may render without an
+// TODO: offscreen surface.
class VectorDrawableAtlas : public virtual RefBase {
public:
- enum class StorageMode {
- allowSharedSurface,
- disallowSharedSurface
- };
+ enum class StorageMode { allowSharedSurface, disallowSharedSurface };
VectorDrawableAtlas(size_t surfaceArea,
- StorageMode storageMode = StorageMode::allowSharedSurface);
+ StorageMode storageMode = StorageMode::allowSharedSurface);
/**
* "prepareForDraw" may allocate a new surface if needed. It may schedule to repack the
@@ -120,10 +117,8 @@ public:
private:
struct CacheEntry {
CacheEntry(const SkRect& newVDrect, const SkRect& newRect,
- const sk_sp<SkSurface>& newSurface)
- : VDrect(newVDrect)
- , rect(newRect)
- , surface(newSurface) { }
+ const sk_sp<SkSurface>& newSurface)
+ : VDrect(newVDrect), rect(newRect), surface(newSurface) {}
/**
* size and position of VectorDrawable into the atlas or in "this.surface"
@@ -204,7 +199,7 @@ private:
sk_sp<SkSurface> createSurface(int width, int height, GrContext* context);
inline bool fitInAtlas(int width, int height) {
- return 2*width < mWidth && 2*height < mHeight;
+ return 2 * width < mWidth && 2 * height < mHeight;
}
void repack(GrContext* context);
diff --git a/libs/hwui/private/hwui/DrawGlInfo.h b/libs/hwui/private/hwui/DrawGlInfo.h
index f57851322716..efa9da27199d 100644
--- a/libs/hwui/private/hwui/DrawGlInfo.h
+++ b/libs/hwui/private/hwui/DrawGlInfo.h
@@ -81,9 +81,9 @@ struct DrawGlInfo {
// commands are issued.
kStatusDrew = 0x4
};
-}; // struct DrawGlInfo
+}; // struct DrawGlInfo
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_DRAW_GL_INFO_H
+#endif // ANDROID_HWUI_DRAW_GL_INFO_H
diff --git a/libs/hwui/protos/ProtoHelpers.h b/libs/hwui/protos/ProtoHelpers.h
index 832e31200eb6..833c77f2b8cb 100644
--- a/libs/hwui/protos/ProtoHelpers.h
+++ b/libs/hwui/protos/ProtoHelpers.h
@@ -35,7 +35,7 @@ void set(std::string* dest, const SkPath& src) {
src.writeToMemory(&*dest->begin());
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
-#endif // PROTOHELPERS_H
+#endif // PROTOHELPERS_H
diff --git a/libs/hwui/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp
index b1ca4a248a80..5bef01c0ec3c 100644
--- a/libs/hwui/renderstate/Blend.cpp
+++ b/libs/hwui/renderstate/Blend.cpp
@@ -52,49 +52,42 @@ static_assert(17 == static_cast<int>(SkBlendMode::kLighten), "SkBlendMode enums
// In this array, the index of each Blender equals the value of the first
// entry. For instance, gBlends[1] == gBlends[SkBlendMode::kSrc]
-const Blender kBlends[] = {
- { SkBlendMode::kClear, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kSrc, GL_ONE, GL_ZERO },
- { SkBlendMode::kDst, GL_ZERO, GL_ONE },
- { SkBlendMode::kSrcOver, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kDstOver, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
- { SkBlendMode::kSrcIn, GL_DST_ALPHA, GL_ZERO },
- { SkBlendMode::kDstIn, GL_ZERO, GL_SRC_ALPHA },
- { SkBlendMode::kSrcOut, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkBlendMode::kDstOut, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kSrcATop, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kDstATop, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
- { SkBlendMode::kXor, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kPlus, GL_ONE, GL_ONE },
- { SkBlendMode::kModulate, GL_ZERO, GL_SRC_COLOR },
- { SkBlendMode::kScreen, GL_ONE, GL_ONE_MINUS_SRC_COLOR }
-};
+const Blender kBlends[] = {{SkBlendMode::kClear, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kSrc, GL_ONE, GL_ZERO},
+ {SkBlendMode::kDst, GL_ZERO, GL_ONE},
+ {SkBlendMode::kSrcOver, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kDstOver, GL_ONE_MINUS_DST_ALPHA, GL_ONE},
+ {SkBlendMode::kSrcIn, GL_DST_ALPHA, GL_ZERO},
+ {SkBlendMode::kDstIn, GL_ZERO, GL_SRC_ALPHA},
+ {SkBlendMode::kSrcOut, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
+ {SkBlendMode::kDstOut, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kSrcATop, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kDstATop, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA},
+ {SkBlendMode::kXor, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kPlus, GL_ONE, GL_ONE},
+ {SkBlendMode::kModulate, GL_ZERO, GL_SRC_COLOR},
+ {SkBlendMode::kScreen, GL_ONE, GL_ONE_MINUS_SRC_COLOR}};
// This array contains the swapped version of each SkBlendMode. For instance
// this array's SrcOver blending mode is actually DstOver. You can refer to
// createLayer() for more information on the purpose of this array.
-const Blender kBlendsSwap[] = {
- { SkBlendMode::kClear, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkBlendMode::kSrc, GL_ZERO, GL_ONE },
- { SkBlendMode::kDst, GL_ONE, GL_ZERO },
- { SkBlendMode::kSrcOver, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
- { SkBlendMode::kDstOver, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kSrcIn, GL_ZERO, GL_SRC_ALPHA },
- { SkBlendMode::kDstIn, GL_DST_ALPHA, GL_ZERO },
- { SkBlendMode::kSrcOut, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kDstOut, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkBlendMode::kSrcATop, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
- { SkBlendMode::kDstATop, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kXor, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kPlus, GL_ONE, GL_ONE },
- { SkBlendMode::kModulate, GL_DST_COLOR, GL_ZERO },
- { SkBlendMode::kScreen, GL_ONE_MINUS_DST_COLOR, GL_ONE }
-};
+const Blender kBlendsSwap[] = {{SkBlendMode::kClear, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
+ {SkBlendMode::kSrc, GL_ZERO, GL_ONE},
+ {SkBlendMode::kDst, GL_ONE, GL_ZERO},
+ {SkBlendMode::kSrcOver, GL_ONE_MINUS_DST_ALPHA, GL_ONE},
+ {SkBlendMode::kDstOver, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kSrcIn, GL_ZERO, GL_SRC_ALPHA},
+ {SkBlendMode::kDstIn, GL_DST_ALPHA, GL_ZERO},
+ {SkBlendMode::kSrcOut, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kDstOut, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
+ {SkBlendMode::kSrcATop, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA},
+ {SkBlendMode::kDstATop, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kXor, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kPlus, GL_ONE, GL_ONE},
+ {SkBlendMode::kModulate, GL_DST_COLOR, GL_ZERO},
+ {SkBlendMode::kScreen, GL_ONE_MINUS_DST_COLOR, GL_ONE}};
-Blend::Blend()
- : mEnabled(false)
- , mSrcMode(GL_ZERO)
- , mDstMode(GL_ZERO) {
+Blend::Blend() : mEnabled(false), mSrcMode(GL_ZERO), mDstMode(GL_ZERO) {
// gl blending off by default
}
@@ -145,4 +138,3 @@ void Blend::dump() {
} /* namespace uirenderer */
} /* namespace android */
-
diff --git a/libs/hwui/renderstate/Blend.h b/libs/hwui/renderstate/Blend.h
index a9de24631340..7e559bace3f2 100644
--- a/libs/hwui/renderstate/Blend.h
+++ b/libs/hwui/renderstate/Blend.h
@@ -28,6 +28,7 @@ namespace uirenderer {
class Blend {
friend class RenderState;
+
public:
// dictates whether to swap src/dst
enum class ModeOrderSwap {
@@ -36,19 +37,18 @@ public:
};
void syncEnabled();
- static void getFactors(SkBlendMode mode, ModeOrderSwap modeUsage,
- GLenum* outSrc, GLenum* outDst);
+ static void getFactors(SkBlendMode mode, ModeOrderSwap modeUsage, GLenum* outSrc,
+ GLenum* outDst);
void setFactors(GLenum src, GLenum dst);
- bool getEnabled() {
- return mEnabled;
- }
+ bool getEnabled() { return mEnabled; }
void getFactors(GLenum* src, GLenum* dst) {
*src = mSrcMode;
*dst = mDstMode;
}
void dump();
+
private:
Blend();
void invalidate();
@@ -60,4 +60,4 @@ private:
} /* namespace uirenderer */
} /* namespace android */
-#endif // RENDERSTATE_BLEND_H
+#endif // RENDERSTATE_BLEND_H
diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp
index 6d0293695412..4f6c49e67b99 100644
--- a/libs/hwui/renderstate/MeshState.cpp
+++ b/libs/hwui/renderstate/MeshState.cpp
@@ -38,12 +38,12 @@ MeshState::MeshState()
for (uint32_t i = 0; i < kMaxNumberOfQuads; i++) {
uint16_t quad = i * 4;
int index = i * 6;
- regionIndices[index ] = quad; // top-left
- regionIndices[index + 1] = quad + 1; // top-right
- regionIndices[index + 2] = quad + 2; // bottom-left
- regionIndices[index + 3] = quad + 2; // bottom-left
- regionIndices[index + 4] = quad + 1; // top-right
- regionIndices[index + 5] = quad + 3; // bottom-right
+ regionIndices[index] = quad; // top-left
+ regionIndices[index + 1] = quad + 1; // top-right
+ regionIndices[index + 2] = quad + 2; // bottom-left
+ regionIndices[index + 3] = quad + 2; // bottom-left
+ regionIndices[index + 4] = quad + 1; // top-right
+ regionIndices[index + 5] = quad + 3; // bottom-right
}
glGenBuffers(1, &mQuadListIndices);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadListIndices);
@@ -65,10 +65,10 @@ MeshState::~MeshState() {
void MeshState::dump() {
ALOGD("MeshState VBOs: unitQuad %d, current %d", mUnitQuadBuffer, mCurrentBuffer);
ALOGD("MeshState IBOs: quadList %d, current %d", mQuadListIndices, mCurrentIndicesBuffer);
- ALOGD("MeshState vertices: vertex data %p, stride %d",
- mCurrentPositionPointer, mCurrentPositionStride);
- ALOGD("MeshState texCoord: data %p, stride %d",
- mCurrentTexCoordsPointer, mCurrentTexCoordsStride);
+ ALOGD("MeshState vertices: vertex data %p, stride %d", mCurrentPositionPointer,
+ mCurrentPositionStride);
+ ALOGD("MeshState texCoord: data %p, stride %d", mCurrentTexCoordsPointer,
+ mCurrentTexCoordsStride);
}
///////////////////////////////////////////////////////////////////////////////
@@ -89,8 +89,8 @@ void MeshState::unbindMeshBuffer() {
return bindMeshBuffer(0);
}
-void MeshState::genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size,
- const void* data, GLenum usage) {
+void MeshState::genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size, const void* data,
+ GLenum usage) {
if (!*buffer) {
glGenBuffers(1, buffer);
}
@@ -98,8 +98,8 @@ void MeshState::genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size,
glBufferData(GL_ARRAY_BUFFER, size, data, usage);
}
-void MeshState::updateMeshBufferSubData(GLuint buffer, GLintptr offset,
- GLsizeiptr size, const void* data) {
+void MeshState::updateMeshBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size,
+ const void* data) {
bindMeshBuffer(buffer);
glBufferSubData(GL_ARRAY_BUFFER, offset, size, data);
}
@@ -119,9 +119,8 @@ void MeshState::deleteMeshBuffer(GLuint buffer) {
void MeshState::bindPositionVertexPointer(const GLvoid* vertices, GLsizei stride) {
// update pos coords if !current vbo, since vertices may point into mutable memory (e.g. stack)
- if (mCurrentBuffer == 0
- || vertices != mCurrentPositionPointer
- || stride != mCurrentPositionStride) {
+ if (mCurrentBuffer == 0 || vertices != mCurrentPositionPointer ||
+ stride != mCurrentPositionStride) {
glVertexAttribPointer(Program::kBindingPosition, 2, GL_FLOAT, GL_FALSE, stride, vertices);
mCurrentPositionPointer = vertices;
mCurrentPositionStride = stride;
@@ -130,9 +129,8 @@ void MeshState::bindPositionVertexPointer(const GLvoid* vertices, GLsizei stride
void MeshState::bindTexCoordsVertexPointer(const GLvoid* vertices, GLsizei stride) {
// update tex coords if !current vbo, since vertices may point into mutable memory (e.g. stack)
- if (mCurrentBuffer == 0
- || vertices != mCurrentTexCoordsPointer
- || stride != mCurrentTexCoordsStride) {
+ if (mCurrentBuffer == 0 || vertices != mCurrentTexCoordsPointer ||
+ stride != mCurrentTexCoordsStride) {
glVertexAttribPointer(Program::kBindingTexCoords, 2, GL_FLOAT, GL_FALSE, stride, vertices);
mCurrentTexCoordsPointer = vertices;
mCurrentTexCoordsStride = stride;
@@ -179,4 +177,3 @@ void MeshState::unbindIndicesBuffer() {
} /* namespace uirenderer */
} /* namespace android */
-
diff --git a/libs/hwui/renderstate/MeshState.h b/libs/hwui/renderstate/MeshState.h
index 17ad4622e44a..95faf1ebfb02 100644
--- a/libs/hwui/renderstate/MeshState.h
+++ b/libs/hwui/renderstate/MeshState.h
@@ -33,10 +33,7 @@ const uint32_t kMaxNumberOfQuads = 2048;
// This array is never used directly but used as a memcpy source in the
// OpenGLRenderer constructor
const TextureVertex kUnitQuadVertices[] = {
- { 0, 0, 0, 0 },
- { 1, 0, 1, 0 },
- { 0, 1, 0, 1 },
- { 1, 1, 1, 1 },
+ {0, 0, 0, 0}, {1, 0, 1, 0}, {0, 1, 0, 1}, {1, 1, 1, 1},
};
const GLsizei kVertexStride = sizeof(Vertex);
@@ -82,15 +79,13 @@ public:
* Binds an attrib to the specified float vertex pointer.
* Assumes a stride of gTextureVertexStride and a size of 2.
*/
- void bindPositionVertexPointer(const GLvoid* vertices,
- GLsizei stride = kTextureVertexStride);
+ void bindPositionVertexPointer(const GLvoid* vertices, GLsizei stride = kTextureVertexStride);
/**
* Binds an attrib to the specified float vertex pointer.
* Assumes a stride of gTextureVertexStride and a size of 2.
*/
- void bindTexCoordsVertexPointer(const GLvoid* vertices,
- GLsizei stride = kTextureVertexStride);
+ void bindTexCoordsVertexPointer(const GLvoid* vertices, GLsizei stride = kTextureVertexStride);
/**
* Resets the vertex pointers.
@@ -111,6 +106,7 @@ public:
///////////////////////////////////////////////////////////////////////////////
GLuint getUnitQuadVBO() { return mUnitQuadBuffer; }
GLuint getQuadListIBO() { return mQuadListIndices; }
+
private:
MeshState();
@@ -134,4 +130,4 @@ private:
} /* namespace uirenderer */
} /* namespace android */
-#endif // RENDERSTATE_MESHSTATE_H
+#endif // RENDERSTATE_MESHSTATE_H
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.cpp b/libs/hwui/renderstate/OffscreenBufferPool.cpp
index ea292d678c67..a0f5cb9d4e09 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.cpp
+++ b/libs/hwui/renderstate/OffscreenBufferPool.cpp
@@ -33,8 +33,8 @@ namespace uirenderer {
// OffscreenBuffer
////////////////////////////////////////////////////////////////////////////////
-OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches,
- uint32_t viewportWidth, uint32_t viewportHeight, bool wideColorGamut)
+OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches, uint32_t viewportWidth,
+ uint32_t viewportHeight, bool wideColorGamut)
: GpuMemoryTracker(GpuObjectType::OffscreenBuffer)
, renderState(renderState)
, viewportWidth(viewportWidth)
@@ -45,8 +45,8 @@ OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches,
uint32_t height = computeIdealDimension(viewportHeight);
ATRACE_FORMAT("Allocate %ux%u HW Layer", width, height);
caches.textureState().activateTexture(0);
- texture.resize(width, height,
- wideColorGamut ? GL_RGBA16F : caches.rgbaInternalFormat(), GL_RGBA);
+ texture.resize(width, height, wideColorGamut ? GL_RGBA16F : caches.rgbaInternalFormat(),
+ GL_RGBA);
texture.blend = true;
texture.setWrap(GL_CLAMP_TO_EDGE);
// not setting filter on texture, since it's set when drawing, based on transform
@@ -61,8 +61,8 @@ Rect OffscreenBuffer::getTextureCoordinates() {
void OffscreenBuffer::dirty(Rect dirtyArea) {
dirtyArea.doIntersect(0, 0, viewportWidth, viewportHeight);
if (!dirtyArea.isEmpty()) {
- region.orSelf(android::Rect(dirtyArea.left, dirtyArea.top,
- dirtyArea.right, dirtyArea.bottom));
+ region.orSelf(
+ android::Rect(dirtyArea.left, dirtyArea.top, dirtyArea.right, dirtyArea.bottom));
}
}
@@ -78,7 +78,8 @@ void OffscreenBuffer::updateMeshFromRegion() {
const float texX = 1.0f / float(texture.width());
const float texY = 1.0f / float(texture.height());
- FatVector<TextureVertex, 64> meshVector(count * 4); // uses heap if more than 64 vertices needed
+ FatVector<TextureVertex, 64> meshVector(count *
+ 4); // uses heap if more than 64 vertices needed
TextureVertex* mesh = &meshVector[0];
for (size_t i = 0; i < count; i++) {
const android::Rect* r = &rects[i];
@@ -94,10 +95,9 @@ void OffscreenBuffer::updateMeshFromRegion() {
TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
}
elementCount = count * 6;
- renderState.meshState().genOrUpdateMeshBuffer(&vbo,
- sizeof(TextureVertex) * count * 4,
- &meshVector[0],
- GL_DYNAMIC_DRAW); // TODO: GL_STATIC_DRAW if savelayer
+ renderState.meshState().genOrUpdateMeshBuffer(
+ &vbo, sizeof(TextureVertex) * count * 4, &meshVector[0],
+ GL_DYNAMIC_DRAW); // TODO: GL_STATIC_DRAW if savelayer
}
uint32_t OffscreenBuffer::computeIdealDimension(uint32_t dimension) {
@@ -117,12 +117,11 @@ OffscreenBuffer::~OffscreenBuffer() {
///////////////////////////////////////////////////////////////////////////////
OffscreenBufferPool::OffscreenBufferPool()
- // 4 screen-sized RGBA_8888 textures
- : mMaxSize(DeviceInfo::multiplyByResolution(4 * 4)) {
-}
+ // 4 screen-sized RGBA_8888 textures
+ : mMaxSize(DeviceInfo::multiplyByResolution(4 * 4)) {}
OffscreenBufferPool::~OffscreenBufferPool() {
- clear(); // TODO: unique_ptr?
+ clear(); // TODO: unique_ptr?
}
int OffscreenBufferPool::Entry::compare(const Entry& lhs, const Entry& rhs) {
@@ -143,8 +142,8 @@ void OffscreenBufferPool::clear() {
mSize = 0;
}
-OffscreenBuffer* OffscreenBufferPool::get(RenderState& renderState,
- const uint32_t width, const uint32_t height, bool wideColorGamut) {
+OffscreenBuffer* OffscreenBufferPool::get(RenderState& renderState, const uint32_t width,
+ const uint32_t height, bool wideColorGamut) {
OffscreenBuffer* layer = nullptr;
Entry entry(width, height, wideColorGamut);
@@ -159,18 +158,18 @@ OffscreenBuffer* OffscreenBufferPool::get(RenderState& renderState,
layer->viewportHeight = height;
mSize -= layer->getSizeInBytes();
} else {
- layer = new OffscreenBuffer(renderState, Caches::getInstance(),
- width, height, wideColorGamut);
+ layer = new OffscreenBuffer(renderState, Caches::getInstance(), width, height,
+ wideColorGamut);
}
return layer;
}
-OffscreenBuffer* OffscreenBufferPool::resize(OffscreenBuffer* layer,
- const uint32_t width, const uint32_t height) {
+OffscreenBuffer* OffscreenBufferPool::resize(OffscreenBuffer* layer, const uint32_t width,
+ const uint32_t height) {
RenderState& renderState = layer->renderState;
- if (layer->texture.width() == OffscreenBuffer::computeIdealDimension(width)
- && layer->texture.height() == OffscreenBuffer::computeIdealDimension(height)) {
+ if (layer->texture.width() == OffscreenBuffer::computeIdealDimension(width) &&
+ layer->texture.height() == OffscreenBuffer::computeIdealDimension(height)) {
// resize in place
layer->viewportWidth = width;
layer->viewportHeight = height;
@@ -214,5 +213,5 @@ void OffscreenBufferPool::putOrDelete(OffscreenBuffer* layer) {
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.h b/libs/hwui/renderstate/OffscreenBufferPool.h
index d9422c9edd69..08ae052da391 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.h
+++ b/libs/hwui/renderstate/OffscreenBufferPool.h
@@ -18,10 +18,10 @@
#define ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H
#include <GpuMemoryTracker.h>
+#include <ui/Region.h>
#include "Caches.h"
#include "Texture.h"
#include "utils/Macros.h"
-#include <ui/Region.h>
#include <set>
@@ -42,8 +42,8 @@ class RenderState;
*/
class OffscreenBuffer : GpuMemoryTracker {
public:
- OffscreenBuffer(RenderState& renderState, Caches& caches,
- uint32_t viewportWidth, uint32_t viewportHeight, bool wideColorGamut = false);
+ OffscreenBuffer(RenderState& renderState, Caches& caches, uint32_t viewportWidth,
+ uint32_t viewportHeight, bool wideColorGamut = false);
~OffscreenBuffer();
Rect getTextureCoordinates();
@@ -91,11 +91,11 @@ public:
OffscreenBufferPool();
~OffscreenBufferPool();
- WARN_UNUSED_RESULT OffscreenBuffer* get(RenderState& renderState,
- const uint32_t width, const uint32_t height, bool wideColorGamut = false);
+ WARN_UNUSED_RESULT OffscreenBuffer* get(RenderState& renderState, const uint32_t width,
+ const uint32_t height, bool wideColorGamut = false);
- WARN_UNUSED_RESULT OffscreenBuffer* resize(OffscreenBuffer* layer,
- const uint32_t width, const uint32_t height);
+ WARN_UNUSED_RESULT OffscreenBuffer* resize(OffscreenBuffer* layer, const uint32_t width,
+ const uint32_t height);
void putOrDelete(OffscreenBuffer* layer);
@@ -120,6 +120,7 @@ public:
* Prints out the content of the pool.
*/
void dump();
+
private:
struct Entry {
Entry() {}
@@ -133,36 +134,29 @@ private:
: layer(layer)
, width(layer->texture.width())
, height(layer->texture.height())
- , wideColorGamut(layer->wideColorGamut) {
- }
+ , wideColorGamut(layer->wideColorGamut) {}
static int compare(const Entry& lhs, const Entry& rhs);
- bool operator==(const Entry& other) const {
- return compare(*this, other) == 0;
- }
+ bool operator==(const Entry& other) const { return compare(*this, other) == 0; }
- bool operator!=(const Entry& other) const {
- return compare(*this, other) != 0;
- }
+ bool operator!=(const Entry& other) const { return compare(*this, other) != 0; }
- bool operator<(const Entry& other) const {
- return Entry::compare(*this, other) < 0;
- }
+ bool operator<(const Entry& other) const { return Entry::compare(*this, other) < 0; }
OffscreenBuffer* layer = nullptr;
uint32_t width = 0;
uint32_t height = 0;
bool wideColorGamut = false;
- }; // struct Entry
+ }; // struct Entry
std::multiset<Entry> mPool;
uint32_t mSize = 0;
uint32_t mMaxSize;
-}; // class OffscreenBufferCache
+}; // class OffscreenBufferCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H
+#endif // ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H
diff --git a/libs/hwui/renderstate/PixelBufferState.cpp b/libs/hwui/renderstate/PixelBufferState.cpp
index c23af5216592..3a6efb833c47 100644
--- a/libs/hwui/renderstate/PixelBufferState.cpp
+++ b/libs/hwui/renderstate/PixelBufferState.cpp
@@ -18,9 +18,7 @@
namespace android {
namespace uirenderer {
-PixelBufferState::PixelBufferState()
- : mCurrentPixelBuffer(0) {
-}
+PixelBufferState::PixelBufferState() : mCurrentPixelBuffer(0) {}
bool PixelBufferState::bind(GLuint buffer) {
if (mCurrentPixelBuffer != buffer) {
@@ -42,4 +40,3 @@ bool PixelBufferState::unbind() {
} /* namespace uirenderer */
} /* namespace android */
-
diff --git a/libs/hwui/renderstate/PixelBufferState.h b/libs/hwui/renderstate/PixelBufferState.h
index 8dab21db176c..f7ae6c575f6a 100644
--- a/libs/hwui/renderstate/PixelBufferState.h
+++ b/libs/hwui/renderstate/PixelBufferState.h
@@ -22,10 +22,11 @@ namespace android {
namespace uirenderer {
class PixelBufferState {
- friend class Caches; // TODO: move to RenderState
+ friend class Caches; // TODO: move to RenderState
public:
bool bind(GLuint buffer);
bool unbind();
+
private:
PixelBufferState();
GLuint mCurrentPixelBuffer;
@@ -34,4 +35,4 @@ private:
} /* namespace uirenderer */
} /* namespace android */
-#endif // RENDERSTATE_PIXELBUFFERSTATE_H
+#endif // RENDERSTATE_PIXELBUFFERSTATE_H
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 0ceca3368c06..5e33353c3ac6 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include "renderstate/RenderState.h"
+#include <GpuMemoryTracker.h>
#include "DeferredLayerUpdater.h"
#include "GlLayer.h"
#include "VkLayer.h"
-#include <GpuMemoryTracker.h>
-#include "renderstate/RenderState.h"
#include "renderthread/CanvasContext.h"
#include "renderthread/EglManager.h"
@@ -31,21 +31,18 @@ namespace android {
namespace uirenderer {
RenderState::RenderState(renderthread::RenderThread& thread)
- : mRenderThread(thread)
- , mViewportWidth(0)
- , mViewportHeight(0)
- , mFramebuffer(0) {
+ : mRenderThread(thread), mViewportWidth(0), mViewportHeight(0), mFramebuffer(0) {
mThreadId = pthread_self();
}
RenderState::~RenderState() {
LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
- "State object lifecycle not managed correctly");
+ "State object lifecycle not managed correctly");
}
void RenderState::onGLContextCreated() {
LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
- "State object lifecycle not managed correctly");
+ "State object lifecycle not managed correctly");
GpuMemoryTracker::onGpuContextCreated();
mBlend = new Blend();
@@ -67,7 +64,7 @@ void RenderState::onGLContextCreated() {
static void layerLostGlContext(Layer* layer) {
LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::OpenGL,
- "layerLostGlContext on non GL layer");
+ "layerLostGlContext on non GL layer");
static_cast<GlLayer*>(layer)->onGlContextLost();
}
@@ -94,7 +91,7 @@ void RenderState::onGLContextDestroyed() {
void RenderState::onVkContextCreated() {
LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
- "State object lifecycle not managed correctly");
+ "State object lifecycle not managed correctly");
GpuMemoryTracker::onGpuContextCreated();
}
@@ -117,9 +114,9 @@ GrContext* RenderState::getGrContext() const {
void RenderState::flush(Caches::FlushMode mode) {
switch (mode) {
case Caches::FlushMode::Full:
- // fall through
+ // fall through
case Caches::FlushMode::Moderate:
- // fall through
+ // fall through
case Caches::FlushMode::Layers:
if (mLayerPool) mLayerPool->clear();
break;
@@ -140,7 +137,6 @@ void RenderState::setViewport(GLsizei width, GLsizei height) {
glViewport(0, 0, mViewportWidth, mViewportHeight);
}
-
void RenderState::getViewport(GLsizei* outWidth, GLsizei* outHeight) {
*outWidth = mViewportWidth;
*outHeight = mViewportHeight;
@@ -189,15 +185,13 @@ void RenderState::interruptForFunctorInvoke() {
meshState().disableTexCoordsVertexArray();
debugOverdraw(false, false);
// TODO: We need a way to know whether the functor is sRGB aware (b/32072673)
- if (mCaches->extensions().hasLinearBlending() &&
- mCaches->extensions().hasSRGBWriteControl()) {
+ if (mCaches->extensions().hasLinearBlending() && mCaches->extensions().hasSRGBWriteControl()) {
glDisable(GL_FRAMEBUFFER_SRGB_EXT);
}
}
void RenderState::resumeFromFunctorInvoke() {
- if (mCaches->extensions().hasLinearBlending() &&
- mCaches->extensions().hasSRGBWriteControl()) {
+ if (mCaches->extensions().hasLinearBlending() && mCaches->extensions().hasSRGBWriteControl()) {
glEnable(GL_FRAMEBUFFER_SRGB_EXT);
}
@@ -249,7 +243,7 @@ void RenderState::postDecStrong(VirtualLightRefBase* object) {
///////////////////////////////////////////////////////////////////////////////
void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix,
- bool overrideDisableBlending) {
+ bool overrideDisableBlending) {
const Glop::Mesh& mesh = glop.mesh;
const Glop::Mesh::Vertices& vertices = mesh.vertices;
const Glop::Mesh::Indices& indices = mesh.indices;
@@ -266,21 +260,19 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix,
fill.program->setColor(fill.color);
}
- fill.program->set(orthoMatrix,
- glop.transform.modelView,
- glop.transform.meshTransform(),
- glop.transform.transformFlags & TransformFlags::OffsetByFudgeFactor);
+ fill.program->set(orthoMatrix, glop.transform.modelView, glop.transform.meshTransform(),
+ glop.transform.transformFlags & TransformFlags::OffsetByFudgeFactor);
// Color filter uniforms
if (fill.filterMode == ProgramDescription::ColorFilterMode::Blend) {
const FloatColor& color = fill.filter.color;
- glUniform4f(mCaches->program().getUniform("colorBlend"),
- color.r, color.g, color.b, color.a);
+ glUniform4f(mCaches->program().getUniform("colorBlend"), color.r, color.g, color.b,
+ color.a);
} else if (fill.filterMode == ProgramDescription::ColorFilterMode::Matrix) {
glUniformMatrix4fv(mCaches->program().getUniform("colorMatrix"), 1, GL_FALSE,
- fill.filter.matrix.matrix);
+ fill.filter.matrix.matrix);
glUniform4fv(mCaches->program().getUniform("colorMatrixVector"), 1,
- fill.filter.matrix.vector);
+ fill.filter.matrix.vector);
}
// Round rect clipping uniforms
@@ -295,15 +287,14 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix,
// Divide by the radius to simplify the calculations in the fragment shader
// roundRectPos is also passed from vertex shader relative to top/left & radius
glUniform4f(fill.program->getUniform("roundRectInnerRectLTWH"),
- innerRect.left / roundedOutRadius, innerRect.top / roundedOutRadius,
- (innerRect.right - innerRect.left) / roundedOutRadius,
- (innerRect.bottom - innerRect.top) / roundedOutRadius);
+ innerRect.left / roundedOutRadius, innerRect.top / roundedOutRadius,
+ (innerRect.right - innerRect.left) / roundedOutRadius,
+ (innerRect.bottom - innerRect.top) / roundedOutRadius);
- glUniformMatrix4fv(fill.program->getUniform("roundRectInvTransform"),
- 1, GL_FALSE, &state->matrix.data[0]);
+ glUniformMatrix4fv(fill.program->getUniform("roundRectInvTransform"), 1, GL_FALSE,
+ &state->matrix.data[0]);
- glUniform1f(fill.program->getUniform("roundRectRadius"),
- roundedOutRadius);
+ glUniform1f(fill.program->getUniform("roundRectRadius"), roundedOutRadius);
}
GL_CHECKPOINT(MODERATE);
@@ -333,8 +324,8 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix,
}
if (texture.textureTransform) {
- glUniformMatrix4fv(fill.program->getUniform("mainTextureTransform"), 1,
- GL_FALSE, &texture.textureTransform->data[0]);
+ glUniformMatrix4fv(fill.program->getUniform("mainTextureTransform"), 1, GL_FALSE,
+ &texture.textureTransform->data[0]);
}
}
@@ -349,12 +340,13 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix,
if (vertices.attribFlags & VertexAttribFlags::Color) {
colorLocation = fill.program->getAttrib("colors");
glEnableVertexAttribArray(colorLocation);
- glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, vertices.stride, vertices.color);
+ glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, vertices.stride,
+ vertices.color);
}
int alphaLocation = -1;
if (vertices.attribFlags & VertexAttribFlags::Alpha) {
// NOTE: alpha vertex position is computed assuming no VBO
- const void* alphaCoords = ((const GLbyte*) vertices.position) + kVertexAlphaOffset;
+ const void* alphaCoords = ((const GLbyte*)vertices.position) + kVertexAlphaOffset;
alphaLocation = fill.program->getAttrib("vtxAlpha");
glEnableVertexAttribArray(alphaLocation);
glVertexAttribPointer(alphaLocation, 1, GL_FLOAT, GL_FALSE, vertices.stride, alphaCoords);
@@ -363,8 +355,9 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix,
SkiaShader::apply(*mCaches, fill.skiaShaderData, mViewportWidth, mViewportHeight);
GL_CHECKPOINT(MODERATE);
- Texture* texture = (fill.skiaShaderData.skiaShaderType & kBitmap_SkiaShaderType) ?
- fill.skiaShaderData.bitmapData.bitmapTexture : nullptr;
+ Texture* texture = (fill.skiaShaderData.skiaShaderType & kBitmap_SkiaShaderType)
+ ? fill.skiaShaderData.bitmapData.bitmapTexture
+ : nullptr;
const AutoTexture autoCleanup(texture);
// If we have a shader and a base texture, the base texture is assumed to be an alpha mask
@@ -373,8 +366,8 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix,
if (colorSpaceTexture != nullptr) {
if (colorSpaceTexture->hasColorSpaceConversion()) {
const ColorSpaceConnector* connector = colorSpaceTexture->getColorSpaceConnector();
- glUniformMatrix3fv(fill.program->getUniform("colorSpaceMatrix"), 1,
- GL_FALSE, connector->getTransform().asArray());
+ glUniformMatrix3fv(fill.program->getUniform("colorSpaceMatrix"), 1, GL_FALSE,
+ connector->getTransform().asArray());
}
TransferFunctionType transferFunction = colorSpaceTexture->getTransferFunctionType();
@@ -387,15 +380,15 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix,
break;
case TransferFunctionType::Full:
glUniform1fv(fill.program->getUniform("transferFunction"), 7,
- reinterpret_cast<const float*>(&source.getTransferParameters().g));
+ reinterpret_cast<const float*>(&source.getTransferParameters().g));
break;
case TransferFunctionType::Limited:
glUniform1fv(fill.program->getUniform("transferFunction"), 5,
- reinterpret_cast<const float*>(&source.getTransferParameters().g));
+ reinterpret_cast<const float*>(&source.getTransferParameters().g));
break;
case TransferFunctionType::Gamma:
glUniform1f(fill.program->getUniform("transferFunctionGamma"),
- source.getTransferParameters().g);
+ source.getTransferParameters().g);
break;
}
}
@@ -421,16 +414,17 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix,
GLsizei elementsCount = mesh.elementCount;
const GLbyte* vertexData = static_cast<const GLbyte*>(vertices.position);
while (elementsCount > 0) {
- GLsizei drawCount = std::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
+ GLsizei drawCount = std::min(elementsCount, (GLsizei)kMaxNumberOfQuads * 6);
GLsizei vertexCount = (drawCount / 6) * 4;
meshState().bindPositionVertexPointer(vertexData, vertices.stride);
if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
- meshState().bindTexCoordsVertexPointer(
- vertexData + kMeshTextureOffset, vertices.stride);
+ meshState().bindTexCoordsVertexPointer(vertexData + kMeshTextureOffset,
+ vertices.stride);
}
if (mCaches->extensions().getMajorGlVersion() >= 3) {
- glDrawRangeElements(mesh.primitiveMode, 0, vertexCount-1, drawCount, GL_UNSIGNED_SHORT, nullptr);
+ glDrawRangeElements(mesh.primitiveMode, 0, vertexCount - 1, drawCount,
+ GL_UNSIGNED_SHORT, nullptr);
} else {
glDrawElements(mesh.primitiveMode, drawCount, GL_UNSIGNED_SHORT, nullptr);
}
@@ -439,10 +433,13 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix,
}
} else if (indices.bufferObject || indices.indices) {
if (mCaches->extensions().getMajorGlVersion() >= 3) {
- // use glDrawRangeElements to reduce CPU overhead (otherwise the driver has to determine the min/max index values)
- glDrawRangeElements(mesh.primitiveMode, 0, mesh.vertexCount-1, mesh.elementCount, GL_UNSIGNED_SHORT, indices.indices);
+ // use glDrawRangeElements to reduce CPU overhead (otherwise the driver has to determine
+ // the min/max index values)
+ glDrawRangeElements(mesh.primitiveMode, 0, mesh.vertexCount - 1, mesh.elementCount,
+ GL_UNSIGNED_SHORT, indices.indices);
} else {
- glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT, indices.indices);
+ glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT,
+ indices.indices);
}
} else {
glDrawArrays(mesh.primitiveMode, 0, mesh.elementCount);
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index 315fa2db6878..e033cf2c5046 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -26,14 +26,14 @@
#include "renderstate/Stencil.h"
#include "utils/Macros.h"
-#include <set>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#include <private/hwui/DrawGlInfo.h>
#include <ui/Region.h>
-#include <utils/Mutex.h>
#include <utils/Functor.h>
+#include <utils/Mutex.h>
#include <utils/RefBase.h>
-#include <private/hwui/DrawGlInfo.h>
+#include <set>
class GrContext;
@@ -57,6 +57,7 @@ class RenderState {
friend class renderthread::RenderThread;
friend class Caches;
friend class renderthread::CacheManager;
+
public:
void onGLContextCreated();
void onGLContextDestroyed();
@@ -79,12 +80,8 @@ public:
void debugOverdraw(bool enable, bool clear);
- void registerLayer(Layer* layer) {
- mActiveLayers.insert(layer);
- }
- void unregisterLayer(Layer* layer) {
- mActiveLayers.erase(layer);
- }
+ void registerLayer(Layer* layer) { mActiveLayers.insert(layer); }
+ void unregisterLayer(Layer* layer) { mActiveLayers.erase(layer); }
void registerCanvasContext(renderthread::CanvasContext* context) {
mRegisteredContexts.insert(context);
@@ -127,7 +124,6 @@ private:
explicit RenderState(renderthread::RenderThread& thread);
~RenderState();
-
renderthread::RenderThread& mRenderThread;
Caches* mCaches = nullptr;
diff --git a/libs/hwui/renderstate/Scissor.cpp b/libs/hwui/renderstate/Scissor.cpp
index 61dd8c3200a4..e37ed029542b 100644
--- a/libs/hwui/renderstate/Scissor.cpp
+++ b/libs/hwui/renderstate/Scissor.cpp
@@ -23,12 +23,7 @@ namespace android {
namespace uirenderer {
Scissor::Scissor()
- : mEnabled(false)
- , mScissorX(0)
- , mScissorY(0)
- , mScissorWidth(0)
- , mScissorHeight(0) {
-}
+ : mEnabled(false), mScissorX(0), mScissorY(0), mScissorWidth(0), mScissorHeight(0) {}
bool Scissor::setEnabled(bool enabled) {
if (mEnabled != enabled) {
@@ -44,9 +39,8 @@ bool Scissor::setEnabled(bool enabled) {
}
bool Scissor::set(GLint x, GLint y, GLint width, GLint height) {
- if (mEnabled && (x != mScissorX || y != mScissorY
- || width != mScissorWidth || height != mScissorHeight)) {
-
+ if (mEnabled &&
+ (x != mScissorX || y != mScissorY || width != mScissorWidth || height != mScissorHeight)) {
if (x < 0) {
width += x;
x = 0;
@@ -80,10 +74,7 @@ void Scissor::set(int viewportHeight, const Rect& clip) {
GLint width = std::max(0, ((int)clip.right) - x);
GLint height = std::max(0, (viewportHeight - (int)clip.top) - y);
- if (x != mScissorX
- || y != mScissorY
- || width != mScissorWidth
- || height != mScissorHeight) {
+ if (x != mScissorX || y != mScissorY || width != mScissorWidth || height != mScissorHeight) {
glScissor(x, y, width, height);
mScissorX = x;
@@ -104,10 +95,9 @@ void Scissor::invalidate() {
}
void Scissor::dump() {
- ALOGD("Scissor: enabled %d, %d %d %d %d",
- mEnabled, mScissorX, mScissorY, mScissorWidth, mScissorHeight);
+ ALOGD("Scissor: enabled %d, %d %d %d %d", mEnabled, mScissorX, mScissorY, mScissorWidth,
+ mScissorHeight);
}
} /* namespace uirenderer */
} /* namespace android */
-
diff --git a/libs/hwui/renderstate/Scissor.h b/libs/hwui/renderstate/Scissor.h
index f30224470059..2b04f4e1384a 100644
--- a/libs/hwui/renderstate/Scissor.h
+++ b/libs/hwui/renderstate/Scissor.h
@@ -26,6 +26,7 @@ class Rect;
class Scissor {
friend class RenderState;
+
public:
bool setEnabled(bool enabled);
bool set(GLint x, GLint y, GLint width, GLint height);
@@ -33,6 +34,7 @@ public:
void reset();
bool isEnabled() { return mEnabled; }
void dump();
+
private:
Scissor();
void invalidate();
@@ -46,4 +48,4 @@ private:
} /* namespace uirenderer */
} /* namespace android */
-#endif // RENDERSTATE_SCISSOR_H
+#endif // RENDERSTATE_SCISSOR_H
diff --git a/libs/hwui/renderstate/Stencil.cpp b/libs/hwui/renderstate/Stencil.cpp
index f59442196af1..dc465fc7a6f8 100644
--- a/libs/hwui/renderstate/Stencil.cpp
+++ b/libs/hwui/renderstate/Stencil.cpp
@@ -136,5 +136,5 @@ void Stencil::dump() {
ALOGD("Stencil: state %d", mState);
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/renderstate/Stencil.h b/libs/hwui/renderstate/Stencil.h
index 5f7d4056b51d..95f372344ee4 100644
--- a/libs/hwui/renderstate/Stencil.h
+++ b/libs/hwui/renderstate/Stencil.h
@@ -78,36 +78,26 @@ public:
/**
* Indicates whether either test or write is enabled.
*/
- bool isEnabled() {
- return mState != StencilState::Disabled;
- }
+ bool isEnabled() { return mState != StencilState::Disabled; }
/**
* Indicates whether testing only is enabled.
*/
- bool isTestEnabled() {
- return mState == StencilState::Test;
- }
+ bool isTestEnabled() { return mState == StencilState::Test; }
- bool isWriteEnabled() {
- return mState == StencilState::Write;
- }
+ bool isWriteEnabled() { return mState == StencilState::Write; }
void dump();
private:
- enum class StencilState {
- Disabled,
- Test,
- Write
- };
+ enum class StencilState { Disabled, Test, Write };
void enable();
StencilState mState = StencilState::Disabled;
-}; // class Stencil
+}; // class Stencil
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_STENCIL_H
+#endif // ANDROID_HWUI_STENCIL_H
diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp
index f9a1f8c38895..470b4f5de97f 100644
--- a/libs/hwui/renderstate/TextureState.cpp
+++ b/libs/hwui/renderstate/TextureState.cpp
@@ -19,9 +19,9 @@
#include "utils/TraceUtils.h"
#include <GLES3/gl3.h>
-#include <memory>
-#include <SkCanvas.h>
#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <memory>
namespace android {
namespace uirenderer {
@@ -30,22 +30,16 @@ namespace uirenderer {
static const int SHADOW_LUT_SIZE = 128;
// Must define as many texture units as specified by kTextureUnitsCount
-const GLenum kTextureUnits[] = {
- GL_TEXTURE0,
- GL_TEXTURE1,
- GL_TEXTURE2,
- GL_TEXTURE3
-};
-
-TextureState::TextureState()
- : mTextureUnit(0) {
+const GLenum kTextureUnits[] = {GL_TEXTURE0, GL_TEXTURE1, GL_TEXTURE2, GL_TEXTURE3};
+
+TextureState::TextureState() : mTextureUnit(0) {
glActiveTexture(kTextureUnits[0]);
resetBoundTextures();
GLint maxTextureUnits;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
LOG_ALWAYS_FATAL_IF(maxTextureUnits < kTextureUnitsCount,
- "At least %d texture units are required!", kTextureUnitsCount);
+ "At least %d texture units are required!", kTextureUnitsCount);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}
@@ -86,8 +80,8 @@ void TextureState::constructTexture(Caches& caches) {
void TextureState::activateTexture(GLuint textureUnit) {
LOG_ALWAYS_FATAL_IF(textureUnit >= kTextureUnitsCount,
- "Tried to use texture unit index %d, only %d exist",
- textureUnit, kTextureUnitsCount);
+ "Tried to use texture unit index %d, only %d exist", textureUnit,
+ kTextureUnitsCount);
if (mTextureUnit != textureUnit) {
glActiveTexture(kTextureUnits[textureUnit]);
mTextureUnit = textureUnit;
@@ -151,4 +145,3 @@ void TextureState::unbindTexture(GLuint texture) {
} /* namespace uirenderer */
} /* namespace android */
-
diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h
index 7296fd39a705..f1996d431fa2 100644
--- a/libs/hwui/renderstate/TextureState.h
+++ b/libs/hwui/renderstate/TextureState.h
@@ -16,8 +16,8 @@
#ifndef RENDERSTATE_TEXTURESTATE_H
#define RENDERSTATE_TEXTURESTATE_H
-#include "Vertex.h"
#include "Texture.h"
+#include "Vertex.h"
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
@@ -29,9 +29,8 @@ namespace uirenderer {
class Texture;
class TextureState {
- friend class Caches; // TODO: move to RenderState
+ friend class Caches; // TODO: move to RenderState
public:
-
void constructTexture(Caches& caches);
/**
@@ -96,4 +95,4 @@ private:
} /* namespace uirenderer */
} /* namespace android */
-#endif // RENDERSTATE_BLEND_H
+#endif // RENDERSTATE_BLEND_H
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 0572a8d0afac..a33b2874e7a5 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -20,9 +20,9 @@
#include "RenderThread.h"
#include "renderstate/RenderState.h"
-#include <gui/Surface.h>
#include <GrContextOptions.h>
#include <SkExecutor.h>
+#include <gui/Surface.h>
#include <math.h>
#include <set>
@@ -42,9 +42,9 @@ namespace renderthread {
#define FONT_CACHE_MIN_MB (0.5f)
#define FONT_CACHE_MAX_MB (4.0f)
-CacheManager::CacheManager(const DisplayInfo& display)
- : mMaxSurfaceArea(display.w * display.h) {
- mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2,
+CacheManager::CacheManager(const DisplayInfo& display) : mMaxSurfaceArea(display.w * display.h) {
+ mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(
+ mMaxSurfaceArea / 2,
skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface);
}
@@ -63,8 +63,9 @@ void CacheManager::reset(GrContext* context) {
void CacheManager::destroy() {
// cleanup any caches here as the GrContext is about to go away...
mGrContext.reset(nullptr);
- mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2,
- skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface);
+ mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(
+ mMaxSurfaceArea / 2,
+ skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface);
}
void CacheManager::updateContextCacheSizes() {
@@ -137,7 +138,7 @@ void CacheManager::trimMemory(TrimMemoryMode mode) {
switch (mode) {
case TrimMemoryMode::Complete:
- mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2);
+ mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea / 2);
mGrContext->freeGpuResources();
break;
case TrimMemoryMode::UiHidden:
@@ -175,8 +176,8 @@ void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState)
log.appendFormat("Caches:\n");
log.appendFormat(" Current / Maximum\n");
- log.appendFormat(" VectorDrawableAtlas %6.2f kB / %6.2f kB (entries = %zu)\n",
- 0.0f, 0.0f, (size_t)0);
+ log.appendFormat(" VectorDrawableAtlas %6.2f kB / %6.2f kB (entries = %zu)\n", 0.0f, 0.0f,
+ (size_t)0);
if (renderState) {
if (renderState->mActiveLayers.size() > 0) {
@@ -185,24 +186,21 @@ void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState)
size_t layerMemoryTotal = 0;
for (std::set<Layer*>::iterator it = renderState->mActiveLayers.begin();
- it != renderState->mActiveLayers.end(); it++) {
+ it != renderState->mActiveLayers.end(); it++) {
const Layer* layer = *it;
const char* layerType = layer->getApi() == Layer::Api::OpenGL ? "GlLayer" : "VkLayer";
- log.appendFormat(" %s size %dx%d\n", layerType,
- layer->getWidth(), layer->getHeight());
+ log.appendFormat(" %s size %dx%d\n", layerType, layer->getWidth(),
+ layer->getHeight());
layerMemoryTotal += layer->getWidth() * layer->getHeight() * 4;
}
log.appendFormat(" Layers Total %6.2f kB (numLayers = %zu)\n",
layerMemoryTotal / 1024.0f, renderState->mActiveLayers.size());
}
-
log.appendFormat("Total memory usage:\n");
- log.appendFormat(" %zu bytes, %.2f MB (%.2f MB is purgeable)\n",
- bytesCached, bytesCached / 1024.0f / 1024.0f,
+ log.appendFormat(" %zu bytes, %.2f MB (%.2f MB is purgeable)\n", bytesCached,
+ bytesCached / 1024.0f / 1024.0f,
mGrContext->getResourceCachePurgeableBytes() / 1024.0f / 1024.0f);
-
-
}
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h
index 3ba2690caf31..d0370453c258 100644
--- a/libs/hwui/renderthread/CacheManager.h
+++ b/libs/hwui/renderthread/CacheManager.h
@@ -42,10 +42,7 @@ class RenderThread;
class CacheManager {
public:
- enum class TrimMemoryMode {
- Complete,
- UiHidden
- };
+ enum class TrimMemoryMode { Complete, UiHidden };
void configureContext(GrContextOptions* context);
void trimMemory(TrimMemoryMode mode);
@@ -58,12 +55,12 @@ public:
size_t getBackgroundCacheSize() const { return mBackgroundResourceBytes; }
TaskManager* getTaskManager() { return &mTaskManager; }
+
private:
friend class RenderThread;
CacheManager(const DisplayInfo& display);
-
void reset(GrContext* grContext);
void destroy();
void updateContextCacheSizes();
@@ -92,4 +89,3 @@ private:
} /* namespace android */
#endif /* CACHEMANAGER_H */
-
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 36a0da1f3bb6..b7bb2d15f3b8 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -14,24 +14,24 @@
* limitations under the License.
*/
-#include <GpuMemoryTracker.h>
#include "CanvasContext.h"
+#include <GpuMemoryTracker.h>
#include "AnimationContext.h"
#include "Caches.h"
#include "EglManager.h"
#include "Frame.h"
#include "LayerUpdateQueue.h"
+#include "OpenGLPipeline.h"
#include "Properties.h"
#include "RenderThread.h"
#include "hwui/Canvas.h"
-#include "renderstate/RenderState.h"
-#include "renderstate/Stencil.h"
-#include "protos/hwui.pb.h"
-#include "OpenGLPipeline.h"
#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "pipeline/skia/SkiaPipeline.h"
#include "pipeline/skia/SkiaVulkanPipeline.h"
+#include "protos/hwui.pb.h"
+#include "renderstate/RenderState.h"
+#include "renderstate/Stencil.h"
#include "utils/GLUtils.h"
#include "utils/TimeUtils.h"
@@ -40,9 +40,9 @@
#include <private/hwui/DrawGlInfo.h>
#include <strings.h>
-#include <algorithm>
#include <fcntl.h>
#include <sys/stat.h>
+#include <algorithm>
#include <cstdlib>
@@ -63,23 +63,22 @@ namespace android {
namespace uirenderer {
namespace renderthread {
-CanvasContext* CanvasContext::create(RenderThread& thread,
- bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) {
-
+CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent,
+ RenderNode* rootRenderNode, IContextFactory* contextFactory) {
auto renderType = Properties::getRenderPipelineType();
switch (renderType) {
case RenderPipelineType::OpenGL:
return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
- std::make_unique<OpenGLPipeline>(thread));
+ std::make_unique<OpenGLPipeline>(thread));
case RenderPipelineType::SkiaGL:
return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
- std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread));
+ std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread));
case RenderPipelineType::SkiaVulkan:
return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
- std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread));
+ std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread));
default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
return nullptr;
@@ -96,7 +95,7 @@ void CanvasContext::destroyLayer(RenderNode* node) {
skiapipeline::SkiaPipeline::destroyLayer(node);
break;
default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
}
@@ -115,7 +114,7 @@ void CanvasContext::invokeFunctor(const RenderThread& thread, Functor* functor)
skiapipeline::SkiaVulkanPipeline::invokeFunctor(thread, functor);
break;
default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
}
@@ -131,14 +130,14 @@ void CanvasContext::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
skiapipeline::SkiaPipeline::prepareToDraw(thread, bitmap);
break;
default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
}
-CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
- RenderNode* rootRenderNode, IContextFactory* contextFactory,
- std::unique_ptr<IRenderPipeline> renderPipeline)
+CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
+ IContextFactory* contextFactory,
+ std::unique_ptr<IRenderPipeline> renderPipeline)
: mRenderThread(thread)
, mOpaque(!translucent)
, mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
@@ -170,7 +169,7 @@ void CanvasContext::addRenderNode(RenderNode* node, bool placeFront) {
void CanvasContext::removeRenderNode(RenderNode* node) {
node->clearRoot();
mRenderNodes.erase(std::remove(mRenderNodes.begin(), mRenderNodes.end(), node),
- mRenderNodes.end());
+ mRenderNodes.end());
}
void CanvasContext::destroy() {
@@ -192,10 +191,10 @@ void CanvasContext::setSurface(sp<Surface>&& surface) {
mFrameNumber = -1;
if (hasSurface) {
- mHaveNewSurface = true;
- mSwapHistory.clear();
+ mHaveNewSurface = true;
+ mSwapHistory.clear();
} else {
- mRenderThread.removeFrameCallback(this);
+ mRenderThread.removeFrameCallback(this);
}
}
@@ -219,8 +218,7 @@ void CanvasContext::setStopped(bool stopped) {
}
}
-void CanvasContext::setup(float lightRadius,
- uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
+void CanvasContext::setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
mLightGeometry.radius = lightRadius;
mLightInfo.ambientShadowAlpha = ambientShadowAlpha;
mLightInfo.spotShadowAlpha = spotShadowAlpha;
@@ -254,7 +252,7 @@ bool CanvasContext::makeCurrent() {
return true;
default:
LOG_ALWAYS_FATAL("unexpected result %d from IRenderPipeline::makeCurrent",
- (int32_t) result);
+ (int32_t)result);
}
return true;
@@ -277,8 +275,7 @@ bool CanvasContext::isSwapChainStuffed() {
// Was there a happy queue & dequeue time? If so, don't
// consider it stuffed
- if (swapA.dequeueDuration < SLOW_THRESHOLD
- && swapA.queueDuration < SLOW_THRESHOLD) {
+ if (swapA.dequeueDuration < SLOW_THRESHOLD && swapA.queueDuration < SLOW_THRESHOLD) {
return false;
}
@@ -293,8 +290,7 @@ bool CanvasContext::isSwapChainStuffed() {
// Was there a happy queue & dequeue time? If so, don't
// consider it stuffed
- if (swapB.dequeueDuration < SLOW_THRESHOLD
- && swapB.queueDuration < SLOW_THRESHOLD) {
+ if (swapB.dequeueDuration < SLOW_THRESHOLD && swapB.queueDuration < SLOW_THRESHOLD) {
return false;
}
@@ -306,8 +302,8 @@ bool CanvasContext::isSwapChainStuffed() {
return true;
}
-void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
- int64_t syncQueued, RenderNode* target) {
+void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued,
+ RenderNode* target) {
mRenderThread.removeFrameCallback(this);
// If the previous frame was dropped we don't need to hold onto it, so
@@ -358,8 +354,8 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
// Already drew for this vsync pulse, UI draw request missed
// the deadline for RT animations
info.out.canDrawThisFrame = false;
- } else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3
- || (latestVsync - mLastDropVsync) < 500_ms) {
+ } else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3 ||
+ (latestVsync - mLastDropVsync) < 500_ms) {
// It's been several frame intervals, assume the buffer queue is fine
// or the last drop was too recent
info.out.canDrawThisFrame = true;
@@ -402,10 +398,10 @@ void CanvasContext::draw() {
mDamageAccumulator.finish(&dirty);
// TODO: Re-enable after figuring out cause of b/22592975
-// if (dirty.isEmpty() && Properties::skipEmptyFrames) {
-// mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
-// return;
-// }
+ // if (dirty.isEmpty() && Properties::skipEmptyFrames) {
+ // mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
+ // return;
+ // }
mCurrentFrameInfo->markIssueDrawCommandsStart();
@@ -414,18 +410,19 @@ void CanvasContext::draw() {
SkRect windowDirty = computeDirtyRect(frame, &dirty);
bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue,
- mContentDrawBounds, mOpaque, mWideColorGamut, mLightInfo, mRenderNodes, &(profiler()));
+ mContentDrawBounds, mOpaque, mWideColorGamut, mLightInfo,
+ mRenderNodes, &(profiler()));
waitOnFences();
bool requireSwap = false;
- bool didSwap = mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo,
- &requireSwap);
+ bool didSwap =
+ mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap);
mIsDirty = false;
if (requireSwap) {
- if (!didSwap) { //some error happened
+ if (!didSwap) { // some error happened
setSurface(nullptr);
}
SwapHistory& swap = mSwapHistory.next();
@@ -449,10 +446,8 @@ void CanvasContext::draw() {
swap.dequeueDuration = 0;
swap.queueDuration = 0;
}
- mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration)
- = swap.dequeueDuration;
- mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration)
- = swap.queueDuration;
+ mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = swap.dequeueDuration;
+ mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = swap.queueDuration;
mHaveNewSurface = false;
mFrameNumber = -1;
} else {
@@ -464,9 +459,9 @@ void CanvasContext::draw() {
mCurrentFrameInfo->markFrameCompleted();
#if LOG_FRAMETIME_MMA
- float thisFrame = mCurrentFrameInfo->duration(
- FrameInfoIndex::IssueDrawCommandsStart,
- FrameInfoIndex::FrameCompleted) / NANOS_PER_MILLIS_F;
+ float thisFrame = mCurrentFrameInfo->duration(FrameInfoIndex::IssueDrawCommandsStart,
+ FrameInfoIndex::FrameCompleted) /
+ NANOS_PER_MILLIS_F;
if (sFrameCount) {
sBenchMma = ((9 * sBenchMma) + thisFrame) / 10;
} else {
@@ -491,7 +486,6 @@ void CanvasContext::draw() {
caches.fontRenderer.getFontRenderer().historyTracker().frameCompleted();
}
#endif
-
}
// Called by choreographer to do an RT-driven animation
@@ -505,9 +499,7 @@ void CanvasContext::prepareAndDraw(RenderNode* node) {
nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos();
int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
- UiFrameInfoBuilder(frameInfo)
- .addFlag(FrameInfoFlags::RTAnimation)
- .setVsync(vsync, vsync);
+ UiFrameInfoBuilder(frameInfo).addFlag(FrameInfoFlags::RTAnimation).setVsync(vsync, vsync);
TreeInfo info(TreeInfo::MODE_RT_ONLY, *this);
prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node);
@@ -529,7 +521,7 @@ void CanvasContext::freePrefetchedLayers() {
if (mPrefetchedLayers.size()) {
for (auto& node : mPrefetchedLayers) {
ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...",
- node->getName());
+ node->getName());
node->destroyLayers();
node->decStrong(nullptr);
}
@@ -555,8 +547,8 @@ void CanvasContext::buildLayer(RenderNode* node) {
// purposes when the frame is actually drawn
node->setPropertyFieldsDirty(RenderNode::GENERIC);
- mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue,
- mOpaque, mWideColorGamut, mLightInfo);
+ mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mWideColorGamut,
+ mLightInfo);
node->incStrong(nullptr);
mPrefetchedLayers.insert(node);
@@ -607,7 +599,7 @@ void CanvasContext::trimMemory(RenderThread& thread, int level) {
break;
}
default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
}
@@ -634,7 +626,7 @@ void CanvasContext::serializeDisplayListTree() {
using namespace google::protobuf::io;
char package[128];
// Check whether tracing is enabled for this process.
- FILE * file = fopen("/proc/self/cmdline", "r");
+ FILE* file = fopen("/proc/self/cmdline", "r");
if (file) {
if (!fgets(package, 128, file)) {
ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno);
@@ -643,8 +635,7 @@ void CanvasContext::serializeDisplayListTree() {
}
fclose(file);
} else {
- ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno),
- errno);
+ ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno), errno);
return;
}
char path[1024];
@@ -675,8 +666,7 @@ void CanvasContext::waitOnFences() {
class CanvasContext::FuncTaskProcessor : public TaskProcessor<bool> {
public:
- explicit FuncTaskProcessor(TaskManager* taskManager)
- : TaskProcessor<bool>(taskManager) {}
+ explicit FuncTaskProcessor(TaskManager* taskManager) : TaskProcessor<bool>(taskManager) {}
virtual void onProcess(const sp<Task<bool> >& task) override {
FuncTask* t = static_cast<FuncTask*>(task.get());
@@ -714,8 +704,8 @@ SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) {
dirty->setEmpty();
} else {
if (!dirty->isEmpty() && !dirty->intersect(0, 0, frame.width(), frame.height())) {
- ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?",
- SK_RECT_ARGS(*dirty), frame.width(), frame.height());
+ ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?", SK_RECT_ARGS(*dirty),
+ frame.width(), frame.height());
dirty->setEmpty();
}
profiler().unionDirty(dirty);
@@ -735,7 +725,7 @@ SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) {
// last frame so there's nothing to union() against
// Therefore we only care about the > 1 case.
if (frame.bufferAge() > 1) {
- if (frame.bufferAge() > (int) mSwapHistory.size()) {
+ if (frame.bufferAge() > (int)mSwapHistory.size()) {
// We don't have enough history to handle this old of a buffer
// Just do a full-draw
dirty->set(0, 0, frame.width(), frame.height());
@@ -744,7 +734,7 @@ SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) {
// to the damage history (happens below)
// So we need to damage
for (int i = mSwapHistory.size() - 1;
- i > ((int) mSwapHistory.size()) - frame.bufferAge(); i--) {
+ i > ((int)mSwapHistory.size()) - frame.bufferAge(); i--) {
dirty->join(mSwapHistory[i].damage);
}
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index f8a877584792..d80a24737a7a 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -27,17 +27,17 @@
#include "IRenderPipeline.h"
#include "LayerUpdateQueue.h"
#include "RenderNode.h"
-#include "thread/Task.h"
-#include "thread/TaskProcessor.h"
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
+#include "thread/Task.h"
+#include "thread/TaskProcessor.h"
-#include <cutils/compiler.h>
#include <EGL/egl.h>
#include <SkBitmap.h>
#include <SkRect.h>
-#include <utils/Functor.h>
+#include <cutils/compiler.h>
#include <gui/Surface.h>
+#include <utils/Functor.h>
#include <functional>
#include <set>
@@ -63,8 +63,8 @@ class Frame;
// TODO: Rename to Renderer or some other per-window, top-level manager
class CanvasContext : public IFrameCallback {
public:
- static CanvasContext* create(RenderThread& thread, bool translucent,
- RenderNode* rootRenderNode, IContextFactory* contextFactory);
+ static CanvasContext* create(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
+ IContextFactory* contextFactory);
virtual ~CanvasContext();
/**
@@ -89,9 +89,7 @@ public:
bool pinImages(std::vector<SkImage*>& mutableImages) {
return mRenderPipeline->pinImages(mutableImages);
}
- bool pinImages(LsaVector<sk_sp<Bitmap>>& images) {
- return mRenderPipeline->pinImages(images);
- }
+ bool pinImages(LsaVector<sk_sp<Bitmap>>& images) { return mRenderPipeline->pinImages(images); }
/**
* Unpin any image that had be previously pinned to the GPU cache
@@ -122,14 +120,12 @@ public:
void setStopped(bool stopped);
bool hasSurface() { return mNativeSurface.get(); }
- void setup(float lightRadius,
- uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
+ void setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
void setLightCenter(const Vector3& lightCenter);
void setOpaque(bool opaque);
void setWideGamut(bool wideGamut);
bool makeCurrent();
- void prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
- int64_t syncQueued, RenderNode* target);
+ void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target);
void draw();
void destroy();
@@ -161,13 +157,9 @@ public:
void addRenderNode(RenderNode* node, bool placeFront);
void removeRenderNode(RenderNode* node);
- void setContentDrawBounds(const Rect& bounds) {
- mContentDrawBounds = bounds;
- }
+ void setContentDrawBounds(const Rect& bounds) { mContentDrawBounds = bounds; }
- RenderState& getRenderState() {
- return mRenderThread.renderState();
- }
+ RenderState& getRenderState() { return mRenderThread.renderState(); }
void addFrameMetricsObserver(FrameMetricsObserver* observer) {
if (mFrameMetricsReporter.get() == nullptr) {
@@ -197,7 +189,7 @@ public:
private:
CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
- IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
+ IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
friend class RegisterFrameCallbackTask;
// TODO: Replace with something better for layer & other GL object
@@ -239,14 +231,14 @@ private:
bool mOpaque;
bool mWideColorGamut = false;
BakedOpRenderer::LightInfo mLightInfo;
- FrameBuilder::LightGeometry mLightGeometry = { {0, 0, 0}, 0 };
+ FrameBuilder::LightGeometry mLightGeometry = {{0, 0, 0}, 0};
bool mHaveNewSurface = false;
DamageAccumulator mDamageAccumulator;
LayerUpdateQueue mLayerUpdateQueue;
std::unique_ptr<AnimationContext> mAnimationContext;
- std::vector< sp<RenderNode> > mRenderNodes;
+ std::vector<sp<RenderNode>> mRenderNodes;
FrameInfo* mCurrentFrameInfo = nullptr;
std::string mName;
@@ -266,8 +258,8 @@ private:
};
class FuncTaskProcessor;
- std::vector< sp<FuncTask> > mFrameFences;
- sp<TaskProcessor<bool> > mFrameWorkProcessor;
+ std::vector<sp<FuncTask>> mFrameFences;
+ sp<TaskProcessor<bool>> mFrameWorkProcessor;
std::unique_ptr<IRenderPipeline> mRenderPipeline;
};
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 0a94678a5c83..8372331c0352 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -33,21 +33,20 @@ DrawFrameTask::DrawFrameTask()
: mRenderThread(nullptr)
, mContext(nullptr)
, mContentDrawBounds(0, 0, 0, 0)
- , mSyncResult(SyncResult::OK) {
-}
+ , mSyncResult(SyncResult::OK) {}
-DrawFrameTask::~DrawFrameTask() {
-}
+DrawFrameTask::~DrawFrameTask() {}
void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context,
- RenderNode* targetNode) {
+ RenderNode* targetNode) {
mRenderThread = thread;
mContext = context;
mTargetNode = targetNode;
}
void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) {
- LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to pushLayerUpdate with!");
+ LOG_ALWAYS_FATAL_IF(!mContext,
+ "Lifecycle violation, there's no context to pushLayerUpdate with!");
for (size_t i = 0; i < mLayers.size(); i++) {
if (mLayers[i].get() == layer) {
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 4e4b6da3083a..ea51ae4a42b7 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -24,8 +24,8 @@
#include "RenderTask.h"
-#include "../Rect.h"
#include "../FrameInfo.h"
+#include "../Rect.h"
#include "../TreeInfo.h"
namespace android {
@@ -90,7 +90,7 @@ private:
/*********************************************
* Single frame data
*********************************************/
- std::vector< sp<DeferredLayerUpdater> > mLayers;
+ std::vector<sp<DeferredLayerUpdater> > mLayers;
int mSyncResult;
int64_t mSyncQueued;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 87e5bfdc8ca5..4df7cafa4792 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -18,17 +18,17 @@
#include <string>
-#include "utils/StringUtils.h"
#include <cutils/properties.h>
#include <log/log.h>
+#include "utils/StringUtils.h"
#include "Caches.h"
#include "DeviceInfo.h"
#include "Frame.h"
#include "Properties.h"
#include "RenderThread.h"
-#include "renderstate/RenderState.h"
#include "Texture.h"
+#include "renderstate/RenderState.h"
#include <EGL/eglext.h>
#include <GrContextOptions.h>
@@ -47,7 +47,9 @@ namespace android {
namespace uirenderer {
namespace renderthread {
-#define ERROR_CASE(x) case x: return #x;
+#define ERROR_CASE(x) \
+ case x: \
+ return #x;
static const char* egl_error_str(EGLint error) {
switch (error) {
ERROR_CASE(EGL_SUCCESS)
@@ -65,8 +67,8 @@ static const char* egl_error_str(EGLint error) {
ERROR_CASE(EGL_BAD_PARAMETER)
ERROR_CASE(EGL_BAD_SURFACE)
ERROR_CASE(EGL_CONTEXT_LOST)
- default:
- return "Unknown error";
+ default:
+ return "Unknown error";
}
}
const char* EglManager::eglErrorString() {
@@ -89,8 +91,7 @@ EglManager::EglManager(RenderThread& thread)
, mEglConfigWideGamut(nullptr)
, mEglContext(EGL_NO_CONTEXT)
, mPBufferSurface(EGL_NO_SURFACE)
- , mCurrentSurface(EGL_NO_SURFACE) {
-}
+ , mCurrentSurface(EGL_NO_SURFACE) {}
void EglManager::initialize() {
if (hasEglContext()) return;
@@ -98,12 +99,12 @@ void EglManager::initialize() {
ATRACE_NAME("Creating EGLContext");
mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
- "Failed to get EGL_DEFAULT_DISPLAY! err=%s", eglErrorString());
+ LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
+ eglErrorString());
EGLint major, minor;
LOG_ALWAYS_FATAL_IF(eglInitialize(mEglDisplay, &major, &minor) == EGL_FALSE,
- "Failed to initialize display %p! err=%s", mEglDisplay, eglErrorString());
+ "Failed to initialize display %p! err=%s", mEglDisplay, eglErrorString());
ALOGI("Initialized EGL, version %d.%d", (int)major, (int)minor);
@@ -141,23 +142,22 @@ void EglManager::initialize() {
options.fDisableDistanceFieldPaths = true;
mRenderThread.cacheManager().configureContext(&options);
mRenderThread.setGrContext(GrContext::Create(GrBackend::kOpenGL_GrBackend,
- (GrBackendContext)glInterface.get(), options));
+ (GrBackendContext)glInterface.get(), options));
}
}
void EglManager::initExtensions() {
- auto extensions = StringUtils::split(
- eglQueryString(mEglDisplay, EGL_EXTENSIONS));
+ auto extensions = StringUtils::split(eglQueryString(mEglDisplay, EGL_EXTENSIONS));
// For our purposes we don't care if EGL_BUFFER_AGE is a result of
// EGL_EXT_buffer_age or EGL_KHR_partial_update as our usage is covered
// under EGL_KHR_partial_update and we don't need the expanded scope
// that EGL_EXT_buffer_age provides.
- EglExtensions.bufferAge = extensions.has("EGL_EXT_buffer_age")
- || extensions.has("EGL_KHR_partial_update");
+ EglExtensions.bufferAge =
+ extensions.has("EGL_EXT_buffer_age") || extensions.has("EGL_KHR_partial_update");
EglExtensions.setDamage = extensions.has("EGL_KHR_partial_update");
LOG_ALWAYS_FATAL_IF(!extensions.has("EGL_KHR_swap_buffers_with_damage"),
- "Missing required extension EGL_KHR_swap_buffers_with_damage");
+ "Missing required extension EGL_KHR_swap_buffers_with_damage");
EglExtensions.glColorSpace = extensions.has("EGL_KHR_gl_colorspace");
EglExtensions.noConfigContext = extensions.has("EGL_KHR_no_config_context");
@@ -175,30 +175,37 @@ bool EglManager::hasEglContext() {
void EglManager::loadConfigs() {
ALOGD("Swap behavior %d", static_cast<int>(mSwapBehavior));
- EGLint swapBehavior = (mSwapBehavior == SwapBehavior::Preserved)
- ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
- EGLint attribs[] = {
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL_RED_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_BLUE_SIZE, 8,
- EGL_ALPHA_SIZE, 8,
- EGL_DEPTH_SIZE, 0,
- EGL_CONFIG_CAVEAT, EGL_NONE,
- EGL_STENCIL_SIZE, Stencil::getStencilSize(),
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
- EGL_NONE
- };
+ EGLint swapBehavior =
+ (mSwapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+ EGLint attribs[] = {EGL_RENDERABLE_TYPE,
+ EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE,
+ 8,
+ EGL_GREEN_SIZE,
+ 8,
+ EGL_BLUE_SIZE,
+ 8,
+ EGL_ALPHA_SIZE,
+ 8,
+ EGL_DEPTH_SIZE,
+ 0,
+ EGL_CONFIG_CAVEAT,
+ EGL_NONE,
+ EGL_STENCIL_SIZE,
+ Stencil::getStencilSize(),
+ EGL_SURFACE_TYPE,
+ EGL_WINDOW_BIT | swapBehavior,
+ EGL_NONE};
EGLint numConfigs = 1;
- if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, numConfigs, &numConfigs)
- || numConfigs != 1) {
+ if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, numConfigs, &numConfigs) ||
+ numConfigs != 1) {
if (mSwapBehavior == SwapBehavior::Preserved) {
// Try again without dirty regions enabled
ALOGW("Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...");
mSwapBehavior = SwapBehavior::Discard;
loadConfigs();
- return; // the call to loadConfigs() we just made picks the wide gamut config
+ return; // the call to loadConfigs() we just made picks the wide gamut config
} else {
// Failed to get a valid config
LOG_ALWAYS_FATAL("Failed to choose config, error = %s", eglErrorString());
@@ -207,22 +214,30 @@ void EglManager::loadConfigs() {
if (EglExtensions.pixelFormatFloat) {
// If we reached this point, we have a valid swap behavior
- EGLint attribs16F[] = {
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
- EGL_RED_SIZE, 16,
- EGL_GREEN_SIZE, 16,
- EGL_BLUE_SIZE, 16,
- EGL_ALPHA_SIZE, 16,
- EGL_DEPTH_SIZE, 0,
- EGL_STENCIL_SIZE, Stencil::getStencilSize(),
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
- EGL_NONE
- };
+ EGLint attribs16F[] = {EGL_RENDERABLE_TYPE,
+ EGL_OPENGL_ES2_BIT,
+ EGL_COLOR_COMPONENT_TYPE_EXT,
+ EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
+ EGL_RED_SIZE,
+ 16,
+ EGL_GREEN_SIZE,
+ 16,
+ EGL_BLUE_SIZE,
+ 16,
+ EGL_ALPHA_SIZE,
+ 16,
+ EGL_DEPTH_SIZE,
+ 0,
+ EGL_STENCIL_SIZE,
+ Stencil::getStencilSize(),
+ EGL_SURFACE_TYPE,
+ EGL_WINDOW_BIT | swapBehavior,
+ EGL_NONE};
numConfigs = 1;
- if (!eglChooseConfig(mEglDisplay, attribs16F, &mEglConfigWideGamut, numConfigs, &numConfigs)
- || numConfigs != 1) {
+ if (!eglChooseConfig(mEglDisplay, attribs16F, &mEglConfigWideGamut, numConfigs,
+ &numConfigs) ||
+ numConfigs != 1) {
LOG_ALWAYS_FATAL(
"Device claims wide gamut support, cannot find matching config, error = %s",
eglErrorString());
@@ -231,23 +246,20 @@ void EglManager::loadConfigs() {
}
void EglManager::createContext() {
- EGLint attribs[] = {
- EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION,
- EGL_NONE
- };
- mEglContext = eglCreateContext(mEglDisplay,
- EglExtensions.noConfigContext ? ((EGLConfig) nullptr) : mEglConfig,
+ EGLint attribs[] = {EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION, EGL_NONE};
+ mEglContext = eglCreateContext(
+ mEglDisplay, EglExtensions.noConfigContext ? ((EGLConfig) nullptr) : mEglConfig,
EGL_NO_CONTEXT, attribs);
- LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT,
- "Failed to create context, error = %s", eglErrorString());
+ LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT, "Failed to create context, error = %s",
+ eglErrorString());
}
void EglManager::createPBufferSurface() {
LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
- "usePBufferSurface() called on uninitialized GlobalContext!");
+ "usePBufferSurface() called on uninitialized GlobalContext!");
if (mPBufferSurface == EGL_NO_SURFACE) {
- EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
+ EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
mPBufferSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
}
}
@@ -255,8 +267,8 @@ void EglManager::createPBufferSurface() {
EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorGamut) {
initialize();
- wideColorGamut = wideColorGamut && EglExtensions.glColorSpace && EglExtensions.scRGB
- && EglExtensions.pixelFormatFloat && EglExtensions.noConfigContext;
+ wideColorGamut = wideColorGamut && EglExtensions.glColorSpace && EglExtensions.scRGB &&
+ EglExtensions.pixelFormatFloat && EglExtensions.noConfigContext;
// The color space we want to use depends on whether linear blending is turned
// on and whether the app has requested wide color gamut rendering. When wide
@@ -280,10 +292,7 @@ EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorG
// We insert to placeholders to set EGL_GL_COLORSPACE_KHR and its value.
// According to section 3.4.1 of the EGL specification, the attributes
// list is considered empty if the first entry is EGL_NONE
- EGLint attribs[] = {
- EGL_NONE, EGL_NONE,
- EGL_NONE
- };
+ EGLint attribs[] = {EGL_NONE, EGL_NONE, EGL_NONE};
if (EglExtensions.glColorSpace) {
attribs[0] = EGL_GL_COLORSPACE_KHR;
@@ -302,16 +311,17 @@ EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorG
#endif
}
- EGLSurface surface = eglCreateWindowSurface(mEglDisplay,
- wideColorGamut ? mEglConfigWideGamut : mEglConfig, window, attribs);
+ EGLSurface surface = eglCreateWindowSurface(
+ mEglDisplay, wideColorGamut ? mEglConfigWideGamut : mEglConfig, window, attribs);
LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE,
- "Failed to create EGLSurface for window %p, eglErr = %s",
- (void*) window, eglErrorString());
+ "Failed to create EGLSurface for window %p, eglErr = %s", (void*)window,
+ eglErrorString());
if (mSwapBehavior != SwapBehavior::Preserved) {
- LOG_ALWAYS_FATAL_IF(eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED) == EGL_FALSE,
+ LOG_ALWAYS_FATAL_IF(eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR,
+ EGL_BUFFER_DESTROYED) == EGL_FALSE,
"Failed to set swap behavior to destroyed for window %p, eglErr = %s",
- (void*) window, eglErrorString());
+ (void*)window, eglErrorString());
}
return surface;
@@ -353,11 +363,11 @@ bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut) {
if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
if (errOut) {
*errOut = eglGetError();
- ALOGW("Failed to make current on surface %p, error=%s",
- (void*)surface, egl_error_str(*errOut));
+ ALOGW("Failed to make current on surface %p, error=%s", (void*)surface,
+ egl_error_str(*errOut));
} else {
- LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s",
- (void*)surface, eglErrorString());
+ LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s", (void*)surface,
+ eglErrorString());
}
}
mCurrentSurface = surface;
@@ -369,21 +379,20 @@ bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut) {
EGLint EglManager::queryBufferAge(EGLSurface surface) {
switch (mSwapBehavior) {
- case SwapBehavior::Discard:
- return 0;
- case SwapBehavior::Preserved:
- return 1;
- case SwapBehavior::BufferAge:
- EGLint bufferAge;
- eglQuerySurface(mEglDisplay, surface, EGL_BUFFER_AGE_EXT, &bufferAge);
- return bufferAge;
+ case SwapBehavior::Discard:
+ return 0;
+ case SwapBehavior::Preserved:
+ return 1;
+ case SwapBehavior::BufferAge:
+ EGLint bufferAge;
+ eglQuerySurface(mEglDisplay, surface, EGL_BUFFER_AGE_EXT, &bufferAge);
+ return bufferAge;
}
return 0;
}
Frame EglManager::beginFrame(EGLSurface surface) {
- LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE,
- "Tried to beginFrame on EGL_NO_SURFACE!");
+ LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE, "Tried to beginFrame on EGL_NO_SURFACE!");
makeCurrent(surface);
Frame frame;
frame.mSurface = surface;
@@ -401,7 +410,7 @@ void EglManager::damageFrame(const Frame& frame, const SkRect& dirty) {
frame.map(dirty, rects);
if (!eglSetDamageRegionKHR(mEglDisplay, frame.mSurface, rects, 1)) {
LOG_ALWAYS_FATAL("Failed to set damage region on surface %p, error=%s",
- (void*)frame.mSurface, eglErrorString());
+ (void*)frame.mSurface, eglErrorString());
}
}
#endif
@@ -412,7 +421,6 @@ bool EglManager::damageRequiresSwap() {
}
bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) {
-
if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
ATRACE_NAME("Finishing GPU work");
fence();
@@ -420,8 +428,7 @@ bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) {
EGLint rects[4];
frame.map(screenDirty, rects);
- eglSwapBuffersWithDamageKHR(mEglDisplay, frame.mSurface, rects,
- screenDirty.isEmpty() ? 0 : 1);
+ eglSwapBuffersWithDamageKHR(mEglDisplay, frame.mSurface, rects, screenDirty.isEmpty() ? 0 : 1);
EGLint err = eglGetError();
if (CC_LIKELY(err == EGL_SUCCESS)) {
@@ -431,20 +438,18 @@ bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) {
// For some reason our surface was destroyed out from under us
// This really shouldn't happen, but if it does we can recover easily
// by just not trying to use the surface anymore
- ALOGW("swapBuffers encountered EGL error %d on %p, halting rendering...",
- err, frame.mSurface);
+ ALOGW("swapBuffers encountered EGL error %d on %p, halting rendering...", err,
+ frame.mSurface);
return false;
}
- LOG_ALWAYS_FATAL("Encountered EGL error %d %s during rendering",
- err, egl_error_str(err));
+ LOG_ALWAYS_FATAL("Encountered EGL error %d %s during rendering", err, egl_error_str(err));
// Impossible to hit this, but the compiler doesn't know that
return false;
}
void EglManager::fence() {
EGLSyncKHR fence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, NULL);
- eglClientWaitSyncKHR(mEglDisplay, fence,
- EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR);
+ eglClientWaitSyncKHR(mEglDisplay, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR);
eglDestroySyncKHR(mEglDisplay, fence);
}
@@ -452,17 +457,17 @@ bool EglManager::setPreserveBuffer(EGLSurface surface, bool preserve) {
if (mSwapBehavior != SwapBehavior::Preserved) return false;
bool preserved = eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR,
- preserve ? EGL_BUFFER_PRESERVED : EGL_BUFFER_DESTROYED);
+ preserve ? EGL_BUFFER_PRESERVED : EGL_BUFFER_DESTROYED);
if (!preserved) {
- ALOGW("Failed to set EGL_SWAP_BEHAVIOR on surface %p, error=%s",
- (void*) surface, eglErrorString());
+ ALOGW("Failed to set EGL_SWAP_BEHAVIOR on surface %p, error=%s", (void*)surface,
+ eglErrorString());
// Maybe it's already set?
EGLint swapBehavior;
if (eglQuerySurface(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, &swapBehavior)) {
preserved = (swapBehavior == EGL_BUFFER_PRESERVED);
} else {
- ALOGW("Failed to query EGL_SWAP_BEHAVIOR on surface %p, error=%p",
- (void*) surface, eglErrorString());
+ ALOGW("Failed to query EGL_SWAP_BEHAVIOR on surface %p, error=%p", (void*)surface,
+ eglErrorString());
}
}
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 2982c23552c9..ef9effbf9953 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -16,9 +16,9 @@
#ifndef EGLMANAGER_H
#define EGLMANAGER_H
-#include <cutils/compiler.h>
#include <EGL/egl.h>
#include <SkRect.h>
+#include <cutils/compiler.h>
#include <ui/GraphicBuffer.h>
#include <utils/StrongPointer.h>
diff --git a/libs/hwui/renderthread/Frame.h b/libs/hwui/renderthread/Frame.h
index 99996fe40626..d266faa4f7c9 100644
--- a/libs/hwui/renderthread/Frame.h
+++ b/libs/hwui/renderthread/Frame.h
@@ -19,7 +19,7 @@
#include <stdint.h>
struct SkRect;
-typedef void *EGLSurface;
+typedef void* EGLSurface;
namespace android {
namespace uirenderer {
@@ -28,9 +28,7 @@ namespace renderthread {
class Frame {
public:
Frame(int32_t width, int32_t height, int32_t bufferAge)
- : mWidth(width)
- , mHeight(height)
- , mBufferAge(bufferAge) { }
+ : mWidth(width), mHeight(height), mBufferAge(bufferAge) {}
int32_t width() const { return mWidth; }
int32_t height() const { return mHeight; }
@@ -57,4 +55,3 @@ private:
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
-
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index cfc71cb9243c..246ab269b838 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -34,11 +34,7 @@ class DeferredLayerUpdater;
namespace renderthread {
-enum class MakeCurrentResult {
- AlreadyCurrent,
- Failed,
- Succeeded
-};
+enum class MakeCurrentResult { AlreadyCurrent, Failed, Succeeded };
enum class ColorMode {
Srgb,
@@ -53,14 +49,13 @@ public:
virtual MakeCurrentResult makeCurrent() = 0;
virtual Frame getFrame() = 0;
virtual bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo,
- const std::vector< sp<RenderNode> >& renderNodes,
- FrameInfoVisualizer* profiler) = 0;
+ const FrameBuilder::LightGeometry& lightGeometry,
+ LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
+ bool opaque, bool wideColorGamut, const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector<sp<RenderNode>>& renderNodes,
+ FrameInfoVisualizer* profiler) = 0;
virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
+ FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
virtual bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) = 0;
virtual DeferredLayerUpdater* createTextureLayer() = 0;
virtual bool setSurface(Surface* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0;
@@ -69,11 +64,11 @@ public:
virtual bool isContextReady() = 0;
virtual void onDestroyHardwareResources() = 0;
virtual void renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo) = 0;
+ LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo) = 0;
virtual TaskManager* getTaskManager() = 0;
- virtual bool createOrUpdateLayer(RenderNode* node,
- const DamageAccumulator& damageAccumulator, bool wideColorGamut) = 0;
+ virtual bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
+ bool wideColorGamut) = 0;
virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0;
virtual bool pinImages(LsaVector<sk_sp<Bitmap>>& images) = 0;
virtual void unpinImages() = 0;
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index 7283eb123d6a..f3103fd0cbb4 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -20,9 +20,9 @@
#include "EglManager.h"
#include "Frame.h"
#include "GlLayer.h"
+#include "OpenGLReadback.h"
#include "ProfileRenderer.h"
#include "renderstate/RenderState.h"
-#include "OpenGLReadback.h"
#include <cutils/properties.h>
#include <strings.h>
@@ -32,9 +32,7 @@ namespace uirenderer {
namespace renderthread {
OpenGLPipeline::OpenGLPipeline(RenderThread& thread)
- : mEglManager(thread.eglManager())
- , mRenderThread(thread) {
-}
+ : mEglManager(thread.eglManager()), mRenderThread(thread) {}
MakeCurrentResult OpenGLPipeline::makeCurrent() {
// TODO: Figure out why this workaround is needed, see b/13913604
@@ -51,23 +49,21 @@ MakeCurrentResult OpenGLPipeline::makeCurrent() {
Frame OpenGLPipeline::getFrame() {
LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
- "drawRenderNode called on a context with no surface!");
+ "drawRenderNode called on a context with no surface!");
return mEglManager.beginFrame(mEglSurface);
}
bool OpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo,
- const std::vector< sp<RenderNode> >& renderNodes,
- FrameInfoVisualizer* profiler) {
-
+ const FrameBuilder::LightGeometry& lightGeometry,
+ LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
+ bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector<sp<RenderNode>>& renderNodes,
+ FrameInfoVisualizer* profiler) {
mEglManager.damageFrame(frame, dirty);
bool drew = false;
-
auto& caches = Caches::getInstance();
FrameBuilder frameBuilder(dirty, frame.width(), frame.height(), lightGeometry, caches);
@@ -76,8 +72,8 @@ bool OpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const S
frameBuilder.deferRenderNodeScene(renderNodes, contentDrawBounds);
- BakedOpRenderer renderer(caches, mRenderThread.renderState(),
- opaque, wideColorGamut, lightInfo);
+ BakedOpRenderer renderer(caches, mRenderThread.renderState(), opaque, wideColorGamut,
+ lightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
ProfileRenderer profileRenderer(renderer);
profiler->draw(profileRenderer);
@@ -100,8 +96,7 @@ bool OpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const S
}
bool OpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) {
-
+ FrameInfo* currentFrameInfo, bool* requireSwap) {
GL_CHECKPOINT(LOW);
// Even if we decided to cancel the frame, from the perspective of jank
@@ -123,13 +118,13 @@ bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap
layer->updateTexImage();
layer->apply();
return OpenGLReadbackImpl::copyLayerInto(mRenderThread,
- static_cast<GlLayer&>(*layer->backingLayer()), bitmap);
+ static_cast<GlLayer&>(*layer->backingLayer()), bitmap);
}
static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
- GlLayer* layer = new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha,
- mode, blend);
+ SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ GlLayer* layer =
+ new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
Caches::getInstance().textureState().activateTexture(0);
layer->generateTexture();
return layer;
@@ -147,7 +142,6 @@ void OpenGLPipeline::onStop() {
}
bool OpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, ColorMode colorMode) {
-
if (mEglSurface != EGL_NO_SURFACE) {
mEglManager.destroySurface(mEglSurface);
mEglSurface = EGL_NO_SURFACE;
@@ -184,14 +178,16 @@ void OpenGLPipeline::onDestroyHardwareResources() {
}
void OpenGLPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo) {
- static const std::vector< sp<RenderNode> > emptyNodeList;
+ LayerUpdateQueue* layerUpdateQueue, bool opaque,
+ bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo) {
+ static const std::vector<sp<RenderNode>> emptyNodeList;
auto& caches = Caches::getInstance();
FrameBuilder frameBuilder(*layerUpdateQueue, lightGeometry, caches);
layerUpdateQueue->clear();
// TODO: Handle wide color gamut contexts
- BakedOpRenderer renderer(caches, mRenderThread.renderState(), opaque, wideColorGamut, lightInfo);
+ BakedOpRenderer renderer(caches, mRenderThread.renderState(), opaque, wideColorGamut,
+ lightInfo);
LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case");
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
}
@@ -205,13 +201,14 @@ static bool layerMatchesWH(OffscreenBuffer* layer, int width, int height) {
}
bool OpenGLPipeline::createOrUpdateLayer(RenderNode* node,
- const DamageAccumulator& damageAccumulator, bool wideColorGamut) {
+ const DamageAccumulator& damageAccumulator,
+ bool wideColorGamut) {
RenderState& renderState = mRenderThread.renderState();
OffscreenBufferPool& layerPool = renderState.layerPool();
bool transformUpdateNeeded = false;
if (node->getLayer() == nullptr) {
- node->setLayer(layerPool.get(renderState,
- node->getWidth(), node->getHeight(), wideColorGamut));
+ node->setLayer(
+ layerPool.get(renderState, node->getWidth(), node->getHeight(), wideColorGamut));
transformUpdateNeeded = true;
} else if (!layerMatchesWH(node->getLayer(), node->getWidth(), node->getHeight())) {
// TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering)
@@ -273,8 +270,7 @@ void OpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* functor)
class AutoEglFence {
public:
- AutoEglFence(EGLDisplay display)
- : mDisplay(display) {
+ AutoEglFence(EGLDisplay display) : mDisplay(display) {
fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
}
@@ -285,17 +281,17 @@ public:
}
EGLSyncKHR fence = EGL_NO_SYNC_KHR;
+
private:
EGLDisplay mDisplay = EGL_NO_DISPLAY;
};
class AutoEglImage {
public:
- AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer)
- : mDisplay(display) {
- EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
- image = eglCreateImageKHR(display, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
+ AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) {
+ EGLint imageAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+ image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer,
+ imageAttrs);
}
~AutoEglImage() {
@@ -305,21 +301,19 @@ public:
}
EGLImageKHR image = EGL_NO_IMAGE_KHR;
+
private:
EGLDisplay mDisplay = EGL_NO_DISPLAY;
};
class AutoGlTexture {
public:
- AutoGlTexture(uirenderer::Caches& caches)
- : mCaches(caches) {
+ AutoGlTexture(uirenderer::Caches& caches) : mCaches(caches) {
glGenTextures(1, &mTexture);
caches.textureState().bindTexture(mTexture);
}
- ~AutoGlTexture() {
- mCaches.textureState().deleteTexture(mTexture);
- }
+ ~AutoGlTexture() { mCaches.textureState().deleteTexture(mTexture); }
private:
uirenderer::Caches& mCaches;
@@ -327,18 +321,17 @@ private:
};
static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bitmap,
- GraphicBuffer& buffer, GLint format, GLint type) {
+ GraphicBuffer& buffer, GLint format, GLint type) {
EGLDisplay display = eglGetCurrentDisplay();
- LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY,
- "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
- uirenderer::renderthread::EglManager::eglErrorString());
+ LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
+ uirenderer::renderthread::EglManager::eglErrorString());
// We use an EGLImage to access the content of the GraphicBuffer
// The EGL image is later bound to a 2D texture
- EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer.getNativeBuffer();
+ EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer.getNativeBuffer();
AutoEglImage autoImage(display, clientBuffer);
if (autoImage.image == EGL_NO_IMAGE_KHR) {
ALOGW("Could not create EGL image, err =%s",
- uirenderer::renderthread::EglManager::eglErrorString());
+ uirenderer::renderthread::EglManager::eglErrorString());
return false;
}
AutoGlTexture glTexture(caches);
@@ -346,8 +339,8 @@ static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bi
GL_CHECKPOINT(MODERATE);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
- format, type, bitmap.getPixels());
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), format, type,
+ bitmap.getPixels());
GL_CHECKPOINT(MODERATE);
@@ -362,7 +355,7 @@ static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bi
// The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
// pipeline flush (similar to what a glFlush() would do.)
EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence,
- EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
+ EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError());
return false;
@@ -373,24 +366,24 @@ static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bi
// TODO: handle SRGB sanely
static PixelFormat internalFormatToPixelFormat(GLint internalFormat) {
switch (internalFormat) {
- case GL_LUMINANCE:
- return PIXEL_FORMAT_RGBA_8888;
- case GL_SRGB8_ALPHA8:
- return PIXEL_FORMAT_RGBA_8888;
- case GL_RGBA:
- return PIXEL_FORMAT_RGBA_8888;
- case GL_RGB:
- return PIXEL_FORMAT_RGB_565;
- case GL_RGBA16F:
- return PIXEL_FORMAT_RGBA_FP16;
- default:
- LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", internalFormat);
- return PIXEL_FORMAT_UNKNOWN;
+ case GL_LUMINANCE:
+ return PIXEL_FORMAT_RGBA_8888;
+ case GL_SRGB8_ALPHA8:
+ return PIXEL_FORMAT_RGBA_8888;
+ case GL_RGBA:
+ return PIXEL_FORMAT_RGBA_8888;
+ case GL_RGB:
+ return PIXEL_FORMAT_RGB_565;
+ case GL_RGBA16F:
+ return PIXEL_FORMAT_RGBA_FP16;
+ default:
+ LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", internalFormat);
+ return PIXEL_FORMAT_UNKNOWN;
}
}
sk_sp<Bitmap> OpenGLPipeline::allocateHardwareBitmap(RenderThread& renderThread,
- SkBitmap& skBitmap) {
+ SkBitmap& skBitmap) {
renderThread.eglManager().initialize();
uirenderer::Caches& caches = uirenderer::Caches::getInstance();
@@ -404,13 +397,14 @@ sk_sp<Bitmap> OpenGLPipeline::allocateHardwareBitmap(RenderThread& renderThread,
bool hasLinearBlending = caches.extensions().hasLinearBlending();
GLint format, type, internalFormat;
uirenderer::Texture::colorTypeToGlFormatAndType(caches, skBitmap.colorType(),
- needSRGB && hasLinearBlending, &internalFormat, &format, &type);
+ needSRGB && hasLinearBlending, &internalFormat,
+ &format, &type);
PixelFormat pixelFormat = internalFormatToPixelFormat(internalFormat);
- sp<GraphicBuffer> buffer = new GraphicBuffer(info.width(), info.height(), pixelFormat,
- GraphicBuffer::USAGE_HW_TEXTURE |
- GraphicBuffer::USAGE_SW_WRITE_NEVER |
- GraphicBuffer::USAGE_SW_READ_NEVER,
+ sp<GraphicBuffer> buffer = new GraphicBuffer(
+ info.width(), info.height(), pixelFormat,
+ GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
+ GraphicBuffer::USAGE_SW_READ_NEVER,
std::string("Bitmap::allocateHardwareBitmap pid [") + std::to_string(getpid()) + "]");
status_t error = buffer->initCheck();
@@ -420,8 +414,8 @@ sk_sp<Bitmap> OpenGLPipeline::allocateHardwareBitmap(RenderThread& renderThread,
}
SkBitmap bitmap;
- if (CC_UNLIKELY(uirenderer::Texture::hasUnsupportedColorType(skBitmap.info(),
- hasLinearBlending))) {
+ if (CC_UNLIKELY(
+ uirenderer::Texture::hasUnsupportedColorType(skBitmap.info(), hasLinearBlending))) {
sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeSRGB();
bitmap = uirenderer::Texture::uploadToN32(skBitmap, hasLinearBlending, std::move(sRGB));
} else {
diff --git a/libs/hwui/renderthread/OpenGLPipeline.h b/libs/hwui/renderthread/OpenGLPipeline.h
index 1f467c164d7f..118007c6a46c 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.h
+++ b/libs/hwui/renderthread/OpenGLPipeline.h
@@ -16,9 +16,9 @@
#pragma once
-#include "CanvasContext.h"
#include "BakedOpDispatcher.h"
#include "BakedOpRenderer.h"
+#include "CanvasContext.h"
#include "FrameBuilder.h"
#include "IRenderPipeline.h"
@@ -34,14 +34,13 @@ public:
MakeCurrentResult makeCurrent() override;
Frame getFrame() override;
bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo,
- const std::vector< sp<RenderNode> >& renderNodes,
- FrameInfoVisualizer* profiler) override;
+ const FrameBuilder::LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
+ const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector<sp<RenderNode>>& renderNodes,
+ FrameInfoVisualizer* profiler) override;
bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) override;
+ FrameInfo* currentFrameInfo, bool* requireSwap) override;
bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
DeferredLayerUpdater* createTextureLayer() override;
bool setSurface(Surface* window, SwapBehavior swapBehavior, ColorMode colorMode) override;
@@ -50,11 +49,11 @@ public:
bool isContextReady() override;
void onDestroyHardwareResources() override;
void renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo) override;
+ LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo) override;
TaskManager* getTaskManager() override;
- bool createOrUpdateLayer(RenderNode* node,
- const DamageAccumulator& damageAccumulator, bool wideColorGamut) override;
+ bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
+ bool wideColorGamut) override;
bool pinImages(std::vector<SkImage*>& mutableImages) override { return false; }
bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override;
void unpinImages() override;
@@ -62,8 +61,7 @@ public:
static void destroyLayer(RenderNode* node);
static void prepareToDraw(const RenderThread& thread, Bitmap* bitmap);
static void invokeFunctor(const RenderThread& thread, Functor* functor);
- static sk_sp<Bitmap> allocateHardwareBitmap(RenderThread& thread,
- SkBitmap& skBitmap);
+ static sk_sp<Bitmap> allocateHardwareBitmap(RenderThread& thread, SkBitmap& skBitmap);
private:
EglManager& mEglManager;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 2f406da9847d..79e46ed9e65f 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -22,11 +22,11 @@
#include "Readback.h"
#include "Rect.h"
#include "pipeline/skia/VectorDrawableAtlas.h"
+#include "renderstate/RenderState.h"
#include "renderthread/CanvasContext.h"
#include "renderthread/EglManager.h"
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
-#include "renderstate/RenderState.h"
#include "utils/Macros.h"
#include "utils/TimeUtils.h"
@@ -36,9 +36,9 @@ namespace android {
namespace uirenderer {
namespace renderthread {
-RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory)
- : mRenderThread(RenderThread::getInstance())
- , mContext(nullptr) {
+RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode,
+ IContextFactory* contextFactory)
+ : mRenderThread(RenderThread::getInstance()), mContext(nullptr) {
mContext = mRenderThread.queue().runSync([&]() -> CanvasContext* {
return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory);
});
@@ -54,17 +54,13 @@ void RenderProxy::destroyContext() {
mDrawFrameTask.setContext(nullptr, nullptr, nullptr);
// This is also a fence as we need to be certain that there are no
// outstanding mDrawFrame tasks posted before it is destroyed
- mRenderThread.queue().runSync([this]() {
- delete mContext;
- });
+ mRenderThread.queue().runSync([this]() { delete mContext; });
mContext = nullptr;
}
}
void RenderProxy::setSwapBehavior(SwapBehavior swapBehavior) {
- mRenderThread.queue().post([this, swapBehavior]() {
- mContext->setSwapBehavior(swapBehavior);
- });
+ mRenderThread.queue().post([this, swapBehavior]() { mContext->setSwapBehavior(swapBehavior); });
}
bool RenderProxy::loadSystemProperties() {
@@ -83,57 +79,42 @@ bool RenderProxy::loadSystemProperties() {
void RenderProxy::setName(const char* name) {
// block since name/value pointers owned by caller
// TODO: Support move arguments
- mRenderThread.queue().runSync([this, name]() {
- mContext->setName(std::string(name));
- });
+ mRenderThread.queue().runSync([this, name]() { mContext->setName(std::string(name)); });
}
void RenderProxy::initialize(const sp<Surface>& surface) {
- mRenderThread.queue().post([this, surf = surface]() mutable {
- mContext->setSurface(std::move(surf));
- });
+ mRenderThread.queue().post(
+ [ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); });
}
void RenderProxy::updateSurface(const sp<Surface>& surface) {
- mRenderThread.queue().post([this, surf = surface]() mutable {
- mContext->setSurface(std::move(surf));
- });
+ mRenderThread.queue().post(
+ [ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); });
}
bool RenderProxy::pauseSurface(const sp<Surface>& surface) {
- return mRenderThread.queue().runSync([this]() -> bool {
- return mContext->pauseSurface();
- });
+ return mRenderThread.queue().runSync([this]() -> bool { return mContext->pauseSurface(); });
}
void RenderProxy::setStopped(bool stopped) {
- mRenderThread.queue().runSync([this, stopped]() {
- mContext->setStopped(stopped);
- });
+ mRenderThread.queue().runSync([this, stopped]() { mContext->setStopped(stopped); });
}
void RenderProxy::setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
- mRenderThread.queue().post([=]() {
- mContext->setup(lightRadius, ambientShadowAlpha, spotShadowAlpha);
- });
+ mRenderThread.queue().post(
+ [=]() { mContext->setup(lightRadius, ambientShadowAlpha, spotShadowAlpha); });
}
void RenderProxy::setLightCenter(const Vector3& lightCenter) {
- mRenderThread.queue().post([=]() {
- mContext->setLightCenter(lightCenter);
- });
+ mRenderThread.queue().post([=]() { mContext->setLightCenter(lightCenter); });
}
void RenderProxy::setOpaque(bool opaque) {
- mRenderThread.queue().post([=]() {
- mContext->setOpaque(opaque);
- });
+ mRenderThread.queue().post([=]() { mContext->setOpaque(opaque); });
}
void RenderProxy::setWideGamut(bool wideGamut) {
- mRenderThread.queue().post([=]() {
- mContext->setWideGamut(wideGamut);
- });
+ mRenderThread.queue().post([=]() { mContext->setWideGamut(wideGamut); });
}
int64_t* RenderProxy::frameInfo() {
@@ -148,9 +129,7 @@ void RenderProxy::destroy() {
// destroyCanvasAndSurface() needs a fence as when it returns the
// underlying BufferQueue is going to be released from under
// the render thread.
- mRenderThread.queue().runSync([=]() {
- mContext->destroy();
- });
+ mRenderThread.queue().runSync([=]() { mContext->destroy(); });
}
void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
@@ -174,15 +153,12 @@ DeferredLayerUpdater* RenderProxy::createTextureLayer() {
}
void RenderProxy::buildLayer(RenderNode* node) {
- mRenderThread.queue().runSync([&]() {
- mContext->buildLayer(node);
- });
+ mRenderThread.queue().runSync([&]() { mContext->buildLayer(node); });
}
bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap) {
- return mRenderThread.queue().runSync([&]() -> bool {
- return mContext->copyLayerInto(layer, &bitmap);
- });
+ return mRenderThread.queue().runSync(
+ [&]() -> bool { return mContext->copyLayerInto(layer, &bitmap); });
}
void RenderProxy::pushLayerUpdate(DeferredLayerUpdater* layer) {
@@ -194,52 +170,41 @@ void RenderProxy::cancelLayerUpdate(DeferredLayerUpdater* layer) {
}
void RenderProxy::detachSurfaceTexture(DeferredLayerUpdater* layer) {
- return mRenderThread.queue().runSync([&]() {
- layer->detachSurfaceTexture();
- });
+ return mRenderThread.queue().runSync([&]() { layer->detachSurfaceTexture(); });
}
void RenderProxy::destroyHardwareResources() {
- return mRenderThread.queue().runSync([&]() {
- mContext->destroyHardwareResources();
- });
+ return mRenderThread.queue().runSync([&]() { mContext->destroyHardwareResources(); });
}
void RenderProxy::trimMemory(int level) {
// Avoid creating a RenderThread to do a trimMemory.
if (RenderThread::hasInstance()) {
RenderThread& thread = RenderThread::getInstance();
- thread.queue().post([&thread, level]() {
- CanvasContext::trimMemory(thread, level);
- });
+ thread.queue().post([&thread, level]() { CanvasContext::trimMemory(thread, level); });
}
}
void RenderProxy::overrideProperty(const char* name, const char* value) {
// expensive, but block here since name/value pointers owned by caller
- RenderThread::getInstance().queue().runSync([&]() {
- Properties::overrideProperty(name, value);
- });
+ RenderThread::getInstance().queue().runSync(
+ [&]() { Properties::overrideProperty(name, value); });
}
void RenderProxy::fence() {
- mRenderThread.queue().runSync([](){});
+ mRenderThread.queue().runSync([]() {});
}
void RenderProxy::staticFence() {
- RenderThread::getInstance().queue().runSync([](){});
+ RenderThread::getInstance().queue().runSync([]() {});
}
void RenderProxy::stopDrawing() {
- mRenderThread.queue().runSync([this]() {
- mContext->stopDrawing();
- });
+ mRenderThread.queue().runSync([this]() { mContext->stopDrawing(); });
}
void RenderProxy::notifyFramePending() {
- mRenderThread.queue().post([this]() {
- mContext->notifyFramePending();
- });
+ mRenderThread.queue().post([this]() { mContext->notifyFramePending(); });
}
void RenderProxy::dumpProfileInfo(int fd, int dumpFlags) {
@@ -258,9 +223,7 @@ void RenderProxy::dumpProfileInfo(int fd, int dumpFlags) {
}
void RenderProxy::resetProfileInfo() {
- mRenderThread.queue().runSync([=]() {
- mContext->resetFrameStats();
- });
+ mRenderThread.queue().runSync([=]() { mContext->resetFrameStats(); });
}
uint32_t RenderProxy::frameTimePercentile(int percentile) {
@@ -271,14 +234,12 @@ uint32_t RenderProxy::frameTimePercentile(int percentile) {
void RenderProxy::dumpGraphicsMemory(int fd) {
auto& thread = RenderThread::getInstance();
- thread.queue().runSync([&]() {
- thread.dumpGraphicsMemory(fd);
- });
+ thread.queue().runSync([&]() { thread.dumpGraphicsMemory(fd); });
}
void RenderProxy::setProcessStatsBuffer(int fd) {
auto& rt = RenderThread::getInstance();
- rt.queue().post([&rt, fd = dup(fd)]() {
+ rt.queue().post([&rt, fd = dup(fd) ]() {
rt.globalProfileData().switchStorageToAshmem(fd);
close(fd);
});
@@ -286,9 +247,7 @@ void RenderProxy::setProcessStatsBuffer(int fd) {
void RenderProxy::rotateProcessStatsBuffer() {
auto& rt = RenderThread::getInstance();
- rt.queue().post([&rt]() {
- rt.globalProfileData().rotateStorage();
- });
+ rt.queue().post([&rt]() { rt.globalProfileData().rotateStorage(); });
}
int RenderProxy::getRenderThreadTid() {
@@ -296,21 +255,15 @@ int RenderProxy::getRenderThreadTid() {
}
void RenderProxy::addRenderNode(RenderNode* node, bool placeFront) {
- mRenderThread.queue().post([=]() {
- mContext->addRenderNode(node, placeFront);
- });
+ mRenderThread.queue().post([=]() { mContext->addRenderNode(node, placeFront); });
}
void RenderProxy::removeRenderNode(RenderNode* node) {
- mRenderThread.queue().post([=]() {
- mContext->removeRenderNode(node);
- });
+ mRenderThread.queue().post([=]() { mContext->removeRenderNode(node); });
}
void RenderProxy::drawRenderNode(RenderNode* node) {
- mRenderThread.queue().runSync([=]() {
- mContext->prepareAndDraw(node);
- });
+ mRenderThread.queue().runSync([=]() { mContext->prepareAndDraw(node); });
}
void RenderProxy::setContentDrawBounds(int left, int top, int right, int bottom) {
@@ -318,25 +271,23 @@ void RenderProxy::setContentDrawBounds(int left, int top, int right, int bottom)
}
void RenderProxy::serializeDisplayListTree() {
- mRenderThread.queue().post([=]() {
- mContext->serializeDisplayListTree();
- });
+ mRenderThread.queue().post([=]() { mContext->serializeDisplayListTree(); });
}
void RenderProxy::addFrameMetricsObserver(FrameMetricsObserver* observerPtr) {
- mRenderThread.queue().post([this, observer = sp{observerPtr}]() {
+ mRenderThread.queue().post([ this, observer = sp{observerPtr} ]() {
mContext->addFrameMetricsObserver(observer.get());
});
}
void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observerPtr) {
- mRenderThread.queue().post([this, observer = sp{observerPtr}]() {
+ mRenderThread.queue().post([ this, observer = sp{observerPtr} ]() {
mContext->removeFrameMetricsObserver(observer.get());
});
}
-int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top,
- int right, int bottom, SkBitmap* bitmap) {
+int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom,
+ SkBitmap* bitmap) {
auto& thread = RenderThread::getInstance();
return static_cast<int>(thread.queue().runSync([&]() -> auto {
return thread.readback().copySurfaceInto(*surface, Rect(left, top, right, bottom), bitmap);
@@ -372,19 +323,17 @@ void RenderProxy::prepareToDraw(Bitmap& bitmap) {
sk_sp<Bitmap> RenderProxy::allocateHardwareBitmap(SkBitmap& bitmap) {
auto& thread = RenderThread::getInstance();
- return thread.queue().runSync([&]() -> auto {
- return thread.allocateHardwareBitmap(bitmap);
- });
+ return thread.queue().runSync([&]() -> auto { return thread.allocateHardwareBitmap(bitmap); });
}
int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) {
RenderThread& thread = RenderThread::getInstance();
if (Properties::isSkiaEnabled() && gettid() == thread.getTid()) {
- //TODO: fix everything that hits this. We should never be triggering a readback ourselves.
- return (int) thread.readback().copyGraphicBufferInto(buffer, bitmap);
+ // TODO: fix everything that hits this. We should never be triggering a readback ourselves.
+ return (int)thread.readback().copyGraphicBufferInto(buffer, bitmap);
} else {
return thread.queue().runSync([&]() -> int {
- return (int) thread.readback().copyGraphicBufferInto(buffer, bitmap);
+ return (int)thread.readback().copyGraphicBufferInto(buffer, bitmap);
});
}
}
@@ -392,9 +341,8 @@ int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap)
void RenderProxy::onBitmapDestroyed(uint32_t pixelRefId) {
if (!RenderThread::hasInstance()) return;
RenderThread& thread = RenderThread::getInstance();
- thread.queue().post([&thread, pixelRefId]() {
- thread.renderState().onBitmapDestroyed(pixelRefId);
- });
+ thread.queue().post(
+ [&thread, pixelRefId]() { thread.renderState().onBitmapDestroyed(pixelRefId); });
}
void RenderProxy::disableVsync() {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index b46d9cc8d926..bc57d9255ad5 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -17,16 +17,16 @@
#ifndef RENDERPROXY_H_
#define RENDERPROXY_H_
-#include <cutils/compiler.h>
#include <SkBitmap.h>
-#include <utils/Functor.h>
+#include <cutils/compiler.h>
#include <gui/Surface.h>
+#include <utils/Functor.h>
#include "../FrameMetricsObserver.h"
#include "../IContextFactory.h"
-#include "hwui/Bitmap.h"
#include "DrawFrameTask.h"
#include "SwapBehavior.h"
+#include "hwui/Bitmap.h"
namespace android {
class GraphicBuffer;
@@ -44,11 +44,11 @@ class RenderThread;
class RenderProxyBridge;
namespace DumpFlags {
- enum {
- FrameStats = 1 << 0,
- Reset = 1 << 1,
- JankStats = 1 << 2,
- };
+enum {
+ FrameStats = 1 << 0,
+ Reset = 1 << 1,
+ JankStats = 1 << 2,
+};
};
/*
@@ -73,8 +73,7 @@ public:
ANDROID_API void updateSurface(const sp<Surface>& surface);
ANDROID_API bool pauseSurface(const sp<Surface>& surface);
ANDROID_API void setStopped(bool stopped);
- ANDROID_API void setup(float lightRadius,
- uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
+ ANDROID_API void setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
ANDROID_API void setLightCenter(const Vector3& lightCenter);
ANDROID_API void setOpaque(bool opaque);
ANDROID_API void setWideGamut(bool wideGamut);
@@ -121,8 +120,8 @@ public:
ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer);
ANDROID_API long getDroppedFrameReportCount();
- ANDROID_API static int copySurfaceInto(sp<Surface>& surface,
- int left, int top, int right, int bottom, SkBitmap* bitmap);
+ ANDROID_API static int copySurfaceInto(sp<Surface>& surface, int left, int top, int right,
+ int bottom, SkBitmap* bitmap);
ANDROID_API static void prepareToDraw(Bitmap& bitmap);
static sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& bitmap);
diff --git a/libs/hwui/renderthread/RenderTask.h b/libs/hwui/renderthread/RenderTask.h
index a7acf91cbdb1..c56a3578ad58 100644
--- a/libs/hwui/renderthread/RenderTask.h
+++ b/libs/hwui/renderthread/RenderTask.h
@@ -53,7 +53,7 @@ public:
ANDROID_API virtual void run() = 0;
RenderTask* mNext;
- nsecs_t mRunAt; // nano-seconds on the SYSTEM_TIME_MONOTONIC clock
+ nsecs_t mRunAt; // nano-seconds on the SYSTEM_TIME_MONOTONIC clock
};
class SignalingRenderTask : public RenderTask {
@@ -75,8 +75,7 @@ typedef void* (*RunnableMethod)(void* data);
class MethodInvokeRenderTask : public RenderTask {
public:
- explicit MethodInvokeRenderTask(RunnableMethod method)
- : mMethod(method), mReturnPtr(nullptr) {}
+ explicit MethodInvokeRenderTask(RunnableMethod method) : mMethod(method), mReturnPtr(nullptr) {}
void* payload() { return mData; }
void setReturnPtr(void** retptr) { mReturnPtr = retptr; }
@@ -89,6 +88,7 @@ public:
// Commit suicide
delete this;
}
+
private:
RunnableMethod mMethod;
char mData[METHOD_INVOKE_PAYLOAD_SIZE];
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index f3bb120cc0fd..05a9b75b4504 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -16,17 +16,17 @@
#include "RenderThread.h"
-#include "hwui/Bitmap.h"
-#include "renderstate/RenderState.h"
-#include "renderthread/OpenGLPipeline.h"
-#include "pipeline/skia/SkiaOpenGLReadback.h"
-#include "pipeline/skia/SkiaOpenGLPipeline.h"
-#include "pipeline/skia/SkiaVulkanPipeline.h"
#include "CanvasContext.h"
#include "EglManager.h"
#include "OpenGLReadback.h"
#include "RenderProxy.h"
#include "VulkanManager.h"
+#include "hwui/Bitmap.h"
+#include "pipeline/skia/SkiaOpenGLPipeline.h"
+#include "pipeline/skia/SkiaOpenGLReadback.h"
+#include "pipeline/skia/SkiaVulkanPipeline.h"
+#include "renderstate/RenderState.h"
+#include "renderthread/OpenGLPipeline.h"
#include "utils/FatVector.h"
#include <gui/DisplayEventReceiver.h>
@@ -64,7 +64,8 @@ RenderThread& RenderThread::getInstance() {
return *sInstance;
}
-RenderThread::RenderThread() : ThreadBase()
+RenderThread::RenderThread()
+ : ThreadBase()
, mDisplayEventReceiver(nullptr)
, mVsyncRequested(false)
, mFrameCallbackTaskPending(false)
@@ -83,17 +84,18 @@ void RenderThread::initializeDisplayEventReceiver() {
LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?");
mDisplayEventReceiver = new DisplayEventReceiver();
status_t status = mDisplayEventReceiver->initCheck();
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver "
- "failed with status: %d", status);
+ LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
+ "Initialization of DisplayEventReceiver "
+ "failed with status: %d",
+ status);
// Register the FD
- mLooper->addFd(mDisplayEventReceiver->getFd(), 0,
- Looper::EVENT_INPUT, RenderThread::displayEventReceiverCallback, this);
+ mLooper->addFd(mDisplayEventReceiver->getFd(), 0, Looper::EVENT_INPUT,
+ RenderThread::displayEventReceiverCallback, this);
}
void RenderThread::initThreadLocals() {
- sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain));
+ sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo);
LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps);
@@ -133,18 +135,15 @@ void RenderThread::dumpGraphicsMemory(int fd) {
break;
}
default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
- FILE *file = fdopen(fd, "a");
- fprintf(file, "\n%s\n", cachesOutput.string());
- fprintf(file, "\nPipeline=%s\n", pipeline.string());
- fflush(file);
+ dprintf(fd, "\n%s\n", cachesOutput.string());
+ dprintf(fd, "\nPipeline=%s\n", pipeline.string());
}
Readback& RenderThread::readback() {
-
if (!mReadback) {
auto renderType = Properties::getRenderPipelineType();
switch (renderType) {
@@ -159,7 +158,7 @@ Readback& RenderThread::readback() {
mReadback = new skiapipeline::SkiaOpenGLReadback(*this);
break;
default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
}
@@ -178,19 +177,21 @@ void RenderThread::setGrContext(GrContext* context) {
int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
ALOGE("Display event receiver pipe was closed or an error occurred. "
- "events=0x%x", events);
- return 0; // remove the callback
+ "events=0x%x",
+ events);
+ return 0; // remove the callback
}
if (!(events & Looper::EVENT_INPUT)) {
ALOGW("Received spurious callback for unhandled poll event. "
- "events=0x%x", events);
- return 1; // keep the callback
+ "events=0x%x",
+ events);
+ return 1; // keep the callback
}
reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue();
- return 1; // keep the callback
+ return 1; // keep the callback
}
static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) {
@@ -201,9 +202,9 @@ static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) {
for (ssize_t i = 0; i < n; i++) {
const DisplayEventReceiver::Event& ev = buf[i];
switch (ev.header.type) {
- case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
- latest = ev.header.timestamp;
- break;
+ case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
+ latest = ev.header.timestamp;
+ break;
}
}
}
@@ -222,9 +223,7 @@ void RenderThread::drainDisplayEventQueue() {
ATRACE_NAME("queue mFrameCallbackTask");
mFrameCallbackTaskPending = true;
nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY);
- queue().postAt(runAt, [this]() {
- dispatchFrameCallbacks();
- });
+ queue().postAt(runAt, [this]() { dispatchFrameCallbacks(); });
}
}
}
@@ -240,7 +239,8 @@ void RenderThread::dispatchFrameCallbacks() {
// Assume one of them will probably animate again so preemptively
// request the next vsync in case it occurs mid-frame
requestVsync();
- for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) {
+ for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end();
+ it++) {
(*it)->doFrame();
}
}
@@ -250,8 +250,7 @@ void RenderThread::requestVsync() {
if (!mVsyncRequested) {
mVsyncRequested = true;
status_t status = mDisplayEventReceiver->requestNextVsync();
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
- "requestNextVsync failed with status: %d", status);
+ LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "requestNextVsync failed with status: %d", status);
}
}
@@ -265,8 +264,8 @@ bool RenderThread::threadLoop() {
if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
drainDisplayEventQueue();
- mFrameCallbacks.insert(
- mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end());
+ mFrameCallbacks.insert(mPendingRegistrationFrameCallbacks.begin(),
+ mPendingRegistrationFrameCallbacks.end());
mPendingRegistrationFrameCallbacks.clear();
requestVsync();
}
@@ -310,7 +309,7 @@ sk_sp<Bitmap> RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) {
case RenderPipelineType::SkiaVulkan:
return skiapipeline::SkiaVulkanPipeline::allocateHardwareBitmap(*this, skBitmap);
default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
return nullptr;
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index e1d61c5f5ee8..d17a509f6357 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -25,16 +25,16 @@
#include "thread/ThreadBase.h"
#include <GrContext.h>
-#include <cutils/compiler.h>
#include <SkBitmap.h>
+#include <cutils/compiler.h>
#include <ui/DisplayInfo.h>
#include <utils/Looper.h>
#include <utils/Thread.h>
+#include <thread/ThreadBase.h>
#include <memory>
#include <mutex>
#include <set>
-#include <thread/ThreadBase.h>
namespace android {
@@ -65,8 +65,8 @@ protected:
class RenderThread : private ThreadBase {
PREVENT_COPY_AND_ASSIGN(RenderThread);
-public:
+public:
WorkQueue& queue() { return ThreadBase::queue(); }
// Mimics android.view.Choreographer
diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp
index 6c2575f699bb..b82c5d159756 100644
--- a/libs/hwui/renderthread/TimeLord.cpp
+++ b/libs/hwui/renderthread/TimeLord.cpp
@@ -19,10 +19,7 @@ namespace android {
namespace uirenderer {
namespace renderthread {
-TimeLord::TimeLord()
- : mFrameIntervalNanos(milliseconds_to_nanoseconds(16))
- , mFrameTimeNanos(0) {
-}
+TimeLord::TimeLord() : mFrameIntervalNanos(milliseconds_to_nanoseconds(16)), mFrameTimeNanos(0) {}
bool TimeLord::vsyncReceived(nsecs_t vsync) {
if (vsync > mFrameTimeNanos) {
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 2195143658d2..a693e68afd66 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -31,11 +31,10 @@ namespace android {
namespace uirenderer {
namespace renderthread {
-#define GET_PROC(F) m ## F = (PFN_vk ## F) vkGetInstanceProcAddr(instance, "vk" #F)
-#define GET_DEV_PROC(F) m ## F = (PFN_vk ## F) vkGetDeviceProcAddr(device, "vk" #F)
+#define GET_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(instance, "vk" #F)
+#define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(device, "vk" #F)
-VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {
-}
+VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {}
void VulkanManager::destroy() {
if (!hasVkContext()) return;
@@ -51,12 +50,14 @@ void VulkanManager::destroy() {
}
void VulkanManager::initialize() {
- if (hasVkContext()) { return; }
+ if (hasVkContext()) {
+ return;
+ }
auto canPresent = [](VkInstance, VkPhysicalDevice, uint32_t) { return true; };
mBackendContext.reset(GrVkBackendContext::Create(vkGetInstanceProcAddr, vkGetDeviceProcAddr,
- &mPresentQueueIndex, canPresent));
+ &mPresentQueueIndex, canPresent));
// Get all the addresses of needed vulkan functions
VkInstance instance = mBackendContext->fInstance;
@@ -99,15 +100,18 @@ void VulkanManager::initialize() {
// this needs to be on the render queue
commandPoolInfo.queueFamilyIndex = mBackendContext->fGraphicsQueueIndex;
commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
- SkDEBUGCODE(VkResult res =) mCreateCommandPool(mBackendContext->fDevice,
- &commandPoolInfo, nullptr, &mCommandPool);
+ SkDEBUGCODE(VkResult res =) mCreateCommandPool(mBackendContext->fDevice, &commandPoolInfo,
+ nullptr, &mCommandPool);
SkASSERT(VK_SUCCESS == res);
}
mGetDeviceQueue(mBackendContext->fDevice, mPresentQueueIndex, 0, &mPresentQueue);
- mRenderThread.setGrContext(GrContext::Create(kVulkan_GrBackend,
- (GrBackendContext) mBackendContext.get()));
+ GrContextOptions options;
+ options.fDisableDistanceFieldPaths = true;
+ mRenderThread.cacheManager().configureContext(&options);
+ mRenderThread.setGrContext(
+ GrContext::Create(kVulkan_GrBackend, (GrBackendContext)mBackendContext.get(), options));
DeviceInfo::initialize(mRenderThread.getGrContext()->caps()->maxRenderTargetSize());
if (Properties::enablePartialUpdates && Properties::useBufferAge) {
@@ -127,13 +131,13 @@ VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurfa
surface->mCurrentBackbufferIndex = 0;
}
- VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers +
- surface->mCurrentBackbufferIndex;
+ VulkanSurface::BackbufferInfo* backbuffer =
+ surface->mBackbuffers + surface->mCurrentBackbufferIndex;
// Before we reuse a backbuffer, make sure its fences have all signaled so that we can safely
// reuse its commands buffers.
- VkResult res = mWaitForFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences,
- true, UINT64_MAX);
+ VkResult res =
+ mWaitForFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences, true, UINT64_MAX);
if (res != VK_SUCCESS) {
return nullptr;
}
@@ -141,7 +145,6 @@ VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurfa
return backbuffer;
}
-
SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) {
VulkanSurface::BackbufferInfo* backbuffer = getAvailableBackbuffer(surface);
SkASSERT(backbuffer);
@@ -154,7 +157,8 @@ SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) {
// The acquire will signal the attached mAcquireSemaphore. We use this to know the image has
// finished presenting and that it is safe to begin sending new commands to the returned image.
res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX,
- backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, &backbuffer->mImageIndex);
+ backbuffer->mAcquireSemaphore, VK_NULL_HANDLE,
+ &backbuffer->mImageIndex);
if (VK_ERROR_SURFACE_LOST_KHR == res) {
// need to figure out how to create a new vkSurface without the platformData*
@@ -172,7 +176,8 @@ SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) {
// acquire the image
res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX,
- backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, &backbuffer->mImageIndex);
+ backbuffer->mAcquireSemaphore, VK_NULL_HANDLE,
+ &backbuffer->mImageIndex);
if (VK_SUCCESS != res) {
return nullptr;
@@ -182,25 +187,25 @@ SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) {
// set up layout transfer from initial to color attachment
VkImageLayout layout = surface->mImageInfos[backbuffer->mImageIndex].mImageLayout;
SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout);
- VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
- VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT :
- VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout)
+ ? VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
+ : VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- VkAccessFlags srcAccessMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
- 0 : VK_ACCESS_MEMORY_READ_BIT;
+ VkAccessFlags srcAccessMask =
+ (VK_IMAGE_LAYOUT_UNDEFINED == layout) ? 0 : VK_ACCESS_MEMORY_READ_BIT;
VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VkImageMemoryBarrier imageMemoryBarrier = {
- VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
- NULL, // pNext
- srcAccessMask, // outputMask
- dstAccessMask, // inputMask
- layout, // oldLayout
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
- mPresentQueueIndex, // srcQueueFamilyIndex
- mBackendContext->fGraphicsQueueIndex, // dstQueueFamilyIndex
- surface->mImages[backbuffer->mImageIndex], // image
- { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
+ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
+ NULL, // pNext
+ srcAccessMask, // outputMask
+ dstAccessMask, // inputMask
+ layout, // oldLayout
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
+ mPresentQueueIndex, // srcQueueFamilyIndex
+ mBackendContext->fGraphicsQueueIndex, // dstQueueFamilyIndex
+ surface->mImages[backbuffer->mImageIndex], // image
+ {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // subresourceRange
};
mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[0], 0);
@@ -210,8 +215,8 @@ SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) {
info.flags = 0;
mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[0], &info);
- mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[0], srcStageMask, dstStageMask, 0,
- 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
+ mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[0], srcStageMask, dstStageMask, 0, 0,
+ nullptr, 0, nullptr, 1, &imageMemoryBarrier);
mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[0]);
@@ -235,7 +240,7 @@ SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) {
GrVkImageInfo* imageInfo;
sk_sp<SkSurface> skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface;
skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
- SkSurface::kFlushRead_BackendHandleAccess);
+ SkSurface::kFlushRead_BackendHandleAccess);
imageInfo->updateImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
surface->mBackbuffer = std::move(skSurface);
@@ -246,14 +251,14 @@ void VulkanManager::destroyBuffers(VulkanSurface* surface) {
if (surface->mBackbuffers) {
for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
mWaitForFences(mBackendContext->fDevice, 2, surface->mBackbuffers[i].mUsageFences, true,
- UINT64_MAX);
+ UINT64_MAX);
surface->mBackbuffers[i].mImageIndex = -1;
mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mAcquireSemaphore,
- nullptr);
+ nullptr);
mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mRenderSemaphore,
- nullptr);
+ nullptr);
mFreeCommandBuffers(mBackendContext->fDevice, mCommandPool, 2,
- surface->mBackbuffers[i].mTransitionCmdBuffers);
+ surface->mBackbuffers[i].mTransitionCmdBuffers);
mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[0], 0);
mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[1], 0);
}
@@ -290,11 +295,11 @@ void VulkanManager::destroySurface(VulkanSurface* surface) {
void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent) {
mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, &surface->mImageCount,
- nullptr);
+ nullptr);
SkASSERT(surface->mImageCount);
surface->mImages = new VkImage[surface->mImageCount];
- mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain,
- &surface->mImageCount, surface->mImages);
+ mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, &surface->mImageCount,
+ surface->mImages);
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
@@ -303,7 +308,7 @@ void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExt
for (uint32_t i = 0; i < surface->mImageCount; ++i) {
GrVkImageInfo info;
info.fImage = surface->mImages[i];
- info.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
+ info.fAlloc = {VK_NULL_HANDLE, 0, 0, 0};
info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
info.fFormat = format;
@@ -312,8 +317,8 @@ void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExt
GrBackendRenderTarget backendRT(extent.width, extent.height, 0, 0, info);
VulkanSurface::ImageInfo& imageInfo = surface->mImageInfos[i];
- imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget(mRenderThread.getGrContext(),
- backendRT, kTopLeft_GrSurfaceOrigin, nullptr, &props);
+ imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget(
+ mRenderThread.getGrContext(), backendRT, kTopLeft_GrSurfaceOrigin, nullptr, &props);
}
SkASSERT(mCommandPool != VK_NULL_HANDLE);
@@ -343,16 +348,16 @@ void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExt
for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
SkDEBUGCODE(VkResult res);
surface->mBackbuffers[i].mImageIndex = -1;
- SkDEBUGCODE(res = ) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
- &surface->mBackbuffers[i].mAcquireSemaphore);
- SkDEBUGCODE(res = ) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
- &surface->mBackbuffers[i].mRenderSemaphore);
- SkDEBUGCODE(res = ) mAllocateCommandBuffers(mBackendContext->fDevice, &commandBuffersInfo,
- surface->mBackbuffers[i].mTransitionCmdBuffers);
- SkDEBUGCODE(res = ) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
- &surface->mBackbuffers[i].mUsageFences[0]);
- SkDEBUGCODE(res = ) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
- &surface->mBackbuffers[i].mUsageFences[1]);
+ SkDEBUGCODE(res =) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
+ &surface->mBackbuffers[i].mAcquireSemaphore);
+ SkDEBUGCODE(res =) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
+ &surface->mBackbuffers[i].mRenderSemaphore);
+ SkDEBUGCODE(res =) mAllocateCommandBuffers(mBackendContext->fDevice, &commandBuffersInfo,
+ surface->mBackbuffers[i].mTransitionCmdBuffers);
+ SkDEBUGCODE(res =) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
+ &surface->mBackbuffers[i].mUsageFences[0]);
+ SkDEBUGCODE(res =) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
+ &surface->mBackbuffers[i].mUsageFences[1]);
SkASSERT(VK_SUCCESS == res);
}
surface->mCurrentBackbufferIndex = surface->mImageCount;
@@ -362,35 +367,36 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) {
// check for capabilities
VkSurfaceCapabilitiesKHR caps;
VkResult res = mGetPhysicalDeviceSurfaceCapabilitiesKHR(mBackendContext->fPhysicalDevice,
- surface->mVkSurface, &caps);
+ surface->mVkSurface, &caps);
if (VK_SUCCESS != res) {
return false;
}
uint32_t surfaceFormatCount;
res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface,
- &surfaceFormatCount, nullptr);
+ &surfaceFormatCount, nullptr);
if (VK_SUCCESS != res) {
return false;
}
FatVector<VkSurfaceFormatKHR, 4> surfaceFormats(surfaceFormatCount);
res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface,
- &surfaceFormatCount, surfaceFormats.data());
+ &surfaceFormatCount, surfaceFormats.data());
if (VK_SUCCESS != res) {
return false;
}
uint32_t presentModeCount;
res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice,
- surface->mVkSurface, &presentModeCount, nullptr);
+ surface->mVkSurface, &presentModeCount, nullptr);
if (VK_SUCCESS != res) {
return false;
}
FatVector<VkPresentModeKHR, VK_PRESENT_MODE_RANGE_SIZE_KHR> presentModes(presentModeCount);
res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice,
- surface->mVkSurface, &presentModeCount, presentModes.data());
+ surface->mVkSurface, &presentModeCount,
+ presentModes.data());
if (VK_SUCCESS != res) {
return false;
}
@@ -420,12 +426,12 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) {
VK_IMAGE_USAGE_TRANSFER_DST_BIT;
SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
SkASSERT(caps.supportedTransforms & caps.currentTransform);
- SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
- VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
+ SkASSERT(caps.supportedCompositeAlpha &
+ (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
VkCompositeAlphaFlagBitsKHR composite_alpha =
- (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ?
- VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR :
- VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+ (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
+ ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
+ : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
// Pick our surface format. For now, just make sure it matches our sRGB request:
VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
@@ -470,7 +476,7 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) {
swapchainCreateInfo.imageArrayLayers = 1;
swapchainCreateInfo.imageUsage = usageFlags;
- uint32_t queueFamilies[] = { mBackendContext->fGraphicsQueueIndex, mPresentQueueIndex };
+ uint32_t queueFamilies[] = {mBackendContext->fGraphicsQueueIndex, mPresentQueueIndex};
if (mBackendContext->fGraphicsQueueIndex != mPresentQueueIndex) {
swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
swapchainCreateInfo.queueFamilyIndexCount = 2;
@@ -488,7 +494,7 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) {
swapchainCreateInfo.oldSwapchain = surface->mSwapchain;
res = mCreateSwapchainKHR(mBackendContext->fDevice, &swapchainCreateInfo, nullptr,
- &surface->mSwapchain);
+ &surface->mSwapchain);
if (VK_SUCCESS != res) {
return false;
}
@@ -507,7 +513,6 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) {
return true;
}
-
VulkanSurface* VulkanManager::createSurface(ANativeWindow* window) {
initialize();
@@ -524,21 +529,20 @@ VulkanSurface* VulkanManager::createSurface(ANativeWindow* window) {
surfaceCreateInfo.flags = 0;
surfaceCreateInfo.window = window;
- VkResult res = mCreateAndroidSurfaceKHR(mBackendContext->fInstance, &surfaceCreateInfo,
- nullptr, &surface->mVkSurface);
+ VkResult res = mCreateAndroidSurfaceKHR(mBackendContext->fInstance, &surfaceCreateInfo, nullptr,
+ &surface->mVkSurface);
if (VK_SUCCESS != res) {
delete surface;
return nullptr;
}
-SkDEBUGCODE(
- VkBool32 supported;
- res = mGetPhysicalDeviceSurfaceSupportKHR(mBackendContext->fPhysicalDevice,
- mPresentQueueIndex, surface->mVkSurface, &supported);
- // All physical devices and queue families on Android must be capable of presentation with any
- // native window.
- SkASSERT(VK_SUCCESS == res && supported);
-);
+ SkDEBUGCODE(VkBool32 supported; res = mGetPhysicalDeviceSurfaceSupportKHR(
+ mBackendContext->fPhysicalDevice, mPresentQueueIndex,
+ surface->mVkSurface, &supported);
+ // All physical devices and queue families on Android must be capable of
+ // presentation with any
+ // native window.
+ SkASSERT(VK_SUCCESS == res && supported););
if (!createSwapchain(surface)) {
destroySurface(surface);
@@ -573,11 +577,9 @@ static VkAccessFlags layoutToSrcAccessMask(const VkImageLayout layout) {
VkAccessFlags flags = 0;
if (VK_IMAGE_LAYOUT_GENERAL == layout) {
flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
- VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
- VK_ACCESS_TRANSFER_WRITE_BIT |
- VK_ACCESS_TRANSFER_READ_BIT |
- VK_ACCESS_SHADER_READ_BIT |
- VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_HOST_READ_BIT;
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT |
+ VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_HOST_WRITE_BIT |
+ VK_ACCESS_HOST_READ_BIT;
} else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
flags = VK_ACCESS_HOST_WRITE_BIT;
} else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
@@ -600,12 +602,13 @@ void VulkanManager::swapBuffers(VulkanSurface* surface) {
mDeviceWaitIdle(mBackendContext->fDevice);
}
- VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers +
- surface->mCurrentBackbufferIndex;
+ SkASSERT(surface->mBackbuffers);
+ VulkanSurface::BackbufferInfo* backbuffer =
+ surface->mBackbuffers + surface->mCurrentBackbufferIndex;
GrVkImageInfo* imageInfo;
SkSurface* skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface.get();
skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
- SkSurface::kFlushRead_BackendHandleAccess);
+ SkSurface::kFlushRead_BackendHandleAccess);
// Check to make sure we never change the actually wrapped image
SkASSERT(imageInfo->fImage == surface->mImages[backbuffer->mImageIndex]);
@@ -618,16 +621,16 @@ void VulkanManager::swapBuffers(VulkanSurface* surface) {
VkAccessFlags dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
VkImageMemoryBarrier imageMemoryBarrier = {
- VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
- NULL, // pNext
- srcAccessMask, // outputMask
- dstAccessMask, // inputMask
- layout, // oldLayout
- VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout
- mBackendContext->fGraphicsQueueIndex, // srcQueueFamilyIndex
- mPresentQueueIndex, // dstQueueFamilyIndex
- surface->mImages[backbuffer->mImageIndex], // image
- { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
+ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
+ NULL, // pNext
+ srcAccessMask, // outputMask
+ dstAccessMask, // inputMask
+ layout, // oldLayout
+ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout
+ mBackendContext->fGraphicsQueueIndex, // srcQueueFamilyIndex
+ mPresentQueueIndex, // dstQueueFamilyIndex
+ surface->mImages[backbuffer->mImageIndex], // image
+ {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // subresourceRange
};
mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[1], 0);
@@ -636,8 +639,8 @@ void VulkanManager::swapBuffers(VulkanSurface* surface) {
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags = 0;
mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[1], &info);
- mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[1], srcStageMask, dstStageMask, 0,
- 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
+ mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[1], srcStageMask, dstStageMask, 0, 0,
+ nullptr, 0, nullptr, 1, &imageMemoryBarrier);
mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[1]);
surface->mImageInfos[backbuffer->mImageIndex].mImageLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
@@ -661,16 +664,15 @@ void VulkanManager::swapBuffers(VulkanSurface* surface) {
// Submit present operation to present queue. We use a semaphore here to make sure all rendering
// to the image is complete and that the layout has been change to present on the graphics
// queue.
- const VkPresentInfoKHR presentInfo =
- {
- VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
- NULL, // pNext
- 1, // waitSemaphoreCount
- &backbuffer->mRenderSemaphore, // pWaitSemaphores
- 1, // swapchainCount
- &surface->mSwapchain, // pSwapchains
- &backbuffer->mImageIndex, // pImageIndices
- NULL // pResults
+ const VkPresentInfoKHR presentInfo = {
+ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
+ NULL, // pNext
+ 1, // waitSemaphoreCount
+ &backbuffer->mRenderSemaphore, // pWaitSemaphores
+ 1, // swapchainCount
+ &surface->mSwapchain, // pSwapchains
+ &backbuffer->mImageIndex, // pImageIndices
+ NULL // pResults
};
mQueuePresentKHR(mPresentQueue, &presentInfo);
@@ -682,10 +684,11 @@ void VulkanManager::swapBuffers(VulkanSurface* surface) {
}
int VulkanManager::getAge(VulkanSurface* surface) {
- VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers +
- surface->mCurrentBackbufferIndex;
- if (mSwapBehavior == SwapBehavior::Discard
- || surface->mImageInfos[backbuffer->mImageIndex].mInvalid) {
+ SkASSERT(surface->mBackbuffers);
+ VulkanSurface::BackbufferInfo* backbuffer =
+ surface->mBackbuffers + surface->mCurrentBackbufferIndex;
+ if (mSwapBehavior == SwapBehavior::Discard ||
+ surface->mImageInfos[backbuffer->mImageIndex].mInvalid) {
return 0;
}
uint16_t lastUsed = surface->mImageInfos[backbuffer->mImageIndex].mLastUsed;
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index d225b3fc4ec0..c319c9ec209f 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -37,13 +37,14 @@ public:
private:
friend class VulkanManager;
struct BackbufferInfo {
- uint32_t mImageIndex; // image this is associated with
- VkSemaphore mAcquireSemaphore; // we signal on this for acquisition of image
- VkSemaphore mRenderSemaphore; // we wait on this for rendering to be done
- VkCommandBuffer mTransitionCmdBuffers[2]; // to transition layout between present and render
+ uint32_t mImageIndex; // image this is associated with
+ VkSemaphore mAcquireSemaphore; // we signal on this for acquisition of image
+ VkSemaphore mRenderSemaphore; // we wait on this for rendering to be done
+ VkCommandBuffer
+ mTransitionCmdBuffers[2]; // to transition layout between present and render
// We use these fences to make sure the above Command buffers have finished their work
// before attempting to reuse them or destroy them.
- VkFence mUsageFences[2];
+ VkFence mUsageFences[2];
};
struct ImageInfo {
@@ -58,11 +59,11 @@ private:
VkSurfaceKHR mVkSurface = VK_NULL_HANDLE;
VkSwapchainKHR mSwapchain = VK_NULL_HANDLE;
- BackbufferInfo* mBackbuffers;
+ BackbufferInfo* mBackbuffers = nullptr;
uint32_t mCurrentBackbufferIndex;
uint32_t mImageCount;
- VkImage* mImages;
+ VkImage* mImages = nullptr;
ImageInfo* mImageInfos;
uint16_t mCurrentTime = 0;
};
@@ -118,11 +119,16 @@ private:
VulkanSurface::BackbufferInfo* getAvailableBackbuffer(VulkanSurface* surface);
// simple wrapper class that exists only to initialize a pointer to NULL
- template <typename FNPTR_TYPE> class VkPtr {
+ template <typename FNPTR_TYPE>
+ class VkPtr {
public:
VkPtr() : fPtr(NULL) {}
- VkPtr operator=(FNPTR_TYPE ptr) { fPtr = ptr; return *this; }
+ VkPtr operator=(FNPTR_TYPE ptr) {
+ fPtr = ptr;
+ return *this;
+ }
operator FNPTR_TYPE() const { return fPtr; }
+
private:
FNPTR_TYPE fPtr;
};
@@ -183,4 +189,3 @@ private:
} /* namespace android */
#endif /* VULKANMANAGER_H */
-
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index f7a90b0a65ec..3ac1a454bf28 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -25,10 +25,10 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
-#include <sys/mman.h>
namespace android {
namespace uirenderer {
@@ -42,8 +42,8 @@ static_assert(sizeof(sCurrentFileVersion) == sHeaderSize, "Header size is wrong"
constexpr int sHistogramSize = ProfileData::HistogramSize();
static bool mergeProfileDataIntoProto(service::GraphicsStatsProto* proto,
- const std::string& package, int versionCode, int64_t startTime, int64_t endTime,
- const ProfileData* data);
+ const std::string& package, int versionCode,
+ int64_t startTime, int64_t endTime, const ProfileData* data);
static void dumpAsTextToFd(service::GraphicsStatsProto* proto, int outFd);
class FileDescriptor {
@@ -57,6 +57,7 @@ public:
}
bool valid() { return mFd != -1; }
operator int() { return mFd; }
+
private:
int mFd;
};
@@ -68,21 +69,13 @@ public:
int GetErrno() { return mCopyAdapter.mErrno; }
- virtual bool Next(void** data, int* size) override {
- return mImpl.Next(data, size);
- }
+ virtual bool Next(void** data, int* size) override { return mImpl.Next(data, size); }
- virtual void BackUp(int count) override {
- mImpl.BackUp(count);
- }
+ virtual void BackUp(int count) override { mImpl.BackUp(count); }
- virtual int64 ByteCount() const override {
- return mImpl.ByteCount();
- }
+ virtual int64 ByteCount() const override { return mImpl.ByteCount(); }
- bool Flush() {
- return mImpl.Flush();
- }
+ bool Flush() { return mImpl.Flush(); }
private:
struct FDAdapter : public io::CopyingOutputStream {
@@ -95,7 +88,7 @@ private:
virtual bool Write(const void* buffer, int size) override {
int ret;
while (size) {
- ret = TEMP_FAILURE_RETRY( write(mFd, buffer, size) );
+ ret = TEMP_FAILURE_RETRY(write(mFd, buffer, size));
if (ret <= 0) {
mErrno = errno;
return false;
@@ -110,8 +103,8 @@ private:
io::CopyingOutputStreamAdaptor mImpl;
};
-bool GraphicsStatsService::parseFromFile(const std::string& path, service::GraphicsStatsProto* output) {
-
+bool GraphicsStatsService::parseFromFile(const std::string& path,
+ service::GraphicsStatsProto* output) {
FileDescriptor fd{open(path.c_str(), O_RDONLY)};
if (!fd.valid()) {
int err = errno;
@@ -129,7 +122,7 @@ bool GraphicsStatsService::parseFromFile(const std::string& path, service::Graph
// we get an unexpected error
if (err != ENOENT) {
ALOGW("Failed to fstat '%s', errno=%d (%s) (st_size %d)", path.c_str(), err,
- strerror(err), (int) sb.st_size);
+ strerror(err), (int)sb.st_size);
}
return false;
}
@@ -154,14 +147,15 @@ bool GraphicsStatsService::parseFromFile(const std::string& path, service::Graph
io::ArrayInputStream input{data, dataSize};
bool success = output->ParseFromZeroCopyStream(&input);
if (!success) {
- ALOGW("Parse failed on '%s' error='%s'",
- path.c_str(), output->InitializationErrorString().c_str());
+ ALOGW("Parse failed on '%s' error='%s'", path.c_str(),
+ output->InitializationErrorString().c_str());
}
return success;
}
bool mergeProfileDataIntoProto(service::GraphicsStatsProto* proto, const std::string& package,
- int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data) {
+ int versionCode, int64_t startTime, int64_t endTime,
+ const ProfileData* data) {
if (proto->stats_start() == 0 || proto->stats_start() > startTime) {
proto->set_stats_start(startTime);
}
@@ -173,24 +167,23 @@ bool mergeProfileDataIntoProto(service::GraphicsStatsProto* proto, const std::st
auto summary = proto->mutable_summary();
summary->set_total_frames(summary->total_frames() + data->totalFrameCount());
summary->set_janky_frames(summary->janky_frames() + data->jankFrameCount());
- summary->set_missed_vsync_count(
- summary->missed_vsync_count() + data->jankTypeCount(kMissedVsync));
- summary->set_high_input_latency_count(
- summary->high_input_latency_count() + data->jankTypeCount(kHighInputLatency));
- summary->set_slow_ui_thread_count(
- summary->slow_ui_thread_count() + data->jankTypeCount(kSlowUI));
- summary->set_slow_bitmap_upload_count(
- summary->slow_bitmap_upload_count() + data->jankTypeCount(kSlowSync));
- summary->set_slow_draw_count(
- summary->slow_draw_count() + data->jankTypeCount(kSlowRT));
+ summary->set_missed_vsync_count(summary->missed_vsync_count() +
+ data->jankTypeCount(kMissedVsync));
+ summary->set_high_input_latency_count(summary->high_input_latency_count() +
+ data->jankTypeCount(kHighInputLatency));
+ summary->set_slow_ui_thread_count(summary->slow_ui_thread_count() +
+ data->jankTypeCount(kSlowUI));
+ summary->set_slow_bitmap_upload_count(summary->slow_bitmap_upload_count() +
+ data->jankTypeCount(kSlowSync));
+ summary->set_slow_draw_count(summary->slow_draw_count() + data->jankTypeCount(kSlowRT));
bool creatingHistogram = false;
if (proto->histogram_size() == 0) {
proto->mutable_histogram()->Reserve(sHistogramSize);
creatingHistogram = true;
} else if (proto->histogram_size() != sHistogramSize) {
- ALOGE("Histogram size mismatch, proto is %d expected %d",
- proto->histogram_size(), sHistogramSize);
+ ALOGE("Histogram size mismatch, proto is %d expected %d", proto->histogram_size(),
+ sHistogramSize);
return false;
}
int index = 0;
@@ -205,7 +198,8 @@ bool mergeProfileDataIntoProto(service::GraphicsStatsProto* proto, const std::st
} else {
bucket = proto->mutable_histogram(index);
if (bucket->render_millis() != static_cast<int32_t>(entry.renderTimeMs)) {
- ALOGW("Frame time mistmatch %d vs. %u", bucket->render_millis(), entry.renderTimeMs);
+ ALOGW("Frame time mistmatch %d vs. %u", bucket->render_millis(),
+ entry.renderTimeMs);
hitMergeError = true;
return;
}
@@ -232,7 +226,7 @@ void dumpAsTextToFd(service::GraphicsStatsProto* proto, int fd) {
// This isn't a full validation, just enough that we can deref at will
if (proto->package_name().empty() || !proto->has_summary()) {
ALOGW("Skipping dump, invalid package_name() '%s' or summary %d",
- proto->package_name().c_str(), proto->has_summary());
+ proto->package_name().c_str(), proto->has_summary());
return;
}
dprintf(fd, "\nPackage: %s", proto->package_name().c_str());
@@ -242,7 +236,7 @@ void dumpAsTextToFd(service::GraphicsStatsProto* proto, int fd) {
auto summary = proto->summary();
dprintf(fd, "\nTotal frames rendered: %d", summary.total_frames());
dprintf(fd, "\nJanky frames: %d (%.2f%%)", summary.janky_frames(),
- (float) summary.janky_frames() / (float) summary.total_frames() * 100.0f);
+ (float)summary.janky_frames() / (float)summary.total_frames() * 100.0f);
dprintf(fd, "\n50th percentile: %dms", findPercentile(proto, 50));
dprintf(fd, "\n90th percentile: %dms", findPercentile(proto, 90));
dprintf(fd, "\n95th percentile: %dms", findPercentile(proto, 95));
@@ -260,7 +254,8 @@ void dumpAsTextToFd(service::GraphicsStatsProto* proto, int fd) {
}
void GraphicsStatsService::saveBuffer(const std::string& path, const std::string& package,
- int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data) {
+ int versionCode, int64_t startTime, int64_t endTime,
+ const ProfileData* data) {
service::GraphicsStatsProto statsProto;
if (!parseFromFile(path, &statsProto)) {
statsProto.Clear();
@@ -275,8 +270,8 @@ void GraphicsStatsService::saveBuffer(const std::string& path, const std::string
return;
}
if (statsProto.package_name().empty() || !statsProto.has_summary()) {
- ALOGE("missing package_name() '%s' summary %d",
- statsProto.package_name().c_str(), statsProto.has_summary());
+ ALOGE("missing package_name() '%s' summary %d", statsProto.package_name().c_str(),
+ statsProto.has_summary());
return;
}
int outFd = open(path.c_str(), O_CREAT | O_RDWR | O_TRUNC, 0660);
@@ -288,8 +283,8 @@ void GraphicsStatsService::saveBuffer(const std::string& path, const std::string
int wrote = write(outFd, &sCurrentFileVersion, sHeaderSize);
if (wrote != sHeaderSize) {
int err = errno;
- ALOGW("Failed to write header to '%s', returned=%d errno=%d (%s)",
- path.c_str(), wrote, err, strerror(err));
+ ALOGW("Failed to write header to '%s', returned=%d errno=%d (%s)", path.c_str(), wrote, err,
+ strerror(err));
close(outFd);
return;
}
@@ -297,8 +292,8 @@ void GraphicsStatsService::saveBuffer(const std::string& path, const std::string
FileOutputStreamLite output(outFd);
bool success = statsProto.SerializeToZeroCopyStream(&output) && output.Flush();
if (output.GetErrno() != 0) {
- ALOGW("Error writing to fd=%d, path='%s' err=%d (%s)",
- outFd, path.c_str(), output.GetErrno(), strerror(output.GetErrno()));
+ ALOGW("Error writing to fd=%d, path='%s' err=%d (%s)", outFd, path.c_str(),
+ output.GetErrno(), strerror(output.GetErrno()));
success = false;
} else if (!success) {
ALOGW("Serialize failed on '%s' unknown error", path.c_str());
@@ -313,6 +308,7 @@ public:
int fd() { return mFd; }
DumpType type() { return mType; }
service::GraphicsStatsServiceDumpProto& proto() { return mProto; }
+
private:
int mFd;
DumpType mType;
@@ -323,19 +319,20 @@ GraphicsStatsService::Dump* GraphicsStatsService::createDump(int outFd, DumpType
return new Dump(outFd, type);
}
-void GraphicsStatsService::addToDump(Dump* dump, const std::string& path, const std::string& package,
- int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data) {
+void GraphicsStatsService::addToDump(Dump* dump, const std::string& path,
+ const std::string& package, int versionCode, int64_t startTime,
+ int64_t endTime, const ProfileData* data) {
service::GraphicsStatsProto statsProto;
if (!path.empty() && !parseFromFile(path, &statsProto)) {
statsProto.Clear();
}
- if (data && !mergeProfileDataIntoProto(
- &statsProto, package, versionCode, startTime, endTime, data)) {
+ if (data &&
+ !mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data)) {
return;
}
if (!statsProto.IsInitialized()) {
ALOGW("Failed to load profile data from path '%s' and data %p",
- path.empty() ? "<empty>" : path.c_str(), data);
+ path.empty() ? "<empty>" : path.c_str(), data);
return;
}
diff --git a/libs/hwui/service/GraphicsStatsService.h b/libs/hwui/service/GraphicsStatsService.h
index d0fd60ee1aba..7ddc219463f8 100644
--- a/libs/hwui/service/GraphicsStatsService.h
+++ b/libs/hwui/service/GraphicsStatsService.h
@@ -44,11 +44,13 @@ public:
};
ANDROID_API static void saveBuffer(const std::string& path, const std::string& package,
- int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data);
+ int 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, int64_t startTime, int64_t endTime, const ProfileData* data);
+ ANDROID_API static void addToDump(Dump* dump, const std::string& path,
+ const std::string& package, int 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/BitmapAllocationTestUtils.h b/libs/hwui/tests/common/BitmapAllocationTestUtils.h
index 2988979cc266..312b60bbc067 100644
--- a/libs/hwui/tests/common/BitmapAllocationTestUtils.h
+++ b/libs/hwui/tests/common/BitmapAllocationTestUtils.h
@@ -27,17 +27,17 @@ namespace test {
class BitmapAllocationTestUtils {
public:
- static sk_sp<Bitmap> allocateHeapBitmap(int width, int height,
- SkColorType colorType, std::function<void(SkBitmap& bitmap)> setup) {
- sk_sp<Bitmap> bitmap = TestUtils::createBitmap(width, height, colorType);
- SkBitmap skBitmap;
- bitmap->getSkBitmap(&skBitmap);
- setup(skBitmap);
- return bitmap;
+ static sk_sp<Bitmap> allocateHeapBitmap(int width, int height, SkColorType colorType,
+ std::function<void(SkBitmap& bitmap)> setup) {
+ sk_sp<Bitmap> bitmap = TestUtils::createBitmap(width, height, colorType);
+ SkBitmap skBitmap;
+ bitmap->getSkBitmap(&skBitmap);
+ setup(skBitmap);
+ return bitmap;
}
- static sk_sp<Bitmap> allocateHardwareBitmap(int width, int height,
- SkColorType colorType, std::function<void(SkBitmap& bitmap)> setup) {
+ static sk_sp<Bitmap> allocateHardwareBitmap(int width, int height, SkColorType colorType,
+ std::function<void(SkBitmap& bitmap)> setup) {
SkBitmap skBitmap;
SkImageInfo info = SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType);
skBitmap.setInfo(info);
@@ -46,8 +46,8 @@ public:
return Bitmap::allocateHardwareBitmap(skBitmap);
}
- typedef sk_sp<Bitmap> (*BitmapAllocator) (int, int, SkColorType,
- std::function<void(SkBitmap& bitmap)> setup);
+ typedef sk_sp<Bitmap> (*BitmapAllocator)(int, int, SkColorType,
+ std::function<void(SkBitmap& bitmap)> setup);
template <class T, BitmapAllocator allocator>
static test::TestScene* createBitmapAllocationScene(const TestScene::Options&) {
@@ -55,22 +55,16 @@ public:
}
template <class BaseScene>
- static bool registerBitmapAllocationScene(std::string name, std::string description) {
- TestScene::registerScene({
- name + "GlTex",
- description + " (GlTex version).",
- createBitmapAllocationScene<BaseScene, &allocateHeapBitmap>
- });
+ static bool registerBitmapAllocationScene(std::string name, std::string description) {
+ TestScene::registerScene({name + "GlTex", description + " (GlTex version).",
+ createBitmapAllocationScene<BaseScene, &allocateHeapBitmap>});
- TestScene::registerScene({
- name + "EglImage",
- description + " (EglImage version).",
- createBitmapAllocationScene<BaseScene, &allocateHardwareBitmap>
- });
+ TestScene::registerScene({name + "EglImage", description + " (EglImage version).",
+ createBitmapAllocationScene<BaseScene, &allocateHardwareBitmap>});
return true;
}
};
-} // namespace test
-} // namespace uirenderer
-} // namespace android
+} // namespace test
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/common/LeakChecker.cpp b/libs/hwui/tests/common/LeakChecker.cpp
index fe38ec958527..5b361548eeda 100644
--- a/libs/hwui/tests/common/LeakChecker.cpp
+++ b/libs/hwui/tests/common/LeakChecker.cpp
@@ -19,10 +19,10 @@
#include "Caches.h"
#include "TestUtils.h"
-#include <cstdio>
-#include <iostream>
#include <memunreachable/memunreachable.h>
#include <unistd.h>
+#include <cstdio>
+#include <iostream>
#include <unordered_set>
using namespace std;
@@ -45,12 +45,12 @@ static void logUnreachable(initializer_list<UnreachableMemoryInfo> infolist) {
merged.allocation_bytes = max(merged.allocation_bytes, info.allocation_bytes);
merged.num_allocations = max(merged.num_allocations, info.num_allocations);
for (auto& leak : info.leaks) {
- if (addrs.find(leak.begin) == addrs.end()) {
- merged.leaks.push_back(leak);
- merged.num_leaks++;
- merged.leak_bytes += leak.size;
- addrs.insert(leak.begin);
- }
+ if (addrs.find(leak.begin) == addrs.end()) {
+ merged.leaks.push_back(leak);
+ merged.num_leaks++;
+ merged.leak_bytes += leak.size;
+ addrs.insert(leak.begin);
+ }
}
}
@@ -59,7 +59,7 @@ static void logUnreachable(initializer_list<UnreachableMemoryInfo> infolist) {
cout << endl << "Leaked memory!" << endl;
if (!merged.leaks[0].backtrace.num_frames) {
cout << "Re-run with 'export LIBC_DEBUG_MALLOC_OPTIONS=backtrace' to get backtraces"
- << endl;
+ << endl;
}
cout << merged.ToString(false);
}
diff --git a/libs/hwui/tests/common/LeakChecker.h b/libs/hwui/tests/common/LeakChecker.h
index cdf47d6bda80..e43df177cdba 100644
--- a/libs/hwui/tests/common/LeakChecker.h
+++ b/libs/hwui/tests/common/LeakChecker.h
@@ -22,7 +22,7 @@ namespace test {
class LeakChecker {
public:
static void checkForLeaks();
-}; // class TestUtils
+}; // class TestUtils
} /* namespace test */
} /* namespace uirenderer */
diff --git a/libs/hwui/tests/common/TestContext.cpp b/libs/hwui/tests/common/TestContext.cpp
index 1e30d23801e6..92b6cbdfc613 100644
--- a/libs/hwui/tests/common/TestContext.cpp
+++ b/libs/hwui/tests/common/TestContext.cpp
@@ -24,24 +24,23 @@ namespace test {
static const int IDENT_DISPLAYEVENT = 1;
-static android::DisplayInfo DUMMY_DISPLAY {
- 1080, //w
- 1920, //h
- 320.0, // xdpi
- 320.0, // ydpi
- 60.0, // fps
- 2.0, // density
- 0, // orientation
- false, // secure?
- 0, // appVsyncOffset
- 0, // presentationDeadline
+static android::DisplayInfo DUMMY_DISPLAY{
+ 1080, // w
+ 1920, // h
+ 320.0, // xdpi
+ 320.0, // ydpi
+ 60.0, // fps
+ 2.0, // density
+ 0, // orientation
+ false, // secure?
+ 0, // appVsyncOffset
+ 0, // presentationDeadline
};
DisplayInfo getBuiltInDisplay() {
#if !HWUI_NULL_GPU
DisplayInfo display;
- sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain));
+ sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &display);
LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
return display;
@@ -56,8 +55,8 @@ android::DisplayInfo gDisplay = DUMMY_DISPLAY;
TestContext::TestContext() {
mLooper = new Looper(true);
mSurfaceComposerClient = new SurfaceComposerClient();
- mLooper->addFd(mDisplayEventReceiver.getFd(), IDENT_DISPLAYEVENT,
- Looper::EVENT_INPUT, nullptr, nullptr);
+ mLooper->addFd(mDisplayEventReceiver.getFd(), IDENT_DISPLAYEVENT, Looper::EVENT_INPUT, nullptr,
+ nullptr);
}
TestContext::~TestContext() {}
@@ -78,13 +77,11 @@ void TestContext::createSurface() {
}
void TestContext::createWindowSurface() {
- mSurfaceControl = mSurfaceComposerClient->createSurface(String8("HwuiTest"),
- gDisplay.w, gDisplay.h, PIXEL_FORMAT_RGBX_8888);
+ mSurfaceControl = mSurfaceComposerClient->createSurface(String8("HwuiTest"), gDisplay.w,
+ gDisplay.h, PIXEL_FORMAT_RGBX_8888);
SurfaceComposerClient::Transaction t;
- t.setLayer(mSurfaceControl, 0x7FFFFFF)
- .show(mSurfaceControl)
- .apply();
+ t.setLayer(mSurfaceControl, 0x7FFFFFF).show(mSurfaceControl).apply();
mSurface = mSurfaceControl->getSurface();
}
@@ -124,10 +121,11 @@ void TestContext::waitForVsync() {
// Drain it
DisplayEventReceiver::Event buf[100];
- while (mDisplayEventReceiver.getEvents(buf, 100) > 0) { }
+ while (mDisplayEventReceiver.getEvents(buf, 100) > 0) {
+ }
#endif
}
-} // namespace test
-} // namespace uirenderer
-} // namespace android
+} // namespace test
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/common/TestContext.h b/libs/hwui/tests/common/TestContext.h
index 312988b968de..0996f4dc706e 100644
--- a/libs/hwui/tests/common/TestContext.h
+++ b/libs/hwui/tests/common/TestContext.h
@@ -17,24 +17,24 @@
#ifndef TESTCONTEXT_H
#define TESTCONTEXT_H
+#include <gui/BufferItemConsumer.h>
#include <gui/DisplayEventReceiver.h>
#include <gui/ISurfaceComposer.h>
-#include <gui/BufferItemConsumer.h>
+#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceControl.h>
-#include <gui/Surface.h>
#include <ui/DisplayInfo.h>
#include <utils/Looper.h>
-#include <thread>
#include <atomic>
+#include <thread>
namespace android {
namespace uirenderer {
namespace test {
extern DisplayInfo gDisplay;
-#define dp(x) ((x) * android::uirenderer::test::gDisplay.density)
+#define dp(x) ((x)*android::uirenderer::test::gDisplay.density)
DisplayInfo getBuiltInDisplay();
@@ -45,8 +45,7 @@ public:
// Must be called before surface();
void setRenderOffscreen(bool renderOffscreen) {
- LOG_ALWAYS_FATAL_IF(mSurface.get(),
- "Must be called before surface is created");
+ LOG_ALWAYS_FATAL_IF(mSurface.get(), "Must be called before surface is created");
mRenderOffscreen = renderOffscreen;
}
@@ -68,8 +67,8 @@ private:
bool mRenderOffscreen;
};
-} // namespace test
-} // namespace uirenderer
-} // namespace android
+} // namespace test
+} // namespace uirenderer
+} // namespace android
#endif
diff --git a/libs/hwui/tests/common/TestListViewSceneBase.cpp b/libs/hwui/tests/common/TestListViewSceneBase.cpp
index 38c4848ebc41..a7f4d4d3991f 100644
--- a/libs/hwui/tests/common/TestListViewSceneBase.cpp
+++ b/libs/hwui/tests/common/TestListViewSceneBase.cpp
@@ -35,17 +35,17 @@ void TestListViewSceneBase::createContent(int width, int height, Canvas& canvas)
for (int y = 0; y < height + (heightWithSpacing - 1); y += heightWithSpacing) {
int id = mListItems.size();
auto setup = std::bind(&TestListViewSceneBase::createListItem, this, std::placeholders::_1,
- std::placeholders::_2, id, mItemWidth, mItemHeight);
- auto node = TestUtils::createNode(mItemLeft, y, mItemLeft + mItemWidth,
- y + mItemHeight, setup);
+ std::placeholders::_2, id, mItemWidth, mItemHeight);
+ auto node =
+ TestUtils::createNode(mItemLeft, y, mItemLeft + mItemWidth, y + mItemHeight, setup);
mListItems.push_back(node);
}
mListView = TestUtils::createNode(0, 0, width, height,
- [this](RenderProperties& props, Canvas& canvas) {
- for (size_t ci = 0; ci < mListItems.size(); ci++) {
- canvas.drawRenderNode(mListItems[ci].get());
- }
- });
+ [this](RenderProperties& props, Canvas& canvas) {
+ for (size_t ci = 0; ci < mListItems.size(); ci++) {
+ canvas.drawRenderNode(mListItems[ci].get());
+ }
+ });
canvas.drawColor(Color::Grey_500, SkBlendMode::kSrcOver);
canvas.drawRenderNode(mListView.get());
@@ -56,8 +56,8 @@ void TestListViewSceneBase::doFrame(int frameNr) {
int itemIndexOffset = scrollPx / (mItemSpacing + mItemHeight);
int pxOffset = -(scrollPx % (mItemSpacing + mItemHeight));
- std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(mListView->stagingProperties().getWidth(),
- mListView->stagingProperties().getHeight()));
+ std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
+ mListView->stagingProperties().getWidth(), mListView->stagingProperties().getHeight()));
for (size_t ci = 0; ci < mListItems.size(); ci++) {
// update item position
auto listItem = mListItems[(ci + itemIndexOffset) % mListItems.size()];
@@ -72,6 +72,6 @@ void TestListViewSceneBase::doFrame(int frameNr) {
mListView->setStagingDisplayList(canvas->finishRecording());
}
-} // namespace test
-} // namespace uirenderer
-} // namespace android
+} // namespace test
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/common/TestListViewSceneBase.h b/libs/hwui/tests/common/TestListViewSceneBase.h
index ed6867ab3750..ab0d3c74226b 100644
--- a/libs/hwui/tests/common/TestListViewSceneBase.h
+++ b/libs/hwui/tests/common/TestListViewSceneBase.h
@@ -15,9 +15,9 @@
*/
#pragma once
-#include "TestScene.h"
#include <RenderNode.h>
#include <RenderProperties.h>
+#include "TestScene.h"
namespace android {
namespace uirenderer {
@@ -25,20 +25,21 @@ namespace test {
class TestListViewSceneBase : public TestScene {
public:
- virtual void createListItem(RenderProperties& props, Canvas& canvas, int id,
- int itemWidth, int itemHeight) = 0;
+ virtual void createListItem(RenderProperties& props, Canvas& canvas, int id, int itemWidth,
+ int itemHeight) = 0;
+
private:
int mItemHeight;
int mItemSpacing;
int mItemWidth;
int mItemLeft;
sp<RenderNode> mListView;
- std::vector< sp<RenderNode> > mListItems;
+ std::vector<sp<RenderNode> > mListItems;
void createContent(int width, int height, Canvas& canvas) override;
void doFrame(int frameNr) override;
};
-} // namespace test
-} // namespace uirenderer
-} // namespace android
+} // namespace test
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/common/TestScene.h b/libs/hwui/tests/common/TestScene.h
index f6f7c62a4f63..91022cfe734b 100644
--- a/libs/hwui/tests/common/TestScene.h
+++ b/libs/hwui/tests/common/TestScene.h
@@ -16,6 +16,9 @@
#pragma once
+#include <gui/Surface.h>
+#include <utils/StrongPointer.h>
+
#include <string>
#include <unordered_map>
@@ -52,9 +55,8 @@ public:
class Registrar {
public:
- explicit Registrar(const TestScene::Info& info) {
- TestScene::registerScene(info);
- }
+ explicit Registrar(const TestScene::Info& info) { TestScene::registerScene(info); }
+
private:
Registrar() = delete;
Registrar(const Registrar&) = delete;
@@ -67,8 +69,10 @@ public:
static std::unordered_map<std::string, Info>& testMap();
static void registerScene(const Info& info);
+
+ sp<Surface> renderTarget;
};
-} // namespace test
-} // namespace uirenderer
-} // namespace android
+} // namespace test
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index e6137763cbe7..1e424258b016 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -16,17 +16,17 @@
#include "TestUtils.h"
-#include "hwui/Paint.h"
#include "DeferredLayerUpdater.h"
+#include "hwui/Paint.h"
+#include <SkClipStack.h>
#include <minikin/Layout.h>
-#include <renderthread/EglManager.h>
-#include <renderthread/OpenGLPipeline.h>
#include <pipeline/skia/SkiaOpenGLPipeline.h>
#include <pipeline/skia/SkiaVulkanPipeline.h>
+#include <renderthread/EglManager.h>
+#include <renderthread/OpenGLPipeline.h>
#include <renderthread/VulkanManager.h>
#include <utils/Unicode.h>
-#include <SkClipStack.h>
#include <SkGlyphCache.h>
@@ -44,10 +44,10 @@ SkColor TestUtils::interpolateColor(float fraction, SkColor start, SkColor end)
int endG = (end >> 8) & 0xff;
int endB = end & 0xff;
- return (int)((startA + (int)(fraction * (endA - startA))) << 24)
- | (int)((startR + (int)(fraction * (endR - startR))) << 16)
- | (int)((startG + (int)(fraction * (endG - startG))) << 8)
- | (int)((startB + (int)(fraction * (endB - startB))));
+ return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
+ (int)((startR + (int)(fraction * (endR - startR))) << 16) |
+ (int)((startG + (int)(fraction * (endG - startG))) << 8) |
+ (int)((startB + (int)(fraction * (endB - startB))));
}
sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
@@ -77,15 +77,16 @@ sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
// updateLayer so it's ready to draw
layerUpdater->updateLayer(true, Matrix4::identity().data);
if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
- static_cast<GlLayer*>(layerUpdater->backingLayer())->setRenderTarget(
- GL_TEXTURE_EXTERNAL_OES);
+ static_cast<GlLayer*>(layerUpdater->backingLayer())
+ ->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
}
return layerUpdater;
}
void TestUtils::layoutTextUnscaled(const SkPaint& paint, const char* text,
- std::vector<glyph_t>* outGlyphs, std::vector<float>* outPositions,
- float* outTotalAdvance, Rect* outBounds) {
+ std::vector<glyph_t>* outGlyphs,
+ std::vector<float>* outPositions, float* outTotalAdvance,
+ Rect* outBounds) {
Rect bounds;
float totalAdvance = 0;
SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
@@ -118,19 +119,18 @@ void TestUtils::layoutTextUnscaled(const SkPaint& paint, const char* text,
*outTotalAdvance = totalAdvance;
}
-
-void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text,
- const SkPaint& paint, float x, float y) {
+void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint, float x,
+ float y) {
auto utf16 = asciiToUtf16(text);
canvas->drawText(utf16.get(), 0, strlen(text), strlen(text), x, y, minikin::Bidi::LTR, paint,
- nullptr);
+ nullptr);
}
-void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text,
- const SkPaint& paint, const SkPath& path) {
+void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint,
+ const SkPath& path) {
auto utf16 = asciiToUtf16(text);
canvas->drawTextOnPath(utf16.get(), strlen(text), minikin::Bidi::LTR, path, 0, 0, paint,
- nullptr);
+ nullptr);
}
void TestUtils::TestTask::run() {
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index c383fcf26bb3..1bfa046eff63 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -22,11 +22,11 @@
#include <Properties.h>
#include <Rect.h>
#include <RenderNode.h>
+#include <Snapshot.h>
#include <hwui/Bitmap.h>
#include <pipeline/skia/SkiaRecordingCanvas.h>
#include <renderstate/RenderState.h>
#include <renderthread/RenderThread.h>
-#include <Snapshot.h>
#include <RecordedOp.h>
#include <RecordingCanvas.h>
@@ -36,85 +36,88 @@
namespace android {
namespace uirenderer {
-#define EXPECT_MATRIX_APPROX_EQ(a, b) \
- EXPECT_TRUE(TestUtils::matricesAreApproxEqual(a, b))
-
-#define EXPECT_RECT_APPROX_EQ(a, b) \
- EXPECT_TRUE(MathUtils::areEqual((a).left, (b).left) \
- && MathUtils::areEqual((a).top, (b).top) \
- && MathUtils::areEqual((a).right, (b).right) \
- && MathUtils::areEqual((a).bottom, (b).bottom));
-
-#define EXPECT_CLIP_RECT(expRect, clipStatePtr) \
- EXPECT_NE(nullptr, (clipStatePtr)) << "Op is unclipped"; \
- if ((clipStatePtr)->mode == ClipMode::Rectangle) { \
- EXPECT_EQ((expRect), reinterpret_cast<const ClipRect*>(clipStatePtr)->rect); \
- } else { \
- ADD_FAILURE() << "ClipState not a rect"; \
- }
+#define EXPECT_MATRIX_APPROX_EQ(a, b) EXPECT_TRUE(TestUtils::matricesAreApproxEqual(a, b))
+
+#define EXPECT_RECT_APPROX_EQ(a, b) \
+ EXPECT_TRUE(MathUtils::areEqual((a).left, (b).left) && \
+ MathUtils::areEqual((a).top, (b).top) && \
+ MathUtils::areEqual((a).right, (b).right) && \
+ MathUtils::areEqual((a).bottom, (b).bottom));
+
+#define EXPECT_CLIP_RECT(expRect, clipStatePtr) \
+ EXPECT_NE(nullptr, (clipStatePtr)) << "Op is unclipped"; \
+ if ((clipStatePtr)->mode == ClipMode::Rectangle) { \
+ EXPECT_EQ((expRect), reinterpret_cast<const ClipRect*>(clipStatePtr)->rect); \
+ } else { \
+ ADD_FAILURE() << "ClipState not a rect"; \
+ }
#define INNER_PIPELINE_TEST(test_case_name, test_name, pipeline, functionCall) \
- TEST(test_case_name, test_name##_##pipeline) { \
- RenderPipelineType oldType = Properties::getRenderPipelineType(); \
- Properties::overrideRenderPipelineType(RenderPipelineType::pipeline); \
- functionCall; \
- Properties::overrideRenderPipelineType(oldType); \
+ TEST(test_case_name, test_name##_##pipeline) { \
+ RenderPipelineType oldType = Properties::getRenderPipelineType(); \
+ Properties::overrideRenderPipelineType(RenderPipelineType::pipeline); \
+ functionCall; \
+ Properties::overrideRenderPipelineType(oldType); \
};
/**
* Like gtests' TEST, but only runs with the OpenGL RenderPipelineType
*/
-#define OPENGL_PIPELINE_TEST(test_case_name, test_name) \
- class test_case_name##_##test_name##_HwuiTest { \
- public: \
- static void doTheThing(); \
- }; \
- INNER_PIPELINE_TEST(test_case_name, test_name, OpenGL, \
- test_case_name##_##test_name##_HwuiTest::doTheThing()) \
+#define OPENGL_PIPELINE_TEST(test_case_name, test_name) \
+ class test_case_name##_##test_name##_HwuiTest { \
+ public: \
+ static void doTheThing(); \
+ }; \
+ INNER_PIPELINE_TEST(test_case_name, test_name, OpenGL, \
+ test_case_name##_##test_name##_HwuiTest::doTheThing()) \
void test_case_name##_##test_name##_HwuiTest::doTheThing()
#define INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, pipeline) \
- INNER_PIPELINE_TEST(test_case_name, test_name, pipeline, \
- TestUtils::runOnRenderThread(test_case_name##_##test_name##_RenderThreadTest::doTheThing))
+ INNER_PIPELINE_TEST(test_case_name, test_name, pipeline, \
+ TestUtils::runOnRenderThread( \
+ test_case_name##_##test_name##_RenderThreadTest::doTheThing))
/**
* Like gtest's TEST, but runs on the RenderThread, and 'renderThread' is passed, in top level scope
* (for e.g. accessing its RenderState)
*/
-#define RENDERTHREAD_TEST(test_case_name, test_name) \
- class test_case_name##_##test_name##_RenderThreadTest { \
- public: \
- static void doTheThing(renderthread::RenderThread& renderThread); \
- }; \
- INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, OpenGL); \
- INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
+#define RENDERTHREAD_TEST(test_case_name, test_name) \
+ class test_case_name##_##test_name##_RenderThreadTest { \
+ public: \
+ static void doTheThing(renderthread::RenderThread& renderThread); \
+ }; \
+ INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, OpenGL); \
+ INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
/* Temporarily disabling Vulkan until we can figure out a way to stub out the driver */ \
- /* INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); */ \
- void test_case_name##_##test_name##_RenderThreadTest::doTheThing(renderthread::RenderThread& renderThread)
+ /* INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); */ \
+ void test_case_name##_##test_name##_RenderThreadTest::doTheThing( \
+ renderthread::RenderThread& renderThread)
/**
* Like RENDERTHREAD_TEST, but only runs with the OpenGL RenderPipelineType
*/
-#define RENDERTHREAD_OPENGL_PIPELINE_TEST(test_case_name, test_name) \
- class test_case_name##_##test_name##_RenderThreadTest { \
- public: \
+#define RENDERTHREAD_OPENGL_PIPELINE_TEST(test_case_name, test_name) \
+ class test_case_name##_##test_name##_RenderThreadTest { \
+ public: \
static void doTheThing(renderthread::RenderThread& renderThread); \
- }; \
- INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, OpenGL); \
- void test_case_name##_##test_name##_RenderThreadTest::doTheThing(renderthread::RenderThread& renderThread)
+ }; \
+ INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, OpenGL); \
+ void test_case_name##_##test_name##_RenderThreadTest::doTheThing( \
+ renderthread::RenderThread& renderThread)
/**
* Like RENDERTHREAD_TEST, but only runs with the Skia RenderPipelineTypes
*/
-#define RENDERTHREAD_SKIA_PIPELINE_TEST(test_case_name, test_name) \
- class test_case_name##_##test_name##_RenderThreadTest { \
- public: \
- static void doTheThing(renderthread::RenderThread& renderThread); \
- }; \
- INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
+#define RENDERTHREAD_SKIA_PIPELINE_TEST(test_case_name, test_name) \
+ class test_case_name##_##test_name##_RenderThreadTest { \
+ public: \
+ static void doTheThing(renderthread::RenderThread& renderThread); \
+ }; \
+ INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
/* Temporarily disabling Vulkan until we can figure out a way to stub out the driver */ \
- /* INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); */ \
- void test_case_name##_##test_name##_RenderThreadTest::doTheThing(renderthread::RenderThread& renderThread)
+ /* INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); */ \
+ void test_case_name##_##test_name##_RenderThreadTest::doTheThing( \
+ renderthread::RenderThread& renderThread)
/**
* Sets a property value temporarily, generally for the duration of a test, restoring the previous
@@ -125,14 +128,11 @@ namespace uirenderer {
template <typename T>
class ScopedProperty {
public:
- ScopedProperty(T& property, T newValue)
- : mPropertyPtr(&property)
- , mOldValue(property) {
+ ScopedProperty(T& property, T newValue) : mPropertyPtr(&property), mOldValue(property) {
property = newValue;
}
- ~ScopedProperty() {
- *mPropertyPtr = mOldValue;
- }
+ ~ScopedProperty() { *mPropertyPtr = mOldValue; }
+
private:
T* mPropertyPtr;
T mOldValue;
@@ -142,18 +142,15 @@ class TestUtils {
public:
class SignalingDtor {
public:
- SignalingDtor()
- : mSignal(nullptr) {}
- explicit SignalingDtor(int* signal)
- : mSignal(signal) {}
- void setSignal(int* signal) {
- mSignal = signal;
- }
+ SignalingDtor() : mSignal(nullptr) {}
+ explicit SignalingDtor(int* signal) : mSignal(signal) {}
+ void setSignal(int* signal) { mSignal = signal; }
~SignalingDtor() {
if (mSignal) {
(*mSignal)++;
}
}
+
private:
int* mSignal;
};
@@ -181,7 +178,7 @@ public:
}
static sk_sp<Bitmap> createBitmap(int width, int height,
- SkColorType colorType = kN32_SkColorType) {
+ SkColorType colorType = kN32_SkColorType) {
SkImageInfo info = SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType);
return Bitmap::allocateHeapBitmap(info);
}
@@ -199,15 +196,16 @@ public:
renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
const SkMatrix& transform);
- template<class CanvasType>
- static std::unique_ptr<DisplayList> createDisplayList(int width, int height,
- std::function<void(CanvasType& canvas)> canvasCallback) {
+ template <class CanvasType>
+ static std::unique_ptr<DisplayList> createDisplayList(
+ int width, int height, std::function<void(CanvasType& canvas)> canvasCallback) {
CanvasType canvas(width, height);
canvasCallback(canvas);
return std::unique_ptr<DisplayList>(canvas.finishRecording());
}
- static sp<RenderNode> createNode(int left, int top, int right, int bottom,
+ static sp<RenderNode> createNode(
+ int left, int top, int right, int bottom,
std::function<void(RenderProperties& props, Canvas& canvas)> setup) {
#if HWUI_NULL_GPU
// if RenderNodes are being sync'd/used, device info will be needed, since
@@ -219,8 +217,8 @@ public:
RenderProperties& props = node->mutateStagingProperties();
props.setLeftTopRightBottom(left, top, right, bottom);
if (setup) {
- std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(props.getWidth(),
- props.getHeight()));
+ std::unique_ptr<Canvas> canvas(
+ Canvas::create_recording_canvas(props.getWidth(), props.getHeight()));
setup(props, *canvas.get());
node->setStagingDisplayList(canvas->finishRecording());
}
@@ -228,8 +226,9 @@ public:
return node;
}
- template<class RecordingCanvasType>
- static sp<RenderNode> createNode(int left, int top, int right, int bottom,
+ template <class RecordingCanvasType>
+ static sp<RenderNode> createNode(
+ int left, int top, int right, int bottom,
std::function<void(RenderProperties& props, RecordingCanvasType& canvas)> setup) {
#if HWUI_NULL_GPU
// if RenderNodes are being sync'd/used, device info will be needed, since
@@ -249,22 +248,23 @@ public:
return node;
}
- static void recordNode(RenderNode& node,
- std::function<void(Canvas&)> contentCallback) {
- std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
- node.stagingProperties().getWidth(), node.stagingProperties().getHeight()));
- contentCallback(*canvas.get());
- node.setStagingDisplayList(canvas->finishRecording());
+ static void recordNode(RenderNode& node, std::function<void(Canvas&)> contentCallback) {
+ std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
+ node.stagingProperties().getWidth(), node.stagingProperties().getHeight()));
+ contentCallback(*canvas.get());
+ node.setStagingDisplayList(canvas->finishRecording());
}
- static sp<RenderNode> createSkiaNode(int left, int top, int right, int bottom,
- std::function<void(RenderProperties& props, skiapipeline::SkiaRecordingCanvas& canvas)> setup,
+ static sp<RenderNode> createSkiaNode(
+ int left, int top, int right, int bottom,
+ std::function<void(RenderProperties& props, skiapipeline::SkiaRecordingCanvas& canvas)>
+ setup,
const char* name = nullptr, skiapipeline::SkiaDisplayList* displayList = nullptr) {
- #if HWUI_NULL_GPU
+#if HWUI_NULL_GPU
// if RenderNodes are being sync'd/used, device info will be needed, since
// DeviceInfo::maxTextureSize() affects layer property
DeviceInfo::initialize();
- #endif
+#endif
sp<RenderNode> node = new RenderNode();
if (name) {
node->setName(name);
@@ -276,8 +276,8 @@ public:
}
if (setup) {
std::unique_ptr<skiapipeline::SkiaRecordingCanvas> canvas(
- new skiapipeline::SkiaRecordingCanvas(nullptr,
- props.getWidth(), props.getHeight()));
+ new skiapipeline::SkiaRecordingCanvas(nullptr, props.getWidth(),
+ props.getHeight()));
setup(props, *canvas.get());
node->setStagingDisplayList(canvas->finishRecording());
}
@@ -306,8 +306,7 @@ public:
class TestTask : public renderthread::RenderTask {
public:
- explicit TestTask(RtCallback rtCallback)
- : rtCallback(rtCallback) {}
+ explicit TestTask(RtCallback rtCallback) : rtCallback(rtCallback) {}
virtual ~TestTask() {}
virtual void run() override;
RtCallback rtCallback;
@@ -318,39 +317,37 @@ public:
*/
static void runOnRenderThread(RtCallback rtCallback) {
TestTask task(rtCallback);
- renderthread::RenderThread::getInstance().queue().runSync([&]() {
- task.run();
- });
+ renderthread::RenderThread::getInstance().queue().runSync([&]() { task.run(); });
}
- static bool isRenderThreadRunning() {
- return renderthread::RenderThread::hasInstance();
- }
+ static bool isRenderThreadRunning() { return renderthread::RenderThread::hasInstance(); }
static SkColor interpolateColor(float fraction, SkColor start, SkColor end);
static void layoutTextUnscaled(const SkPaint& paint, const char* text,
- std::vector<glyph_t>* outGlyphs, std::vector<float>* outPositions,
- float* outTotalAdvance, Rect* outBounds);
+ std::vector<glyph_t>* outGlyphs,
+ std::vector<float>* outPositions, float* outTotalAdvance,
+ Rect* outBounds);
- static void drawUtf8ToCanvas(Canvas* canvas, const char* text,
- const SkPaint& paint, float x, float y);
+ static void drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint, float x,
+ float y);
- static void drawUtf8ToCanvas(Canvas* canvas, const char* text,
- const SkPaint& paint, const SkPath& path);
+ static void drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint,
+ const SkPath& path);
static std::unique_ptr<uint16_t[]> asciiToUtf16(const char* str);
class MockFunctor : public Functor {
- public:
- virtual status_t operator ()(int what, void* data) {
- mLastMode = what;
- return DrawGlInfo::kStatusDone;
- }
- int getLastMode() const { return mLastMode; }
- private:
- int mLastMode = -1;
- };
+ public:
+ virtual status_t operator()(int what, void* data) {
+ mLastMode = what;
+ return DrawGlInfo::kStatusDone;
+ }
+ int getLastMode() const { return mLastMode; }
+
+ private:
+ int mLastMode = -1;
+ };
static SkColor getColor(const sk_sp<SkSurface>& surface, int x, int y);
@@ -369,7 +366,8 @@ private:
if (displayList) {
if (displayList->isSkiaDL()) {
for (auto&& childDr : static_cast<skiapipeline::SkiaDisplayList*>(
- const_cast<DisplayList*>(displayList))->mChildNodes) {
+ const_cast<DisplayList*>(displayList))
+ ->mChildNodes) {
syncHierarchyPropertiesAndDisplayListImpl(childDr.getRenderNode());
}
} else {
@@ -380,7 +378,7 @@ private:
}
}
-}; // class TestUtils
+}; // class TestUtils
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/tests/common/scenes/BitmapFillrate.cpp b/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
index be58d09b7f4d..1d3d60716d68 100644
--- a/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
@@ -32,8 +32,7 @@ static bool _BitmapFillrate(
class BitmapFillrate : public TestScene {
public:
BitmapFillrate(BitmapAllocationTestUtils::BitmapAllocator allocator)
- : TestScene()
- , mAllocator(allocator) { }
+ : TestScene(), mAllocator(allocator) {}
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
@@ -41,7 +40,7 @@ public:
createNode(canvas, 0xA0CDDC39, width / 3, height / 3, width, height);
createNode(canvas, 0x90009688, width / 3, 0, width, height);
createNode(canvas, 0xA0FF5722, 0, height / 3, width, height);
- createNode(canvas, 0x9000796B, width / 6, height/6, width, height);
+ createNode(canvas, 0x9000796B, width / 6, height / 6, width, height);
createNode(canvas, 0xA0FFC107, width / 6, 0, width, height);
}
@@ -52,23 +51,23 @@ public:
mNodes[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
}
+
private:
- void createNode(Canvas& canvas, SkColor color, int left, int top,
- int width, int height) {
+ void createNode(Canvas& canvas, SkColor color, int left, int top, int width, int height) {
int itemWidth = 2 * width / 3;
int itemHeight = 2 * height / 3;
- auto card = TestUtils::createNode(left, top, left + itemWidth , top + itemHeight,
+ auto card = TestUtils::createNode(
+ left, top, left + itemWidth, top + itemHeight,
[this, itemWidth, itemHeight, color](RenderProperties& props, Canvas& canvas) {
- sk_sp<Bitmap> bitmap = mAllocator(itemWidth, itemHeight, kRGBA_8888_SkColorType,
- [color](SkBitmap& skBitmap) {
- skBitmap.eraseColor(color);
- });
- canvas.drawBitmap(*bitmap, 0, 0, nullptr);
- });
+ sk_sp<Bitmap> bitmap =
+ mAllocator(itemWidth, itemHeight, kRGBA_8888_SkColorType,
+ [color](SkBitmap& skBitmap) { skBitmap.eraseColor(color); });
+ canvas.drawBitmap(*bitmap, 0, 0, nullptr);
+ });
canvas.drawRenderNode(card.get());
mNodes.push_back(card);
}
BitmapAllocationTestUtils::BitmapAllocator mAllocator;
- std::vector< sp<RenderNode> > mNodes;
+ std::vector<sp<RenderNode> > mNodes;
}; \ No newline at end of file
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index 0f2dc034d125..15039b5fa976 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -14,56 +14,52 @@
* limitations under the License.
*/
+#include <SkImagePriv.h>
#include "TestSceneBase.h"
-#include "utils/Color.h"
#include "tests/common/BitmapAllocationTestUtils.h"
-#include <SkImagePriv.h>
+#include "utils/Color.h"
class BitmapShaders;
-static bool _BitmapShaders(
- BitmapAllocationTestUtils::registerBitmapAllocationScene<BitmapShaders>(
- "bitmapShader", "Draws bitmap shaders with repeat and mirror modes."));
+static bool _BitmapShaders(BitmapAllocationTestUtils::registerBitmapAllocationScene<BitmapShaders>(
+ "bitmapShader", "Draws bitmap shaders with repeat and mirror modes."));
class BitmapShaders : public TestScene {
public:
BitmapShaders(BitmapAllocationTestUtils::BitmapAllocator allocator)
- : TestScene()
- , mAllocator(allocator) { }
+ : TestScene(), mAllocator(allocator) {}
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::Grey_200, SkBlendMode::kSrcOver);
- sk_sp<Bitmap> hwuiBitmap = mAllocator(200, 200, kRGBA_8888_SkColorType,
- [](SkBitmap& skBitmap) {
- skBitmap.eraseColor(Color::White);
- SkCanvas skCanvas(skBitmap);
- SkPaint skPaint;
- skPaint.setColor(Color::Red_500);
- skCanvas.drawRect(SkRect::MakeWH(100, 100), skPaint);
- skPaint.setColor(Color::Blue_500);
- skCanvas.drawRect(SkRect::MakeXYWH(100, 100, 100, 100), skPaint);
- });
+ sk_sp<Bitmap> hwuiBitmap =
+ mAllocator(200, 200, kRGBA_8888_SkColorType, [](SkBitmap& skBitmap) {
+ skBitmap.eraseColor(Color::White);
+ SkCanvas skCanvas(skBitmap);
+ SkPaint skPaint;
+ skPaint.setColor(Color::Red_500);
+ skCanvas.drawRect(SkRect::MakeWH(100, 100), skPaint);
+ skPaint.setColor(Color::Blue_500);
+ skCanvas.drawRect(SkRect::MakeXYWH(100, 100, 100, 100), skPaint);
+ });
SkPaint paint;
sk_sp<SkColorFilter> colorFilter;
sk_sp<SkImage> image = hwuiBitmap->makeImage(&colorFilter);
- sk_sp<SkShader> repeatShader = image->makeShader(
- SkShader::TileMode::kRepeat_TileMode,
- SkShader::TileMode::kRepeat_TileMode,
- nullptr);
+ sk_sp<SkShader> repeatShader =
+ image->makeShader(SkShader::TileMode::kRepeat_TileMode,
+ SkShader::TileMode::kRepeat_TileMode, nullptr);
paint.setShader(std::move(repeatShader));
canvas.drawRoundRect(0, 0, 500, 500, 50.0f, 50.0f, paint);
- sk_sp<SkShader> mirrorShader = image->makeShader(
- SkShader::TileMode::kMirror_TileMode,
- SkShader::TileMode::kMirror_TileMode,
- nullptr);
+ sk_sp<SkShader> mirrorShader =
+ image->makeShader(SkShader::TileMode::kMirror_TileMode,
+ SkShader::TileMode::kMirror_TileMode, nullptr);
paint.setShader(std::move(mirrorShader));
canvas.drawRoundRect(0, 600, 500, 1100, 50.0f, 50.0f, paint);
}
- void doFrame(int frameNr) override { }
+ void doFrame(int frameNr) override {}
BitmapAllocationTestUtils::BitmapAllocator mAllocator;
};
diff --git a/libs/hwui/tests/common/scenes/ClippingAnimation.cpp b/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
index f47e05a1f3e6..2a016ac1b5bc 100644
--- a/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
@@ -19,19 +19,17 @@
class ClippingAnimation;
static TestScene::Registrar _RectGrid(TestScene::Info{
- "clip",
- "Complex clip cases"
- "Low CPU/GPU load.",
- TestScene::simpleCreateScene<ClippingAnimation>
-});
+ "clip",
+ "Complex clip cases"
+ "Low CPU/GPU load.",
+ TestScene::simpleCreateScene<ClippingAnimation>});
class ClippingAnimation : public TestScene {
public:
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
- card = TestUtils::createNode(0, 0, 200, 400,
- [](RenderProperties& props, Canvas& canvas) {
+ card = TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
canvas.save(SaveFlags::MatrixClip);
{
canvas.clipRect(0, 0, 200, 200, SkClipOp::kIntersect);
diff --git a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
index 21d8d75fbf18..bf0aed98cd70 100644
--- a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
@@ -25,30 +25,28 @@
class GlyphStressAnimation;
static TestScene::Registrar _GlyphStress(TestScene::Info{
- "glyphstress",
- "A stress test for both the glyph cache, and glyph rendering.",
- TestScene::simpleCreateScene<GlyphStressAnimation>
-});
+ "glyphstress", "A stress test for both the glyph cache, and glyph rendering.",
+ TestScene::simpleCreateScene<GlyphStressAnimation>});
class GlyphStressAnimation : public TestScene {
public:
sp<RenderNode> container;
void createContent(int width, int height, Canvas& canvas) override {
container = TestUtils::createNode(0, 0, width, height, nullptr);
- doFrame(0); // update container
+ doFrame(0); // update container
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
canvas.drawRenderNode(container.get());
}
void doFrame(int frameNr) override {
- std::unique_ptr<uint16_t[]> text = TestUtils::asciiToUtf16(
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ std::unique_ptr<uint16_t[]> text =
+ TestUtils::asciiToUtf16("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
ssize_t textLength = 26 * 2;
- std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
- container->stagingProperties().getWidth(),
- container->stagingProperties().getHeight()));
+ std::unique_ptr<Canvas> canvas(
+ Canvas::create_recording_canvas(container->stagingProperties().getWidth(),
+ container->stagingProperties().getHeight()));
Paint paint;
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
@@ -56,8 +54,8 @@ public:
paint.setColor(Color::Black);
for (int i = 0; i < 5; i++) {
paint.setTextSize(10 + (frameNr % 20) + i * 20);
- canvas->drawText(text.get(), 0, textLength, textLength,
- 0, 100 * (i + 2), minikin::Bidi::FORCE_LTR, paint, nullptr);
+ canvas->drawText(text.get(), 0, textLength, textLength, 0, 100 * (i + 2),
+ minikin::Bidi::FORCE_LTR, paint, nullptr);
}
container->setStagingDisplayList(canvas->finishRecording());
diff --git a/libs/hwui/tests/common/scenes/HwBitmap565.cpp b/libs/hwui/tests/common/scenes/HwBitmap565.cpp
index 18fea3d1cb81..cbdb756b8fa7 100644
--- a/libs/hwui/tests/common/scenes/HwBitmap565.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmap565.cpp
@@ -15,16 +15,14 @@
*/
#include "TestSceneBase.h"
-#include "utils/Color.h"
#include "tests/common/BitmapAllocationTestUtils.h"
+#include "utils/Color.h"
class HwBitmap565;
static TestScene::Registrar _HwBitmap565(TestScene::Info{
- "hwBitmap565",
- "Draws composite shader with hardware bitmap",
- TestScene::simpleCreateScene<HwBitmap565>
-});
+ "hwBitmap565", "Draws composite shader with hardware bitmap",
+ TestScene::simpleCreateScene<HwBitmap565>});
class HwBitmap565 : public TestScene {
public:
@@ -32,18 +30,18 @@ public:
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::Grey_200, SkBlendMode::kSrcOver);
- sk_sp<Bitmap> hardwareBitmap = BitmapAllocationTestUtils::allocateHardwareBitmap(200, 200,
- kRGB_565_SkColorType, [](SkBitmap& skBitmap) {
- skBitmap.eraseColor(Color::White);
- SkCanvas skCanvas(skBitmap);
- SkPaint skPaint;
- skPaint.setColor(Color::Red_500);
- skCanvas.drawRect(SkRect::MakeWH(100, 100), skPaint);
- skPaint.setColor(Color::Blue_500);
- skCanvas.drawRect(SkRect::MakeXYWH(100, 100, 100, 100), skPaint);
- });
+ sk_sp<Bitmap> hardwareBitmap = BitmapAllocationTestUtils::allocateHardwareBitmap(
+ 200, 200, kRGB_565_SkColorType, [](SkBitmap& skBitmap) {
+ skBitmap.eraseColor(Color::White);
+ SkCanvas skCanvas(skBitmap);
+ SkPaint skPaint;
+ skPaint.setColor(Color::Red_500);
+ skCanvas.drawRect(SkRect::MakeWH(100, 100), skPaint);
+ skPaint.setColor(Color::Blue_500);
+ skCanvas.drawRect(SkRect::MakeXYWH(100, 100, 100, 100), skPaint);
+ });
canvas.drawBitmap(*hardwareBitmap, 10.0f, 10.0f, nullptr);
}
- void doFrame(int frameNr) override { }
+ void doFrame(int frameNr) override {}
}; \ No newline at end of file
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
index 960b05340063..f137562e7c73 100644
--- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -17,17 +17,15 @@
#include "TestSceneBase.h"
#include "utils/Color.h"
-#include <ui/PixelFormat.h>
#include <SkGradientShader.h>
#include <SkImagePriv.h>
+#include <ui/PixelFormat.h>
class HwBitmapInCompositeShader;
static TestScene::Registrar _HwBitmapInCompositeShader(TestScene::Info{
- "hwbitmapcompositeshader",
- "Draws composite shader with hardware bitmap",
- TestScene::simpleCreateScene<HwBitmapInCompositeShader>
-});
+ "hwbitmapcompositeshader", "Draws composite shader with hardware bitmap",
+ TestScene::simpleCreateScene<HwBitmapInCompositeShader>});
class HwBitmapInCompositeShader : public TestScene {
public:
@@ -35,16 +33,15 @@ public:
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
- uint32_t usage = GraphicBuffer::USAGE_HW_TEXTURE
- | GraphicBuffer::USAGE_SW_READ_NEVER
- | GRALLOC_USAGE_SW_WRITE_RARELY;
+ uint32_t usage = GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_READ_NEVER |
+ GRALLOC_USAGE_SW_WRITE_RARELY;
sp<GraphicBuffer> buffer = new GraphicBuffer(400, 200, PIXEL_FORMAT_RGBA_8888, usage);
unsigned char* pixels = nullptr;
buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, ((void**)&pixels));
- size_t size = bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride()
- * buffer->getHeight();
+ size_t size =
+ bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride() * buffer->getHeight();
memset(pixels, 0, size);
for (int i = 0; i < 6000; i++) {
pixels[4000 + 4 * i + 0] = 255;
@@ -61,8 +58,8 @@ public:
SkColor colors[2];
colors[0] = Color::Black;
colors[1] = Color::White;
- sk_sp<SkShader> gradientShader = SkGradientShader::MakeRadial(center, 50, colors, nullptr,
- 2, SkShader::TileMode::kRepeat_TileMode);
+ sk_sp<SkShader> gradientShader = SkGradientShader::MakeRadial(
+ center, 50, colors, nullptr, 2, SkShader::TileMode::kRepeat_TileMode);
sk_sp<SkShader> compositeShader(
SkShader::MakeComposeShader(hardwareShader, gradientShader, SkBlendMode::kDstATop));
@@ -72,12 +69,12 @@ public:
canvas.drawRoundRect(0, 0, 400, 200, 10.0f, 10.0f, paint);
}
- void doFrame(int frameNr) override { }
+ void doFrame(int frameNr) override {}
sk_sp<SkShader> createBitmapShader(Bitmap& bitmap) {
sk_sp<SkColorFilter> colorFilter;
sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
return image->makeShader(SkShader::TileMode::kClamp_TileMode,
- SkShader::TileMode::kClamp_TileMode);
+ SkShader::TileMode::kClamp_TileMode);
}
};
diff --git a/libs/hwui/tests/common/scenes/HwLayerAnimation.cpp b/libs/hwui/tests/common/scenes/HwLayerAnimation.cpp
index 3a230ae6e8b7..cac2fb3d8d5c 100644
--- a/libs/hwui/tests/common/scenes/HwLayerAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/HwLayerAnimation.cpp
@@ -19,22 +19,20 @@
class HwLayerAnimation;
static TestScene::Registrar _HwLayer(TestScene::Info{
- "hwlayer",
- "A nested pair of nodes with LAYER_TYPE_HARDWARE set on each. "
- "Tests the hardware layer codepath.",
- TestScene::simpleCreateScene<HwLayerAnimation>
-});
+ "hwlayer",
+ "A nested pair of nodes with LAYER_TYPE_HARDWARE set on each. "
+ "Tests the hardware layer codepath.",
+ TestScene::simpleCreateScene<HwLayerAnimation>});
class HwLayerAnimation : public TestScene {
public:
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
- card = TestUtils::createNode(0, 0, 200, 200,
- [](RenderProperties& props, Canvas& canvas) {
+ card = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, Canvas& canvas) {
props.mutateLayerProperties().setType(LayerType::RenderLayer);
canvas.drawColor(0xFF0000FF, SkBlendMode::kSrcOver);
});
- canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); // background
+ canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); // background
canvas.drawRenderNode(card.get());
}
void doFrame(int frameNr) override {
diff --git a/libs/hwui/tests/common/scenes/HwLayerSizeAnimation.cpp b/libs/hwui/tests/common/scenes/HwLayerSizeAnimation.cpp
index d84113238e53..77a59dfe6ba5 100644
--- a/libs/hwui/tests/common/scenes/HwLayerSizeAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/HwLayerSizeAnimation.cpp
@@ -19,29 +19,27 @@
class HwLayerSizeAnimation;
static TestScene::Registrar _HwLayerSize(TestScene::Info{
- "hwlayersize",
- "A nested pair of nodes with LayerType::RenderLayer(hardware) set on the child and "
- "LayerType::None on the parent. "
- "Tests animating the size of a hardware layer.",
- TestScene::simpleCreateScene<HwLayerSizeAnimation>
-});
+ "hwlayersize",
+ "A nested pair of nodes with LayerType::RenderLayer(hardware) set on the child and "
+ "LayerType::None on the parent. "
+ "Tests animating the size of a hardware layer.",
+ TestScene::simpleCreateScene<HwLayerSizeAnimation>});
class HwLayerSizeAnimation : public TestScene {
public:
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
- card = TestUtils::createNode(0, 0, 200, 200,
- [](RenderProperties& props, Canvas& canvas) {
+ card = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, Canvas& canvas) {
props.mutateLayerProperties().setType(LayerType::RenderLayer);
canvas.drawColor(0xFF0000FF, SkBlendMode::kSrcOver);
});
- canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); // background
+ canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); // background
canvas.drawRenderNode(card.get());
}
void doFrame(int frameNr) override {
int curFrame = frameNr % 150;
- //we animate left and top coordinates, which in turn animates width and
- //height (bottom/right coordinates are fixed)
+ // we animate left and top coordinates, which in turn animates width and
+ // height (bottom/right coordinates are fixed)
card->mutateStagingProperties().setLeftTop(curFrame, curFrame);
card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
diff --git a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
index b7357e179bfe..58c99800875b 100644
--- a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
@@ -22,15 +22,14 @@
class ListOfFadedTextAnimation;
static TestScene::Registrar _ListOfFadedTextAnimation(TestScene::Info{
- "fadingedges",
- "A mock ListView of scrolling text with faded edge. Doesn't re-bind/re-record views"
- "as they are recycled, so won't upload much content (either glyphs, or bitmaps).",
- TestScene::simpleCreateScene<ListOfFadedTextAnimation>
-});
+ "fadingedges",
+ "A mock ListView of scrolling text with faded edge. Doesn't re-bind/re-record views"
+ "as they are recycled, so won't upload much content (either glyphs, or bitmaps).",
+ TestScene::simpleCreateScene<ListOfFadedTextAnimation>});
class ListOfFadedTextAnimation : public TestListViewSceneBase {
- void createListItem(RenderProperties& props, Canvas& canvas, int id,
- int itemWidth, int itemHeight) override {
+ void createListItem(RenderProperties& props, Canvas& canvas, int id, int itemWidth,
+ int itemHeight) override {
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
int length = dp(100);
canvas.saveLayer(0, 0, length, itemHeight, nullptr, SaveFlags::HasAlphaLayer);
@@ -44,8 +43,8 @@ class ListOfFadedTextAnimation : public TestListViewSceneBase {
pts[1].set(0, 1);
SkColor colors[2] = {Color::Black, Color::Transparent};
- sk_sp<SkShader> s(SkGradientShader::MakeLinear(pts, colors, NULL, 2,
- SkShader::kClamp_TileMode));
+ sk_sp<SkShader> s(
+ SkGradientShader::MakeLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode));
SkMatrix matrix;
matrix.setScale(1, length);
diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
index c1144be5b57c..d7ec288a8a7b 100644
--- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
@@ -22,11 +22,11 @@
class ListViewAnimation;
static TestScene::Registrar _ListView(TestScene::Info{
- "listview",
- "A mock ListView of scrolling content. Doesn't re-bind/re-record views as they are recycled, so"
- "won't upload much content (either glyphs, or bitmaps).",
- TestScene::simpleCreateScene<ListViewAnimation>
-});
+ "listview",
+ "A mock ListView of scrolling content. Doesn't re-bind/re-record views as they are "
+ "recycled, so"
+ "won't upload much content (either glyphs, or bitmaps).",
+ TestScene::simpleCreateScene<ListViewAnimation>});
class ListViewAnimation : public TestListViewSceneBase {
sk_sp<Bitmap> createRandomCharIcon(int cardHeight) {
@@ -42,15 +42,15 @@ class ListViewAnimation : public TestListViewSceneBase {
paint.setColor(randomColor);
canvas.drawCircle(size / 2, size / 2, size / 2, paint);
- bool bgDark = SkColorGetR(randomColor) + SkColorGetG(randomColor) + SkColorGetB(randomColor)
- < 128 * 3;
+ bool bgDark =
+ SkColorGetR(randomColor) + SkColorGetG(randomColor) + SkColorGetB(randomColor) <
+ 128 * 3;
paint.setColor(bgDark ? Color::White : Color::Grey_700);
paint.setTextAlign(SkPaint::kCenter_Align);
paint.setTextSize(size / 2);
char charToShow = 'A' + (rand() % 26);
- const SkPoint pos[] = {{
- SkIntToScalar(size / 2),
- /*approximate centering*/ SkFloatToScalar(size * 0.7f)}};
+ const SkPoint pos[] = {{SkIntToScalar(size / 2),
+ /*approximate centering*/ SkFloatToScalar(size * 0.7f)}};
canvas.drawPosText(&charToShow, 1, pos, paint);
return bitmap;
}
@@ -72,8 +72,8 @@ class ListViewAnimation : public TestListViewSceneBase {
return bitmap;
}
- void createListItem(RenderProperties& props, Canvas& canvas, int cardId,
- int itemWidth, int itemHeight) override {
+ void createListItem(RenderProperties& props, Canvas& canvas, int cardId, int itemWidth,
+ int itemHeight) override {
static sk_sp<Bitmap> filledBox(createBoxBitmap(true));
static sk_sp<Bitmap> strokedBox(createBoxBitmap(false));
// TODO: switch to using round rect clipping, once merging correctly handles that
@@ -92,7 +92,7 @@ class ListViewAnimation : public TestListViewSceneBase {
TestUtils::drawUtf8ToCanvas(&canvas, buf, textPaint, itemHeight, dp(25));
textPaint.setTextSize(dp(15));
TestUtils::drawUtf8ToCanvas(&canvas, "This is some more text on the card", textPaint,
- itemHeight, dp(45));
+ itemHeight, dp(45));
auto randomIcon = createRandomCharIcon(itemHeight);
canvas.drawBitmap(*randomIcon, dp(10), dp(10), nullptr);
diff --git a/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp b/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp
new file mode 100644
index 000000000000..9eddc209a9a9
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/MagnifierAnimation.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TestSceneBase.h"
+#include "renderthread/RenderProxy.h"
+#include "utils/Color.h"
+
+class MagnifierAnimation;
+
+static TestScene::Registrar _Magnifier(TestScene::Info{
+ "magnifier", "A sample magnifier using Readback",
+ TestScene::simpleCreateScene<MagnifierAnimation>});
+
+class MagnifierAnimation : public TestScene {
+public:
+ sp<RenderNode> card;
+ sp<RenderNode> zoomImageView;
+
+ void createContent(int width, int height, Canvas& canvas) override {
+ magnifier = TestUtils::createBitmap(200, 100);
+ SkBitmap temp;
+ magnifier->getSkBitmap(&temp);
+ temp.eraseColor(Color::White);
+ canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
+ card = TestUtils::createNode(
+ 0, 0, width, height, [&](RenderProperties& props, Canvas& canvas) {
+ SkPaint paint;
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setAntiAlias(true);
+ paint.setTextSize(50);
+
+ paint.setColor(Color::Black);
+ TestUtils::drawUtf8ToCanvas(&canvas, "Test string", paint, 10, 400);
+ });
+ canvas.drawRenderNode(card.get());
+ zoomImageView = TestUtils::createNode(
+ 100, 100, 500, 300, [&](RenderProperties& props, Canvas& canvas) {
+ props.setElevation(dp(16));
+ props.mutableOutline().setRoundRect(0, 0, props.getWidth(), props.getHeight(),
+ dp(6), 1);
+ props.mutableOutline().setShouldClip(true);
+ canvas.drawBitmap(*magnifier, 0.0f, 0.0f, (float)magnifier->width(),
+ (float)magnifier->height(), 0, 0, (float)props.getWidth(),
+ (float)props.getHeight(), nullptr);
+ });
+ canvas.insertReorderBarrier(true);
+ canvas.drawRenderNode(zoomImageView.get());
+ canvas.insertReorderBarrier(false);
+ }
+
+ void doFrame(int frameNr) override {
+ int curFrame = frameNr % 150;
+ card->mutateStagingProperties().setTranslationX(curFrame);
+ card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+ if (renderTarget) {
+ SkBitmap temp;
+ magnifier->getSkBitmap(&temp);
+ constexpr int x = 90;
+ constexpr int y = 325;
+ RenderProxy::copySurfaceInto(renderTarget, x, y, x + magnifier->width(),
+ y + magnifier->height(), &temp);
+ }
+ }
+
+ sk_sp<Bitmap> magnifier;
+};
diff --git a/libs/hwui/tests/common/scenes/OpPropAnimation.cpp b/libs/hwui/tests/common/scenes/OpPropAnimation.cpp
index 68051d63e855..a24cae0ecf8a 100644
--- a/libs/hwui/tests/common/scenes/OpPropAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/OpPropAnimation.cpp
@@ -20,10 +20,8 @@
class OpPropAnimation;
static TestScene::Registrar _Shapes(TestScene::Info{
- "opprops",
- "A minimal demonstration of CanvasProperty drawing operations.",
- TestScene::simpleCreateScene<OpPropAnimation>
-});
+ "opprops", "A minimal demonstration of CanvasProperty drawing operations.",
+ TestScene::simpleCreateScene<OpPropAnimation>});
class OpPropAnimation : public TestScene {
public:
@@ -42,8 +40,9 @@ public:
sp<RenderNode> content;
void createContent(int width, int height, Canvas& canvas) override {
- content = TestUtils::createNode(0, 0, width, height,
- [this, width, height](RenderProperties& props, Canvas& canvas) {
+ content = TestUtils::createNode(0, 0, width, height, [this, width, height](
+ RenderProperties& props,
+ Canvas& canvas) {
mPaint->value.setAntiAlias(true);
mPaint->value.setColor(Color::Blue_500);
@@ -54,9 +53,9 @@ public:
mCircleY->value = height * 0.75;
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
- canvas.drawRoundRect(mRoundRectLeft.get(), mRoundRectTop.get(),
- mRoundRectRight.get(), mRoundRectBottom.get(),
- mRoundRectRx.get(), mRoundRectRy.get(), mPaint.get());
+ canvas.drawRoundRect(mRoundRectLeft.get(), mRoundRectTop.get(), mRoundRectRight.get(),
+ mRoundRectBottom.get(), mRoundRectRx.get(), mRoundRectRy.get(),
+ mPaint.get());
canvas.drawCircle(mCircleX.get(), mCircleY.get(), mCircleRadius.get(), mPaint.get());
});
canvas.drawRenderNode(content.get());
diff --git a/libs/hwui/tests/common/scenes/OvalAnimation.cpp b/libs/hwui/tests/common/scenes/OvalAnimation.cpp
index d6fd60494812..4ff868b9d068 100644
--- a/libs/hwui/tests/common/scenes/OvalAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/OvalAnimation.cpp
@@ -19,19 +19,15 @@
class OvalAnimation;
-static TestScene::Registrar _Oval(TestScene::Info{
- "oval",
- "Draws 1 oval.",
- TestScene::simpleCreateScene<OvalAnimation>
-});
+static TestScene::Registrar _Oval(TestScene::Info{"oval", "Draws 1 oval.",
+ TestScene::simpleCreateScene<OvalAnimation>});
class OvalAnimation : public TestScene {
public:
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
- card = TestUtils::createNode(0, 0, 200, 200,
- [](RenderProperties& props, Canvas& canvas) {
+ card = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, Canvas& canvas) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(Color::Black);
diff --git a/libs/hwui/tests/common/scenes/PartialDamageAnimation.cpp b/libs/hwui/tests/common/scenes/PartialDamageAnimation.cpp
index bc04d81296df..fb1b000a995e 100644
--- a/libs/hwui/tests/common/scenes/PartialDamageAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/PartialDamageAnimation.cpp
@@ -19,22 +19,18 @@
class PartialDamageAnimation;
static TestScene::Registrar _PartialDamage(TestScene::Info{
- "partialdamage",
- "Tests the partial invalidation path. Draws a grid of rects and animates 1 "
- "of them, should be low CPU & GPU load if EGL_EXT_buffer_age or "
- "EGL_KHR_partial_update is supported by the device & are enabled in hwui.",
- TestScene::simpleCreateScene<PartialDamageAnimation>
-});
+ "partialdamage",
+ "Tests the partial invalidation path. Draws a grid of rects and animates 1 "
+ "of them, should be low CPU & GPU load if EGL_EXT_buffer_age or "
+ "EGL_KHR_partial_update is supported by the device & are enabled in hwui.",
+ TestScene::simpleCreateScene<PartialDamageAnimation>});
class PartialDamageAnimation : public TestScene {
public:
- std::vector< sp<RenderNode> > cards;
+ std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
static SkColor COLORS[] = {
- 0xFFF44336,
- 0xFF9C27B0,
- 0xFF2196F3,
- 0xFF4CAF50,
+ 0xFFF44336, 0xFF9C27B0, 0xFF2196F3, 0xFF4CAF50,
};
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
@@ -42,11 +38,11 @@ public:
for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
SkColor color = COLORS[static_cast<int>((y / dp(116))) % 4];
- sp<RenderNode> card = TestUtils::createNode(x, y,
- x + dp(100), y + dp(100),
- [color](RenderProperties& props, Canvas& canvas) {
- canvas.drawColor(color, SkBlendMode::kSrcOver);
- });
+ sp<RenderNode> card =
+ TestUtils::createNode(x, y, x + dp(100), y + dp(100),
+ [color](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(color, SkBlendMode::kSrcOver);
+ });
canvas.drawRenderNode(card.get());
cards.push_back(card);
}
@@ -59,8 +55,7 @@ public:
cards[0]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
TestUtils::recordNode(*cards[0], [curFrame](Canvas& canvas) {
- SkColor color = TestUtils::interpolateColor(
- curFrame / 150.0f, 0xFFF44336, 0xFFF8BBD0);
+ SkColor color = TestUtils::interpolateColor(curFrame / 150.0f, 0xFFF44336, 0xFFF8BBD0);
canvas.drawColor(color, SkBlendMode::kSrcOver);
});
}
diff --git a/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp b/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp
index bc6fc6452e90..1d17a021069b 100644
--- a/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp
+++ b/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp
@@ -19,10 +19,8 @@
class ReadbackFromHardware;
static TestScene::Registrar _SaveLayer(TestScene::Info{
- "readbackFromHBitmap",
- "Allocates hardware bitmap and readback data from it.",
- TestScene::simpleCreateScene<ReadbackFromHardware>
-});
+ "readbackFromHBitmap", "Allocates hardware bitmap and readback data from it.",
+ TestScene::simpleCreateScene<ReadbackFromHardware>});
class ReadbackFromHardware : public TestScene {
public:
@@ -41,7 +39,7 @@ public:
}
void createContent(int width, int height, Canvas& canvas) override {
- canvas.drawColor(Color::White, SkBlendMode::kSrcOver); // background
+ canvas.drawColor(Color::White, SkBlendMode::kSrcOver); // background
sk_sp<Bitmap> hardwareBitmap(createHardwareBitmap());
@@ -50,7 +48,7 @@ public:
SkBitmap canvasBitmap;
sk_sp<Bitmap> heapBitmap(TestUtils::createBitmap(hardwareBitmap->width(),
- hardwareBitmap->height(), &canvasBitmap));
+ hardwareBitmap->height(), &canvasBitmap));
SkCanvas skCanvas(canvasBitmap);
skCanvas.drawBitmap(readback, 0, 0);
@@ -59,5 +57,5 @@ public:
canvas.drawBitmap(*hardwareBitmap, 0, 500, nullptr);
}
- void doFrame(int frameNr) override { }
+ void doFrame(int frameNr) override {}
};
diff --git a/libs/hwui/tests/common/scenes/RecentsAnimation.cpp b/libs/hwui/tests/common/scenes/RecentsAnimation.cpp
index 825602466f92..3480a0f18407 100644
--- a/libs/hwui/tests/common/scenes/RecentsAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RecentsAnimation.cpp
@@ -20,20 +20,16 @@
class RecentsAnimation;
static TestScene::Registrar _Recents(TestScene::Info{
- "recents",
- "A recents-like scrolling list of textures. "
- "Consists of updating a texture every frame",
- TestScene::simpleCreateScene<RecentsAnimation>
-});
+ "recents",
+ "A recents-like scrolling list of textures. "
+ "Consists of updating a texture every frame",
+ TestScene::simpleCreateScene<RecentsAnimation>});
class RecentsAnimation : public TestScene {
public:
void createContent(int width, int height, Canvas& renderer) override {
static SkColor COLORS[] = {
- Color::Red_500,
- Color::Purple_500,
- Color::Blue_500,
- Color::Green_500,
+ Color::Red_500, Color::Purple_500, Color::Blue_500, Color::Green_500,
};
thumbnailSize = std::min(std::min(width, height) / 2, 720);
@@ -65,25 +61,26 @@ public:
mCards[ci]->mutateStagingProperties().setTranslationY(curFrame);
mCards[ci]->setPropertyFieldsDirty(RenderNode::Y);
}
- mThumbnail.eraseColor(TestUtils::interpolateColor(
- curFrame / 150.0f, Color::Green_500, Color::DeepOrange_500));
+ mThumbnail.eraseColor(TestUtils::interpolateColor(curFrame / 150.0f, Color::Green_500,
+ Color::DeepOrange_500));
}
private:
sp<RenderNode> createCard(int x, int y, int width, int height, Bitmap& thumb) {
- return TestUtils::createNode(x, y, x + width, y + height,
+ return TestUtils::createNode(
+ x, y, x + width, y + height,
[&thumb, width, height](RenderProperties& props, Canvas& canvas) {
- props.setElevation(dp(16));
- props.mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1);
- props.mutableOutline().setShouldClip(true);
+ props.setElevation(dp(16));
+ props.mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1);
+ props.mutableOutline().setShouldClip(true);
- canvas.drawColor(Color::Grey_200, SkBlendMode::kSrcOver);
- canvas.drawBitmap(thumb, 0, 0, thumb.width(), thumb.height(),
- 0, 0, width, height, nullptr);
- });
+ canvas.drawColor(Color::Grey_200, SkBlendMode::kSrcOver);
+ canvas.drawBitmap(thumb, 0, 0, thumb.width(), thumb.height(), 0, 0, width,
+ height, nullptr);
+ });
}
SkBitmap mThumbnail;
- std::vector< sp<RenderNode> > mCards;
+ std::vector<sp<RenderNode> > mCards;
int thumbnailSize;
};
diff --git a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
index 668eec69c2d0..6a3b6a57b28a 100644
--- a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
@@ -14,17 +14,15 @@
* limitations under the License.
*/
-
#include "TestSceneBase.h"
class RectGridAnimation;
static TestScene::Registrar _RectGrid(TestScene::Info{
- "rectgrid",
- "A dense grid of 1x1 rects that should visually look like a single rect. "
- "Low CPU/GPU load.",
- TestScene::simpleCreateScene<RectGridAnimation>
-});
+ "rectgrid",
+ "A dense grid of 1x1 rects that should visually look like a single rect. "
+ "Low CPU/GPU load.",
+ TestScene::simpleCreateScene<RectGridAnimation>});
class RectGridAnimation : public TestScene {
public:
@@ -33,13 +31,12 @@ public:
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
canvas.insertReorderBarrier(true);
- card = TestUtils::createNode(50, 50, 250, 250,
- [](RenderProperties& props, Canvas& canvas) {
+ card = TestUtils::createNode(50, 50, 250, 250, [](RenderProperties& props, Canvas& canvas) {
canvas.drawColor(0xFFFF00FF, SkBlendMode::kSrcOver);
SkRegion region;
- for (int xOffset = 0; xOffset < 200; xOffset+=2) {
- for (int yOffset = 0; yOffset < 200; yOffset+=2) {
+ for (int xOffset = 0; xOffset < 200; xOffset += 2) {
+ for (int yOffset = 0; yOffset < 200; yOffset += 2) {
region.op(xOffset, yOffset, xOffset + 1, yOffset + 1, SkRegion::kUnion_Op);
}
}
diff --git a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
index 4b6632d244f5..314e922e9f38 100644
--- a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
#include "TestSceneBase.h"
#include <vector>
@@ -23,10 +22,9 @@ class RoundRectClippingAnimation : public TestScene {
public:
int mSpacing, mSize;
- RoundRectClippingAnimation(int spacing, int size)
- : mSpacing(spacing), mSize(size) {}
+ RoundRectClippingAnimation(int spacing, int size) : mSpacing(spacing), mSize(size) {}
- std::vector< sp<RenderNode> > cards;
+ std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
canvas.insertReorderBarrier(true);
@@ -35,13 +33,13 @@ public:
for (int x = 0; x < width; x += mSpacing) {
for (int y = 0; y < height; y += mSpacing) {
auto color = BrightColors[ci++ % BrightColorsCount];
- auto card = TestUtils::createNode(x, y, x + mSize, y + mSize,
- [&](RenderProperties& props, Canvas& canvas) {
- canvas.drawColor(color, SkBlendMode::kSrcOver);
- props.mutableOutline().setRoundRect(0, 0,
- props.getWidth(), props.getHeight(), mSize * .25, 1);
- props.mutableOutline().setShouldClip(true);
- });
+ auto card = TestUtils::createNode(
+ x, y, x + mSize, y + mSize, [&](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(color, SkBlendMode::kSrcOver);
+ props.mutableOutline().setRoundRect(0, 0, props.getWidth(),
+ props.getHeight(), mSize * .25, 1);
+ props.mutableOutline().setShouldClip(true);
+ });
canvas.drawRenderNode(card.get());
cards.push_back(card);
}
@@ -61,17 +59,15 @@ public:
};
static TestScene::Registrar _RoundRectClippingGpu(TestScene::Info{
- "roundRectClipping-gpu",
- "A bunch of RenderNodes with round rect clipping outlines that's GPU limited.",
- [](const TestScene::Options&) -> test::TestScene* {
- return new RoundRectClippingAnimation(dp(40), dp(200));
- }
-});
+ "roundRectClipping-gpu",
+ "A bunch of RenderNodes with round rect clipping outlines that's GPU limited.",
+ [](const TestScene::Options&) -> test::TestScene* {
+ return new RoundRectClippingAnimation(dp(40), dp(200));
+ }});
static TestScene::Registrar _RoundRectClippingCpu(TestScene::Info{
- "roundRectClipping-cpu",
- "A bunch of RenderNodes with round rect clipping outlines that's CPU limited.",
- [](const TestScene::Options&) -> test::TestScene* {
- return new RoundRectClippingAnimation(dp(20), dp(20));
- }
-});
+ "roundRectClipping-cpu",
+ "A bunch of RenderNodes with round rect clipping outlines that's CPU limited.",
+ [](const TestScene::Options&) -> test::TestScene* {
+ return new RoundRectClippingAnimation(dp(20), dp(20));
+ }});
diff --git a/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
index d678af9bd3e4..75b231dd1052 100644
--- a/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
+++ b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
@@ -14,19 +14,18 @@
* limitations under the License.
*/
-#include "TestSceneBase.h"
-#include <string>
#include <hwui/Paint.h>
#include <minikin/Layout.h>
+#include <string>
+#include "TestSceneBase.h"
class SaveLayer2Animation;
static TestScene::Registrar _SaveLayer(TestScene::Info{
- "savelayer2",
- "Interleaving 20 drawText/drawRect ops with saveLayer"
- "Tests the clipped saveLayer performance and FBO switching overhead.",
- TestScene::simpleCreateScene<SaveLayer2Animation>
-});
+ "savelayer2",
+ "Interleaving 20 drawText/drawRect ops with saveLayer"
+ "Tests the clipped saveLayer performance and FBO switching overhead.",
+ TestScene::simpleCreateScene<SaveLayer2Animation>});
class SaveLayer2Animation : public TestScene {
public:
@@ -37,7 +36,7 @@ public:
canvas.drawColor(SkColorSetARGB(255, 255, 0, 0), SkBlendMode::kSrcOver);
SkIRect bounds = SkIRect::MakeWH(width, height);
int regions = 20;
- int smallRectHeight = (bounds.height()/regions);
+ int smallRectHeight = (bounds.height() / regions);
int padding = smallRectHeight / 4;
int top = bounds.fTop;
@@ -46,27 +45,26 @@ public:
mGreenPaint.setColor(SkColorSetARGB(255, 0, 255, 0));
mGreenPaint.setTextSize(padding);
- //interleave drawText and drawRect with saveLayer ops
+ // interleave drawText and drawRect with saveLayer ops
for (int i = 0; i < regions; i++, top += smallRectHeight) {
- canvas.saveLayer(bounds.fLeft, top, bounds.fRight, top + padding,
- &mBluePaint, SaveFlags::ClipToLayer | SaveFlags::MatrixClip);
+ canvas.saveLayer(bounds.fLeft, top, bounds.fRight, top + padding, &mBluePaint,
+ SaveFlags::ClipToLayer | SaveFlags::MatrixClip);
canvas.drawColor(SkColorSetARGB(255, 255, 255, 0), SkBlendMode::kSrcOver);
std::string stri = std::to_string(i);
std::string offscreen = "offscreen line " + stri;
std::unique_ptr<uint16_t[]> offtext = TestUtils::asciiToUtf16(offscreen.c_str());
- canvas.drawText(offtext.get(), 0, offscreen.length(), offscreen.length(),
- bounds.fLeft, top + padding, minikin::Bidi::FORCE_LTR, mBluePaint, nullptr);
+ canvas.drawText(offtext.get(), 0, offscreen.length(), offscreen.length(), bounds.fLeft,
+ top + padding, minikin::Bidi::FORCE_LTR, mBluePaint, nullptr);
canvas.restore();
canvas.drawRect(bounds.fLeft, top + padding, bounds.fRight,
- top + smallRectHeight - padding, mBluePaint);
+ top + smallRectHeight - padding, mBluePaint);
std::string onscreen = "onscreen line " + stri;
std::unique_ptr<uint16_t[]> ontext = TestUtils::asciiToUtf16(onscreen.c_str());
canvas.drawText(ontext.get(), 0, onscreen.length(), onscreen.length(), bounds.fLeft,
- top + smallRectHeight - padding, minikin::Bidi::FORCE_LTR, mGreenPaint,
- nullptr);
+ top + smallRectHeight - padding, minikin::Bidi::FORCE_LTR, mGreenPaint,
+ nullptr);
}
}
- void doFrame(int frameNr) override {
- }
+ void doFrame(int frameNr) override {}
};
diff --git a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
index 7e8a7d9d14f2..02dd42ff2ae8 100644
--- a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
@@ -19,20 +19,19 @@
class SaveLayerAnimation;
static TestScene::Registrar _SaveLayer(TestScene::Info{
- "savelayer",
- "A nested pair of clipped saveLayer operations. "
- "Tests the clipped saveLayer codepath. Draws content into offscreen buffers and back again.",
- TestScene::simpleCreateScene<SaveLayerAnimation>
-});
+ "savelayer",
+ "A nested pair of clipped saveLayer operations. "
+ "Tests the clipped saveLayer codepath. Draws content into offscreen buffers and back "
+ "again.",
+ TestScene::simpleCreateScene<SaveLayerAnimation>});
class SaveLayerAnimation : public TestScene {
public:
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
- canvas.drawColor(Color::White, SkBlendMode::kSrcOver); // background
+ canvas.drawColor(Color::White, SkBlendMode::kSrcOver); // background
- card = TestUtils::createNode(0, 0, 400, 800,
- [](RenderProperties& props, Canvas& canvas) {
+ card = TestUtils::createNode(0, 0, 400, 800, [](RenderProperties& props, Canvas& canvas) {
// nested clipped saveLayers
canvas.saveLayerAlpha(0, 0, 400, 400, 200, SaveFlags::ClipToLayer);
canvas.drawColor(Color::Green_700, SkBlendMode::kSrcOver);
@@ -45,7 +44,7 @@ public:
// single unclipped saveLayer
canvas.save(SaveFlags::MatrixClip);
canvas.translate(0, 400);
- canvas.saveLayerAlpha(100, 100, 300, 300, 128, SaveFlags::Flags(0)); // unclipped
+ canvas.saveLayerAlpha(100, 100, 300, 300, 128, SaveFlags::Flags(0)); // unclipped
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(Color::Green_700);
diff --git a/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp b/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp
index 0a69b62fe615..bdc991ba1890 100644
--- a/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp
+++ b/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp
@@ -19,15 +19,14 @@
class ShadowGrid2Animation;
static TestScene::Registrar _ShadowGrid2(TestScene::Info{
- "shadowgrid2",
- "A dense grid of rounded rects that cast a shadow. This is a higher CPU load "
- "variant of shadowgrid. Very high CPU load, high GPU load.",
- TestScene::simpleCreateScene<ShadowGrid2Animation>
-});
+ "shadowgrid2",
+ "A dense grid of rounded rects that cast a shadow. This is a higher CPU load "
+ "variant of shadowgrid. Very high CPU load, high GPU load.",
+ TestScene::simpleCreateScene<ShadowGrid2Animation>});
class ShadowGrid2Animation : public TestScene {
public:
- std::vector< sp<RenderNode> > cards;
+ std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
canvas.insertReorderBarrier(true);
@@ -50,14 +49,16 @@ public:
cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
}
+
private:
sp<RenderNode> createCard(int x, int y, int width, int height) {
return TestUtils::createNode(x, y, x + width, y + height,
- [width, height](RenderProperties& props, Canvas& canvas) {
- props.setElevation(dp(16));
- props.mutableOutline().setRoundRect(0, 0, width, height, dp(6), 1);
- props.mutableOutline().setShouldClip(true);
- canvas.drawColor(0xFFEEEEEE, SkBlendMode::kSrcOver);
- });
+ [width, height](RenderProperties& props, Canvas& canvas) {
+ props.setElevation(dp(16));
+ props.mutableOutline().setRoundRect(0, 0, width, height,
+ dp(6), 1);
+ props.mutableOutline().setShouldClip(true);
+ canvas.drawColor(0xFFEEEEEE, SkBlendMode::kSrcOver);
+ });
}
};
diff --git a/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp b/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp
index 4a024295cb25..a12fd4d69280 100644
--- a/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp
@@ -19,15 +19,14 @@
class ShadowGridAnimation;
static TestScene::Registrar _ShadowGrid(TestScene::Info{
- "shadowgrid",
- "A grid of rounded rects that cast a shadow. Simplified scenario of an "
- "Android TV-style launcher interface. High CPU/GPU load.",
- TestScene::simpleCreateScene<ShadowGridAnimation>
-});
+ "shadowgrid",
+ "A grid of rounded rects that cast a shadow. Simplified scenario of an "
+ "Android TV-style launcher interface. High CPU/GPU load.",
+ TestScene::simpleCreateScene<ShadowGridAnimation>});
class ShadowGridAnimation : public TestScene {
public:
- std::vector< sp<RenderNode> > cards;
+ std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
canvas.insertReorderBarrier(true);
@@ -50,14 +49,16 @@ public:
cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
}
+
private:
sp<RenderNode> createCard(int x, int y, int width, int height) {
return TestUtils::createNode(x, y, x + width, y + height,
- [width, height](RenderProperties& props, Canvas& canvas) {
- props.setElevation(dp(16));
- props.mutableOutline().setRoundRect(0, 0, width, height, dp(6), 1);
- props.mutableOutline().setShouldClip(true);
- canvas.drawColor(0xFFEEEEEE, SkBlendMode::kSrcOver);
- });
+ [width, height](RenderProperties& props, Canvas& canvas) {
+ props.setElevation(dp(16));
+ props.mutableOutline().setRoundRect(0, 0, width, height,
+ dp(6), 1);
+ props.mutableOutline().setShouldClip(true);
+ canvas.drawColor(0xFFEEEEEE, SkBlendMode::kSrcOver);
+ });
}
};
diff --git a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
index fac3968ff3d4..9f599100200e 100644
--- a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
@@ -19,23 +19,22 @@
class ShadowShaderAnimation;
static TestScene::Registrar _ShadowShader(TestScene::Info{
- "shadowshader",
- "A set of overlapping shadowed areas with simple tessellation useful for"
- " benchmarking shadow shader performance.",
- TestScene::simpleCreateScene<ShadowShaderAnimation>
-});
+ "shadowshader",
+ "A set of overlapping shadowed areas with simple tessellation useful for"
+ " benchmarking shadow shader performance.",
+ TestScene::simpleCreateScene<ShadowShaderAnimation>});
class ShadowShaderAnimation : public TestScene {
public:
- std::vector< sp<RenderNode> > cards;
+ std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
canvas.insertReorderBarrier(true);
int outset = 50;
for (int i = 0; i < 10; i++) {
- sp<RenderNode> card = createCard(outset, outset,
- width - (outset * 2), height - (outset * 2));
+ sp<RenderNode> card =
+ createCard(outset, outset, width - (outset * 2), height - (outset * 2));
canvas.drawRenderNode(card.get());
cards.push_back(card);
}
@@ -50,19 +49,24 @@ public:
cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
}
+
private:
sp<RenderNode> createCard(int x, int y, int width, int height) {
return TestUtils::createNode(x, y, x + width, y + height,
- [width, height](RenderProperties& props, Canvas& canvas) {
- props.setElevation(1000);
+ [width, height](RenderProperties& props, Canvas& canvas) {
+ props.setElevation(1000);
- // Set 0 radius, no clipping, so shadow is easy to compute. Slightly transparent outline
- // to signal contents aren't opaque (not necessary though, as elevation is so high, no
- // inner content to cut out)
- props.mutableOutline().setRoundRect(0, 0, width, height, 0, 0.99f);
- props.mutableOutline().setShouldClip(false);
+ // Set 0 radius, no clipping, so shadow is easy to compute.
+ // Slightly transparent outline
+ // to signal contents aren't opaque (not necessary though,
+ // as elevation is so high, no
+ // inner content to cut out)
+ props.mutableOutline().setRoundRect(0, 0, width, height, 0,
+ 0.99f);
+ props.mutableOutline().setShouldClip(false);
- // don't draw anything to card's canvas - we just want the shadow
- });
+ // don't draw anything to card's canvas - we just want the
+ // shadow
+ });
}
};
diff --git a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
index 09e70ebf7b5f..0d87776e083e 100644
--- a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
@@ -21,79 +21,75 @@
class ShapeAnimation;
-static TestScene::Registrar _Shapes(TestScene::Info{
- "shapes",
- "A grid of shape drawing test cases.",
- TestScene::simpleCreateScene<ShapeAnimation>
-});
+static TestScene::Registrar _Shapes(TestScene::Info{"shapes", "A grid of shape drawing test cases.",
+ TestScene::simpleCreateScene<ShapeAnimation>});
class ShapeAnimation : public TestScene {
public:
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
- card = TestUtils::createNode(0, 0, width, height,
- [width](RenderProperties& props, Canvas& canvas) {
- std::function<void(Canvas&, float, const SkPaint&)> ops[] = {
- [](Canvas& canvas, float size, const SkPaint& paint) {
- canvas.drawArc(0, 0, size, size, 50, 189, true, paint);
- },
- [](Canvas& canvas, float size, const SkPaint& paint) {
- canvas.drawOval(0, 0, size, size, paint);
- },
- [](Canvas& canvas, float size, const SkPaint& paint) {
- SkPath diamondPath;
- diamondPath.moveTo(size / 2, 0);
- diamondPath.lineTo(size, size / 2);
- diamondPath.lineTo(size / 2, size);
- diamondPath.lineTo(0, size / 2);
- diamondPath.close();
- canvas.drawPath(diamondPath, paint);
- },
- [](Canvas& canvas, float size, const SkPaint& paint) {
- float data[] = {0, 0, size, size, 0, size, size, 0 };
- canvas.drawLines(data, sizeof(data) / sizeof(float), paint);
- },
- [](Canvas& canvas, float size, const SkPaint& paint) {
- float data[] = {0, 0, size, size, 0, size, size, 0 };
- canvas.drawPoints(data, sizeof(data) / sizeof(float), paint);
- },
- [](Canvas& canvas, float size, const SkPaint& paint) {
- canvas.drawRect(0, 0, size, size, paint);
- },
- [](Canvas& canvas, float size, const SkPaint& paint) {
- float rad = size / 4;
- canvas.drawRoundRect(0, 0, size, size, rad, rad, paint);
- }
- };
- float cellSpace = dp(4);
- float cellSize = floorf(width / 7 - cellSpace);
+ card = TestUtils::createNode(
+ 0, 0, width, height, [width](RenderProperties& props, Canvas& canvas) {
+ std::function<void(Canvas&, float, const SkPaint&)> ops[] = {
+ [](Canvas& canvas, float size, const SkPaint& paint) {
+ canvas.drawArc(0, 0, size, size, 50, 189, true, paint);
+ },
+ [](Canvas& canvas, float size, const SkPaint& paint) {
+ canvas.drawOval(0, 0, size, size, paint);
+ },
+ [](Canvas& canvas, float size, const SkPaint& paint) {
+ SkPath diamondPath;
+ diamondPath.moveTo(size / 2, 0);
+ diamondPath.lineTo(size, size / 2);
+ diamondPath.lineTo(size / 2, size);
+ diamondPath.lineTo(0, size / 2);
+ diamondPath.close();
+ canvas.drawPath(diamondPath, paint);
+ },
+ [](Canvas& canvas, float size, const SkPaint& paint) {
+ float data[] = {0, 0, size, size, 0, size, size, 0};
+ canvas.drawLines(data, sizeof(data) / sizeof(float), paint);
+ },
+ [](Canvas& canvas, float size, const SkPaint& paint) {
+ float data[] = {0, 0, size, size, 0, size, size, 0};
+ canvas.drawPoints(data, sizeof(data) / sizeof(float), paint);
+ },
+ [](Canvas& canvas, float size, const SkPaint& paint) {
+ canvas.drawRect(0, 0, size, size, paint);
+ },
+ [](Canvas& canvas, float size, const SkPaint& paint) {
+ float rad = size / 4;
+ canvas.drawRoundRect(0, 0, size, size, rad, rad, paint);
+ }};
+ float cellSpace = dp(4);
+ float cellSize = floorf(width / 7 - cellSpace);
- // each combination of strokeWidth + style gets a column
- int outerCount = canvas.save(SaveFlags::MatrixClip);
- SkPaint paint;
- paint.setAntiAlias(true);
- SkPaint::Style styles[] = {
- SkPaint::kStroke_Style, SkPaint::kFill_Style, SkPaint::kStrokeAndFill_Style };
- for (auto style : styles) {
- paint.setStyle(style);
- for (auto strokeWidth : { 0.0f, 0.5f, 8.0f }) {
- paint.setStrokeWidth(strokeWidth);
- // fill column with each op
- int middleCount = canvas.save(SaveFlags::MatrixClip);
- for (auto op : ops) {
- int innerCount = canvas.save(SaveFlags::MatrixClip);
- canvas.clipRect(0, 0, cellSize, cellSize, SkClipOp::kIntersect);
- canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
- op(canvas, cellSize, paint);
- canvas.restoreToCount(innerCount);
- canvas.translate(cellSize + cellSpace, 0);
+ // each combination of strokeWidth + style gets a column
+ int outerCount = canvas.save(SaveFlags::MatrixClip);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkPaint::Style styles[] = {SkPaint::kStroke_Style, SkPaint::kFill_Style,
+ SkPaint::kStrokeAndFill_Style};
+ for (auto style : styles) {
+ paint.setStyle(style);
+ for (auto strokeWidth : {0.0f, 0.5f, 8.0f}) {
+ paint.setStrokeWidth(strokeWidth);
+ // fill column with each op
+ int middleCount = canvas.save(SaveFlags::MatrixClip);
+ for (auto op : ops) {
+ int innerCount = canvas.save(SaveFlags::MatrixClip);
+ canvas.clipRect(0, 0, cellSize, cellSize, SkClipOp::kIntersect);
+ canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
+ op(canvas, cellSize, paint);
+ canvas.restoreToCount(innerCount);
+ canvas.translate(cellSize + cellSpace, 0);
+ }
+ canvas.restoreToCount(middleCount);
+ canvas.translate(0, cellSize + cellSpace);
+ }
}
- canvas.restoreToCount(middleCount);
- canvas.translate(0, cellSize + cellSpace);
- }
- }
- canvas.restoreToCount(outerCount);
- });
+ canvas.restoreToCount(outerCount);
+ });
canvas.drawColor(Color::Grey_500, SkBlendMode::kSrcOver);
canvas.drawRenderNode(card.get());
}
diff --git a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
index a63a5852a9ff..ff0cb3705cb8 100644
--- a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
@@ -22,15 +22,15 @@
class SimpleColorMatrixAnimation;
static TestScene::Registrar _SimpleColorMatrix(TestScene::Info{
- "simpleColorMatrix",
- "A color matrix shader benchmark for the simple scale/translate case, which has R, G, and B "
- "all scaled and translated the same amount.",
- TestScene::simpleCreateScene<SimpleColorMatrixAnimation>
-});
+ "simpleColorMatrix",
+ "A color matrix shader benchmark for the simple scale/translate case, which has R, G, and "
+ "B "
+ "all scaled and translated the same amount.",
+ TestScene::simpleCreateScene<SimpleColorMatrixAnimation>});
class SimpleColorMatrixAnimation : public TestScene {
public:
- std::vector< sp<RenderNode> > cards;
+ std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
@@ -46,38 +46,41 @@ public:
cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
}
+
private:
sp<RenderNode> createCard(int x, int y, int width, int height) {
- return TestUtils::createNode(x, y, x + width, y + height,
+ return TestUtils::createNode(
+ x, y, x + width, y + height,
[width, height](RenderProperties& props, Canvas& canvas) {
- SkPaint paint;
- float matrix[20] = { 0 };
+ SkPaint paint;
+ float matrix[20] = {0};
- // Simple scale/translate case where R, G, and B are all treated equivalently
- matrix[SkColorMatrix::kR_Scale] = 1.1f;
- matrix[SkColorMatrix::kG_Scale] = 1.1f;
- matrix[SkColorMatrix::kB_Scale] = 1.1f;
- matrix[SkColorMatrix::kA_Scale] = 0.5f;
+ // Simple scale/translate case where R, G, and B are all treated equivalently
+ matrix[SkColorMatrix::kR_Scale] = 1.1f;
+ matrix[SkColorMatrix::kG_Scale] = 1.1f;
+ matrix[SkColorMatrix::kB_Scale] = 1.1f;
+ matrix[SkColorMatrix::kA_Scale] = 0.5f;
- matrix[SkColorMatrix::kR_Trans] = 5.0f;
- matrix[SkColorMatrix::kG_Trans] = 5.0f;
- matrix[SkColorMatrix::kB_Trans] = 5.0f;
- matrix[SkColorMatrix::kA_Trans] = 10.0f;
+ matrix[SkColorMatrix::kR_Trans] = 5.0f;
+ matrix[SkColorMatrix::kG_Trans] = 5.0f;
+ matrix[SkColorMatrix::kB_Trans] = 5.0f;
+ matrix[SkColorMatrix::kA_Trans] = 10.0f;
- paint.setColorFilter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
+ paint.setColorFilter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
- // set a shader so it's not likely for the matrix to be optimized away (since a clever
- // enough renderer might apply it directly to the paint color)
- float pos[] = { 0, 1 };
- SkPoint pts[] = { SkPoint::Make(0, 0), SkPoint::Make(width, height) };
- SkColor colors[2] = { Color::DeepPurple_500, Color::DeepOrange_500 };
- paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2,
- SkShader::kClamp_TileMode));
+ // set a shader so it's not likely for the matrix to be optimized away (since a
+ // clever
+ // enough renderer might apply it directly to the paint color)
+ float pos[] = {0, 1};
+ SkPoint pts[] = {SkPoint::Make(0, 0), SkPoint::Make(width, height)};
+ SkColor colors[2] = {Color::DeepPurple_500, Color::DeepOrange_500};
+ paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2,
+ SkShader::kClamp_TileMode));
- // overdraw several times to emphasize shader cost
- for (int i = 0; i < 10; i++) {
- canvas.drawRect(i, i, width, height, paint);
- }
- });
+ // overdraw several times to emphasize shader cost
+ for (int i = 0; i < 10; i++) {
+ canvas.drawRect(i, i, width, height, paint);
+ }
+ });
}
};
diff --git a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
index 053eb6dee31c..016c65c17c4c 100644
--- a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
#include "TestSceneBase.h"
#include <SkGradientShader.h>
@@ -22,14 +21,13 @@
class SimpleGradientAnimation;
static TestScene::Registrar _SimpleGradient(TestScene::Info{
- "simpleGradient",
- "A benchmark of shader performance of linear, 2 color gradients with black in them.",
- TestScene::simpleCreateScene<SimpleGradientAnimation>
-});
+ "simpleGradient",
+ "A benchmark of shader performance of linear, 2 color gradients with black in them.",
+ TestScene::simpleCreateScene<SimpleGradientAnimation>});
class SimpleGradientAnimation : public TestScene {
public:
- std::vector< sp<RenderNode> > cards;
+ std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
@@ -45,21 +43,23 @@ public:
cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
}
+
private:
sp<RenderNode> createCard(int x, int y, int width, int height) {
- return TestUtils::createNode(x, y, x + width, y + height,
+ return TestUtils::createNode(
+ x, y, x + width, y + height,
[width, height](RenderProperties& props, Canvas& canvas) {
- float pos[] = { 0, 1 };
- SkPoint pts[] = { SkPoint::Make(0, 0), SkPoint::Make(width, height) };
- SkPaint paint;
- // overdraw several times to emphasize shader cost
- for (int i = 0; i < 10; i++) {
- // use i%2 start position to pick 2 color combo with black in it
- SkColor colors[3] = { Color::Transparent, Color::Black, Color::Cyan_500 };
- paint.setShader(SkGradientShader::MakeLinear(pts, colors + (i % 2), pos, 2,
- SkShader::kClamp_TileMode));
- canvas.drawRect(i, i, width, height, paint);
- }
- });
+ float pos[] = {0, 1};
+ SkPoint pts[] = {SkPoint::Make(0, 0), SkPoint::Make(width, height)};
+ SkPaint paint;
+ // overdraw several times to emphasize shader cost
+ for (int i = 0; i < 10; i++) {
+ // use i%2 start position to pick 2 color combo with black in it
+ SkColor colors[3] = {Color::Transparent, Color::Black, Color::Cyan_500};
+ paint.setShader(SkGradientShader::MakeLinear(pts, colors + (i % 2), pos, 2,
+ SkShader::kClamp_TileMode));
+ canvas.drawRect(i, i, width, height, paint);
+ }
+ });
}
};
diff --git a/libs/hwui/tests/common/scenes/TextAnimation.cpp b/libs/hwui/tests/common/scenes/TextAnimation.cpp
index 438f877deb3e..a502116c30a0 100644
--- a/libs/hwui/tests/common/scenes/TextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/TextAnimation.cpp
@@ -15,23 +15,19 @@
*/
#include "TestSceneBase.h"
-#include "utils/Color.h"
class TextAnimation;
-static TestScene::Registrar _Text(TestScene::Info{
- "text",
- "Draws a bunch of text.",
- TestScene::simpleCreateScene<TextAnimation>
-});
+static TestScene::Registrar _Text(TestScene::Info{"text", "Draws a bunch of text.",
+ TestScene::simpleCreateScene<TextAnimation>});
class TextAnimation : public TestScene {
public:
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
- card = TestUtils::createNode(0, 0, width, height,
- [](RenderProperties& props, Canvas& canvas) {
+ card = TestUtils::createNode(0, 0, width, height, [](RenderProperties& props,
+ Canvas& canvas) {
SkPaint paint;
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setAntiAlias(true);
diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp
index 04fc2d46f946..c845e6c89747 100644
--- a/libs/hwui/tests/common/scenes/TvApp.cpp
+++ b/libs/hwui/tests/common/scenes/TvApp.cpp
@@ -14,40 +14,42 @@
* limitations under the License.
*/
+#include "SkBlendMode.h"
#include "TestSceneBase.h"
#include "tests/common/BitmapAllocationTestUtils.h"
-#include "SkBlendMode.h"
class TvApp;
class TvAppNoRoundedCorner;
class TvAppColorFilter;
class TvAppNoRoundedCornerColorFilter;
-static bool _TvApp(
- BitmapAllocationTestUtils::registerBitmapAllocationScene<TvApp>(
- "tvapp", "A dense grid of cards:"
- "with rounded corner, using overlay RenderNode for dimming."));
+static bool _TvApp(BitmapAllocationTestUtils::registerBitmapAllocationScene<TvApp>(
+ "tvapp",
+ "A dense grid of cards:"
+ "with rounded corner, using overlay RenderNode for dimming."));
static bool _TvAppNoRoundedCorner(
BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppNoRoundedCorner>(
- "tvapp_norc", "A dense grid of cards:"
+ "tvapp_norc",
+ "A dense grid of cards:"
"no rounded corner, using overlay RenderNode for dimming"));
static bool _TvAppColorFilter(
BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppColorFilter>(
- "tvapp_cf", "A dense grid of cards:"
+ "tvapp_cf",
+ "A dense grid of cards:"
"with rounded corner, using ColorFilter for dimming"));
static bool _TvAppNoRoundedCornerColorFilter(
BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppNoRoundedCornerColorFilter>(
- "tvapp_norc_cf", "A dense grid of cards:"
+ "tvapp_norc_cf",
+ "A dense grid of cards:"
"no rounded corner, using ColorFilter for dimming"));
class TvApp : public TestScene {
public:
TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator)
- : TestScene()
- , mAllocator(allocator) { }
+ : TestScene(), mAllocator(allocator) {}
sp<RenderNode> mBg;
std::vector<sp<RenderNode>> mCards;
@@ -66,9 +68,7 @@ public:
canvas.insertReorderBarrier(true);
mSingleBitmap = mAllocator(dp(160), dp(120), kRGBA_8888_SkColorType,
- [](SkBitmap& skBitmap) {
- skBitmap.eraseColor(0xFF0000FF);
- });
+ [](SkBitmap& skBitmap) { skBitmap.eraseColor(0xFF0000FF); });
for (int y = dp(18) - dp(178); y < height - dp(18); y += dp(178)) {
bool isFirstCard = true;
@@ -90,69 +90,64 @@ public:
}
private:
- sp<RenderNode> createBitmapNode(Canvas& canvas, SkColor color, int left, int top,
- int width, int height) {
- return TestUtils::createNode(left, top, left + width , top + height,
+ sp<RenderNode> createBitmapNode(Canvas& canvas, SkColor color, int left, int top, int width,
+ int height) {
+ return TestUtils::createNode(
+ left, top, left + width, top + height,
[this, width, height, color](RenderProperties& props, Canvas& canvas) {
- sk_sp<Bitmap> bitmap = mAllocator(width, height, kRGBA_8888_SkColorType,
- [color](SkBitmap& skBitmap) {
- skBitmap.eraseColor(color);
- });
- canvas.drawBitmap(*bitmap, 0, 0, nullptr);
- });
+ sk_sp<Bitmap> bitmap =
+ mAllocator(width, height, kRGBA_8888_SkColorType,
+ [color](SkBitmap& skBitmap) { skBitmap.eraseColor(color); });
+ canvas.drawBitmap(*bitmap, 0, 0, nullptr);
+ });
}
- sp<RenderNode> createSharedBitmapNode(Canvas& canvas, int left, int top,
- int width, int height, sk_sp<Bitmap>bitmap) {
- return TestUtils::createNode(left, top, left + width , top + height,
- [bitmap](RenderProperties& props, Canvas& canvas) {
- canvas.drawBitmap(*bitmap, 0, 0, nullptr);
- });
+ sp<RenderNode> createSharedBitmapNode(Canvas& canvas, int left, int top, int width, int height,
+ sk_sp<Bitmap> bitmap) {
+ return TestUtils::createNode(left, top, left + width, top + height,
+ [bitmap](RenderProperties& props, Canvas& canvas) {
+ canvas.drawBitmap(*bitmap, 0, 0, nullptr);
+ });
}
- sp<RenderNode> createInfoNode(Canvas& canvas, int left, int top,
- int width, int height, const char* text, const char* text2) {
- return TestUtils::createNode(left, top, left + width , top + height,
- [text, text2](RenderProperties& props, Canvas& canvas) {
- canvas.drawColor(0xFFFFEEEE, SkBlendMode::kSrcOver);
+ sp<RenderNode> createInfoNode(Canvas& canvas, int left, int top, int width, int height,
+ const char* text, const char* text2) {
+ return TestUtils::createNode(left, top, left + width, top + height,
+ [text, text2](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(0xFFFFEEEE, SkBlendMode::kSrcOver);
- SkPaint paint;
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- paint.setAntiAlias(true);
- paint.setTextSize(24);
+ SkPaint paint;
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setAntiAlias(true);
+ paint.setTextSize(24);
- paint.setColor(Color::Black);
- TestUtils::drawUtf8ToCanvas(&canvas, text, paint, 10, 30);
- paint.setTextSize(20);
- TestUtils::drawUtf8ToCanvas(&canvas, text2, paint, 10, 54);
+ paint.setColor(Color::Black);
+ TestUtils::drawUtf8ToCanvas(&canvas, text, paint, 10, 30);
+ paint.setTextSize(20);
+ TestUtils::drawUtf8ToCanvas(&canvas, text2, paint, 10, 54);
- });
+ });
}
- sp<RenderNode> createColorNode(Canvas& canvas, int left, int top,
- int width, int height, SkColor color) {
- return TestUtils::createNode(left, top, left + width , top + height,
- [color](RenderProperties& props, Canvas& canvas) {
- canvas.drawColor(color, SkBlendMode::kSrcOver);
- });
+ sp<RenderNode> createColorNode(Canvas& canvas, int left, int top, int width, int height,
+ SkColor color) {
+ return TestUtils::createNode(left, top, left + width, top + height,
+ [color](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(color, SkBlendMode::kSrcOver);
+ });
}
- virtual bool useSingleBitmap() {
- return false;
- }
+ virtual bool useSingleBitmap() { return false; }
- virtual float roundedCornerRadius() {
- return dp(2);
- }
+ virtual float roundedCornerRadius() { return dp(2); }
// when true, use overlay RenderNode for dimming, otherwise apply a ColorFilter to dim image
- virtual bool useOverlay() {
- return true;
- }
+ virtual bool useOverlay() { return true; }
sp<RenderNode> createCard(int x, int y, int width, int height, bool selected) {
- return TestUtils::createNode(x, y, x + width, y + height,
- [width, height, selected, this](RenderProperties& props, Canvas& canvas) {
+ return TestUtils::createNode(x, y, x + width, y + height, [width, height, selected, this](
+ RenderProperties& props,
+ Canvas& canvas) {
if (selected) {
props.setElevation(dp(16));
props.setScaleX(1.2);
@@ -161,12 +156,14 @@ private:
props.mutableOutline().setRoundRect(0, 0, width, height, roundedCornerRadius(), 1);
props.mutableOutline().setShouldClip(true);
- sk_sp<Bitmap> bitmap = useSingleBitmap() ? mSingleBitmap
- : mAllocator(width, dp(120), kRGBA_8888_SkColorType, [this](SkBitmap& skBitmap) {
- skBitmap.eraseColor(0xFF000000 | ((mSeed << 3) & 0xFF));
- });
- sp<RenderNode> cardImage = createSharedBitmapNode(canvas, 0, 0, width, dp(120),
- bitmap);
+ sk_sp<Bitmap> bitmap =
+ useSingleBitmap() ? mSingleBitmap
+ : mAllocator(width, dp(120), kRGBA_8888_SkColorType,
+ [this](SkBitmap& skBitmap) {
+ skBitmap.eraseColor(0xFF000000 |
+ ((mSeed << 3) & 0xFF));
+ });
+ sp<RenderNode> cardImage = createSharedBitmapNode(canvas, 0, 0, width, dp(120), bitmap);
canvas.drawRenderNode(cardImage.get());
mCachedBitmaps.push_back(bitmap);
mImages.push_back(cardImage);
@@ -176,12 +173,14 @@ private:
mSeed++;
char buffer2[128];
sprintf(buffer2, "Studio %d", mSeed2++);
- sp<RenderNode> infoArea = createInfoNode(canvas, 0, dp(120), width, height, buffer, buffer2);
+ sp<RenderNode> infoArea =
+ createInfoNode(canvas, 0, dp(120), width, height, buffer, buffer2);
canvas.drawRenderNode(infoArea.get());
mInfoAreas.push_back(infoArea);
if (useOverlay()) {
- sp<RenderNode> overlayColor = createColorNode(canvas, 0, 0, width, height, 0x00000000);
+ sp<RenderNode> overlayColor =
+ createColorNode(canvas, 0, 0, width, height, 0x00000000);
canvas.drawRenderNode(overlayColor.get());
mOverlays.push_back(overlayColor);
}
@@ -196,30 +195,28 @@ private:
// re-recording card's canvas, not necessary but to add some burden to CPU
std::unique_ptr<Canvas> cardcanvas(Canvas::create_recording_canvas(
- card->stagingProperties().getWidth(),
- card->stagingProperties().getHeight()));
+ card->stagingProperties().getWidth(), card->stagingProperties().getHeight()));
sp<RenderNode> image = mImages[ci];
sp<RenderNode> infoArea = mInfoAreas[ci];
cardcanvas->drawRenderNode(infoArea.get());
if (useOverlay()) {
- cardcanvas->drawRenderNode(image.get());
+ cardcanvas->drawRenderNode(image.get());
// re-recording card overlay's canvas, animating overlay color alpha
sp<RenderNode> overlay = mOverlays[ci];
- std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
- overlay->stagingProperties().getWidth(),
- overlay->stagingProperties().getHeight()));
+ std::unique_ptr<Canvas> canvas(
+ Canvas::create_recording_canvas(overlay->stagingProperties().getWidth(),
+ overlay->stagingProperties().getHeight()));
canvas->drawColor((curFrame % 150) << 24, SkBlendMode::kSrcOver);
overlay->setStagingDisplayList(canvas->finishRecording());
cardcanvas->drawRenderNode(overlay.get());
} else {
// re-recording image node's canvas, animating ColorFilter
std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
- image->stagingProperties().getWidth(),
- image->stagingProperties().getHeight()));
+ image->stagingProperties().getWidth(), image->stagingProperties().getHeight()));
SkPaint paint;
- sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter((curFrame % 150) << 24,
- SkBlendMode::kSrcATop));
+ sk_sp<SkColorFilter> filter(
+ SkColorFilter::MakeModeFilter((curFrame % 150) << 24, SkBlendMode::kSrcATop));
paint.setColorFilter(filter);
sk_sp<Bitmap> bitmap = mCachedBitmaps[ci];
canvas->drawBitmap(*bitmap, 0, 0, &paint);
@@ -233,42 +230,27 @@ private:
class TvAppNoRoundedCorner : public TvApp {
public:
- TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator)
- : TvApp(allocator) { }
+ TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
private:
-
- virtual float roundedCornerRadius() override {
- return dp(0);
- }
+ virtual float roundedCornerRadius() override { return dp(0); }
};
class TvAppColorFilter : public TvApp {
public:
- TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
- : TvApp(allocator) { }
+ TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
private:
-
- virtual bool useOverlay() override {
- return false;
- }
+ virtual bool useOverlay() override { return false; }
};
class TvAppNoRoundedCornerColorFilter : public TvApp {
public:
TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
- : TvApp(allocator) { }
+ : TvApp(allocator) {}
private:
+ virtual float roundedCornerRadius() override { return dp(0); }
- virtual float roundedCornerRadius() override {
- return dp(0);
- }
-
- virtual bool useOverlay() override {
- return false;
- }
+ virtual bool useOverlay() override { return false; }
};
-
-
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index f8d63978bb53..9428f532434a 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -16,11 +16,11 @@
#include "AnimationContext.h"
#include "RenderNode.h"
+#include "renderthread/RenderProxy.h"
+#include "renderthread/RenderTask.h"
#include "tests/common/TestContext.h"
#include "tests/common/TestScene.h"
#include "tests/common/scenes/TestSceneBase.h"
-#include "renderthread/RenderProxy.h"
-#include "renderthread/RenderTask.h"
#include <benchmark/benchmark.h>
#include <gui/Surface.h>
@@ -39,7 +39,7 @@ public:
}
};
-template<class T>
+template <class T>
class ModifiedMovingAverage {
public:
explicit ModifiedMovingAverage(int weight) : mWeight(weight) {}
@@ -53,9 +53,7 @@ public:
return mAverage;
}
- T average() {
- return mAverage;
- }
+ T average() { return mAverage; }
private:
bool mHasValue = false;
@@ -64,8 +62,8 @@ private:
};
void outputBenchmarkReport(const TestScene::Info& info, const TestScene::Options& opts,
- benchmark::BenchmarkReporter* reporter, RenderProxy* proxy,
- double durationInS) {
+ benchmark::BenchmarkReporter* reporter, RenderProxy* proxy,
+ double durationInS) {
using namespace benchmark;
struct ReportInfo {
@@ -74,10 +72,8 @@ void outputBenchmarkReport(const TestScene::Info& info, const TestScene::Options
};
static std::array<ReportInfo, 4> REPORTS = {
- ReportInfo { 50, "_50th" },
- ReportInfo { 90, "_90th" },
- ReportInfo { 95, "_95th" },
- ReportInfo { 99, "_99th" },
+ ReportInfo{50, "_50th"}, ReportInfo{90, "_90th"}, ReportInfo{95, "_95th"},
+ ReportInfo{99, "_99th"},
};
// Although a vector is used, it must stay with only a single element
@@ -111,12 +107,10 @@ void outputBenchmarkReport(const TestScene::Info& info, const TestScene::Options
}
void run(const TestScene::Info& info, const TestScene::Options& opts,
- benchmark::BenchmarkReporter* reporter) {
+ benchmark::BenchmarkReporter* reporter) {
// Switch to the real display
gDisplay = getBuiltInDisplay();
- std::unique_ptr<TestScene> scene(info.createScene(opts));
-
Properties::forceDrawFrame = true;
TestContext testContext;
testContext.setRenderOffscreen(opts.renderOffscreen);
@@ -126,15 +120,17 @@ void run(const TestScene::Info& info, const TestScene::Options& opts,
const int height = gDisplay.h;
sp<Surface> surface = testContext.surface();
- sp<RenderNode> rootNode = TestUtils::createNode(0, 0, width, height,
- [&scene, width, height](RenderProperties& props, Canvas& canvas) {
- props.setClipToBounds(false);
- scene->createContent(width, height, canvas);
- });
+ std::unique_ptr<TestScene> scene(info.createScene(opts));
+ scene->renderTarget = surface;
+
+ sp<RenderNode> rootNode = TestUtils::createNode(
+ 0, 0, width, height, [&scene, width, height](RenderProperties& props, Canvas& canvas) {
+ props.setClipToBounds(false);
+ scene->createContent(width, height, canvas);
+ });
ContextFactory factory;
- std::unique_ptr<RenderProxy> proxy(new RenderProxy(false,
- rootNode.get(), &factory));
+ std::unique_ptr<RenderProxy> proxy(new RenderProxy(false, rootNode.get(), &factory));
proxy->loadSystemProperties();
proxy->initialize(surface);
float lightX = width / 2.0;
@@ -182,8 +178,7 @@ void run(const TestScene::Info& info, const TestScene::Options& opts,
nsecs_t end = systemTime(CLOCK_MONOTONIC);
if (reporter) {
- outputBenchmarkReport(info, opts, reporter, proxy.get(),
- (end - start) / (double) s2ns(1));
+ outputBenchmarkReport(info, opts, reporter, proxy.get(), (end - start) / (double)s2ns(1));
} else {
proxy->dumpProfileInfo(STDOUT_FILENO, DumpFlags::JankStats);
}
diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp
index 1f5622252f6a..8c0ca5c12d1e 100644
--- a/libs/hwui/tests/macrobench/main.cpp
+++ b/libs/hwui/tests/macrobench/main.cpp
@@ -17,24 +17,24 @@
#include "tests/common/LeakChecker.h"
#include "tests/common/TestScene.h"
+#include "Properties.h"
#include "hwui/Typeface.h"
#include "protos/hwui.pb.h"
-#include "Properties.h"
-#include <benchmark/benchmark.h>
#include <../src/sysinfo.h>
+#include <benchmark/benchmark.h>
#include <getopt.h>
+#include <pthread.h>
#include <stdio.h>
-#include <string>
#include <unistd.h>
+#include <string>
#include <unordered_map>
#include <vector>
-#include <pthread.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
using namespace android;
using namespace android::uirenderer;
@@ -46,7 +46,7 @@ static TestScene::Options gOpts;
std::unique_ptr<benchmark::BenchmarkReporter> gBenchmarkReporter;
void run(const TestScene::Info& info, const TestScene::Options& opts,
- benchmark::BenchmarkReporter* reporter);
+ benchmark::BenchmarkReporter* reporter);
static void printHelp() {
printf(R"(
@@ -68,6 +68,7 @@ OPTIONS:
--onscreen Render tests on device screen. By default tests
are offscreen rendered
--benchmark_format Set output format. Possible values are tabular, json, csv
+ --renderer=TYPE Sets the render pipeline to use. May be opengl, skiagl, or skiavk
)");
}
@@ -82,7 +83,7 @@ static void listTests() {
do {
int toPrint = dlen;
if (toPrint > 50) {
- char* found = (char*) memrchr(col2, ' ', 50);
+ char* found = (char*)memrchr(col2, ' ', 50);
if (found) {
toPrint = found - col2;
} else {
@@ -94,7 +95,8 @@ static void listTests() {
col2 += toPrint;
dlen -= toPrint;
while (*col2 == ' ') {
- col2++; dlen--;
+ col2++;
+ dlen--;
}
} while (dlen > 0);
printf("\n");
@@ -120,7 +122,7 @@ static void moveToCpuSet(const char* cpusetName) {
}
pid_t pid = getpid();
- int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long) pid);
+ int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long)pid);
if (towrite >= BUF_SIZE) {
fprintf(stderr, "Buffer wasn't large enough?\n");
} else {
@@ -145,6 +147,20 @@ static bool setBenchmarkFormat(const char* format) {
return true;
}
+static bool setRenderer(const char* renderer) {
+ if (!strcmp(renderer, "opengl")) {
+ Properties::overrideRenderPipelineType(RenderPipelineType::OpenGL);
+ } else if (!strcmp(renderer, "skiagl")) {
+ Properties::overrideRenderPipelineType(RenderPipelineType::SkiaGL);
+ } else if (!strcmp(renderer, "skiavk")) {
+ Properties::overrideRenderPipelineType(RenderPipelineType::SkiaVulkan);
+ } else {
+ fprintf(stderr, "Unknown format '%s'", renderer);
+ return false;
+ }
+ return true;
+}
+
// For options that only exist in long-form. Anything in the
// 0-255 range is reserved for short options (which just use their ASCII value)
namespace LongOpts {
@@ -157,22 +173,23 @@ enum {
BenchmarkFormat,
Onscreen,
Offscreen,
+ Renderer,
};
}
static const struct option LONG_OPTIONS[] = {
- { "frames", required_argument, nullptr, 'f' },
- { "repeat", required_argument, nullptr, 'r' },
- { "help", no_argument, nullptr, 'h' },
- { "list", no_argument, nullptr, LongOpts::List },
- { "wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu },
- { "report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime },
- { "cpuset", required_argument, nullptr, LongOpts::CpuSet },
- { "benchmark_format", required_argument, nullptr, LongOpts::BenchmarkFormat },
- { "onscreen", no_argument, nullptr, LongOpts::Onscreen },
- { "offscreen", no_argument, nullptr, LongOpts::Offscreen },
- { 0, 0, 0, 0 }
-};
+ {"frames", required_argument, nullptr, 'f'},
+ {"repeat", required_argument, nullptr, 'r'},
+ {"help", no_argument, nullptr, 'h'},
+ {"list", no_argument, nullptr, LongOpts::List},
+ {"wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu},
+ {"report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime},
+ {"cpuset", required_argument, nullptr, LongOpts::CpuSet},
+ {"benchmark_format", required_argument, nullptr, LongOpts::BenchmarkFormat},
+ {"onscreen", no_argument, nullptr, LongOpts::Onscreen},
+ {"offscreen", no_argument, nullptr, LongOpts::Offscreen},
+ {"renderer", required_argument, nullptr, LongOpts::Renderer},
+ {0, 0, 0, 0}};
static const char* SHORT_OPTIONS = "c:r:h";
@@ -182,97 +199,105 @@ void parseOptions(int argc, char* argv[]) {
opterr = 0;
while (true) {
-
/* getopt_long stores the option index here. */
int option_index = 0;
c = getopt_long(argc, argv, SHORT_OPTIONS, LONG_OPTIONS, &option_index);
- if (c == -1)
- break;
+ if (c == -1) break;
switch (c) {
- case 0:
- // Option set a flag, don't need to do anything
- // (although none of the current LONG_OPTIONS do this...)
- break;
-
- case LongOpts::List:
- listTests();
- exit(EXIT_SUCCESS);
- break;
-
- case 'c':
- gOpts.count = atoi(optarg);
- if (!gOpts.count) {
- fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
- error = true;
- }
- break;
+ case 0:
+ // Option set a flag, don't need to do anything
+ // (although none of the current LONG_OPTIONS do this...)
+ break;
- case 'r':
- gRepeatCount = atoi(optarg);
- if (!gRepeatCount) {
- fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
- error = true;
- } else {
- gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX);
- }
- break;
+ case LongOpts::List:
+ listTests();
+ exit(EXIT_SUCCESS);
+ break;
- case LongOpts::ReportFrametime:
- if (optarg) {
- gOpts.reportFrametimeWeight = atoi(optarg);
- if (!gOpts.reportFrametimeWeight) {
- fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
+ case 'c':
+ gOpts.count = atoi(optarg);
+ if (!gOpts.count) {
+ fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
error = true;
}
- } else {
- gOpts.reportFrametimeWeight = 10;
- }
- break;
+ break;
- case LongOpts::WaitForGpu:
- Properties::waitForGpuCompletion = true;
- break;
+ case 'r':
+ gRepeatCount = atoi(optarg);
+ if (!gRepeatCount) {
+ fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
+ error = true;
+ } else {
+ gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX);
+ }
+ break;
- case LongOpts::CpuSet:
- if (!optarg) {
- error = true;
+ case LongOpts::ReportFrametime:
+ if (optarg) {
+ gOpts.reportFrametimeWeight = atoi(optarg);
+ if (!gOpts.reportFrametimeWeight) {
+ fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
+ error = true;
+ }
+ } else {
+ gOpts.reportFrametimeWeight = 10;
+ }
break;
- }
- moveToCpuSet(optarg);
- break;
- case LongOpts::BenchmarkFormat:
- if (!optarg) {
- error = true;
+ case LongOpts::WaitForGpu:
+ Properties::waitForGpuCompletion = true;
+ break;
+
+ case LongOpts::CpuSet:
+ if (!optarg) {
+ error = true;
+ break;
+ }
+ moveToCpuSet(optarg);
+ break;
+
+ case LongOpts::BenchmarkFormat:
+ if (!optarg) {
+ error = true;
+ break;
+ }
+ if (!setBenchmarkFormat(optarg)) {
+ error = true;
+ }
+ break;
+
+ case LongOpts::Renderer:
+ if (!optarg) {
+ error = true;
+ break;
+ }
+ if (!setRenderer(optarg)) {
+ error = true;
+ }
break;
- }
- if (!setBenchmarkFormat(optarg)) {
- error = true;
- }
- break;
- case LongOpts::Onscreen:
- gOpts.renderOffscreen = false;
- break;
+ case LongOpts::Onscreen:
+ gOpts.renderOffscreen = false;
+ break;
- case LongOpts::Offscreen:
- gOpts.renderOffscreen = true;
- break;
+ case LongOpts::Offscreen:
+ gOpts.renderOffscreen = true;
+ break;
- case 'h':
- printHelp();
- exit(EXIT_SUCCESS);
- break;
+ case 'h':
+ printHelp();
+ exit(EXIT_SUCCESS);
+ break;
- case '?':
- fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]);
+ case '?':
+ fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]);
// fall-through
- default:
- error = true;
- break;
+ default:
+ error = true;
+ break;
}
}
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index 3089447cbfc5..0aaf7731c927 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -114,7 +114,7 @@ void BM_DisplayListCanvas_record_simpleBitmapView(benchmark::State& benchState)
}
BENCHMARK(BM_DisplayListCanvas_record_simpleBitmapView);
-class NullClient: public CanvasStateClient {
+class NullClient : public CanvasStateClient {
void onViewportInitialized() override {}
void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
GLuint getTargetFbo() const override { return 0; }
@@ -161,8 +161,7 @@ void BM_CanvasState_translate(benchmark::State& benchState) {
BENCHMARK(BM_CanvasState_translate);
void BM_DisplayListCanvas_basicViewGroupDraw(benchmark::State& benchState) {
- sp<RenderNode> child = TestUtils::createNode(50, 50, 100, 100,
- [](auto& props, auto& canvas) {
+ sp<RenderNode> child = TestUtils::createNode(50, 50, 100, 100, [](auto& props, auto& canvas) {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
});
@@ -171,7 +170,7 @@ void BM_DisplayListCanvas_basicViewGroupDraw(benchmark::State& benchState) {
while (benchState.KeepRunning()) {
canvas->resetRecording(200, 200);
- canvas->translate(0, 0); // mScrollX, mScrollY
+ canvas->translate(0, 0); // mScrollX, mScrollY
// Clip to padding
// Can expect ~25% of views to have clip to padding with a non-null padding
diff --git a/libs/hwui/tests/microbench/FontBench.cpp b/libs/hwui/tests/microbench/FontBench.cpp
index df3d041e722d..4e9b540a5c3d 100644
--- a/libs/hwui/tests/microbench/FontBench.cpp
+++ b/libs/hwui/tests/microbench/FontBench.cpp
@@ -37,8 +37,8 @@ void BM_FontRenderer_precache_cachehits(benchmark::State& state) {
std::vector<float> positions;
float totalAdvance;
uirenderer::Rect bounds;
- TestUtils::layoutTextUnscaled(paint, "This is a test",
- &glyphs, &positions, &totalAdvance, &bounds);
+ TestUtils::layoutTextUnscaled(paint, "This is a test", &glyphs, &positions, &totalAdvance,
+ &bounds);
fontRenderer.precache(&paint, glyphs.data(), glyphs.size(), SkMatrix::I());
diff --git a/libs/hwui/tests/microbench/FrameBuilderBench.cpp b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
index a5e85df22c8e..b6217665d743 100644
--- a/libs/hwui/tests/microbench/FrameBuilderBench.cpp
+++ b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
@@ -16,17 +16,17 @@
#include <benchmark/benchmark.h>
-#include "BakedOpState.h"
#include "BakedOpDispatcher.h"
#include "BakedOpRenderer.h"
+#include "BakedOpState.h"
#include "FrameBuilder.h"
#include "LayerUpdateQueue.h"
#include "RecordedOp.h"
#include "RecordingCanvas.h"
+#include "Vector.h"
#include "tests/common/TestContext.h"
#include "tests/common/TestScene.h"
#include "tests/common/TestUtils.h"
-#include "Vector.h"
#include <vector>
@@ -35,25 +35,25 @@ using namespace android::uirenderer;
using namespace android::uirenderer::renderthread;
using namespace android::uirenderer::test;
-const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
-const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
+const FrameBuilder::LightGeometry sLightGeometry = {{100, 100, 100}, 50};
+const BakedOpRenderer::LightInfo sLightInfo = {128, 128};
static sp<RenderNode> createTestNode() {
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- sk_sp<Bitmap> bitmap(TestUtils::createBitmap(10, 10));
- SkPaint paint;
-
- // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
- // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
- canvas.save(SaveFlags::MatrixClip);
- for (int i = 0; i < 30; i++) {
- canvas.translate(0, 10);
- canvas.drawRect(0, 0, 10, 10, paint);
- canvas.drawBitmap(*bitmap, 5, 0, nullptr);
- }
- canvas.restore();
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ sk_sp<Bitmap> bitmap(TestUtils::createBitmap(10, 10));
+ SkPaint paint;
+
+ // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
+ // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
+ canvas.save(SaveFlags::MatrixClip);
+ for (int i = 0; i < 30; i++) {
+ canvas.translate(0, 10);
+ canvas.drawRect(0, 0, 10, 10, paint);
+ canvas.drawBitmap(*bitmap, 5, 0, nullptr);
+ }
+ canvas.restore();
+ });
TestUtils::syncHierarchyPropertiesAndDisplayList(node);
return node;
}
@@ -62,8 +62,8 @@ void BM_FrameBuilder_defer(benchmark::State& state) {
TestUtils::runOnRenderThread([&state](RenderThread& thread) {
auto node = createTestNode();
while (state.KeepRunning()) {
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*node);
benchmark::DoNotOptimize(&frameBuilder);
}
@@ -79,8 +79,7 @@ void BM_FrameBuilder_deferAndRender(benchmark::State& state) {
Caches& caches = Caches::getInstance();
while (state.KeepRunning()) {
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
- sLightGeometry, caches);
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200, sLightGeometry, caches);
frameBuilder.deferRenderNode(*node);
BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo);
@@ -92,16 +91,17 @@ void BM_FrameBuilder_deferAndRender(benchmark::State& state) {
BENCHMARK(BM_FrameBuilder_deferAndRender);
static sp<RenderNode> getSyncedSceneNode(const char* sceneName) {
- gDisplay = getBuiltInDisplay(); // switch to real display if present
+ gDisplay = getBuiltInDisplay(); // switch to real display if present
TestContext testContext;
TestScene::Options opts;
std::unique_ptr<TestScene> scene(TestScene::testMap()[sceneName].createScene(opts));
- sp<RenderNode> rootNode = TestUtils::createNode<RecordingCanvas>(0, 0, gDisplay.w, gDisplay.h,
- [&scene](RenderProperties& props, RecordingCanvas& canvas) {
- scene->createContent(gDisplay.w, gDisplay.h, canvas);
- });
+ sp<RenderNode> rootNode = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, gDisplay.w, gDisplay.h,
+ [&scene](RenderProperties& props, RecordingCanvas& canvas) {
+ scene->createContent(gDisplay.w, gDisplay.h, canvas);
+ });
TestUtils::syncHierarchyPropertiesAndDisplayList(rootNode);
return rootNode;
@@ -117,9 +117,8 @@ void BM_FrameBuilder_defer_scene(benchmark::State& state) {
state.SetLabel(sceneName);
auto node = getSyncedSceneNode(sceneName);
while (state.KeepRunning()) {
- FrameBuilder frameBuilder(SkRect::MakeWH(gDisplay.w, gDisplay.h),
- gDisplay.w, gDisplay.h,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w,
+ gDisplay.h, sLightGeometry, Caches::getInstance());
frameBuilder.deferRenderNode(*node);
benchmark::DoNotOptimize(&frameBuilder);
}
@@ -137,9 +136,8 @@ void BM_FrameBuilder_deferAndRender_scene(benchmark::State& state) {
Caches& caches = Caches::getInstance();
while (state.KeepRunning()) {
- FrameBuilder frameBuilder(SkRect::MakeWH(gDisplay.w, gDisplay.h),
- gDisplay.w, gDisplay.h,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w,
+ gDisplay.h, sLightGeometry, Caches::getInstance());
frameBuilder.deferRenderNode(*node);
BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo);
diff --git a/libs/hwui/tests/microbench/PathParserBench.cpp b/libs/hwui/tests/microbench/PathParserBench.cpp
index b43c4c3b63c1..00ae8c11124f 100644
--- a/libs/hwui/tests/microbench/PathParserBench.cpp
+++ b/libs/hwui/tests/microbench/PathParserBench.cpp
@@ -24,7 +24,9 @@
using namespace android;
using namespace android::uirenderer;
-static const char* sPathString = "M 1 1 m 2 2, l 3 3 L 3 3 H 4 h4 V5 v5, Q6 6 6 6 q 6 6 6 6t 7 7 T 7 7 C 8 8 8 8 8 8 c 8 8 8 8 8 8 S 9 9 9 9 s 9 9 9 9 A 10 10 0 1 1 10 10 a 10 10 0 1 1 10 10";
+static const char* sPathString =
+ "M 1 1 m 2 2, l 3 3 L 3 3 H 4 h4 V5 v5, Q6 6 6 6 q 6 6 6 6t 7 7 T 7 7 C 8 8 8 8 8 8 c 8 8 "
+ "8 8 8 8 S 9 9 9 9 s 9 9 9 9 A 10 10 0 1 1 10 10 a 10 10 0 1 1 10 10";
void BM_PathParser_parseStringPathForSkPath(benchmark::State& state) {
SkPath skPath;
diff --git a/libs/hwui/tests/microbench/RenderNodeBench.cpp b/libs/hwui/tests/microbench/RenderNodeBench.cpp
index a5bed0026b1c..206dcd58d785 100644
--- a/libs/hwui/tests/microbench/RenderNodeBench.cpp
+++ b/libs/hwui/tests/microbench/RenderNodeBench.cpp
@@ -30,4 +30,3 @@ void BM_RenderNode_create(benchmark::State& state) {
}
}
BENCHMARK(BM_RenderNode_create);
-
diff --git a/libs/hwui/tests/microbench/ShadowBench.cpp b/libs/hwui/tests/microbench/ShadowBench.cpp
index a0fc6e8f9f53..12da7837e2e9 100644
--- a/libs/hwui/tests/microbench/ShadowBench.cpp
+++ b/libs/hwui/tests/microbench/ShadowBench.cpp
@@ -18,9 +18,9 @@
#include "Matrix.h"
#include "Rect.h"
+#include "TessellationCache.h"
#include "Vector.h"
#include "VertexBuffer.h"
-#include "TessellationCache.h"
#include <SkPath.h>
@@ -40,22 +40,13 @@ struct ShadowTestData {
void createShadowTestData(ShadowTestData* out) {
static float SAMPLE_DRAW_TRANSFORM[] = {
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1,
+ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
};
static float SAMPLE_CASTERXY[] = {
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 32, 32, 0, 1,
+ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 32, 32, 0, 1,
};
static float SAMPLE_CASTERZ[] = {
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 32, 32, 32, 1,
+ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 32, 32, 32, 1,
};
static Rect SAMPLE_CLIP(0, 0, 1536, 2048);
static Vector3 SAMPLE_LIGHT_CENTER{768, -400, 1600};
@@ -69,12 +60,11 @@ void createShadowTestData(ShadowTestData* out) {
out->lightRadius = SAMPLE_LIGHT_RADIUS;
}
-static inline void tessellateShadows(ShadowTestData& testData, bool opaque,
- const SkPath& shape, VertexBuffer* ambient, VertexBuffer* spot) {
- tessellateShadows(&testData.drawTransform, &testData.localClip,
- opaque, &shape, &testData.casterTransformXY,
- &testData.casterTransformZ, testData.lightCenter,
- testData.lightRadius, *ambient, *spot);
+static inline void tessellateShadows(ShadowTestData& testData, bool opaque, const SkPath& shape,
+ VertexBuffer* ambient, VertexBuffer* spot) {
+ tessellateShadows(&testData.drawTransform, &testData.localClip, opaque, &shape,
+ &testData.casterTransformXY, &testData.casterTransformZ, testData.lightCenter,
+ testData.lightRadius, *ambient, *spot);
}
void BM_TessellateShadows_roundrect_opaque(benchmark::State& state) {
diff --git a/libs/hwui/tests/microbench/TaskManagerBench.cpp b/libs/hwui/tests/microbench/TaskManagerBench.cpp
index 67cb428102d3..4153baec22b5 100644
--- a/libs/hwui/tests/microbench/TaskManagerBench.cpp
+++ b/libs/hwui/tests/microbench/TaskManagerBench.cpp
@@ -31,10 +31,9 @@ class TrivialTask : public Task<char> {};
class TrivialProcessor : public TaskProcessor<char> {
public:
- explicit TrivialProcessor(TaskManager* manager)
- : TaskProcessor(manager) {}
+ explicit TrivialProcessor(TaskManager* manager) : TaskProcessor(manager) {}
virtual ~TrivialProcessor() {}
- virtual void onProcess(const sp<Task<char> >& task) override {
+ virtual void onProcess(const sp<Task<char>>& task) override {
TrivialTask* t = static_cast<TrivialTask*>(task.get());
t->setResult(reinterpret_cast<intptr_t>(t) % 16 == 0 ? 'a' : 'b');
}
@@ -43,7 +42,7 @@ public:
class TestThread : public ThreadBase, public virtual RefBase {};
void BM_TaskManager_allocateTask(benchmark::State& state) {
- std::vector<sp<TrivialTask> > tasks;
+ std::vector<sp<TrivialTask>> tasks;
tasks.reserve(state.max_iterations);
while (state.KeepRunning()) {
@@ -56,7 +55,7 @@ BENCHMARK(BM_TaskManager_allocateTask);
void BM_TaskManager_enqueueTask(benchmark::State& state) {
TaskManager taskManager;
sp<TrivialProcessor> processor(new TrivialProcessor(&taskManager));
- std::vector<sp<TrivialTask> > tasks;
+ std::vector<sp<TrivialTask>> tasks;
tasks.reserve(state.max_iterations);
while (state.KeepRunning()) {
@@ -74,7 +73,7 @@ BENCHMARK(BM_TaskManager_enqueueTask);
void BM_TaskManager_enqueueRunDeleteTask(benchmark::State& state) {
TaskManager taskManager;
sp<TrivialProcessor> processor(new TrivialProcessor(&taskManager));
- std::vector<sp<TrivialTask> > tasks;
+ std::vector<sp<TrivialTask>> tasks;
tasks.reserve(state.max_iterations);
while (state.KeepRunning()) {
@@ -99,11 +98,9 @@ void BM_Thread_enqueueTask(benchmark::State& state) {
int expected = 0;
while (state.KeepRunning()) {
expected++;
- thread->queue().post([&counter](){
- counter++;
- });
+ thread->queue().post([&counter]() { counter++; });
}
- thread->queue().runSync([](){});
+ thread->queue().runSync([]() {});
thread->requestExit();
thread->join();
@@ -121,9 +118,7 @@ void BM_Thread_enqueueRunDeleteTask(benchmark::State& state) {
int expected = 0;
while (state.KeepRunning()) {
- tasks.emplace_back(thread->queue().async([expected]() -> int {
- return expected + 1;
- }));
+ tasks.emplace_back(thread->queue().async([expected]() -> int { return expected + 1; }));
expected++;
}
state.ResumeTiming();
diff --git a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
index b0ef11f26bdd..09f0b06ded39 100644
--- a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
@@ -20,8 +20,8 @@
#include <BakedOpRenderer.h>
#include <FrameBuilder.h>
#include <LayerUpdateQueue.h>
-#include <hwui/Paint.h>
#include <RecordedOp.h>
+#include <hwui/Paint.h>
#include <tests/common/TestUtils.h>
#include <utils/Color.h>
@@ -32,19 +32,20 @@
using namespace android::uirenderer;
static BakedOpRenderer::LightInfo sLightInfo;
-const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
+const FrameBuilder::LightGeometry sLightGeometry = {{100, 100, 100}, 50};
class ValidatingBakedOpRenderer : public BakedOpRenderer {
public:
- ValidatingBakedOpRenderer(RenderState& renderState, std::function<void(const Glop& glop)> validator)
+ ValidatingBakedOpRenderer(RenderState& renderState,
+ std::function<void(const Glop& glop)> validator)
: BakedOpRenderer(Caches::getInstance(), renderState, true, false, sLightInfo)
, mValidator(validator) {
mGlopReceiver = ValidatingGlopReceiver;
}
+
private:
static void ValidatingGlopReceiver(BakedOpRenderer& renderer, const Rect* dirtyBounds,
- const ClipBase* clip, const Glop& glop) {
-
+ const ClipBase* clip, const Glop& glop) {
auto vbor = reinterpret_cast<ValidatingBakedOpRenderer*>(&renderer);
vbor->mValidator(glop);
}
@@ -54,7 +55,8 @@ private:
typedef void (*TestBakedOpReceiver)(BakedOpRenderer&, const BakedOpState&);
static void testUnmergedGlopDispatch(renderthread::RenderThread& renderThread, RecordedOp* op,
- std::function<void(const Glop& glop)> glopVerifier, int expectedGlopCount = 1) {
+ std::function<void(const Glop& glop)> glopVerifier,
+ int expectedGlopCount = 1) {
// Create op, and wrap with basic state.
LinearAllocator allocator;
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 100));
@@ -62,22 +64,22 @@ static void testUnmergedGlopDispatch(renderthread::RenderThread& renderThread, R
ASSERT_NE(nullptr, state);
int glopCount = 0;
- auto glopReceiver = [&glopVerifier, &glopCount, &expectedGlopCount] (const Glop& glop) {
+ auto glopReceiver = [&glopVerifier, &glopCount, &expectedGlopCount](const Glop& glop) {
ASSERT_LE(glopCount++, expectedGlopCount) << expectedGlopCount << "glop(s) expected";
glopVerifier(glop);
};
ValidatingBakedOpRenderer renderer(renderThread.renderState(), glopReceiver);
- // Dispatch based on op type created, similar to Frame/LayerBuilder dispatch behavior
-#define X(Type) \
- [](BakedOpRenderer& renderer, const BakedOpState& state) { \
- BakedOpDispatcher::on##Type(renderer, static_cast<const Type&>(*(state.op)), state); \
- },
+// Dispatch based on op type created, similar to Frame/LayerBuilder dispatch behavior
+#define X(Type) \
+ [](BakedOpRenderer& renderer, const BakedOpState& state) { \
+ BakedOpDispatcher::on##Type(renderer, static_cast<const Type&>(*(state.op)), state); \
+ },
static TestBakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X);
#undef X
unmergedReceivers[op->opId](renderer, *state);
ASSERT_EQ(expectedGlopCount, glopCount) << "Exactly " << expectedGlopCount
- << "Glop(s) expected";
+ << "Glop(s) expected";
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, pathTexture_positionOvalArc) {
@@ -88,7 +90,7 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, pathTexture_positionOvalArc
float intervals[] = {1.0f, 1.0f};
strokePaint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0));
- auto textureGlopVerifier = [] (const Glop& glop) {
+ auto textureGlopVerifier = [](const Glop& glop) {
// validate glop produced by renderPathTexture (so texture, unit quad)
auto texture = glop.fill.texture.texture;
ASSERT_NE(nullptr, texture);
@@ -116,16 +118,15 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, pathTexture_positionOvalArc
RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, onLayerOp_bufferless) {
SkPaint layerPaint;
layerPaint.setAlpha(128);
- OffscreenBuffer* buffer = nullptr; // no providing a buffer, should hit rect fallback case
+ OffscreenBuffer* buffer = nullptr; // no providing a buffer, should hit rect fallback case
LayerOp op(Rect(10, 10), Matrix4::identity(), nullptr, &layerPaint, &buffer);
- testUnmergedGlopDispatch(renderThread, &op, [] (const Glop& glop) {
- ADD_FAILURE() << "Nothing should happen";
- }, 0);
+ testUnmergedGlopDispatch(renderThread, &op,
+ [](const Glop& glop) { ADD_FAILURE() << "Nothing should happen"; }, 0);
}
static int getGlopTransformFlags(renderthread::RenderThread& renderThread, RecordedOp* op) {
int result = 0;
- testUnmergedGlopDispatch(renderThread, op, [&result] (const Glop& glop) {
+ testUnmergedGlopDispatch(renderThread, op, [&result](const Glop& glop) {
result = glop.transform.transformFlags;
});
return result;
@@ -144,7 +145,7 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, offsetFlags) {
const float points[4] = {0.5, 0.5, 1.0, 1.0};
PointsOp antiAliasedPointsOp(bounds, Matrix4::identity(), nullptr, &aaPaint, points, 4);
EXPECT_EQ(TransformFlags::None, getGlopTransformFlags(renderThread, &antiAliasedPointsOp))
- << "Expect no offset for AA points.";
+ << "Expect no offset for AA points.";
PointsOp pointsOp(bounds, Matrix4::identity(), nullptr, &paint, points, 4);
EXPECT_EQ(TransformFlags::OffsetByFudgeFactor, getGlopTransformFlags(renderThread, &pointsOp))
<< "Expect an offset for non-AA points.";
@@ -158,21 +159,21 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, offsetFlags) {
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, renderTextWithShadow) {
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
- android::Paint shadowPaint;
- shadowPaint.setColor(SK_ColorRED);
+ android::Paint shadowPaint;
+ shadowPaint.setColor(SK_ColorRED);
- SkScalar sigma = Blur::convertRadiusToSigma(5);
- shadowPaint.setLooper(SkBlurDrawLooper::Make(SK_ColorWHITE, sigma, 3, 3));
+ SkScalar sigma = Blur::convertRadiusToSigma(5);
+ shadowPaint.setLooper(SkBlurDrawLooper::Make(SK_ColorWHITE, sigma, 3, 3));
- TestUtils::drawUtf8ToCanvas(&canvas, "A", shadowPaint, 25, 25);
- TestUtils::drawUtf8ToCanvas(&canvas, "B", shadowPaint, 50, 50);
- });
+ TestUtils::drawUtf8ToCanvas(&canvas, "A", shadowPaint, 25, 25);
+ TestUtils::drawUtf8ToCanvas(&canvas, "B", shadowPaint, 50, 50);
+ });
- int glopCount = 0;
- auto glopReceiver = [&glopCount] (const Glop& glop) {
+ int glopCount = 0;
+ auto glopReceiver = [&glopCount](const Glop& glop) {
if (glopCount < 2) {
// two white shadows
EXPECT_EQ(FloatColor({1, 1, 1, 1}), glop.fill.color);
@@ -185,8 +186,8 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, renderTextWithShadow) {
ValidatingBakedOpRenderer renderer(renderThread.renderState(), glopReceiver);
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
@@ -194,15 +195,15 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, renderTextWithShadow) {
}
static void validateLayerDraw(renderthread::RenderThread& renderThread,
- std::function<void(const Glop& glop)> validator) {
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- props.mutateLayerProperties().setType(LayerType::RenderLayer);
-
- // provide different blend mode, so decoration draws contrast
- props.mutateLayerProperties().setXferMode(SkBlendMode::kSrc);
- canvas.drawColor(Color::Black, SkBlendMode::kSrcOver);
- });
+ std::function<void(const Glop& glop)> validator) {
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.mutateLayerProperties().setType(LayerType::RenderLayer);
+
+ // provide different blend mode, so decoration draws contrast
+ props.mutateLayerProperties().setXferMode(SkBlendMode::kSrc);
+ canvas.drawColor(Color::Black, SkBlendMode::kSrcOver);
+ });
OffscreenBuffer** layerHandle = node->getLayerHandle();
auto syncedNode = TestUtils::getSyncedNode(node);
@@ -211,12 +212,12 @@ static void validateLayerDraw(renderthread::RenderThread& renderThread,
OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
*layerHandle = &layer;
{
- LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+ LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(0, 0, 100, 100));
ValidatingBakedOpRenderer renderer(renderThread.renderState(), validator);
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferLayers(layerUpdateQueue);
frameBuilder.deferRenderNode(*syncedNode);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
@@ -233,8 +234,8 @@ static FloatColor makeFloatColor(uint32_t color) {
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, layerUpdateProperties) {
- for (bool debugOverdraw : { false, true }) {
- for (bool debugLayersUpdates : { false, true }) {
+ for (bool debugOverdraw : {false, true}) {
+ for (bool debugLayersUpdates : {false, true}) {
ScopedProperty<bool> ovdProp(Properties::debugOverdraw, debugOverdraw);
ScopedProperty<bool> lupProp(Properties::debugLayersUpdates, debugLayersUpdates);
@@ -253,8 +254,8 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, layerUpdateProperties) {
// blend srcover, different from that of layer
EXPECT_EQ(GLenum(GL_ONE), glop.blend.src);
EXPECT_EQ(GLenum(GL_ONE_MINUS_SRC_ALPHA), glop.blend.dst);
- EXPECT_EQ(makeFloatColor(debugLayersUpdates ? 0x7f00ff00 : 0),
- glop.fill.color) << "Should be transparent green if debugLayersUpdates";
+ EXPECT_EQ(makeFloatColor(debugLayersUpdates ? 0x7f00ff00 : 0), glop.fill.color)
+ << "Should be transparent green if debugLayersUpdates";
} else if (glopCount < 7) {
// 3 - 6 - overdraw indicator overlays, if present
EXPECT_TRUE(glop.fill.colorEnabled);
@@ -279,7 +280,7 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, pathTextureSnapping) {
SkPath path;
path.addRect(SkRect::MakeXYWH(1.5, 3.8, 100, 90));
PathOp op(bounds, Matrix4::identity(), nullptr, &paint, &path);
- testUnmergedGlopDispatch(renderThread, &op, [] (const Glop& glop) {
+ testUnmergedGlopDispatch(renderThread, &op, [](const Glop& glop) {
auto texture = glop.fill.texture.texture;
ASSERT_NE(nullptr, texture);
EXPECT_EQ(1, reinterpret_cast<PathTexture*>(texture)->left);
diff --git a/libs/hwui/tests/unit/BakedOpRendererTests.cpp b/libs/hwui/tests/unit/BakedOpRendererTests.cpp
index 38e106a8ab77..1a3ec39a00d0 100644
--- a/libs/hwui/tests/unit/BakedOpRendererTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpRendererTests.cpp
@@ -22,11 +22,11 @@
using namespace android::uirenderer;
-const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
+const BakedOpRenderer::LightInfo sLightInfo = {128, 128};
RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpRenderer, startRepaintLayer_clear) {
- BakedOpRenderer renderer(Caches::getInstance(), renderThread.renderState(),
- true, false, sLightInfo);
+ BakedOpRenderer renderer(Caches::getInstance(), renderThread.renderState(), true, false,
+ sLightInfo);
OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200u, 200u);
layer.dirty(Rect(200, 200));
@@ -38,9 +38,9 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpRenderer, startRepaintLayer_clear) {
layer.dirty(Rect(200, 200));
{
- renderer.startRepaintLayer(&layer, Rect(100, 200)); // repainting left side
+ renderer.startRepaintLayer(&layer, Rect(100, 200)); // repainting left side
EXPECT_TRUE(layer.region.isRect());
- //ALOGD("bounds %d %d %d %d", RECT_ARGS(layer.region.getBounds()));
+ // ALOGD("bounds %d %d %d %d", RECT_ARGS(layer.region.getBounds()));
EXPECT_EQ(android::Rect(100, 0, 200, 200), layer.region.getBounds())
<< "Left side being repainted, so right side should be clear";
renderer.endLayer();
@@ -48,7 +48,7 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpRenderer, startRepaintLayer_clear) {
// right side is now only dirty portion
{
- renderer.startRepaintLayer(&layer, Rect(100, 0, 200, 200)); // repainting right side
+ renderer.startRepaintLayer(&layer, Rect(100, 0, 200, 200)); // repainting right side
EXPECT_TRUE(layer.region.isEmpty())
<< "Now right side being repainted, so region should be entirely clear";
renderer.endLayer();
diff --git a/libs/hwui/tests/unit/BakedOpStateTests.cpp b/libs/hwui/tests/unit/BakedOpStateTests.cpp
index d51db2ebb169..6f8e24917767 100644
--- a/libs/hwui/tests/unit/BakedOpStateTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpStateTests.cpp
@@ -38,7 +38,7 @@ TEST(ResolvedRenderState, construct) {
ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false);
EXPECT_MATRIX_APPROX_EQ(state.transform, translate10x20);
EXPECT_EQ(Rect(100, 200), state.clipRect());
- EXPECT_EQ(Rect(40, 60, 100, 200), state.clippedBounds); // translated and also clipped
+ EXPECT_EQ(Rect(40, 60, 100, 200), state.clippedBounds); // translated and also clipped
EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
}
{
@@ -72,14 +72,14 @@ TEST(ResolvedRenderState, computeLocalSpaceClip) {
auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false);
EXPECT_EQ(Rect(-10, -20, 90, 180), state.computeLocalSpaceClip())
- << "Local clip rect should be 100x200, offset by -10,-20";
+ << "Local clip rect should be 100x200, offset by -10,-20";
}
{
// recorded with transform + parent transform
auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false);
EXPECT_EQ(Rect(-10, -20, 80, 160), state.computeLocalSpaceClip())
- << "Local clip rect should be 90x190, offset by -10,-20";
+ << "Local clip rect should be 90x190, offset by -10,-20";
}
}
@@ -96,62 +96,51 @@ struct StrokeTestCase {
};
const static StrokeTestCase sStrokeTestCases[] = {
- {
- 1, HAIRLINE, [](const ResolvedRenderState& state) {
- EXPECT_EQ(Rect(49.5f, 49.5f, 150.5f, 150.5f), state.clippedBounds);
- }
- },
- {
- 1, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
- EXPECT_TRUE(state.clippedBounds.contains(49.5f, 49.5f, 150.5f, 150.5f));
- EXPECT_TRUE(Rect(49, 49, 151, 151).contains(state.clippedBounds));
- }
- },
- {
- 1, 20, [](const ResolvedRenderState& state) {
- EXPECT_EQ(Rect(40, 40, 160, 160), state.clippedBounds);
- }
- },
-
- // 3x3 scale:
- {
- 3, HAIRLINE, [](const ResolvedRenderState& state) {
- EXPECT_EQ(Rect(149.5f, 149.5f, 200, 200), state.clippedBounds);
- EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
- }
- },
- {
- 3, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
- EXPECT_TRUE(state.clippedBounds.contains(149.5f, 149.5f, 200, 200));
- EXPECT_TRUE(Rect(149, 149, 200, 200).contains(state.clippedBounds));
- }
- },
- {
- 3, 20, [](const ResolvedRenderState& state) {
- EXPECT_TRUE(state.clippedBounds.contains(120, 120, 200, 200));
- EXPECT_TRUE(Rect(119, 119, 200, 200).contains(state.clippedBounds));
- }
- },
-
- // 0.5f x 0.5f scale
- {
- 0.5f, HAIRLINE, [](const ResolvedRenderState& state) {
- EXPECT_EQ(Rect(24.5f, 24.5f, 75.5f, 75.5f), state.clippedBounds);
- }
- },
- {
- 0.5f, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
- EXPECT_TRUE(state.clippedBounds.contains(24.5f, 24.5f, 75.5f, 75.5f));
- EXPECT_TRUE(Rect(24, 24, 76, 76).contains(state.clippedBounds));
- }
- },
- {
- 0.5f, 20, [](const ResolvedRenderState& state) {
- EXPECT_TRUE(state.clippedBounds.contains(19.5f, 19.5f, 80.5f, 80.5f));
- EXPECT_TRUE(Rect(19, 19, 81, 81).contains(state.clippedBounds));
- }
- }
-};
+ {1, HAIRLINE,
+ [](const ResolvedRenderState& state) {
+ EXPECT_EQ(Rect(49.5f, 49.5f, 150.5f, 150.5f), state.clippedBounds);
+ }},
+ {1, SEMI_HAIRLINE,
+ [](const ResolvedRenderState& state) {
+ EXPECT_TRUE(state.clippedBounds.contains(49.5f, 49.5f, 150.5f, 150.5f));
+ EXPECT_TRUE(Rect(49, 49, 151, 151).contains(state.clippedBounds));
+ }},
+ {1, 20,
+ [](const ResolvedRenderState& state) {
+ EXPECT_EQ(Rect(40, 40, 160, 160), state.clippedBounds);
+ }},
+
+ // 3x3 scale:
+ {3, HAIRLINE,
+ [](const ResolvedRenderState& state) {
+ EXPECT_EQ(Rect(149.5f, 149.5f, 200, 200), state.clippedBounds);
+ EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
+ }},
+ {3, SEMI_HAIRLINE,
+ [](const ResolvedRenderState& state) {
+ EXPECT_TRUE(state.clippedBounds.contains(149.5f, 149.5f, 200, 200));
+ EXPECT_TRUE(Rect(149, 149, 200, 200).contains(state.clippedBounds));
+ }},
+ {3, 20,
+ [](const ResolvedRenderState& state) {
+ EXPECT_TRUE(state.clippedBounds.contains(120, 120, 200, 200));
+ EXPECT_TRUE(Rect(119, 119, 200, 200).contains(state.clippedBounds));
+ }},
+
+ // 0.5f x 0.5f scale
+ {0.5f, HAIRLINE,
+ [](const ResolvedRenderState& state) {
+ EXPECT_EQ(Rect(24.5f, 24.5f, 75.5f, 75.5f), state.clippedBounds);
+ }},
+ {0.5f, SEMI_HAIRLINE,
+ [](const ResolvedRenderState& state) {
+ EXPECT_TRUE(state.clippedBounds.contains(24.5f, 24.5f, 75.5f, 75.5f));
+ EXPECT_TRUE(Rect(24, 24, 76, 76).contains(state.clippedBounds));
+ }},
+ {0.5f, 20, [](const ResolvedRenderState& state) {
+ EXPECT_TRUE(state.clippedBounds.contains(19.5f, 19.5f, 80.5f, 80.5f));
+ EXPECT_TRUE(Rect(19, 19, 81, 81).contains(state.clippedBounds));
+ }}};
TEST(ResolvedRenderState, construct_expandForStroke) {
LinearAllocator allocator;
@@ -163,8 +152,7 @@ TEST(ResolvedRenderState, construct_expandForStroke) {
strokedPaint.setStrokeWidth(testCase.strokeWidth);
ClipRect clip(Rect(200, 200));
- RectOp recordedOp(Rect(50, 50, 150, 150),
- Matrix4::identity(), &clip, &strokedPaint);
+ RectOp recordedOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &strokedPaint);
Matrix4 snapshotMatrix;
snapshotMatrix.loadScale(testCase.scale, testCase.scale, 1);
@@ -204,16 +192,18 @@ TEST(BakedOpState, tryShadowOpConstruct) {
LinearAllocator allocator;
{
- auto snapshot = TestUtils::makeSnapshot(translate10x20, Rect()); // Note: empty clip
- BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
+ auto snapshot = TestUtils::makeSnapshot(translate10x20, Rect()); // Note: empty clip
+ BakedOpState* bakedState =
+ BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
EXPECT_EQ(nullptr, bakedState) << "op should be rejected by clip, so not constructed";
EXPECT_EQ(0u, allocator.usedSize()) << "no serialization, even for clip,"
- "since op is quick rejected based on snapshot clip";
+ "since op is quick rejected based on snapshot clip";
}
{
auto snapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
- BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
+ BakedOpState* bakedState =
+ BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
ASSERT_NE(nullptr, bakedState) << "NOT rejected by clip, so op should be constructed";
EXPECT_LE(64u, allocator.usedSize()) << "relatively large alloc for non-rejected op";
@@ -232,12 +222,13 @@ TEST(BakedOpState, tryStrokeableOpConstruct) {
paint.setStrokeWidth(0.0f);
ClipRect clip(Rect(100, 200));
RectOp rejectOp(Rect(100, 200), Matrix4::identity(), &clip, &paint);
- auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
- auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
- BakedOpState::StrokeBehavior::StyleDefined, false);
+ auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
+ auto bakedState = BakedOpState::tryStrokeableOpConstruct(
+ allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::StyleDefined, false);
EXPECT_EQ(nullptr, bakedState);
- EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
+ EXPECT_GT(8u,
+ allocator.usedSize()); // no significant allocation space used for rejected op
}
{
// check simple unscaled expansion
@@ -247,8 +238,8 @@ TEST(BakedOpState, tryStrokeableOpConstruct) {
ClipRect clip(Rect(200, 200));
RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
- auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
- BakedOpState::StrokeBehavior::StyleDefined, false);
+ auto bakedState = BakedOpState::tryStrokeableOpConstruct(
+ allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::StyleDefined, false);
ASSERT_NE(nullptr, bakedState);
EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds);
@@ -262,8 +253,8 @@ TEST(BakedOpState, tryStrokeableOpConstruct) {
ClipRect clip(Rect(200, 200));
RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
- auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
- BakedOpState::StrokeBehavior::Forced, false);
+ auto bakedState = BakedOpState::tryStrokeableOpConstruct(
+ allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::Forced, false);
ASSERT_NE(nullptr, bakedState);
EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds);
@@ -271,5 +262,5 @@ TEST(BakedOpState, tryStrokeableOpConstruct) {
}
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp
index 6115162c8f81..b1106f0d6a71 100644
--- a/libs/hwui/tests/unit/CacheManagerTests.cpp
+++ b/libs/hwui/tests/unit/CacheManagerTests.cpp
@@ -35,7 +35,8 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, trimMemory) {
GrContext* grContext = renderThread.getGrContext();
ASSERT_TRUE(grContext != nullptr);
- // create pairs of offscreen render targets and images until we exceed the backgroundCacheSizeLimit
+ // create pairs of offscreen render targets and images until we exceed the
+ // backgroundCacheSizeLimit
std::vector<sk_sp<SkSurface>> surfaces;
while (getCacheUsage(grContext) <= renderThread.cacheManager().getBackgroundCacheSize()) {
diff --git a/libs/hwui/tests/unit/CanvasContextTests.cpp b/libs/hwui/tests/unit/CanvasContextTests.cpp
index ef5ce0d9968e..28cff5b9b154 100644
--- a/libs/hwui/tests/unit/CanvasContextTests.cpp
+++ b/libs/hwui/tests/unit/CanvasContextTests.cpp
@@ -35,8 +35,8 @@ public:
RENDERTHREAD_TEST(CanvasContext, create) {
auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
ContextFactory contextFactory;
- std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
- renderThread, false, rootNode.get(), &contextFactory));
+ std::unique_ptr<CanvasContext> canvasContext(
+ CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory));
ASSERT_FALSE(canvasContext->hasSurface());
diff --git a/libs/hwui/tests/unit/CanvasStateTests.cpp b/libs/hwui/tests/unit/CanvasStateTests.cpp
index c41313aebb5d..4c03811b0c96 100644
--- a/libs/hwui/tests/unit/CanvasStateTests.cpp
+++ b/libs/hwui/tests/unit/CanvasStateTests.cpp
@@ -21,14 +21,14 @@
#include "hwui/Canvas.h"
#include "utils/LinearAllocator.h"
-#include <gtest/gtest.h>
-#include <SkPath.h>
#include <SkClipOp.h>
+#include <SkPath.h>
+#include <gtest/gtest.h>
namespace android {
namespace uirenderer {
-class NullClient: public CanvasStateClient {
+class NullClient : public CanvasStateClient {
void onViewportInitialized() override {}
void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
GLuint getTargetFbo() const override { return 0; }
@@ -47,8 +47,7 @@ static bool approxEqual(const Matrix4& a, const Matrix4& b) {
TEST(CanvasState, gettersAndSetters) {
CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200,
- 0, 0, 200, 200, Vector3());
+ state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
ASSERT_EQ(state.getWidth(), 200);
ASSERT_EQ(state.getHeight(), 200);
@@ -65,8 +64,7 @@ TEST(CanvasState, gettersAndSetters) {
TEST(CanvasState, simpleClipping) {
CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200,
- 0, 0, 200, 200, Vector3());
+ state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
state.clipRect(0, 0, 100, 100, SkClipOp::kIntersect);
ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(100, 100));
@@ -80,8 +78,7 @@ TEST(CanvasState, simpleClipping) {
TEST(CanvasState, complexClipping) {
CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200,
- 0, 0, 200, 200, Vector3());
+ state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
state.save(SaveFlags::MatrixClip);
{
@@ -116,8 +113,7 @@ TEST(CanvasState, complexClipping) {
TEST(CanvasState, saveAndRestore) {
CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200,
- 0, 0, 200, 200, Vector3());
+ state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
state.save(SaveFlags::Clip);
{
@@ -125,7 +121,7 @@ TEST(CanvasState, saveAndRestore) {
ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
}
state.restore();
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200)); // verify restore
+ ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200)); // verify restore
Matrix4 simpleTranslate;
simpleTranslate.loadTranslate(10, 10, 0);
@@ -140,27 +136,25 @@ TEST(CanvasState, saveAndRestore) {
TEST(CanvasState, saveAndRestoreButNotTooMuch) {
CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200,
- 0, 0, 200, 200, Vector3());
+ state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
- state.save(SaveFlags::Matrix); // NOTE: clip not saved
+ state.save(SaveFlags::Matrix); // NOTE: clip not saved
{
state.clipRect(0, 0, 10, 10, SkClipOp::kIntersect);
ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
}
state.restore();
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10)); // verify not restored
+ ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10)); // verify not restored
Matrix4 simpleTranslate;
simpleTranslate.loadTranslate(10, 10, 0);
- state.save(SaveFlags::Clip); // NOTE: matrix not saved
+ state.save(SaveFlags::Clip); // NOTE: matrix not saved
{
state.translate(10, 10, 0);
EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
}
state.restore();
- EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate)); // verify not restored
+ EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate)); // verify not restored
}
-
}
}
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
index d4d7919f9eee..450bb679a45f 100644
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ b/libs/hwui/tests/unit/ClipAreaTests.cpp
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
#include <SkPath.h>
#include <SkRegion.h>
+#include <gtest/gtest.h>
#include "ClipArea.h"
@@ -194,7 +194,8 @@ TEST(ClipArea, serializeIntersectedClip) {
{
auto origRectClip = area.serializeClip(allocator);
ASSERT_NE(nullptr, origRectClip);
- EXPECT_EQ(origRectClip, area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()));
+ EXPECT_EQ(origRectClip,
+ area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()));
}
// rect
@@ -208,11 +209,13 @@ TEST(ClipArea, serializeIntersectedClip) {
ASSERT_EQ(ClipMode::Rectangle, resolvedClip->mode);
EXPECT_EQ(Rect(100, 100, 200, 200), resolvedClip->rect);
- EXPECT_EQ(resolvedClip, area.serializeIntersectedClip(allocator, &recordedClip, translateScale))
+ EXPECT_EQ(resolvedClip,
+ area.serializeIntersectedClip(allocator, &recordedClip, translateScale))
<< "Must return previous serialization, since input is same";
ClipRect recordedClip2(Rect(100, 100));
- EXPECT_NE(resolvedClip, area.serializeIntersectedClip(allocator, &recordedClip2, translateScale))
+ EXPECT_NE(resolvedClip,
+ area.serializeIntersectedClip(allocator, &recordedClip2, translateScale))
<< "Shouldn't return previous serialization, since matrix location is different";
}
@@ -222,7 +225,8 @@ TEST(ClipArea, serializeIntersectedClip) {
area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op);
{
ClipRect recordedClip(Rect(100, 100));
- auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, Matrix4::identity());
+ auto resolvedClip =
+ area.serializeIntersectedClip(allocator, &recordedClip, Matrix4::identity());
ASSERT_NE(nullptr, resolvedClip);
ASSERT_EQ(ClipMode::RectangleList, resolvedClip->mode);
auto clipRectList = reinterpret_cast<const ClipRectList*>(resolvedClip);
@@ -243,8 +247,9 @@ TEST(ClipArea, serializeIntersectedClip) {
Matrix4 translate10x20;
translate10x20.loadTranslate(10, 20, 0);
- auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip,
- translate10x20); // Note: only translate for now, others not handled correctly
+ auto resolvedClip = area.serializeIntersectedClip(
+ allocator, &recordedClip,
+ translate10x20); // Note: only translate for now, others not handled correctly
ASSERT_NE(nullptr, resolvedClip);
ASSERT_EQ(ClipMode::Region, resolvedClip->mode);
auto clipRegion = reinterpret_cast<const ClipRegion*>(resolvedClip);
@@ -267,7 +272,8 @@ TEST(ClipArea, serializeIntersectedClip_snap) {
ClipRect recordedClip(Rect(100.12, 100.74));
Matrix4 translateScale;
translateScale.loadTranslate(100, 100, 0);
- translateScale.scale(2, 3, 1); // recorded clip will have non-int coords, even after transform
+ translateScale.scale(2, 3,
+ 1); // recorded clip will have non-int coords, even after transform
auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale);
ASSERT_NE(nullptr, resolvedClip);
EXPECT_EQ(ClipMode::Rectangle, resolvedClip->mode);
@@ -343,5 +349,5 @@ TEST(ClipArea, applyTransformToRegion_rotate90) {
EXPECT_EQ(SkIRect::MakeLTRB(-4, 1, -2, 3), region.getBounds());
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
index 87d897ee6a7b..b8b5050faa11 100644
--- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
+++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
@@ -50,7 +50,6 @@ RENDERTHREAD_TEST(DeferredLayerUpdater, updateLayer) {
glLayer->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
}
-
// the backing layer should now have all the properties applied.
if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
diff --git a/libs/hwui/tests/unit/FatVectorTests.cpp b/libs/hwui/tests/unit/FatVectorTests.cpp
index 64b0ba13562d..8523e6c9e973 100644
--- a/libs/hwui/tests/unit/FatVectorTests.cpp
+++ b/libs/hwui/tests/unit/FatVectorTests.cpp
@@ -22,12 +22,11 @@
using namespace android;
using namespace android::uirenderer;
-template<class VectorType>
+template <class VectorType>
static bool allocationIsInternal(VectorType& v) {
// allocation array (from &v[0] to &v[0] + v.capacity) is
// located within the vector object itself
- return (char*)(&v) <= (char*)(&v[0])
- && (char*)(&v + 1) >= (char*)(&v[0] + v.capacity());
+ return (char*)(&v) <= (char*)(&v[0]) && (char*)(&v + 1) >= (char*)(&v[0] + v.capacity());
}
TEST(FatVector, baseline) {
diff --git a/libs/hwui/tests/unit/FatalTestCanvas.h b/libs/hwui/tests/unit/FatalTestCanvas.h
index 03d94964ac76..9693ce7b6784 100644
--- a/libs/hwui/tests/unit/FatalTestCanvas.h
+++ b/libs/hwui/tests/unit/FatalTestCanvas.h
@@ -16,15 +16,14 @@
#pragma once
-#include <gtest/gtest.h>
#include <SkCanvas.h>
+#include <gtest/gtest.h>
namespace {
class TestCanvasBase : public SkCanvas {
public:
- TestCanvasBase(int width, int height) : SkCanvas(width, height) {
- }
+ TestCanvasBase(int width, int height) : SkCanvas(width, height) {}
void onDrawAnnotation(const SkRect&, const char key[], SkData* value) {
ADD_FAILURE() << "onDrawAnnotation not expected in this test";
}
@@ -32,35 +31,33 @@ public:
ADD_FAILURE() << "onDrawDRRect not expected in this test";
}
void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
- const SkPaint& paint) {
+ const SkPaint& paint) {
ADD_FAILURE() << "onDrawText not expected in this test";
}
void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
- const SkPaint& paint) {
+ const SkPaint& paint) {
ADD_FAILURE() << "onDrawPosText not expected in this test";
}
void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint) {
+ const SkPaint& paint) {
ADD_FAILURE() << "onDrawPosTextH not expected in this test";
}
void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
- const SkMatrix* matrix, const SkPaint& paint) {
+ const SkMatrix* matrix, const SkPaint& paint) {
ADD_FAILURE() << "onDrawTextOnPath not expected in this test";
}
void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform[],
- const SkRect* cullRect, const SkPaint& paint) {
+ const SkRect* cullRect, const SkPaint& paint) {
ADD_FAILURE() << "onDrawTextRSXform not expected in this test";
}
void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) {
ADD_FAILURE() << "onDrawTextBlob not expected in this test";
}
void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4],
- SkBlendMode, const SkPaint& paint) {
+ SkBlendMode, const SkPaint& paint) {
ADD_FAILURE() << "onDrawPatch not expected in this test";
}
- void onDrawPaint(const SkPaint&) {
- ADD_FAILURE() << "onDrawPaint not expected in this test";
- }
+ void onDrawPaint(const SkPaint&) { ADD_FAILURE() << "onDrawPaint not expected in this test"; }
void onDrawRect(const SkRect&, const SkPaint&) {
ADD_FAILURE() << "onDrawRect not expected in this test";
}
@@ -71,7 +68,7 @@ public:
ADD_FAILURE() << "onDrawOval not expected in this test";
}
void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
- const SkPaint&) {
+ const SkPaint&) {
ADD_FAILURE() << "onDrawArc not expected in this test";
}
void onDrawRRect(const SkRRect&, const SkPaint&) {
@@ -84,7 +81,7 @@ public:
ADD_FAILURE() << "onDrawVertices not expected in this test";
}
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int count,
- SkBlendMode, const SkRect* cull, const SkPaint*) {
+ SkBlendMode, const SkRect* cull, const SkPaint*) {
ADD_FAILURE() << "onDrawAtlas not expected in this test";
}
void onDrawPath(const SkPath&, const SkPaint&) {
@@ -94,29 +91,29 @@ public:
ADD_FAILURE() << "onDrawImage not expected in this test";
}
void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*,
- SrcRectConstraint) {
+ SrcRectConstraint) {
ADD_FAILURE() << "onDrawImageRect not expected in this test";
}
void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst, const SkPaint*) {
ADD_FAILURE() << "onDrawImageNine not expected in this test";
}
void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
- const SkPaint*) {
+ const SkPaint*) {
ADD_FAILURE() << "onDrawImageLattice not expected in this test";
}
void onDrawBitmap(const SkBitmap&, SkScalar dx, SkScalar dy, const SkPaint*) {
ADD_FAILURE() << "onDrawBitmap not expected in this test";
}
void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*,
- SrcRectConstraint) {
+ SrcRectConstraint) {
ADD_FAILURE() << "onDrawBitmapRect not expected in this test";
}
void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
- const SkPaint*) {
+ const SkPaint*) {
ADD_FAILURE() << "onDrawBitmapNine not expected in this test";
}
void onDrawBitmapLattice(const SkBitmap&, const Lattice& lattice, const SkRect& dst,
- const SkPaint*) {
+ const SkPaint*) {
ADD_FAILURE() << "onDrawBitmapLattice not expected in this test";
}
void onClipRRect(const SkRRect& rrect, SkClipOp, ClipEdgeStyle) {
@@ -128,14 +125,11 @@ public:
void onClipRegion(const SkRegion& deviceRgn, SkClipOp) {
ADD_FAILURE() << "onClipRegion not expected in this test";
}
- void onDiscard() {
- ADD_FAILURE() << "onDiscard not expected in this test";
- }
+ void onDiscard() { ADD_FAILURE() << "onDiscard not expected in this test"; }
void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) {
ADD_FAILURE() << "onDrawPicture not expected in this test";
}
- int mDrawCounter = 0; //counts how may draw calls of any kind were made to this canvas
+ int mDrawCounter = 0; // counts how may draw calls of any kind were made to this canvas
};
-
} \ No newline at end of file
diff --git a/libs/hwui/tests/unit/FontRendererTests.cpp b/libs/hwui/tests/unit/FontRendererTests.cpp
index ee202367d73e..c78f131ce2ce 100644
--- a/libs/hwui/tests/unit/FontRendererTests.cpp
+++ b/libs/hwui/tests/unit/FontRendererTests.cpp
@@ -40,16 +40,16 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FontRenderer, renderDropShadow) {
std::vector<float> positions;
float totalAdvance;
Rect bounds;
- TestUtils::layoutTextUnscaled(paint, "This is a test",
- &glyphs, &positions, &totalAdvance, &bounds);
+ TestUtils::layoutTextUnscaled(paint, "This is a test", &glyphs, &positions, &totalAdvance,
+ &bounds);
for (int radius : {28, 20, 2}) {
- auto result = fontRenderer.renderDropShadow(&paint, glyphs.data(), glyphs.size(),
- radius, positions.data());
+ auto result = fontRenderer.renderDropShadow(&paint, glyphs.data(), glyphs.size(), radius,
+ positions.data());
ASSERT_NE(nullptr, result.image);
EXPECT_FALSE(isZero(result.image, result.width * result.height));
- EXPECT_LE(bounds.getWidth() + radius * 2, (int) result.width);
- EXPECT_LE(bounds.getHeight() + radius * 2, (int) result.height);
+ EXPECT_LE(bounds.getWidth() + radius * 2, (int)result.width);
+ EXPECT_LE(bounds.getHeight() + radius * 2, (int)result.height);
delete result.image;
}
}
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index fcdd814bb63e..e56d2f864f77 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -30,7 +30,7 @@
namespace android {
namespace uirenderer {
-const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
+const FrameBuilder::LightGeometry sLightGeometry = {{100, 100, 100}, 50};
/**
* Virtual class implemented by each test to redirect static operation / state transitions to
@@ -56,23 +56,21 @@ public:
virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) {
ADD_FAILURE() << "Layer repaint not expected in this test";
}
- virtual void endLayer() {
- ADD_FAILURE() << "Layer updates not expected in this test";
- }
+ virtual void endLayer() { ADD_FAILURE() << "Layer updates not expected in this test"; }
virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
virtual void endFrame(const Rect& repaintRect) {}
- // define virtual defaults for single draw methods
-#define X(Type) \
+// define virtual defaults for single draw methods
+#define X(Type) \
virtual void on##Type(const Type&, const BakedOpState&) { \
- ADD_FAILURE() << #Type " not expected in this test"; \
+ ADD_FAILURE() << #Type " not expected in this test"; \
}
MAP_RENDERABLE_OPS(X)
#undef X
- // define virtual defaults for merged draw methods
-#define X(Type) \
- virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
+// define virtual defaults for merged draw methods
+#define X(Type) \
+ virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \
}
MAP_MERGEABLE_OPS(X)
@@ -90,18 +88,18 @@ protected:
*/
class TestDispatcher {
public:
- // define single op methods, which redirect to TestRendererBase
-#define X(Type) \
+// define single op methods, which redirect to TestRendererBase
+#define X(Type) \
static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
- renderer.on##Type(op, state); \
+ renderer.on##Type(op, state); \
}
MAP_RENDERABLE_OPS(X);
#undef X
- // define merged op methods, which redirect to TestRendererBase
-#define X(Type) \
+// define merged op methods, which redirect to TestRendererBase
+#define X(Type) \
static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \
- renderer.onMerged##Type##s(opList); \
+ renderer.onMerged##Type##s(opList); \
}
MAP_MERGEABLE_OPS(X);
#undef X
@@ -123,24 +121,22 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simple) {
void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
EXPECT_EQ(2, mIndex++);
}
- void endFrame(const Rect& repaintRect) override {
- EXPECT_EQ(3, mIndex++);
- }
+ void endFrame(const Rect& repaintRect) override { EXPECT_EQ(3, mIndex++); }
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
- canvas.drawRect(0, 0, 100, 200, SkPaint());
- canvas.drawBitmap(*bitmap, 10, 10, nullptr);
- });
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
- sLightGeometry, Caches::getInstance());
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
+ canvas.drawRect(0, 0, 100, 200, SkPaint());
+ canvas.drawBitmap(*bitmap, 10, 10, nullptr);
+ });
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SimpleTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
- EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
+ EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleStroke) {
@@ -156,14 +152,14 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleStroke) {
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- SkPaint strokedPaint;
- strokedPaint.setStrokeWidth(10);
- canvas.drawPoint(50, 50, strokedPaint);
- });
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
- sLightGeometry, Caches::getInstance());
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ SkPaint strokedPaint;
+ strokedPaint.setStrokeWidth(10);
+ canvas.drawPoint(50, 50, strokedPaint);
+ });
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SimpleStrokeTestRenderer renderer;
@@ -171,7 +167,6 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleStroke) {
EXPECT_EQ(1, renderer.getIndex());
}
-
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, arcStrokeClip) {
class ArcStrokeClipTestRenderer : public TestRendererBase {
public:
@@ -184,15 +179,15 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, arcStrokeClip) {
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.clipRect(25, 25, 175, 175, SkClipOp::kIntersect);
- SkPaint aaPaint;
- aaPaint.setAntiAlias(true);
- canvas.drawArc(25, 25, 175, 175, 40, 180, true, aaPaint);
- });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.clipRect(25, 25, 175, 175, SkClipOp::kIntersect);
+ SkPaint aaPaint;
+ aaPaint.setAntiAlias(true);
+ canvas.drawArc(25, 25, 175, 175, 40, 180, true, aaPaint);
+ });
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
ArcStrokeClipTestRenderer renderer;
@@ -201,15 +196,15 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, arcStrokeClip) {
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleRejection) {
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
+ auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200, [](RenderProperties& props,
+ RecordingCanvas& canvas) {
canvas.save(SaveFlags::MatrixClip);
- canvas.clipRect(200, 200, 400, 400, SkClipOp::kIntersect); // intersection should be empty
+ canvas.clipRect(200, 200, 400, 400, SkClipOp::kIntersect); // intersection should be empty
canvas.drawRect(0, 0, 400, 400, SkPaint());
canvas.restore();
});
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
FailRenderer renderer;
@@ -228,30 +223,30 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleBatching) {
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
-
- sk_sp<Bitmap> bitmap(TestUtils::createBitmap(10, 10,
- kAlpha_8_SkColorType)); // Disable merging by using alpha 8 bitmap
-
- // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
- // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
- canvas.save(SaveFlags::MatrixClip);
- for (int i = 0; i < LOOPS; i++) {
- canvas.translate(0, 10);
- canvas.drawRect(0, 0, 10, 10, SkPaint());
- canvas.drawBitmap(*bitmap, 5, 0, nullptr);
- }
- canvas.restore();
- });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+
+ sk_sp<Bitmap> bitmap(TestUtils::createBitmap(
+ 10, 10,
+ kAlpha_8_SkColorType)); // Disable merging by using alpha 8 bitmap
+
+ // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
+ // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
+ canvas.save(SaveFlags::MatrixClip);
+ for (int i = 0; i < LOOPS; i++) {
+ canvas.translate(0, 10);
+ canvas.drawRect(0, 0, 10, 10, SkPaint());
+ canvas.drawBitmap(*bitmap, 5, 0, nullptr);
+ }
+ canvas.restore();
+ });
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SimpleBatchingTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
- EXPECT_EQ(2 * LOOPS, renderer.getIndex())
- << "Expect number of ops = 2 * loop count";
+ EXPECT_EQ(2 * LOOPS, renderer.getIndex()) << "Expect number of ops = 2 * loop count";
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferRenderNode_translateClip) {
@@ -261,19 +256,19 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferRenderNode_translateClip) {
EXPECT_EQ(0, mIndex++);
EXPECT_EQ(Rect(5, 10, 55, 60), state.computedState.clippedBounds);
EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom,
- state.computedState.clipSideFlags);
+ state.computedState.clipSideFlags);
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 100, 100, SkPaint());
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 100, 100, SkPaint());
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
- frameBuilder.deferRenderNode(5, 10, Rect(50, 50), // translate + clip node
- *TestUtils::getSyncedNode(node));
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
+ frameBuilder.deferRenderNode(5, 10, Rect(50, 50), // translate + clip node
+ *TestUtils::getSyncedNode(node));
DeferRenderNodeTranslateClipTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
@@ -287,27 +282,27 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferRenderNodeScene) {
const Rect& clippedBounds = state.computedState.clippedBounds;
Matrix4 expected;
switch (mIndex++) {
- case 0:
- // background - left side
- EXPECT_EQ(Rect(600, 100, 700, 500), clippedBounds);
- expected.loadTranslate(100, 100, 0);
- break;
- case 1:
- // background - top side
- EXPECT_EQ(Rect(100, 400, 600, 500), clippedBounds);
- expected.loadTranslate(100, 100, 0);
- break;
- case 2:
- // content
- EXPECT_EQ(Rect(100, 100, 700, 500), clippedBounds);
- expected.loadTranslate(-50, -50, 0);
- break;
- case 3:
- // overlay
- EXPECT_EQ(Rect(0, 0, 800, 200), clippedBounds);
- break;
- default:
- ADD_FAILURE() << "Too many rects observed";
+ case 0:
+ // background - left side
+ EXPECT_EQ(Rect(600, 100, 700, 500), clippedBounds);
+ expected.loadTranslate(100, 100, 0);
+ break;
+ case 1:
+ // background - top side
+ EXPECT_EQ(Rect(100, 400, 600, 500), clippedBounds);
+ expected.loadTranslate(100, 100, 0);
+ break;
+ case 2:
+ // content
+ EXPECT_EQ(Rect(100, 100, 700, 500), clippedBounds);
+ expected.loadTranslate(-50, -50, 0);
+ break;
+ case 3:
+ // overlay
+ EXPECT_EQ(Rect(0, 0, 800, 200), clippedBounds);
+ break;
+ default:
+ ADD_FAILURE() << "Too many rects observed";
}
EXPECT_EQ(expected, state.computedState.transform);
}
@@ -318,31 +313,32 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferRenderNodeScene) {
transparentPaint.setAlpha(128);
// backdrop
- nodes.push_back(TestUtils::createNode<RecordingCanvas>(100, 100, 700, 500, // 600x400
+ nodes.push_back(TestUtils::createNode<RecordingCanvas>(
+ 100, 100, 700, 500, // 600x400
[&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 600, 400, transparentPaint);
- }));
+ canvas.drawRect(0, 0, 600, 400, transparentPaint);
+ }));
// content
- Rect contentDrawBounds(150, 150, 650, 450); // 500x300
- nodes.push_back(TestUtils::createNode<RecordingCanvas>(0, 0, 800, 600,
- [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 800, 600, transparentPaint);
- }));
+ Rect contentDrawBounds(150, 150, 650, 450); // 500x300
+ nodes.push_back(TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 800, 600, [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 800, 600, transparentPaint);
+ }));
// overlay
- nodes.push_back(TestUtils::createNode<RecordingCanvas>(0, 0, 800, 600,
- [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 800, 200, transparentPaint);
- }));
+ nodes.push_back(TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 800, 600, [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 800, 200, transparentPaint);
+ }));
for (auto& node : nodes) {
TestUtils::syncHierarchyPropertiesAndDisplayList(node);
}
{
- FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds);
DeferRenderNodeSceneTestRenderer renderer;
@@ -363,8 +359,8 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferRenderNodeScene) {
{
// Validate no crashes if any nodes are missing DisplayLists
- FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds);
FailRenderer renderer;
@@ -396,24 +392,22 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, empty_withFbo0) {
void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
EXPECT_EQ(0, mIndex++);
}
- void endFrame(const Rect& repaintRect) override {
- EXPECT_EQ(1, mIndex++);
- }
+ void endFrame(const Rect& repaintRect) override { EXPECT_EQ(1, mIndex++); }
};
- auto node = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- // no drawn content
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 10, 10, 110, 110, [](RenderProperties& props, RecordingCanvas& canvas) {
+ // no drawn content
+ });
// Draw, but pass node without draw content, so no work is done for primary frame
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
EmptyWithFbo0TestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2, renderer.getIndex()) << "No drawing content produced,"
- " but fbo0 update lifecycle should still be observed";
+ " but fbo0 update lifecycle should still be observed";
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, avoidOverdraw_rects) {
@@ -425,17 +419,17 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, avoidOverdraw_rects) {
<< "Last rect should occlude others.";
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 200, 200, SkPaint());
- canvas.drawRect(0, 0, 200, 200, SkPaint());
- canvas.drawRect(10, 10, 190, 190, SkPaint());
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 200, 200, SkPaint());
+ canvas.drawRect(0, 0, 200, 200, SkPaint());
+ canvas.drawRect(10, 10, 190, 190, SkPaint());
+ });
// Damage (and therefore clip) is same as last draw, subset of renderable area.
// This means last op occludes other contents, and they'll be rejected to avoid overdraw.
- FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 190, 190), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 190, 190), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
EXPECT_EQ(3u, node->getDisplayList()->getOps().size())
@@ -447,38 +441,38 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, avoidOverdraw_rects) {
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, avoidOverdraw_bitmaps) {
- static sk_sp<Bitmap> opaqueBitmap(TestUtils::createBitmap(50, 50,
- SkColorType::kRGB_565_SkColorType));
- static sk_sp<Bitmap> transpBitmap(TestUtils::createBitmap(50, 50,
- SkColorType::kAlpha_8_SkColorType));
+ static sk_sp<Bitmap> opaqueBitmap(
+ TestUtils::createBitmap(50, 50, SkColorType::kRGB_565_SkColorType));
+ static sk_sp<Bitmap> transpBitmap(
+ TestUtils::createBitmap(50, 50, SkColorType::kAlpha_8_SkColorType));
class AvoidOverdrawBitmapsTestRenderer : public TestRendererBase {
public:
void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
- switch(mIndex++) {
- case 0:
- EXPECT_EQ(opaqueBitmap.get(), op.bitmap);
- break;
- case 1:
- EXPECT_EQ(transpBitmap.get(), op.bitmap);
- break;
- default:
- ADD_FAILURE() << "Only two ops expected.";
+ switch (mIndex++) {
+ case 0:
+ EXPECT_EQ(opaqueBitmap.get(), op.bitmap);
+ break;
+ case 1:
+ EXPECT_EQ(transpBitmap.get(), op.bitmap);
+ break;
+ default:
+ ADD_FAILURE() << "Only two ops expected.";
}
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 50, 50,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 50, 50, SkPaint());
- canvas.drawRect(0, 0, 50, 50, SkPaint());
- canvas.drawBitmap(*transpBitmap, 0, 0, nullptr);
-
- // only the below draws should remain, since they're
- canvas.drawBitmap(*opaqueBitmap, 0, 0, nullptr);
- canvas.drawBitmap(*transpBitmap, 0, 0, nullptr);
- });
- FrameBuilder frameBuilder(SkRect::MakeWH(50, 50), 50, 50,
- sLightGeometry, Caches::getInstance());
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 50, 50, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 50, 50, SkPaint());
+ canvas.drawRect(0, 0, 50, 50, SkPaint());
+ canvas.drawBitmap(*transpBitmap, 0, 0, nullptr);
+
+ // only the below draws should remain, since they're
+ canvas.drawBitmap(*opaqueBitmap, 0, 0, nullptr);
+ canvas.drawBitmap(*transpBitmap, 0, 0, nullptr);
+ });
+ FrameBuilder frameBuilder(SkRect::MakeWH(50, 50), 50, 50, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
EXPECT_EQ(5u, node->getDisplayList()->getOps().size())
@@ -498,32 +492,32 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, clippedMerging) {
EXPECT_EQ(4u, opList.count);
EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip);
EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right,
- opList.clipSideFlags);
+ opList.clipSideFlags);
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- sk_sp<Bitmap> bitmap(TestUtils::createBitmap(20, 20));
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ sk_sp<Bitmap> bitmap(TestUtils::createBitmap(20, 20));
- // left side clipped (to inset left half)
- canvas.clipRect(10, 0, 50, 100, SkClipOp::kReplace_deprecated);
- canvas.drawBitmap(*bitmap, 0, 40, nullptr);
+ // left side clipped (to inset left half)
+ canvas.clipRect(10, 0, 50, 100, SkClipOp::kReplace_deprecated);
+ canvas.drawBitmap(*bitmap, 0, 40, nullptr);
- // top side clipped (to inset top half)
- canvas.clipRect(0, 10, 100, 50, SkClipOp::kReplace_deprecated);
- canvas.drawBitmap(*bitmap, 40, 0, nullptr);
+ // top side clipped (to inset top half)
+ canvas.clipRect(0, 10, 100, 50, SkClipOp::kReplace_deprecated);
+ canvas.drawBitmap(*bitmap, 40, 0, nullptr);
- // right side clipped (to inset right half)
- canvas.clipRect(50, 0, 90, 100, SkClipOp::kReplace_deprecated);
- canvas.drawBitmap(*bitmap, 80, 40, nullptr);
+ // right side clipped (to inset right half)
+ canvas.clipRect(50, 0, 90, 100, SkClipOp::kReplace_deprecated);
+ canvas.drawBitmap(*bitmap, 80, 40, nullptr);
- // bottom not clipped, just abutting (inset bottom half)
- canvas.clipRect(0, 50, 100, 90, SkClipOp::kReplace_deprecated);
- canvas.drawBitmap(*bitmap, 40, 70, nullptr);
- });
+ // bottom not clipped, just abutting (inset bottom half)
+ canvas.clipRect(0, 50, 100, 90, SkClipOp::kReplace_deprecated);
+ canvas.drawBitmap(*bitmap, 40, 70, nullptr);
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
ClippedMergingTestRenderer renderer;
@@ -536,23 +530,23 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, regionClipStopsMerge) {
public:
void onTextOp(const TextOp& op, const BakedOpState& state) override { mIndex++; }
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- SkPath path;
- path.addCircle(200, 200, 200, SkPath::kCW_Direction);
- canvas.save(SaveFlags::MatrixClip);
- canvas.clipPath(&path, SkClipOp::kIntersect);
- SkPaint paint;
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- paint.setAntiAlias(true);
- paint.setTextSize(50);
- TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
- TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 200);
- canvas.restore();
- });
-
- FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
- sLightGeometry, Caches::getInstance());
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 400, 400, [](RenderProperties& props, RecordingCanvas& canvas) {
+ SkPath path;
+ path.addCircle(200, 200, 200, SkPath::kCW_Direction);
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.clipPath(&path, SkClipOp::kIntersect);
+ SkPaint paint;
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setAntiAlias(true);
+ paint.setTextSize(50);
+ TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
+ TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 200);
+ canvas.restore();
+ });
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
RegionClipStopsMergeTestRenderer renderer;
@@ -572,17 +566,17 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textMerging) {
EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags);
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
- [](RenderProperties& props, RecordingCanvas& canvas) {
+ auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400, [](RenderProperties& props,
+ RecordingCanvas& canvas) {
SkPaint paint;
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setAntiAlias(true);
paint.setTextSize(50);
- TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
- TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
+ TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
+ TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
});
- FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
TextMergingTestRenderer renderer;
@@ -603,30 +597,28 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textStrikethrough) {
EXPECT_EQ(5u, opList.count);
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 2000,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- SkPaint textPaint;
- textPaint.setAntiAlias(true);
- textPaint.setTextSize(20);
- textPaint.setFlags(textPaint.getFlags() | SkPaint::kStrikeThruText_ReserveFlag);
- textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- for (int i = 0; i < LOOPS; i++) {
- TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
- }
- });
-
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 2000), 200, 2000,
- sLightGeometry, Caches::getInstance());
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 2000, [](RenderProperties& props, RecordingCanvas& canvas) {
+ SkPaint textPaint;
+ textPaint.setAntiAlias(true);
+ textPaint.setTextSize(20);
+ textPaint.setFlags(textPaint.getFlags() | SkPaint::kStrikeThruText_ReserveFlag);
+ textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ for (int i = 0; i < LOOPS; i++) {
+ TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
+ }
+ });
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 2000), 200, 2000, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
TextStrikethroughTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
- EXPECT_EQ(2 * LOOPS, renderer.getIndex())
- << "Expect number of ops = 2 * loop count";
+ EXPECT_EQ(2 * LOOPS, renderer.getIndex()) << "Expect number of ops = 2 * loop count";
}
-static auto styles = {
- SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style };
+static auto styles = {SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style};
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textStyle) {
class TextStyleTestRenderer : public TestRendererBase {
@@ -659,23 +651,23 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textStyle) {
EXPECT_EQ(stroke, outsetFill);
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- SkPaint paint;
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- paint.setAntiAlias(true);
- paint.setTextSize(50);
- paint.setStrokeWidth(10);
-
- // draw 3 copies of the same text overlapping, each with a different style.
- // They'll get merged, but with
- for (auto style : styles) {
- paint.setStyle(style);
- TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
- }
- });
- FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
- sLightGeometry, Caches::getInstance());
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 400, 400, [](RenderProperties& props, RecordingCanvas& canvas) {
+ SkPaint paint;
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setAntiAlias(true);
+ paint.setTextSize(50);
+ paint.setStrokeWidth(10);
+
+ // draw 3 copies of the same text overlapping, each with a different style.
+ // They'll get merged, but with
+ for (auto style : styles) {
+ paint.setStyle(style);
+ TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
+ }
+ });
+ FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
TextStyleTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
@@ -696,19 +688,19 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_clipLocalMatrix) {
}
};
- auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
- SkMatrix::MakeTrans(5, 5));
+ auto layerUpdater =
+ TestUtils::createTextureLayerUpdater(renderThread, 100, 100, SkMatrix::MakeTrans(5, 5));
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.save(SaveFlags::MatrixClip);
- canvas.clipRect(50, 50, 150, 150, SkClipOp::kIntersect);
- canvas.drawLayer(layerUpdater.get());
- canvas.restore();
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.clipRect(50, 50, 150, 150, SkClipOp::kIntersect);
+ canvas.drawLayer(layerUpdater.get());
+ canvas.restore();
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
TextureLayerClipLocalMatrixTestRenderer renderer;
@@ -728,19 +720,19 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_combineMatrices) {
}
};
- auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
- SkMatrix::MakeTrans(5, 5));
+ auto layerUpdater =
+ TestUtils::createTextureLayerUpdater(renderThread, 100, 100, SkMatrix::MakeTrans(5, 5));
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.save(SaveFlags::MatrixClip);
- canvas.translate(30, 40);
- canvas.drawLayer(layerUpdater.get());
- canvas.restore();
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.translate(30, 40);
+ canvas.drawLayer(layerUpdater.get());
+ canvas.restore();
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
TextureLayerCombineMatricesTestRenderer renderer;
@@ -749,20 +741,20 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_combineMatrices) {
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_reject) {
- auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
- SkMatrix::MakeTrans(5, 5));
+ auto layerUpdater =
+ TestUtils::createTextureLayerUpdater(renderThread, 100, 100, SkMatrix::MakeTrans(5, 5));
EXPECT_EQ(Layer::Api::OpenGL, layerUpdater->backingLayer()->getApi());
GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
- glLayer->setRenderTarget(GL_NONE); // Should be rejected
+ glLayer->setRenderTarget(GL_NONE); // Should be rejected
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.drawLayer(layerUpdater.get());
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawLayer(layerUpdater.get());
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
FailRenderer renderer;
@@ -779,14 +771,14 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, functor_reject) {
Functor noopFunctor;
// 1 million pixel tall view, scrolled down 80%
- auto scrolledFunctorView = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 1000000,
- [&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.translate(0, -800000);
- canvas.callDrawGLFunction(&noopFunctor, nullptr);
- });
-
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ auto scrolledFunctorView = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 400, 1000000, [&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.translate(0, -800000);
+ canvas.callDrawGLFunction(&noopFunctor, nullptr);
+ });
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(scrolledFunctorView));
FunctorTestRenderer renderer;
@@ -804,14 +796,14 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferColorOp_unbounded) {
}
};
- auto unclippedColorView = TestUtils::createNode<RecordingCanvas>(0, 0, 10, 10,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setClipToBounds(false);
- canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
- });
+ auto unclippedColorView = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 10, 10, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setClipToBounds(false);
+ canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(unclippedColorView));
ColorTestRenderer renderer;
@@ -823,42 +815,42 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderNode) {
class RenderNodeTestRenderer : public TestRendererBase {
public:
void onRectOp(const RectOp& op, const BakedOpState& state) override {
- switch(mIndex++) {
- case 0:
- EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
- EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
- break;
- case 1:
- EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
- EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
- break;
- default:
- ADD_FAILURE();
+ switch (mIndex++) {
+ case 0:
+ EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
+ EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
+ break;
+ case 1:
+ EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
+ EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
+ break;
+ default:
+ ADD_FAILURE();
}
}
};
- auto child = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
-
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [&child](RenderProperties& props, RecordingCanvas& canvas) {
- SkPaint paint;
- paint.setColor(SK_ColorDKGRAY);
- canvas.drawRect(0, 0, 200, 200, paint);
-
- canvas.save(SaveFlags::MatrixClip);
- canvas.translate(40, 40);
- canvas.drawRenderNode(child.get());
- canvas.restore();
- });
-
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ auto child = TestUtils::createNode<RecordingCanvas>(
+ 10, 10, 110, 110, [](RenderProperties& props, RecordingCanvas& canvas) {
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
+
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [&child](RenderProperties& props, RecordingCanvas& canvas) {
+ SkPaint paint;
+ paint.setColor(SK_ColorDKGRAY);
+ canvas.drawRect(0, 0, 200, 200, paint);
+
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.translate(40, 40);
+ canvas.drawRenderNode(child.get());
+ canvas.restore();
+ });
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
RenderNodeTestRenderer renderer;
@@ -877,15 +869,15 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, clipped) {
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- sk_sp<Bitmap> bitmap(TestUtils::createBitmap(200, 200));
- canvas.drawBitmap(*bitmap, 0, 0, nullptr);
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ sk_sp<Bitmap> bitmap(TestUtils::createBitmap(200, 200));
+ canvas.drawBitmap(*bitmap, 0, 0, nullptr);
+ });
// clip to small area, should see in receiver
- FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 20, 30, 40), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 20, 30, 40), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
ClippedTestRenderer renderer;
@@ -901,9 +893,7 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_simple) {
EXPECT_EQ(180u, height);
return nullptr;
}
- void endLayer() override {
- EXPECT_EQ(2, mIndex++);
- }
+ void endLayer() override { EXPECT_EQ(2, mIndex++); }
void onRectOp(const RectOp& op, const BakedOpState& state) override {
EXPECT_EQ(1, mIndex++);
EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
@@ -926,15 +916,15 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_simple) {
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer);
- canvas.drawRect(10, 10, 190, 190, SkPaint());
- canvas.restore();
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer);
+ canvas.drawRect(10, 10, 190, 190, SkPaint());
+ canvas.restore();
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SaveLayerSimpleTestRenderer renderer;
@@ -955,13 +945,15 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_nested) {
if (index == 0) {
EXPECT_EQ(400u, width);
EXPECT_EQ(400u, height);
- return (OffscreenBuffer*) 0x400;
+ return (OffscreenBuffer*)0x400;
} else if (index == 3) {
EXPECT_EQ(800u, width);
EXPECT_EQ(800u, height);
- return (OffscreenBuffer*) 0x800;
- } else { ADD_FAILURE(); }
- return (OffscreenBuffer*) nullptr;
+ return (OffscreenBuffer*)0x800;
+ } else {
+ ADD_FAILURE();
+ }
+ return (OffscreenBuffer*)nullptr;
}
void endLayer() override {
int index = mIndex++;
@@ -970,26 +962,28 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_nested) {
void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
EXPECT_EQ(7, mIndex++);
}
- void endFrame(const Rect& repaintRect) override {
- EXPECT_EQ(9, mIndex++);
- }
+ void endFrame(const Rect& repaintRect) override { EXPECT_EQ(9, mIndex++); }
void onRectOp(const RectOp& op, const BakedOpState& state) override {
const int index = mIndex++;
if (index == 1) {
- EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
+ EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
} else if (index == 4) {
- EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
- } else { ADD_FAILURE(); }
+ EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
+ } else {
+ ADD_FAILURE();
+ }
}
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
const int index = mIndex++;
if (index == 5) {
EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
- EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
+ EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
} else if (index == 8) {
EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
- EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
- } else { ADD_FAILURE(); }
+ EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
+ } else {
+ ADD_FAILURE();
+ }
}
void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
const int index = mIndex++;
@@ -998,26 +992,26 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_nested) {
EXPECT_EQ((OffscreenBuffer*)0x400, offscreenBuffer);
} else if (index == 11) {
EXPECT_EQ((OffscreenBuffer*)0x800, offscreenBuffer);
- } else { ADD_FAILURE(); }
- }
- };
-
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 800, 800,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer);
- {
- canvas.drawRect(0, 0, 800, 800, SkPaint());
- canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
- {
- canvas.drawRect(0, 0, 400, 400, SkPaint());
+ } else {
+ ADD_FAILURE();
}
- canvas.restore();
}
- canvas.restore();
- });
+ };
- FrameBuilder frameBuilder(SkRect::MakeWH(800, 800), 800, 800,
- sLightGeometry, Caches::getInstance());
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 800, 800, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer);
+ {
+ canvas.drawRect(0, 0, 800, 800, SkPaint());
+ canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
+ { canvas.drawRect(0, 0, 400, 400, SkPaint()); }
+ canvas.restore();
+ }
+ canvas.restore();
+ });
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(800, 800), 800, 800, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SaveLayerNestedTestRenderer renderer;
@@ -1026,21 +1020,21 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_nested) {
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_contentRejection) {
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.save(SaveFlags::MatrixClip);
- canvas.clipRect(200, 200, 400, 400, SkClipOp::kIntersect);
- canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.clipRect(200, 200, 400, 400, SkClipOp::kIntersect);
+ canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
- // draw within save layer may still be recorded, but shouldn't be drawn
- canvas.drawRect(200, 200, 400, 400, SkPaint());
+ // draw within save layer may still be recorded, but shouldn't be drawn
+ canvas.drawRect(200, 200, 400, 400, SkPaint());
- canvas.restore();
- canvas.restore();
- });
+ canvas.restore();
+ canvas.restore();
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
FailRenderer renderer;
@@ -1077,15 +1071,15 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_simple) {
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
- canvas.drawRect(0, 0, 200, 200, SkPaint());
- canvas.restore();
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
+ canvas.drawRect(0, 0, 200, 200, SkPaint());
+ canvas.restore();
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SaveLayerUnclippedSimpleTestRenderer renderer;
@@ -1110,16 +1104,16 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_round) {
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.saveLayerAlpha(10.95f, 10.5f, 189.75f, 189.25f, // values should all round out
- 128, (SaveFlags::Flags)(0));
+ auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200, [](RenderProperties& props,
+ RecordingCanvas& canvas) {
+ canvas.saveLayerAlpha(10.95f, 10.5f, 189.75f, 189.25f, // values should all round out
+ 128, (SaveFlags::Flags)(0));
canvas.drawRect(0, 0, 200, 200, SkPaint());
canvas.restore();
});
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SaveLayerUnclippedRoundTestRenderer renderer;
@@ -1162,21 +1156,21 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_mergedClears)
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
-
- int restoreTo = canvas.save(SaveFlags::MatrixClip);
- canvas.scale(2, 2);
- canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip);
- canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip);
- canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip);
- canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip);
- canvas.drawRect(0, 0, 100, 100, SkPaint());
- canvas.restoreToCount(restoreTo);
- });
-
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+
+ int restoreTo = canvas.save(SaveFlags::MatrixClip);
+ canvas.scale(2, 2);
+ canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip);
+ canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip);
+ canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip);
+ canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip);
+ canvas.drawRect(0, 0, 100, 100, SkPaint());
+ canvas.restoreToCount(restoreTo);
+ });
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SaveLayerUnclippedMergedClearsTestRenderer renderer;
@@ -1209,17 +1203,17 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_clearClip) {
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- // save smaller than clip, so we get unclipped behavior
- canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
- canvas.drawRect(0, 0, 200, 200, SkPaint());
- canvas.restore();
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ // save smaller than clip, so we get unclipped behavior
+ canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
+ canvas.drawRect(0, 0, 200, 200, SkPaint());
+ canvas.restore();
+ });
// draw with partial screen dirty, and assert we see that rect later
- FrameBuilder frameBuilder(SkRect::MakeLTRB(50, 50, 150, 150), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeLTRB(50, 50, 150, 150), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SaveLayerUnclippedClearClipTestRenderer renderer;
@@ -1228,17 +1222,17 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_clearClip) {
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_reject) {
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- // unclipped savelayer + rect both in area that won't intersect with dirty
- canvas.saveLayerAlpha(100, 100, 200, 200, 128, (SaveFlags::Flags)(0));
- canvas.drawRect(100, 100, 200, 200, SkPaint());
- canvas.restore();
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ // unclipped savelayer + rect both in area that won't intersect with dirty
+ canvas.saveLayerAlpha(100, 100, 200, 200, 128, (SaveFlags::Flags)(0));
+ canvas.drawRect(100, 100, 200, 200, SkPaint());
+ canvas.restore();
+ });
// draw with partial screen dirty that doesn't intersect with savelayer
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
FailRenderer renderer;
@@ -1253,7 +1247,7 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_complex) {
class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
public:
OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
- EXPECT_EQ(0, mIndex++); // savelayer first
+ EXPECT_EQ(0, mIndex++); // savelayer first
return (OffscreenBuffer*)0xabcd;
}
void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
@@ -1275,9 +1269,7 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_complex) {
int index = mIndex++;
EXPECT_TRUE(index == 4 || index == 10);
}
- void endLayer() override {
- EXPECT_EQ(5, mIndex++);
- }
+ void endLayer() override { EXPECT_EQ(5, mIndex++); }
void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
EXPECT_EQ(6, mIndex++);
}
@@ -1285,28 +1277,27 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_complex) {
EXPECT_EQ(9, mIndex++);
EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
}
- void endFrame(const Rect& repaintRect) override {
- EXPECT_EQ(11, mIndex++);
- }
+ void endFrame(const Rect& repaintRect) override { EXPECT_EQ(11, mIndex++); }
void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
EXPECT_EQ(12, mIndex++);
EXPECT_EQ((OffscreenBuffer*)0xabcd, offscreenBuffer);
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 600, 600, // 500x500 triggers clipping
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 600, 600, // 500x500 triggers clipping
[](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped
- canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped
- canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped
- canvas.drawRect(200, 200, 300, 300, SkPaint());
- canvas.restore();
- canvas.restore();
- canvas.restore();
- });
-
- FrameBuilder frameBuilder(SkRect::MakeWH(600, 600), 600, 600,
- sLightGeometry, Caches::getInstance());
+ canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped
+ canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped
+ canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped
+ canvas.drawRect(200, 200, 300, 300, SkPaint());
+ canvas.restore();
+ canvas.restore();
+ canvas.restore();
+ });
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(600, 600), 600, 600, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SaveLayerUnclippedComplexTestRenderer renderer;
@@ -1332,27 +1323,23 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, hwLayer_simple) {
EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
<< "Damage rect should be used to clip layer content";
}
- void endLayer() override {
- EXPECT_EQ(2, mIndex++);
- }
+ void endLayer() override { EXPECT_EQ(2, mIndex++); }
void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
EXPECT_EQ(3, mIndex++);
}
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(4, mIndex++);
}
- void endFrame(const Rect& repaintRect) override {
- EXPECT_EQ(5, mIndex++);
- }
+ void endFrame(const Rect& repaintRect) override { EXPECT_EQ(5, mIndex++); }
};
- auto node = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- props.mutateLayerProperties().setType(LayerType::RenderLayer);
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 10, 10, 110, 110, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.mutateLayerProperties().setType(LayerType::RenderLayer);
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
OffscreenBuffer** layerHandle = node->getLayerHandle();
// create RenderNode's layer here in same way prepareTree would
@@ -1362,11 +1349,11 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, hwLayer_simple) {
auto syncedNode = TestUtils::getSyncedNode(node);
// only enqueue partial damage
- LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+ LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferLayers(layerUpdateQueue);
frameBuilder.deferRenderNode(*syncedNode);
@@ -1388,7 +1375,7 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, hwLayer_complex) {
class HwLayerComplexTestRenderer : public TestRendererBase {
public:
OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
- EXPECT_EQ(3, mIndex++); // savelayer first
+ EXPECT_EQ(3, mIndex++); // savelayer first
return (OffscreenBuffer*)0xabcd;
}
void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
@@ -1401,7 +1388,9 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, hwLayer_complex) {
// starting outer layer
EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
- } else { ADD_FAILURE(); }
+ } else {
+ ADD_FAILURE();
+ }
}
void onRectOp(const RectOp& op, const BakedOpState& state) override {
int index = mIndex++;
@@ -1411,7 +1400,9 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, hwLayer_complex) {
} else if (index == 7) {
// outer layer's rect (grey)
EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
- } else { ADD_FAILURE(); }
+ } else {
+ ADD_FAILURE();
+ }
}
void endLayer() override {
int index = mIndex++;
@@ -1431,49 +1422,49 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, hwLayer_complex) {
} else if (index == 11) {
EXPECT_EQ(200u, layer->viewportWidth);
EXPECT_EQ(200u, layer->viewportHeight);
- } else { ADD_FAILURE(); }
- }
- void endFrame(const Rect& repaintRect) override {
- EXPECT_EQ(12, mIndex++);
+ } else {
+ ADD_FAILURE();
+ }
}
+ void endFrame(const Rect& repaintRect) override { EXPECT_EQ(12, mIndex++); }
void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
EXPECT_EQ(13, mIndex++);
}
};
- auto child = TestUtils::createNode<RecordingCanvas>(50, 50, 150, 150,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- props.mutateLayerProperties().setType(LayerType::RenderLayer);
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
+ auto child = TestUtils::createNode<RecordingCanvas>(
+ 50, 50, 150, 150, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.mutateLayerProperties().setType(LayerType::RenderLayer);
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
*(child->getLayerHandle()) = &childLayer;
RenderNode* childPtr = child.get();
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
- props.mutateLayerProperties().setType(LayerType::RenderLayer);
- SkPaint paint;
- paint.setColor(SK_ColorDKGRAY);
- canvas.drawRect(0, 0, 200, 200, paint);
-
- canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer);
- canvas.drawRenderNode(childPtr);
- canvas.restore();
- });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
+ props.mutateLayerProperties().setType(LayerType::RenderLayer);
+ SkPaint paint;
+ paint.setColor(SK_ColorDKGRAY);
+ canvas.drawRect(0, 0, 200, 200, paint);
+
+ canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer);
+ canvas.drawRenderNode(childPtr);
+ canvas.restore();
+ });
OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
*(parent->getLayerHandle()) = &parentLayer;
auto syncedNode = TestUtils::getSyncedNode(parent);
- LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+ LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferLayers(layerUpdateQueue);
frameBuilder.deferRenderNode(*syncedNode);
@@ -1486,7 +1477,6 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, hwLayer_complex) {
*(parent->getLayerHandle()) = nullptr;
}
-
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, buildLayer) {
class BuildLayerTestRenderer : public TestRendererBase {
public:
@@ -1505,9 +1495,7 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, buildLayer) {
EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
<< "Damage rect should be used to clip layer content";
}
- void endLayer() override {
- EXPECT_EQ(2, mIndex++);
- }
+ void endLayer() override { EXPECT_EQ(2, mIndex++); }
void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
ADD_FAILURE() << "Primary frame draw not expected in this test";
}
@@ -1516,11 +1504,11 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, buildLayer) {
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- props.mutateLayerProperties().setType(LayerType::RenderLayer);
- canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 10, 10, 110, 110, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.mutateLayerProperties().setType(LayerType::RenderLayer);
+ canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+ });
OffscreenBuffer** layerHandle = node->getLayerHandle();
// create RenderNode's layer here in same way prepareTree would
@@ -1530,7 +1518,7 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, buildLayer) {
TestUtils::syncHierarchyPropertiesAndDisplayList(node);
// only enqueue partial damage
- LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+ LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
// Draw, but pass empty node list, so no work is done for primary frame
@@ -1552,65 +1540,69 @@ static void drawOrderedRect(Canvas* canvas, uint8_t expectedDrawOrder) {
canvas->drawRect(0, 0, 100, 100, paint);
}
static void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder, float z) {
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedRect(&canvas, expectedDrawOrder);
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedRect(&canvas, expectedDrawOrder);
+ });
node->mutateStagingProperties().setTranslationZ(z);
node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
- canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
+ canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
}
-static void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder,
+static void drawOrderedNode(
+ Canvas* canvas, uint8_t expectedDrawOrder,
std::function<void(RenderProperties& props, RecordingCanvas& canvas)> setup) {
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100,
[expectedDrawOrder, setup](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedRect(&canvas, expectedDrawOrder);
- if (setup) {
- setup(props, canvas);
- }
- });
- canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
+ drawOrderedRect(&canvas, expectedDrawOrder);
+ if (setup) {
+ setup(props, canvas);
+ }
+ });
+ canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
}
class ZReorderTestRenderer : public TestRendererBase {
public:
void onRectOp(const RectOp& op, const BakedOpState& state) override {
- int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
+ int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
}
};
-} // end anonymous namespace
+} // end anonymous namespace
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, zReorder) {
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.insertReorderBarrier(true);
- canvas.insertReorderBarrier(false);
- drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
- drawOrderedRect(&canvas, 1);
- canvas.insertReorderBarrier(true);
- drawOrderedNode(&canvas, 6, 2.0f);
- drawOrderedRect(&canvas, 3);
- drawOrderedNode(&canvas, 4, 0.0f);
- drawOrderedRect(&canvas, 5);
- drawOrderedNode(&canvas, 2, -2.0f);
- drawOrderedNode(&canvas, 7, 2.0f);
- canvas.insertReorderBarrier(false);
- drawOrderedRect(&canvas, 8);
- drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
- canvas.insertReorderBarrier(true); //reorder a node ahead of drawrect op
- drawOrderedRect(&canvas, 11);
- drawOrderedNode(&canvas, 10, -1.0f);
- canvas.insertReorderBarrier(false);
- canvas.insertReorderBarrier(true); //test with two empty reorder sections
- canvas.insertReorderBarrier(true);
- canvas.insertReorderBarrier(false);
- drawOrderedRect(&canvas, 12);
- });
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.insertReorderBarrier(true);
+ canvas.insertReorderBarrier(false);
+ drawOrderedNode(&canvas, 0,
+ 10.0f); // in reorder=false at this point, so played inorder
+ drawOrderedRect(&canvas, 1);
+ canvas.insertReorderBarrier(true);
+ drawOrderedNode(&canvas, 6, 2.0f);
+ drawOrderedRect(&canvas, 3);
+ drawOrderedNode(&canvas, 4, 0.0f);
+ drawOrderedRect(&canvas, 5);
+ drawOrderedNode(&canvas, 2, -2.0f);
+ drawOrderedNode(&canvas, 7, 2.0f);
+ canvas.insertReorderBarrier(false);
+ drawOrderedRect(&canvas, 8);
+ drawOrderedNode(&canvas, 9,
+ -10.0f); // in reorder=false at this point, so played inorder
+ canvas.insertReorderBarrier(true); // reorder a node ahead of drawrect op
+ drawOrderedRect(&canvas, 11);
+ drawOrderedNode(&canvas, 10, -1.0f);
+ canvas.insertReorderBarrier(false);
+ canvas.insertReorderBarrier(true); // test with two empty reorder sections
+ canvas.insertReorderBarrier(true);
+ canvas.insertReorderBarrier(false);
+ drawOrderedRect(&canvas, 12);
+ });
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
ZReorderTestRenderer renderer;
@@ -1628,28 +1620,28 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorder) {
Matrix4 expectedMatrix;
switch (index) {
- case 0:
- EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
- EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
- expectedMatrix.loadIdentity();
- EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
- break;
- case 1:
- EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
- EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
- expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0);
- ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
- EXPECT_EQ(Rect(-35, -30, 45, 50),
- Rect(state.computedState.localProjectionPathMask->getBounds()));
- break;
- case 2:
- EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
- EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
- expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
- EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
- break;
- default:
- ADD_FAILURE();
+ case 0:
+ EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
+ EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
+ expectedMatrix.loadIdentity();
+ EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
+ break;
+ case 1:
+ EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
+ EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
+ expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0);
+ ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
+ EXPECT_EQ(Rect(-35, -30, 45, 50),
+ Rect(state.computedState.localProjectionPathMask->getBounds()));
+ break;
+ case 2:
+ EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
+ EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
+ expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
+ EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
+ break;
+ default:
+ ADD_FAILURE();
}
EXPECT_EQ(expectedMatrix, state.computedState.transform);
}
@@ -1663,47 +1655,51 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorder) {
* The parent is scrolled by scrollX/scrollY, but this does not affect the background
* (which isn't affected by scroll).
*/
- auto receiverBackground = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& properties, RecordingCanvas& canvas) {
- properties.setProjectionReceiver(true);
- // scroll doesn't apply to background, so undone via translationX/Y
- // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
- properties.setTranslationX(scrollX);
- properties.setTranslationY(scrollY);
-
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
- auto projectingRipple = TestUtils::createNode<RecordingCanvas>(50, 0, 100, 50,
- [](RenderProperties& properties, RecordingCanvas& canvas) {
- properties.setProjectBackwards(true);
- properties.setClipToBounds(false);
- SkPaint paint;
- paint.setColor(SK_ColorDKGRAY);
- canvas.drawRect(-10, -10, 60, 60, paint);
- });
- auto child = TestUtils::createNode<RecordingCanvas>(0, 50, 100, 100,
+ auto receiverBackground = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& properties, RecordingCanvas& canvas) {
+ properties.setProjectionReceiver(true);
+ // scroll doesn't apply to background, so undone via translationX/Y
+ // NOTE: translationX/Y only! no other transform properties may be set for a proj
+ // receiver!
+ properties.setTranslationX(scrollX);
+ properties.setTranslationY(scrollY);
+
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
+ auto projectingRipple = TestUtils::createNode<RecordingCanvas>(
+ 50, 0, 100, 50, [](RenderProperties& properties, RecordingCanvas& canvas) {
+ properties.setProjectBackwards(true);
+ properties.setClipToBounds(false);
+ SkPaint paint;
+ paint.setColor(SK_ColorDKGRAY);
+ canvas.drawRect(-10, -10, 60, 60, paint);
+ });
+ auto child = TestUtils::createNode<RecordingCanvas>(
+ 0, 50, 100, 100,
[&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
- SkPaint paint;
- paint.setColor(SK_ColorBLUE);
- canvas.drawRect(0, 0, 100, 50, paint);
- canvas.drawRenderNode(projectingRipple.get());
- });
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
+ SkPaint paint;
+ paint.setColor(SK_ColorBLUE);
+ canvas.drawRect(0, 0, 100, 50, paint);
+ canvas.drawRenderNode(projectingRipple.get());
+ });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100,
[&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
- // Set a rect outline for the projecting ripple to be masked against.
- properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
-
- canvas.save(SaveFlags::MatrixClip);
- canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
- canvas.drawRenderNode(receiverBackground.get());
- canvas.drawRenderNode(child.get());
- canvas.restore();
- });
-
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ // Set a rect outline for the projecting ripple to be masked against.
+ properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
+
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.translate(-scrollX,
+ -scrollY); // Apply scroll (note: bg undoes this internally)
+ canvas.drawRenderNode(receiverBackground.get());
+ canvas.drawRenderNode(child.get());
+ canvas.restore();
+ });
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
ProjectionReorderTestRenderer renderer;
@@ -1723,9 +1719,7 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionHwLayer) {
EXPECT_EQ(1, mIndex++);
ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
}
- void endLayer() override {
- EXPECT_EQ(2, mIndex++);
- }
+ void endLayer() override { EXPECT_EQ(2, mIndex++); }
void onRectOp(const RectOp& op, const BakedOpState& state) override {
EXPECT_EQ(3, mIndex++);
ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
@@ -1737,60 +1731,64 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionHwLayer) {
expected.loadTranslate(100 - scrollX, 100 - scrollY, 0);
EXPECT_EQ(expected, state.computedState.transform);
EXPECT_EQ(Rect(-85, -80, 295, 300),
- Rect(state.computedState.localProjectionPathMask->getBounds()));
+ Rect(state.computedState.localProjectionPathMask->getBounds()));
}
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(5, mIndex++);
ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
}
};
- auto receiverBackground = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
- [](RenderProperties& properties, RecordingCanvas& canvas) {
- properties.setProjectionReceiver(true);
- // scroll doesn't apply to background, so undone via translationX/Y
- // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
- properties.setTranslationX(scrollX);
- properties.setTranslationY(scrollY);
+ auto receiverBackground = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 400, 400, [](RenderProperties& properties, RecordingCanvas& canvas) {
+ properties.setProjectionReceiver(true);
+ // scroll doesn't apply to background, so undone via translationX/Y
+ // NOTE: translationX/Y only! no other transform properties may be set for a proj
+ // receiver!
+ properties.setTranslationX(scrollX);
+ properties.setTranslationY(scrollY);
- canvas.drawRect(0, 0, 400, 400, SkPaint());
- });
- auto projectingRipple = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& properties, RecordingCanvas& canvas) {
- properties.setProjectBackwards(true);
- properties.setClipToBounds(false);
- canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
- });
- auto child = TestUtils::createNode<RecordingCanvas>(100, 100, 300, 300,
+ canvas.drawRect(0, 0, 400, 400, SkPaint());
+ });
+ auto projectingRipple = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& properties, RecordingCanvas& canvas) {
+ properties.setProjectBackwards(true);
+ properties.setClipToBounds(false);
+ canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
+ });
+ auto child = TestUtils::createNode<RecordingCanvas>(
+ 100, 100, 300, 300,
[&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
- properties.mutateLayerProperties().setType(LayerType::RenderLayer);
- canvas.drawRenderNode(projectingRipple.get());
- canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint());
- });
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
+ properties.mutateLayerProperties().setType(LayerType::RenderLayer);
+ canvas.drawRenderNode(projectingRipple.get());
+ canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint());
+ });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 400, 400,
[&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
- // Set a rect outline for the projecting ripple to be masked against.
- properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
- canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
- canvas.drawRenderNode(receiverBackground.get());
- canvas.drawRenderNode(child.get());
- });
+ // Set a rect outline for the projecting ripple to be masked against.
+ properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
+ canvas.translate(-scrollX,
+ -scrollY); // Apply scroll (note: bg undoes this internally)
+ canvas.drawRenderNode(receiverBackground.get());
+ canvas.drawRenderNode(child.get());
+ });
OffscreenBuffer** layerHandle = child->getLayerHandle();
// create RenderNode's layer here in same way prepareTree would, setting windowTransform
OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200, 200);
Matrix4 windowTransform;
- windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin
+ windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin
layer.setWindowTransform(windowTransform);
*layerHandle = &layer;
auto syncedNode = TestUtils::getSyncedNode(parent);
- LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+ LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(200, 200));
- FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferLayers(layerUpdateQueue);
frameBuilder.deferRenderNode(*syncedNode);
@@ -1819,37 +1817,41 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionChildScroll) {
EXPECT_TRUE(state.computedState.transform.isIdentity());
}
};
- auto receiverBackground = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
- [](RenderProperties& properties, RecordingCanvas& canvas) {
- properties.setProjectionReceiver(true);
- canvas.drawRect(0, 0, 400, 400, SkPaint());
- });
- auto projectingRipple = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& properties, RecordingCanvas& canvas) {
- // scroll doesn't apply to background, so undone via translationX/Y
- // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
- properties.setTranslationX(scrollX);
- properties.setTranslationY(scrollY);
- properties.setProjectBackwards(true);
- properties.setClipToBounds(false);
- canvas.drawOval(0, 0, 200, 200, SkPaint());
- });
- auto child = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
+ auto receiverBackground = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 400, 400, [](RenderProperties& properties, RecordingCanvas& canvas) {
+ properties.setProjectionReceiver(true);
+ canvas.drawRect(0, 0, 400, 400, SkPaint());
+ });
+ auto projectingRipple = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& properties, RecordingCanvas& canvas) {
+ // scroll doesn't apply to background, so undone via translationX/Y
+ // NOTE: translationX/Y only! no other transform properties may be set for a proj
+ // receiver!
+ properties.setTranslationX(scrollX);
+ properties.setTranslationY(scrollY);
+ properties.setProjectBackwards(true);
+ properties.setClipToBounds(false);
+ canvas.drawOval(0, 0, 200, 200, SkPaint());
+ });
+ auto child = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 400, 400,
[&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
- // Record time clip will be ignored by projectee
- canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
-
- canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
- canvas.drawRenderNode(projectingRipple.get());
- });
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
+ // Record time clip will be ignored by projectee
+ canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
+
+ canvas.translate(-scrollX,
+ -scrollY); // Apply scroll (note: bg undoes this internally)
+ canvas.drawRenderNode(projectingRipple.get());
+ });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 400, 400,
[&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
- canvas.drawRenderNode(receiverBackground.get());
- canvas.drawRenderNode(child.get());
- });
+ canvas.drawRenderNode(receiverBackground.get());
+ canvas.drawRenderNode(child.get());
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
ProjectionChildScrollTestRenderer renderer;
@@ -1859,14 +1861,14 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionChildScroll) {
// creates a 100x100 shadow casting node with provided translationZ
static sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
- return TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
- properties.setTranslationZ(translationZ);
- properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
+ return TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
+ properties.setTranslationZ(translationZ);
+ properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadow) {
@@ -1887,14 +1889,14 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadow) {
}
};
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.insertReorderBarrier(true);
- canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
- });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.insertReorderBarrier(true);
+ canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
ShadowTestRenderer renderer;
@@ -1917,9 +1919,7 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowSaveLayer) {
void onRectOp(const RectOp& op, const BakedOpState& state) override {
EXPECT_EQ(2, mIndex++);
}
- void endLayer() override {
- EXPECT_EQ(3, mIndex++);
- }
+ void endLayer() override { EXPECT_EQ(3, mIndex++); }
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(4, mIndex++);
}
@@ -1928,19 +1928,20 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowSaveLayer) {
}
};
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- // save/restore outside of reorderBarrier, so they don't get moved out of place
- canvas.translate(20, 10);
- int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer);
- canvas.insertReorderBarrier(true);
- canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
- canvas.insertReorderBarrier(false);
- canvas.restoreToCount(count);
- });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ // save/restore outside of reorderBarrier, so they don't get moved out of place
+ canvas.translate(20, 10);
+ int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer);
+ canvas.insertReorderBarrier(true);
+ canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
+ canvas.insertReorderBarrier(false);
+ canvas.restoreToCount(count);
+ });
FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
+ (FrameBuilder::LightGeometry){{100, 100, 100}, 50},
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
ShadowSaveLayerTestRenderer renderer;
@@ -1963,38 +1964,37 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowHwLayer) {
void onRectOp(const RectOp& op, const BakedOpState& state) override {
EXPECT_EQ(2, mIndex++);
}
- void endLayer() override {
- EXPECT_EQ(3, mIndex++);
- }
+ void endLayer() override { EXPECT_EQ(3, mIndex++); }
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(4, mIndex++);
}
};
- auto parent = TestUtils::createNode<RecordingCanvas>(50, 60, 150, 160,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- props.mutateLayerProperties().setType(LayerType::RenderLayer);
- canvas.insertReorderBarrier(true);
- canvas.save(SaveFlags::MatrixClip);
- canvas.translate(20, 10);
- canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
- canvas.restore();
- });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 50, 60, 150, 160, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.mutateLayerProperties().setType(LayerType::RenderLayer);
+ canvas.insertReorderBarrier(true);
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.translate(20, 10);
+ canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
+ canvas.restore();
+ });
OffscreenBuffer** layerHandle = parent->getLayerHandle();
// create RenderNode's layer here in same way prepareTree would, setting windowTransform
OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
Matrix4 windowTransform;
- windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
+ windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
layer.setWindowTransform(windowTransform);
*layerHandle = &layer;
auto syncedNode = TestUtils::getSyncedNode(parent);
- LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+ LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30}, Caches::getInstance());
+ (FrameBuilder::LightGeometry){{100, 100, 100}, 30},
+ Caches::getInstance());
frameBuilder.deferLayers(layerUpdateQueue);
frameBuilder.deferRenderNode(*syncedNode);
@@ -2018,14 +2018,15 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowLayering) {
EXPECT_TRUE(index == 2 || index == 3);
}
};
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.insertReorderBarrier(true);
- canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
- canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
- });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.insertReorderBarrier(true);
+ canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
+ canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
+ });
FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
+ (FrameBuilder::LightGeometry){{100, 100, 100}, 50},
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
ShadowLayeringTestRenderer renderer;
@@ -2045,17 +2046,18 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowClipping) {
EXPECT_EQ(1, mIndex++);
}
};
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- // Apply a clip before the reorder barrier/shadow casting child is drawn.
- // This clip must be applied to the shadow cast by the child.
- canvas.clipRect(25, 25, 75, 75, SkClipOp::kIntersect);
- canvas.insertReorderBarrier(true);
- canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
- });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ // Apply a clip before the reorder barrier/shadow casting child is drawn.
+ // This clip must be applied to the shadow cast by the child.
+ canvas.clipRect(25, 25, 75, 75, SkClipOp::kIntersect);
+ canvas.insertReorderBarrier(true);
+ canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
+ });
FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
+ (FrameBuilder::LightGeometry){{100, 100, 100}, 50},
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
ShadowClippingTestRenderer renderer;
@@ -2063,11 +2065,13 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowClipping) {
EXPECT_EQ(2, renderer.getIndex());
}
-static void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
+static void testProperty(
+ std::function<void(RenderProperties&)> propSetupCallback,
std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
class PropertyTestRenderer : public TestRendererBase {
public:
- explicit PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
+ explicit PropertyTestRenderer(
+ std::function<void(const RectOp&, const BakedOpState&)> callback)
: mCallback(callback) {}
void onRectOp(const RectOp& op, const BakedOpState& state) override {
EXPECT_EQ(mIndex++, 0);
@@ -2076,16 +2080,16 @@ static void testProperty(std::function<void(RenderProperties&)> propSetupCallbac
std::function<void(const RectOp&, const BakedOpState&)> mCallback;
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
- propSetupCallback(props);
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
+ propSetupCallback(props);
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
PropertyTestRenderer renderer(opValidateCallback);
@@ -2094,78 +2098,89 @@ static void testProperty(std::function<void(RenderProperties&)> propSetupCallbac
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
- testProperty([](RenderProperties& properties) {
- properties.setAlpha(0.5f);
- properties.setHasOverlappingRendering(false);
- }, [](const RectOp& op, const BakedOpState& state) {
- EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
- });
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.setAlpha(0.5f);
+ properties.setHasOverlappingRendering(false);
+ },
+ [](const RectOp& op, const BakedOpState& state) {
+ EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
+ });
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropClipping) {
- testProperty([](RenderProperties& properties) {
- properties.setClipToBounds(true);
- properties.setClipBounds(Rect(10, 20, 300, 400));
- }, [](const RectOp& op, const BakedOpState& state) {
- EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
- << "Clip rect should be intersection of node bounds and clip bounds";
- });
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.setClipToBounds(true);
+ properties.setClipBounds(Rect(10, 20, 300, 400));
+ },
+ [](const RectOp& op, const BakedOpState& state) {
+ EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
+ << "Clip rect should be intersection of node bounds and clip bounds";
+ });
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropRevealClip) {
- testProperty([](RenderProperties& properties) {
- properties.mutableRevealClip().set(true, 50, 50, 25);
- }, [](const RectOp& op, const BakedOpState& state) {
- ASSERT_NE(nullptr, state.roundRectClipState);
- EXPECT_TRUE(state.roundRectClipState->highPriority);
- EXPECT_EQ(25, state.roundRectClipState->radius);
- EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
- });
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.mutableRevealClip().set(true, 50, 50, 25);
+ },
+ [](const RectOp& op, const BakedOpState& state) {
+ ASSERT_NE(nullptr, state.roundRectClipState);
+ EXPECT_TRUE(state.roundRectClipState->highPriority);
+ EXPECT_EQ(25, state.roundRectClipState->radius);
+ EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
+ });
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropOutlineClip) {
- testProperty([](RenderProperties& properties) {
- properties.mutableOutline().setShouldClip(true);
- properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
- }, [](const RectOp& op, const BakedOpState& state) {
- ASSERT_NE(nullptr, state.roundRectClipState);
- EXPECT_FALSE(state.roundRectClipState->highPriority);
- EXPECT_EQ(5, state.roundRectClipState->radius);
- EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
- });
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.mutableOutline().setShouldClip(true);
+ properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
+ },
+ [](const RectOp& op, const BakedOpState& state) {
+ ASSERT_NE(nullptr, state.roundRectClipState);
+ EXPECT_FALSE(state.roundRectClipState->highPriority);
+ EXPECT_EQ(5, state.roundRectClipState->radius);
+ EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
+ });
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropTransform) {
- testProperty([](RenderProperties& properties) {
- properties.setLeftTopRightBottom(10, 10, 110, 110);
-
- SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
- properties.setStaticMatrix(&staticMatrix);
-
- // ignored, since static overrides animation
- SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
- properties.setAnimationMatrix(&animationMatrix);
-
- properties.setTranslationX(10);
- properties.setTranslationY(20);
- properties.setScaleX(0.5f);
- properties.setScaleY(0.7f);
- }, [](const RectOp& op, const BakedOpState& state) {
- Matrix4 matrix;
- matrix.loadTranslate(10, 10, 0); // left, top
- matrix.scale(1.2f, 1.2f, 1); // static matrix
- // ignore animation matrix, since static overrides it
-
- // translation xy
- matrix.translate(10, 20);
-
- // scale xy (from default pivot - center)
- matrix.translate(50, 50);
- matrix.scale(0.5f, 0.7f, 1);
- matrix.translate(-50, -50);
- EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
- << "Op draw matrix must match expected combination of transformation properties";
- });
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.setLeftTopRightBottom(10, 10, 110, 110);
+
+ SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
+ properties.setStaticMatrix(&staticMatrix);
+
+ // ignored, since static overrides animation
+ SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
+ properties.setAnimationMatrix(&animationMatrix);
+
+ properties.setTranslationX(10);
+ properties.setTranslationY(20);
+ properties.setScaleX(0.5f);
+ properties.setScaleY(0.7f);
+ },
+ [](const RectOp& op, const BakedOpState& state) {
+ Matrix4 matrix;
+ matrix.loadTranslate(10, 10, 0); // left, top
+ matrix.scale(1.2f, 1.2f, 1); // static matrix
+ // ignore animation matrix, since static overrides it
+
+ // translation xy
+ matrix.translate(10, 20);
+
+ // scale xy (from default pivot - center)
+ matrix.translate(50, 50);
+ matrix.scale(0.5f, 0.7f, 1);
+ matrix.translate(-50, -50);
+ EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
+ << "Op draw matrix must match expected combination of transformation "
+ "properties";
+ });
}
struct SaveLayerAlphaData {
@@ -2186,11 +2201,10 @@ struct SaveLayerAlphaData {
* (for efficiency, and to fit in layer size constraints) based on parent clip.
*/
void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
- std::function<void(RenderProperties&)> propSetupCallback) {
+ std::function<void(RenderProperties&)> propSetupCallback) {
class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
public:
- explicit SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
- : mOutData(outData) {}
+ explicit SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData) : mOutData(outData) {}
OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
EXPECT_EQ(0, mIndex++);
@@ -2204,9 +2218,7 @@ void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
mOutData->rectClippedBounds = state.computedState.clippedBounds;
mOutData->rectMatrix = state.computedState.transform;
}
- void endLayer() override {
- EXPECT_EQ(2, mIndex++);
- }
+ void endLayer() override { EXPECT_EQ(2, mIndex++); }
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(3, mIndex++);
mOutData->drawLayerMatrix = state.computedState.transform;
@@ -2214,27 +2226,29 @@ void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
EXPECT_EQ(4, mIndex++);
}
+
private:
SaveLayerAlphaData* mOutData;
};
ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
<< "Node must be bigger than max texture size to exercise saveLayer codepath";
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 10000, 10000,
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 10000, 10000,
[&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
- properties.setHasOverlappingRendering(true);
- properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
- // apply other properties
- propSetupCallback(properties);
-
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 10000, 10000, paint);
- });
- auto syncedNode = TestUtils::getSyncedNode(node); // sync before querying height
-
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ properties.setHasOverlappingRendering(true);
+ properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
+ // apply other properties
+ propSetupCallback(properties);
+
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 10000, 10000, paint);
+ });
+ auto syncedNode = TestUtils::getSyncedNode(node); // sync before querying height
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*syncedNode);
SaveLayerAlphaClipTestRenderer renderer(outObservedData);
@@ -2247,8 +2261,8 @@ void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
SaveLayerAlphaData observedData;
testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
- properties.setTranslationX(10); // offset rendering content
- properties.setTranslationY(-2000); // offset rendering content
+ properties.setTranslationX(10); // offset rendering content
+ properties.setTranslationY(-2000); // offset rendering content
});
EXPECT_EQ(190u, observedData.layerWidth);
EXPECT_EQ(200u, observedData.layerHeight);
@@ -2260,7 +2274,7 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig)
<< "expect content to be translated as part of being clipped";
expected.loadTranslate(10, 0, 0);
EXPECT_MATRIX_APPROX_EQ(expected, observedData.drawLayerMatrix)
- << "expect drawLayer to be translated as part of being clipped";
+ << "expect drawLayer to be translated as part of being clipped";
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
@@ -2306,14 +2320,14 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, clip_replace) {
<< "Expect resolved clip to be intersection of viewport clip and clip op";
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(20, 20, 30, 30,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace_deprecated);
- canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
- });
-
- FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 40, 40), 50, 50,
- sLightGeometry, Caches::getInstance());
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 20, 20, 30, 30, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace_deprecated);
+ canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+ });
+
+ FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 40, 40), 50, 50, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
ClipReplaceTestRenderer renderer;
@@ -2329,21 +2343,22 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedInMidd
|
R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
-
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setProjectionReceiver(true);
+ }); // nodeB
+ drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 1,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2360,22 +2375,24 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectLast) {
|
R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, nullptr); //nodeB
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 3, [](RenderProperties& props, RecordingCanvas& canvas) { //drawn as 2
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //drawn as 3
- props.setProjectionReceiver(true);
- } ); //nodeE
- }); //nodeA
-
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, nullptr); // nodeB
+ drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 3, [](RenderProperties& props,
+ RecordingCanvas& canvas) { // drawn as 2
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ drawOrderedNode(&canvas, 2, [](RenderProperties& props,
+ RecordingCanvas& canvas) { // drawn as 3
+ props.setProjectionReceiver(true);
+ }); // nodeE
+ }); // nodeA
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2391,20 +2408,21 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderNoReceivable) {
|
R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, nullptr); //nodeB
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 255, [](RenderProperties& props, RecordingCanvas& canvas) {
- //not having a projection receiver is an undefined behavior
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
-
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, nullptr); // nodeB
+ drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 255,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ // not having a projection receiver is an undefined behavior
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2420,20 +2438,21 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderParentReceivabl
|
R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, nullptr); //nodeB
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setProjectionReceiver(true);
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
-
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, nullptr); // nodeB
+ drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setProjectionReceiver(true);
+ drawOrderedNode(&canvas, 2,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2442,21 +2461,23 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderParentReceivabl
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderSameNodeReceivable) {
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, nullptr); //nodeB
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 255, [](RenderProperties& props, RecordingCanvas& canvas) {
- //having a node that is projected on itself is an undefined/unexpected behavior
- props.setProjectionReceiver(true);
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
-
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, nullptr); // nodeB
+ drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 255,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ // having a node that is projected on itself is an
+ // undefined/unexpected behavior
+ props.setProjectionReceiver(true);
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2465,9 +2486,9 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderSameNodeReceiva
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedSibling) {
- //TODO: this test together with the next "projectionReorderProjectedSibling2" likely expose a
- //bug in HWUI. First test draws R, while the second test does not draw R for a nearly identical
- //tree setup. The correct behaviour is to not draw R, because the receiver cannot be a sibling
+ // TODO: this test together with the next "projectionReorderProjectedSibling2" likely expose a
+ // bug in HWUI. First test draws R, while the second test does not draw R for a nearly identical
+ // tree setup. The correct behaviour is to not draw R, because the receiver cannot be a sibling
/* R is backward projected on B. R is not expected to be drawn (see Sibling2 outcome below),
but for some reason it is drawn.
A
@@ -2475,21 +2496,21 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedSiblin
/ | \
B C R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
- } ); //nodeC
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- }); //nodeA
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setProjectionReceiver(true);
+ }); // nodeB
+ drawOrderedNode(&canvas, 2,
+ [](RenderProperties& props, RecordingCanvas& canvas) {}); // nodeC
+ drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeA
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2506,23 +2527,27 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedSiblin
/ | \
B C R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { //G
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { //B
- props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //C
- } ); //nodeC
- drawOrderedNode(&canvas, 255, [](RenderProperties& props, RecordingCanvas& canvas) { //R
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeG
- }); //nodeA
-
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, [](RenderProperties& props,
+ RecordingCanvas& canvas) { // G
+ drawOrderedNode(&canvas, 1,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // B
+ props.setProjectionReceiver(true);
+ }); // nodeB
+ drawOrderedNode(&canvas, 2,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // C
+ }); // nodeC
+ drawOrderedNode(&canvas, 255,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // R
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeG
+ }); // nodeA
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2540,21 +2565,23 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderGrandparentRece
|
R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setProjectionReceiver(true);
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- } ); //nodeB
- }); //nodeA
-
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setProjectionReceiver(true);
+ drawOrderedNode(&canvas, 1,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 2, [](RenderProperties& props,
+ RecordingCanvas& canvas) {
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ }); // nodeB
+ }); // nodeA
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2570,24 +2597,28 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivables)
/ \
G R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { //B
- props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //C
- drawOrderedNode(&canvas, 3, [](RenderProperties& props, RecordingCanvas& canvas) { //G
- props.setProjectionReceiver(true);
- } ); //nodeG
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { //R
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
-
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // B
+ props.setProjectionReceiver(true);
+ }); // nodeB
+ drawOrderedNode(&canvas, 2, [](RenderProperties& props,
+ RecordingCanvas& canvas) { // C
+ drawOrderedNode(&canvas, 3,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // G
+ props.setProjectionReceiver(true);
+ }); // nodeG
+ drawOrderedNode(&canvas, 1,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // R
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2603,24 +2634,28 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivablesL
/ \
G R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { //B
- props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //C
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { //G
- props.setProjectionReceiver(true);
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeG
- drawOrderedNode(&canvas, 3, [](RenderProperties& props, RecordingCanvas& canvas) { //R
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
-
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // B
+ props.setProjectionReceiver(true);
+ }); // nodeB
+ drawOrderedNode(&canvas, 2, [](RenderProperties& props,
+ RecordingCanvas& canvas) { // C
+ drawOrderedNode(&canvas, 1,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // G
+ props.setProjectionReceiver(true);
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeG
+ drawOrderedNode(&canvas, 3,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // R
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2638,26 +2673,31 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivablesD
|
R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { //B
- props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { //C
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //G
- props.setProjectionReceiver(true);
- } ); //nodeG
- drawOrderedNode(&canvas, 4, [](RenderProperties& props, RecordingCanvas& canvas) { //D
- drawOrderedNode(&canvas, 3, [](RenderProperties& props, RecordingCanvas& canvas) { //R
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeD
- } ); //nodeC
- }); //nodeA
-
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // B
+ props.setProjectionReceiver(true);
+ }); // nodeB
+ drawOrderedNode(&canvas, 1, [](RenderProperties& props,
+ RecordingCanvas& canvas) { // C
+ drawOrderedNode(&canvas, 2,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // G
+ props.setProjectionReceiver(true);
+ }); // nodeG
+ drawOrderedNode(
+ &canvas, 4, [](RenderProperties& props, RecordingCanvas& canvas) { // D
+ drawOrderedNode(&canvas, 3, [](RenderProperties& props,
+ RecordingCanvas& canvas) { // R
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeD
+ }); // nodeC
+ }); // nodeA
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2665,5 +2705,5 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivablesD
EXPECT_EQ(5, renderer.getIndex());
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/unit/GlopBuilderTests.cpp b/libs/hwui/tests/unit/GlopBuilderTests.cpp
index caeb6bf0081b..c8bfc99fac92 100644
--- a/libs/hwui/tests/unit/GlopBuilderTests.cpp
+++ b/libs/hwui/tests/unit/GlopBuilderTests.cpp
@@ -28,8 +28,7 @@ using namespace android::uirenderer;
static void expectFillEq(Glop::Fill& expectedFill, Glop::Fill& builtFill) {
EXPECT_EQ(expectedFill.colorEnabled, builtFill.colorEnabled);
- if (expectedFill.colorEnabled)
- EXPECT_EQ(expectedFill.color, builtFill.color);
+ if (expectedFill.colorEnabled) EXPECT_EQ(expectedFill.color, builtFill.color);
EXPECT_EQ(expectedFill.filterMode, builtFill.filterMode);
if (expectedFill.filterMode == ProgramDescription::ColorFilterMode::Blend) {
@@ -38,15 +37,15 @@ static void expectFillEq(Glop::Fill& expectedFill, Glop::Fill& builtFill) {
Glop::Fill::Filter::Matrix& expectedMatrix = expectedFill.filter.matrix;
Glop::Fill::Filter::Matrix& builtMatrix = expectedFill.filter.matrix;
EXPECT_TRUE(std::memcmp(expectedMatrix.matrix, builtMatrix.matrix,
- sizeof(Glop::Fill::Filter::Matrix::matrix)));
+ sizeof(Glop::Fill::Filter::Matrix::matrix)));
EXPECT_TRUE(std::memcmp(expectedMatrix.vector, builtMatrix.vector,
- sizeof(Glop::Fill::Filter::Matrix::vector)));
+ sizeof(Glop::Fill::Filter::Matrix::vector)));
}
EXPECT_EQ(expectedFill.skiaShaderData.skiaShaderType, builtFill.skiaShaderData.skiaShaderType);
EXPECT_EQ(expectedFill.texture.clamp, builtFill.texture.clamp);
EXPECT_EQ(expectedFill.texture.filter, builtFill.texture.filter);
- EXPECT_TRUE((expectedFill.texture.texture && builtFill.texture.texture)
- || (!expectedFill.texture.texture && !builtFill.texture.texture));
+ EXPECT_TRUE((expectedFill.texture.texture && builtFill.texture.texture) ||
+ (!expectedFill.texture.texture && !builtFill.texture.texture));
if (expectedFill.texture.texture) {
EXPECT_EQ(expectedFill.texture.texture->target(), builtFill.texture.texture->target());
}
@@ -97,22 +96,23 @@ static void expectGlopEq(Glop& expectedGlop, Glop& builtGlop) {
static std::unique_ptr<Glop> blackUnitQuadGlop(RenderState& renderState) {
std::unique_ptr<Glop> glop(new Glop());
- glop->blend = { GL_ZERO, GL_ZERO };
+ glop->blend = {GL_ZERO, GL_ZERO};
glop->mesh.elementCount = 4;
glop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
glop->mesh.indices.indices = nullptr;
glop->mesh.indices.bufferObject = GL_ZERO;
- glop->mesh.vertices = {
- renderState.meshState().getUnitQuadVBO(),
- VertexAttribFlags::None,
- nullptr, nullptr, nullptr,
- kTextureVertexStride };
+ glop->mesh.vertices = {renderState.meshState().getUnitQuadVBO(),
+ VertexAttribFlags::None,
+ nullptr,
+ nullptr,
+ nullptr,
+ kTextureVertexStride};
glop->transform.modelView.loadIdentity();
glop->fill.colorEnabled = true;
glop->fill.color.set(Color::Black);
glop->fill.skiaShaderData.skiaShaderType = kNone_SkiaShaderType;
glop->fill.filterMode = ProgramDescription::ColorFilterMode::None;
- glop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
+ glop->fill.texture = {nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
return glop;
}
diff --git a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp
index 8cbd24edbde2..9bfb08292be2 100644
--- a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp
+++ b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp
@@ -14,9 +14,8 @@
* limitations under the License.
*/
-
-#include <gtest/gtest.h>
#include <GpuMemoryTracker.h>
+#include <gtest/gtest.h>
#include "renderthread/EglManager.h"
#include "renderthread/RenderThread.h"
@@ -32,9 +31,7 @@ class TestGPUObject : public GpuMemoryTracker {
public:
TestGPUObject() : GpuMemoryTracker(GpuObjectType::Texture) {}
- void changeSize(int newSize) {
- notifySizeChanged(newSize);
- }
+ void changeSize(int newSize) { notifySizeChanged(newSize); }
};
// Other tests may have created a renderthread and EGL context.
@@ -42,9 +39,7 @@ public:
// current thread can spoof being a GPU thread
static void destroyEglContext() {
if (TestUtils::isRenderThreadRunning()) {
- TestUtils::runOnRenderThread([](RenderThread& thread) {
- thread.eglManager().destroy();
- });
+ TestUtils::runOnRenderThread([](RenderThread& thread) { thread.eglManager().destroy(); });
}
}
diff --git a/libs/hwui/tests/unit/GradientCacheTests.cpp b/libs/hwui/tests/unit/GradientCacheTests.cpp
index a3b346f11a87..6710c71c386f 100644
--- a/libs/hwui/tests/unit/GradientCacheTests.cpp
+++ b/libs/hwui/tests/unit/GradientCacheTests.cpp
@@ -28,12 +28,12 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(GradientCache, addRemove) {
GradientCache cache(extensions);
ASSERT_LT(1000u, cache.getMaxSize()) << "Expect non-trivial size";
- SkColor colors[] = { 0xFF00FF00, 0xFFFF0000, 0xFF0000FF };
- float positions[] = { 1, 2, 3 };
+ SkColor colors[] = {0xFF00FF00, 0xFFFF0000, 0xFF0000FF};
+ float positions[] = {1, 2, 3};
Texture* texture = cache.get(colors, positions, 3);
ASSERT_TRUE(texture);
ASSERT_FALSE(texture->cleanup);
- ASSERT_EQ((uint32_t) texture->objectSize(), cache.getSize());
+ ASSERT_EQ((uint32_t)texture->objectSize(), cache.getSize());
ASSERT_TRUE(cache.getSize());
cache.clear();
ASSERT_EQ(cache.getSize(), 0u);
diff --git a/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp b/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
index fda3a79a69da..30c3b4ea5ab3 100644
--- a/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
+++ b/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
@@ -20,10 +20,10 @@
#include <frameworks/base/core/proto/android/service/graphicsstats.pb.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
using namespace android;
@@ -35,8 +35,8 @@ std::string findRootPath() {
// < 1023 because we need room for the null terminator
if (r <= 0 || r > 1023) {
int err = errno;
- fprintf(stderr, "Failed to read from /proc/self/exe; r=%zd, err=%d (%s)\n",
- r, err, strerror(err));
+ fprintf(stderr, "Failed to read from /proc/self/exe; r=%zd, err=%d (%s)\n", r, err,
+ strerror(err));
exit(EXIT_FAILURE);
}
while (--r > 0) {
@@ -88,8 +88,8 @@ TEST(GraphicsStats, saveLoad) {
EXPECT_EQ(20, loadedProto.summary().janky_frames());
EXPECT_EQ(100, loadedProto.summary().total_frames());
EXPECT_EQ(mockData.editFrameCounts().size() + mockData.editSlowFrameCounts().size(),
- (size_t) loadedProto.histogram_size());
- for (size_t i = 0; i < (size_t) loadedProto.histogram_size(); i++) {
+ (size_t)loadedProto.histogram_size());
+ for (size_t i = 0; i < (size_t)loadedProto.histogram_size(); i++) {
int expectedCount, expectedBucket;
if (i < mockData.editFrameCounts().size()) {
expectedCount = ((i % 10) + 1) * 2;
@@ -144,8 +144,8 @@ TEST(GraphicsStats, merge) {
EXPECT_EQ(20 + 50, loadedProto.summary().janky_frames());
EXPECT_EQ(100 + 500, loadedProto.summary().total_frames());
EXPECT_EQ(mockData.editFrameCounts().size() + mockData.editSlowFrameCounts().size(),
- (size_t) loadedProto.histogram_size());
- for (size_t i = 0; i < (size_t) loadedProto.histogram_size(); i++) {
+ (size_t)loadedProto.histogram_size());
+ for (size_t i = 0; i < (size_t)loadedProto.histogram_size(); i++) {
int expectedCount, expectedBucket;
if (i < mockData.editFrameCounts().size()) {
expectedCount = ((i % 10) + 1) * 2;
diff --git a/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp b/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp
index 91c7514e271e..217d63f9c2e1 100644
--- a/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp
+++ b/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp
@@ -51,9 +51,9 @@ TEST(LayerUpdateQueue, enqueueSimple) {
EXPECT_EQ(a.get(), queue.entries()[0].renderNode.get());
EXPECT_EQ(Rect(25, 25, 75, 75), queue.entries()[0].damage);
EXPECT_EQ(b.get(), queue.entries()[1].renderNode.get());
- EXPECT_EQ(Rect(100, 100, 200, 200), queue.entries()[1].damage); // clipped to bounds
+ EXPECT_EQ(Rect(100, 100, 200, 200), queue.entries()[1].damage); // clipped to bounds
EXPECT_EQ(c.get(), queue.entries()[2].renderNode.get());
- EXPECT_EQ(Rect(0, 0, 1, 1), queue.entries()[2].damage); // rounded out
+ EXPECT_EQ(Rect(0, 0, 1, 1), queue.entries()[2].damage); // rounded out
}
TEST(LayerUpdateQueue, enqueueUnion) {
@@ -81,6 +81,5 @@ TEST(LayerUpdateQueue, clear) {
EXPECT_TRUE(queue.entries().empty());
}
-
};
};
diff --git a/libs/hwui/tests/unit/LeakCheckTests.cpp b/libs/hwui/tests/unit/LeakCheckTests.cpp
index 19d7ef59e397..20ec0848212f 100644
--- a/libs/hwui/tests/unit/LeakCheckTests.cpp
+++ b/libs/hwui/tests/unit/LeakCheckTests.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include "BakedOpRenderer.h"
#include "BakedOpDispatcher.h"
+#include "BakedOpRenderer.h"
#include "FrameBuilder.h"
#include "LayerUpdateQueue.h"
#include "RecordingCanvas.h"
@@ -26,12 +26,11 @@
using namespace android;
using namespace android::uirenderer;
-const FrameBuilder::LightGeometry sLightGeometery = { {100, 100, 100}, 50};
-const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
+const FrameBuilder::LightGeometry sLightGeometery = {{100, 100, 100}, 50};
+const BakedOpRenderer::LightInfo sLightInfo = {128, 128};
RENDERTHREAD_OPENGL_PIPELINE_TEST(LeakCheck, saveLayer_overdrawRejection) {
- auto node = TestUtils::createNode(0, 0, 100, 100,
- [](RenderProperties& props, Canvas& canvas) {
+ auto node = TestUtils::createNode(0, 0, 100, 100, [](RenderProperties& props, Canvas& canvas) {
canvas.saveLayerAlpha(0, 0, 100, 100, 128, SaveFlags::ClipToLayer);
canvas.drawRect(0, 0, 100, 100, SkPaint());
canvas.restore();
@@ -42,16 +41,15 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(LeakCheck, saveLayer_overdrawRejection) {
RenderState& renderState = renderThread.renderState();
Caches& caches = Caches::getInstance();
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometery, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometery,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(LeakCheck, saveLayerUnclipped_simple) {
- auto node = TestUtils::createNode(0, 0, 200, 200,
- [](RenderProperties& props, Canvas& canvas) {
+ auto node = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, Canvas& canvas) {
canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
canvas.drawRect(0, 0, 200, 200, SkPaint());
canvas.restore();
@@ -59,8 +57,8 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(LeakCheck, saveLayerUnclipped_simple) {
RenderState& renderState = renderThread.renderState();
Caches& caches = Caches::getInstance();
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometery, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometery,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
diff --git a/libs/hwui/tests/unit/LinearAllocatorTests.cpp b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
index ffcbf128fc3a..1038da3c4cd0 100644
--- a/libs/hwui/tests/unit/LinearAllocatorTests.cpp
+++ b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
@@ -43,7 +43,7 @@ TEST(LinearAllocator, create) {
}
TEST(LinearAllocator, dtor) {
- int destroyed[10] = { 0 };
+ int destroyed[10] = {0};
{
LinearAllocator la;
for (int i = 0; i < 5; i++) {
@@ -111,7 +111,6 @@ TEST(LinearStdAllocator, simpleAllocate) {
EXPECT_LT(lastLocation, &v[0]);
EXPECT_GT(lastLocation + 20, &v[0]);
-
}
TEST(LsaVector, dtorCheck) {
@@ -126,7 +125,7 @@ TEST(LsaVector, dtorCheck) {
vector.emplace_back(new TestUtils::SignalingDtor(&destroyed));
}
EXPECT_EQ(0, destroyed);
- EXPECT_EQ(size, (int) vector.size());
+ EXPECT_EQ(size, (int)vector.size());
}
EXPECT_EQ(size, destroyed);
}
diff --git a/libs/hwui/tests/unit/MatrixTests.cpp b/libs/hwui/tests/unit/MatrixTests.cpp
index eddab878a49d..16a396e00790 100644
--- a/libs/hwui/tests/unit/MatrixTests.cpp
+++ b/libs/hwui/tests/unit/MatrixTests.cpp
@@ -32,8 +32,7 @@ TEST(Matrix, mapRect_emptyScaleSkew) {
ASSERT_TRUE(empty.isEmpty());
scaleMatrix.mapRect(empty);
EXPECT_EQ(Rect(170, 215, 250, 1015), empty);
- EXPECT_FALSE(empty.isEmpty())
- << "Empty 'line' rect doesn't remain empty when skewed.";
+ EXPECT_FALSE(empty.isEmpty()) << "Empty 'line' rect doesn't remain empty when skewed.";
}
TEST(Matrix, mapRect_emptyRotate) {
@@ -45,6 +44,5 @@ TEST(Matrix, mapRect_emptyRotate) {
Rect lineRect(0, 100);
ASSERT_TRUE(lineRect.isEmpty());
skewMatrix.mapRect(lineRect);
- EXPECT_FALSE(lineRect.isEmpty())
- << "Empty 'line' rect doesn't remain empty when rotated.";
+ EXPECT_FALSE(lineRect.isEmpty()) << "Empty 'line' rect doesn't remain empty when rotated.";
}
diff --git a/libs/hwui/tests/unit/MeshStateTests.cpp b/libs/hwui/tests/unit/MeshStateTests.cpp
index 511d6d25fbaf..1573fd30d5cb 100644
--- a/libs/hwui/tests/unit/MeshStateTests.cpp
+++ b/libs/hwui/tests/unit/MeshStateTests.cpp
@@ -16,8 +16,8 @@
#include <debug/MockGlesDriver.h>
#include <debug/ScopedReplaceDriver.h>
-#include <gtest/gtest.h>
#include <gmock/gmock.h>
+#include <gtest/gtest.h>
#include <renderstate/MeshState.h>
#include <tests/common/TestUtils.h>
@@ -32,5 +32,6 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(MeshState, genOrUpdate) {
EXPECT_CALL(mockGlDriver, glBufferData_(_, _, _, _));
GLuint buffer = 0;
- renderThread.renderState().meshState().genOrUpdateMeshBuffer(&buffer, 10, nullptr, GL_DYNAMIC_DRAW);
+ renderThread.renderState().meshState().genOrUpdateMeshBuffer(&buffer, 10, nullptr,
+ GL_DYNAMIC_DRAW);
}
diff --git a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
index 308fef303740..0d4736757629 100644
--- a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
+++ b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
#include <Rect.h>
+#include <gtest/gtest.h>
#include <renderstate/OffscreenBufferPool.h>
#include <tests/common/TestUtils.h>
@@ -56,12 +56,10 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, constructWideColorGamut) {
RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, getTextureCoordinates) {
OffscreenBuffer layerAligned(renderThread.renderState(), Caches::getInstance(), 256u, 256u);
- EXPECT_EQ(Rect(0, 1, 1, 0),
- layerAligned.getTextureCoordinates());
+ EXPECT_EQ(Rect(0, 1, 1, 0), layerAligned.getTextureCoordinates());
OffscreenBuffer layerUnaligned(renderThread.renderState(), Caches::getInstance(), 200u, 225u);
- EXPECT_EQ(Rect(0, 225.0f / 256.0f, 200.0f / 256.0f, 0),
- layerUnaligned.getTextureCoordinates());
+ EXPECT_EQ(Rect(0, 225.0f / 256.0f, 200.0f / 256.0f, 0), layerUnaligned.getTextureCoordinates());
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, dirty) {
@@ -221,7 +219,7 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, putAndDestroy) {
auto hugeLayer = pool.get(renderThread.renderState(), pool.getMaxSize() / 64, 64);
EXPECT_GT(hugeLayer->getSizeInBytes(), pool.getMaxSize());
pool.putOrDelete(hugeLayer);
- EXPECT_EQ(0u, pool.getCount()); // failed to put (so was destroyed instead)
+ EXPECT_EQ(0u, pool.getCount()); // failed to put (so was destroyed instead)
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, clear) {
@@ -244,4 +242,3 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, clear) {
EXPECT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer));
}
-
diff --git a/libs/hwui/tests/unit/OpDumperTests.cpp b/libs/hwui/tests/unit/OpDumperTests.cpp
index 01840d72b766..ef30e872a7bd 100644
--- a/libs/hwui/tests/unit/OpDumperTests.cpp
+++ b/libs/hwui/tests/unit/OpDumperTests.cpp
@@ -16,8 +16,8 @@
#include <gtest/gtest.h>
-#include "tests/common/TestUtils.h"
#include "OpDumper.h"
+#include "tests/common/TestUtils.h"
using namespace android;
using namespace android::uirenderer;
diff --git a/libs/hwui/tests/unit/PathInterpolatorTests.cpp b/libs/hwui/tests/unit/PathInterpolatorTests.cpp
index d7cb23a4b793..d888012a80ce 100644
--- a/libs/hwui/tests/unit/PathInterpolatorTests.cpp
+++ b/libs/hwui/tests/unit/PathInterpolatorTests.cpp
@@ -37,55 +37,36 @@ const static TestData sTestDataSet[] = {
{0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f},
},
- {
- {
- 0.0f, 0.5f, 0.5178955f, 0.5341797f, 0.5489991f, 0.5625f, 0.5748291f,
- 0.5861328f, 0.60625005f, 0.62402344f, 0.640625f, 0.675f, 0.6951172f,
- 0.71875f, 0.7470703f, 0.78125f, 0.82246095f, 0.84606934f, 0.871875f,
- 0.9000244f, 0.93066406f, 0.96394044f, 1.0f
- },
- {
- 0.0f, 0.0f, 0.0028686523f, 0.011230469f, 0.024719238f, 0.04296875f,
- 0.06561279f, 0.092285156f, 0.15625f, 0.2319336f, 0.31640625f, 0.5f,
- 0.5932617f, 0.68359375f, 0.7680664f, 0.84375f, 0.90771484f, 0.9343872f,
- 0.95703125f, 0.97528076f, 0.98876953f, 0.99713135f, 1.0f
- },
- {
- 0.0f, 0.03375840187072754f, 0.13503384590148926f, 0.23630905151367188f,
- 0.336834192276001f, 0.4508626461029053f, 0.564141035079956f,
- 0.6781694889068604f, 0.7921979427337646f, 0.9054763317108154f, 1.0f
- },
- {
- 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0459827296435833f,
- 0.5146934390068054f, 0.8607426285743713f, 0.9776809215545654f, 1.0f
+ {{0.0f, 0.5f, 0.5178955f, 0.5341797f, 0.5489991f, 0.5625f,
+ 0.5748291f, 0.5861328f, 0.60625005f, 0.62402344f, 0.640625f, 0.675f,
+ 0.6951172f, 0.71875f, 0.7470703f, 0.78125f, 0.82246095f, 0.84606934f,
+ 0.871875f, 0.9000244f, 0.93066406f, 0.96394044f, 1.0f},
+ {0.0f, 0.0f, 0.0028686523f, 0.011230469f, 0.024719238f, 0.04296875f,
+ 0.06561279f, 0.092285156f, 0.15625f, 0.2319336f, 0.31640625f, 0.5f,
+ 0.5932617f, 0.68359375f, 0.7680664f, 0.84375f, 0.90771484f, 0.9343872f,
+ 0.95703125f, 0.97528076f, 0.98876953f, 0.99713135f, 1.0f},
+ {0.0f, 0.03375840187072754f, 0.13503384590148926f, 0.23630905151367188f,
+ 0.336834192276001f, 0.4508626461029053f, 0.564141035079956f, 0.6781694889068604f,
+ 0.7921979427337646f, 0.9054763317108154f, 1.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0459827296435833f, 0.5146934390068054f,
+ 0.8607426285743713f, 0.9776809215545654f, 1.0f
- }
+ }
},
- {
- {
- 0.0f, 0.017895509f, 0.034179688f, 0.048999026f, 0.0625f, 0.0748291f,
- 0.08613282f, 0.10625f, 0.12402344f, 0.140625f, 0.17500001f, 0.19511719f,
- 0.21875f, 0.24707031f, 0.28125f, 0.32246095f, 0.34606934f, 0.371875f,
- 0.4000244f, 0.43066406f, 0.46394044f, 0.5f, 1.0f
- },
- {
- 0.0f, 0.0028686523f, 0.011230469f, 0.024719238f, 0.04296875f, 0.06561279f,
- 0.092285156f, 0.15625f, 0.2319336f, 0.31640625f, 0.5f, 0.5932617f,
- 0.68359375f, 0.7680664f, 0.84375f, 0.90771484f, 0.9343872f, 0.95703125f,
- 0.97528076f, 0.98876953f, 0.99713135f, 1.0f, 1.0f
- },
- {
- 0.0f, 0.102020263671875f, 0.20330810546875f, 0.3165740966796875f,
- 0.43060302734375f, 0.5318756103515625f, 0.6331634521484375f,
- 0.746429443359375f, 0.84771728515625f, 0.9617462158203125f, 1.0f
- },
- {
- 0.0f, 0.14280107617378235f, 0.6245699524879456f, 0.8985776901245117f,
- 0.9887426495552063f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
- }
- },
-
+ {{0.0f, 0.017895509f, 0.034179688f, 0.048999026f, 0.0625f, 0.0748291f,
+ 0.08613282f, 0.10625f, 0.12402344f, 0.140625f, 0.17500001f, 0.19511719f,
+ 0.21875f, 0.24707031f, 0.28125f, 0.32246095f, 0.34606934f, 0.371875f,
+ 0.4000244f, 0.43066406f, 0.46394044f, 0.5f, 1.0f},
+ {0.0f, 0.0028686523f, 0.011230469f, 0.024719238f, 0.04296875f, 0.06561279f,
+ 0.092285156f, 0.15625f, 0.2319336f, 0.31640625f, 0.5f, 0.5932617f,
+ 0.68359375f, 0.7680664f, 0.84375f, 0.90771484f, 0.9343872f, 0.95703125f,
+ 0.97528076f, 0.98876953f, 0.99713135f, 1.0f, 1.0f},
+ {0.0f, 0.102020263671875f, 0.20330810546875f, 0.3165740966796875f, 0.43060302734375f,
+ 0.5318756103515625f, 0.6331634521484375f, 0.746429443359375f, 0.84771728515625f,
+ 0.9617462158203125f, 1.0f},
+ {0.0f, 0.14280107617378235f, 0.6245699524879456f, 0.8985776901245117f, 0.9887426495552063f,
+ 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}},
};
@@ -98,13 +79,12 @@ static std::vector<float> getY(const TestData& data) {
}
TEST(Interpolator, pathInterpolation) {
- for (const TestData& data: sTestDataSet) {
+ for (const TestData& data : sTestDataSet) {
PathInterpolator interpolator(getX(data), getY(data));
for (size_t i = 0; i < data.inFraction.size(); i++) {
EXPECT_FLOAT_EQ(data.outFraction[i], interpolator.interpolate(data.inFraction[i]));
}
}
}
-
}
}
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index dab1f894b681..5aae15f478b8 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -32,7 +32,7 @@ namespace android {
namespace uirenderer {
static void playbackOps(const DisplayList& displayList,
- std::function<void(const RecordedOp&)> opReceiver) {
+ std::function<void(const RecordedOp&)> opReceiver) {
for (auto& chunk : displayList.getChunks()) {
for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
RecordedOp* op = displayList.getOps()[opIndex];
@@ -42,7 +42,7 @@ static void playbackOps(const DisplayList& displayList,
}
static void validateSingleOp(std::unique_ptr<DisplayList>& dl,
- std::function<void(const RecordedOp& op)> opValidator) {
+ std::function<void(const RecordedOp& op)> opValidator) {
ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
opValidator(*(dl->getOps()[0]));
}
@@ -82,7 +82,7 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, emptyClipRect) {
canvas.save(SaveFlags::MatrixClip);
canvas.clipRect(0, 0, 100, 100, SkClipOp::kIntersect);
canvas.clipRect(100, 100, 200, 200, SkClipOp::kIntersect);
- canvas.drawRect(0, 0, 50, 50, SkPaint()); // rejected at record time
+ canvas.drawRect(0, 0, 50, 50, SkPaint()); // rejected at record time
canvas.restore();
});
ASSERT_EQ(0u, dl->getOps().size()) << "Must be zero ops. Rect should be rejected.";
@@ -120,16 +120,16 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, drawArc) {
EXPECT_EQ(RecordedOpId::ArcOp, ops[0]->opId);
EXPECT_EQ(Rect(200, 200), ops[0]->unmappedBounds);
- EXPECT_EQ(RecordedOpId::OvalOp, ops[1]->opId)
- << "Circular arcs should be converted to ovals";
+ EXPECT_EQ(RecordedOpId::OvalOp, ops[1]->opId) << "Circular arcs should be converted to ovals";
EXPECT_EQ(Rect(100, 100), ops[1]->unmappedBounds);
}
OPENGL_PIPELINE_TEST(RecordingCanvas, drawLines) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
SkPaint paint;
- paint.setStrokeWidth(20); // doesn't affect recorded bounds - would be resolved at bake time
- float points[] = { 0, 0, 20, 10, 30, 40, 90 }; // NB: only 1 valid line
+ paint.setStrokeWidth(
+ 20); // doesn't affect recorded bounds - would be resolved at bake time
+ float points[] = {0, 0, 20, 10, 30, 40, 90}; // NB: only 1 valid line
canvas.drawLines(&points[0], 7, paint);
});
@@ -143,9 +143,8 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, drawLines) {
}
OPENGL_PIPELINE_TEST(RecordingCanvas, drawRect) {
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
- canvas.drawRect(10, 20, 90, 180, SkPaint());
- });
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 100, 200, [](RecordingCanvas& canvas) { canvas.drawRect(10, 20, 90, 180, SkPaint()); });
ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
auto op = *(dl->getOps()[0]);
@@ -168,7 +167,7 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, drawRoundRect) {
});
ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
ASSERT_EQ(RecordedOpId::RectOp, dl->getOps()[0]->opId)
- << "Non-rounded rects should be converted";
+ << "Non-rounded rects should be converted";
}
OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs) {
@@ -221,17 +220,17 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs_strikeThruAndUnderline) {
ASSERT_EQ(8u, ops.size());
int index = 0;
- EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId); // no underline or strikethrough
+ EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId); // no underline or strikethrough
EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId);
- EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough only
+ EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough only
EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId);
- EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // underline only
+ EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // underline only
EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId);
- EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // underline
- EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough
+ EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // underline
+ EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough
}
OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs_forceAlignLeft) {
@@ -329,15 +328,14 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, backgroundAndImage) {
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(RecordingCanvas, textureLayer) {
- auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
- SkMatrix::MakeTrans(5, 5));
+ auto layerUpdater =
+ TestUtils::createTextureLayerUpdater(renderThread, 100, 100, SkMatrix::MakeTrans(5, 5));
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200,
- [&layerUpdater](RecordingCanvas& canvas) {
- canvas.drawLayer(layerUpdater.get());
- });
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 200, 200,
+ [&layerUpdater](RecordingCanvas& canvas) { canvas.drawLayer(layerUpdater.get()); });
- validateSingleOp(dl, [] (const RecordedOp& op) {
+ validateSingleOp(dl, [](const RecordedOp& op) {
ASSERT_EQ(RecordedOpId::TextureLayerOp, op.opId);
ASSERT_TRUE(op.localMatrix.isIdentity()) << "Op must not apply matrix at record time.";
});
@@ -352,26 +350,26 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_simple) {
int count = 0;
playbackOps(*dl, [&count](const RecordedOp& op) {
Matrix4 expectedMatrix;
- switch(count++) {
- case 0:
- EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId);
- EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
- EXPECT_EQ(nullptr, op.localClip);
- EXPECT_TRUE(op.localMatrix.isIdentity());
- break;
- case 1:
- EXPECT_EQ(RecordedOpId::RectOp, op.opId);
- EXPECT_CLIP_RECT(Rect(180, 160), op.localClip);
- EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
- expectedMatrix.loadTranslate(-10, -20, 0);
- EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
- break;
- case 2:
- EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId);
- // Don't bother asserting recording state data - it's not used
- break;
- default:
- ADD_FAILURE();
+ switch (count++) {
+ case 0:
+ EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId);
+ EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
+ EXPECT_EQ(nullptr, op.localClip);
+ EXPECT_TRUE(op.localMatrix.isIdentity());
+ break;
+ case 1:
+ EXPECT_EQ(RecordedOpId::RectOp, op.opId);
+ EXPECT_CLIP_RECT(Rect(180, 160), op.localClip);
+ EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
+ expectedMatrix.loadTranslate(-10, -20, 0);
+ EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
+ break;
+ case 2:
+ EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId);
+ // Don't bother asserting recording state data - it's not used
+ break;
+ default:
+ ADD_FAILURE();
}
});
EXPECT_EQ(3, count);
@@ -379,14 +377,14 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_simple) {
OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rounding) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) {
- canvas.saveLayerAlpha(10.25f, 10.75f, 89.25f, 89.75f, 128, SaveFlags::ClipToLayer);
- canvas.drawRect(20, 20, 80, 80, SkPaint());
- canvas.restore();
- });
- int count = 0;
- playbackOps(*dl, [&count](const RecordedOp& op) {
- Matrix4 expectedMatrix;
- switch(count++) {
+ canvas.saveLayerAlpha(10.25f, 10.75f, 89.25f, 89.75f, 128, SaveFlags::ClipToLayer);
+ canvas.drawRect(20, 20, 80, 80, SkPaint());
+ canvas.restore();
+ });
+ int count = 0;
+ playbackOps(*dl, [&count](const RecordedOp& op) {
+ Matrix4 expectedMatrix;
+ switch (count++) {
case 0:
EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId);
EXPECT_EQ(Rect(10, 10, 90, 90), op.unmappedBounds) << "Expect bounds rounded out";
@@ -402,9 +400,9 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rounding) {
break;
default:
ADD_FAILURE();
- }
- });
- EXPECT_EQ(3, count);
+ }
+ });
+ EXPECT_EQ(3, count);
}
OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_missingRestore) {
@@ -424,31 +422,31 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_missingRestore) {
OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_simpleUnclipped) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
- canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
+ canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
canvas.drawRect(10, 20, 190, 180, SkPaint());
canvas.restore();
});
int count = 0;
playbackOps(*dl, [&count](const RecordedOp& op) {
- switch(count++) {
- case 0:
- EXPECT_EQ(RecordedOpId::BeginUnclippedLayerOp, op.opId);
- EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
- EXPECT_EQ(nullptr, op.localClip);
- EXPECT_TRUE(op.localMatrix.isIdentity());
- break;
- case 1:
- EXPECT_EQ(RecordedOpId::RectOp, op.opId);
- EXPECT_EQ(nullptr, op.localClip);
- EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
- EXPECT_TRUE(op.localMatrix.isIdentity());
- break;
- case 2:
- EXPECT_EQ(RecordedOpId::EndUnclippedLayerOp, op.opId);
- // Don't bother asserting recording state data - it's not used
- break;
- default:
- ADD_FAILURE();
+ switch (count++) {
+ case 0:
+ EXPECT_EQ(RecordedOpId::BeginUnclippedLayerOp, op.opId);
+ EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
+ EXPECT_EQ(nullptr, op.localClip);
+ EXPECT_TRUE(op.localMatrix.isIdentity());
+ break;
+ case 1:
+ EXPECT_EQ(RecordedOpId::RectOp, op.opId);
+ EXPECT_EQ(nullptr, op.localClip);
+ EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
+ EXPECT_TRUE(op.localMatrix.isIdentity());
+ break;
+ case 2:
+ EXPECT_EQ(RecordedOpId::EndUnclippedLayerOp, op.opId);
+ // Don't bother asserting recording state data - it's not used
+ break;
+ default:
+ ADD_FAILURE();
}
});
EXPECT_EQ(3, count);
@@ -458,7 +456,7 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_addClipFlag) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
canvas.save(SaveFlags::MatrixClip);
canvas.clipRect(10, 20, 190, 180, SkClipOp::kIntersect);
- canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
+ canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
canvas.drawRect(10, 20, 190, 180, SkPaint());
canvas.restore();
canvas.restore();
@@ -487,7 +485,7 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_viewportCrop) {
if (count++ == 1) {
Matrix4 expectedMatrix;
EXPECT_EQ(RecordedOpId::RectOp, op.opId);
- EXPECT_CLIP_RECT(Rect(100, 100), op.localClip) // Recorded clip rect should be
+ EXPECT_CLIP_RECT(Rect(100, 100), op.localClip) // Recorded clip rect should be
// intersection of viewport and saveLayer bounds, in layer space;
EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
expectedMatrix.loadTranslate(-100, -100, 0);
@@ -564,7 +562,7 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rotateClipped) {
OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rejectBegin) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
canvas.save(SaveFlags::MatrixClip);
- canvas.translate(0, -20); // avoid identity case
+ canvas.translate(0, -20); // avoid identity case
// empty clip rect should force layer + contents to be rejected
canvas.clipRect(0, -20, 200, -20, SkClipOp::kIntersect);
canvas.saveLayerAlpha(0, 0, 200, 200, 128, SaveFlags::ClipToLayer);
@@ -577,37 +575,38 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rejectBegin) {
}
OPENGL_PIPELINE_TEST(RecordingCanvas, drawRenderNode_rejection) {
- auto child = TestUtils::createNode(50, 50, 150, 150,
- [](RenderProperties& props, Canvas& canvas) {
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
-
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [&child](RecordingCanvas& canvas) {
- canvas.clipRect(0, 0, 0, 0, SkClipOp::kIntersect); // empty clip, reject node
- canvas.drawRenderNode(child.get()); // shouldn't crash when rejecting node...
- });
+ auto child =
+ TestUtils::createNode(50, 50, 150, 150, [](RenderProperties& props, Canvas& canvas) {
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
+
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 200, 200, [&child](RecordingCanvas& canvas) {
+ canvas.clipRect(0, 0, 0, 0, SkClipOp::kIntersect); // empty clip, reject node
+ canvas.drawRenderNode(child.get()); // shouldn't crash when rejecting node...
+ });
ASSERT_TRUE(dl->isEmpty());
}
OPENGL_PIPELINE_TEST(RecordingCanvas, drawRenderNode_projection) {
- sp<RenderNode> background = TestUtils::createNode(50, 50, 150, 150,
- [](RenderProperties& props, Canvas& canvas) {
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
+ sp<RenderNode> background =
+ TestUtils::createNode(50, 50, 150, 150, [](RenderProperties& props, Canvas& canvas) {
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
{
background->mutateStagingProperties().setProjectionReceiver(false);
// NO RECEIVER PRESENT
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200,
- [&background](RecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 100, 100, SkPaint());
- canvas.drawRenderNode(background.get());
- canvas.drawRect(0, 0, 100, 100, SkPaint());
- });
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 200, 200, [&background](RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 100, 100, SkPaint());
+ canvas.drawRenderNode(background.get());
+ canvas.drawRect(0, 0, 100, 100, SkPaint());
+ });
EXPECT_EQ(-1, dl->projectionReceiveIndex)
<< "no projection receiver should have been observed";
}
@@ -615,18 +614,17 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, drawRenderNode_projection) {
background->mutateStagingProperties().setProjectionReceiver(true);
// RECEIVER PRESENT
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200,
- [&background](RecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 100, 100, SkPaint());
- canvas.drawRenderNode(background.get());
- canvas.drawRect(0, 0, 100, 100, SkPaint());
- });
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 200, 200, [&background](RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 100, 100, SkPaint());
+ canvas.drawRenderNode(background.get());
+ canvas.drawRect(0, 0, 100, 100, SkPaint());
+ });
ASSERT_EQ(3u, dl->getOps().size()) << "Must be three ops";
auto op = dl->getOps()[1];
EXPECT_EQ(RecordedOpId::RenderNodeOp, op->opId);
- EXPECT_EQ(1, dl->projectionReceiveIndex)
- << "correct projection receiver not identified";
+ EXPECT_EQ(1, dl->projectionReceiveIndex) << "correct projection receiver not identified";
// verify the behavior works even though projection receiver hasn't been sync'd yet
EXPECT_TRUE(background->stagingProperties().isProjectionReceiver());
@@ -718,17 +716,18 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, insertReorderBarrier_clip) {
OPENGL_PIPELINE_TEST(RecordingCanvas, refPaint) {
SkPaint paint;
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [&paint](RecordingCanvas& canvas) {
- paint.setColor(SK_ColorBLUE);
- // first two should use same paint
- canvas.drawRect(0, 0, 200, 10, paint);
- SkPaint paintCopy(paint);
- canvas.drawRect(0, 10, 200, 20, paintCopy);
-
- // only here do we use different paint ptr
- paint.setColor(SK_ColorRED);
- canvas.drawRect(0, 20, 200, 30, paint);
- });
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 200, 200, [&paint](RecordingCanvas& canvas) {
+ paint.setColor(SK_ColorBLUE);
+ // first two should use same paint
+ canvas.drawRect(0, 0, 200, 10, paint);
+ SkPaint paintCopy(paint);
+ canvas.drawRect(0, 10, 200, 20, paintCopy);
+
+ // only here do we use different paint ptr
+ paint.setColor(SK_ColorRED);
+ canvas.drawRect(0, 20, 200, 30, paint);
+ });
auto ops = dl->getOps();
ASSERT_EQ(3u, ops.size());
@@ -745,56 +744,58 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, refPaint) {
OPENGL_PIPELINE_TEST(RecordingCanvas, refBitmap) {
sk_sp<Bitmap> bitmap(TestUtils::createBitmap(100, 100));
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
- canvas.drawBitmap(*bitmap, 0, 0, nullptr);
- });
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 100, 100,
+ [&bitmap](RecordingCanvas& canvas) { canvas.drawBitmap(*bitmap, 0, 0, nullptr); });
auto& bitmaps = dl->getBitmapResources();
EXPECT_EQ(1u, bitmaps.size());
}
OPENGL_PIPELINE_TEST(RecordingCanvas, refBitmapInShader_bitmapShader) {
sk_sp<Bitmap> bitmap = TestUtils::createBitmap(100, 100);
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
- SkPaint paint;
- SkBitmap skBitmap;
- bitmap->getSkBitmap(&skBitmap);
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode);
- sk_sp<SkShader> shader = image->makeShader(
- SkShader::TileMode::kClamp_TileMode,
- SkShader::TileMode::kClamp_TileMode,
- nullptr);
- paint.setShader(std::move(shader));
- canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint);
- });
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 100, 100, [&bitmap](RecordingCanvas& canvas) {
+ SkPaint paint;
+ SkBitmap skBitmap;
+ bitmap->getSkBitmap(&skBitmap);
+ sk_sp<SkImage> image =
+ SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode);
+ sk_sp<SkShader> shader =
+ image->makeShader(SkShader::TileMode::kClamp_TileMode,
+ SkShader::TileMode::kClamp_TileMode, nullptr);
+ paint.setShader(std::move(shader));
+ canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint);
+ });
auto& bitmaps = dl->getBitmapResources();
EXPECT_EQ(1u, bitmaps.size());
}
OPENGL_PIPELINE_TEST(RecordingCanvas, refBitmapInShader_composeShader) {
sk_sp<Bitmap> bitmap = TestUtils::createBitmap(100, 100);
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
- SkPaint paint;
- SkBitmap skBitmap;
- bitmap->getSkBitmap(&skBitmap);
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode);
- sk_sp<SkShader> shader1 = image->makeShader(
- SkShader::TileMode::kClamp_TileMode,
- SkShader::TileMode::kClamp_TileMode,
- nullptr);
-
- SkPoint center;
- center.set(50, 50);
- SkColor colors[2];
- colors[0] = Color::Black;
- colors[1] = Color::White;
- sk_sp<SkShader> shader2 = SkGradientShader::MakeRadial(center, 50, colors, nullptr, 2,
- SkShader::TileMode::kRepeat_TileMode);
-
- sk_sp<SkShader> composeShader = SkShader::MakeComposeShader(std::move(shader1), std::move(shader2),
- SkBlendMode::kMultiply);
- paint.setShader(std::move(composeShader));
- canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint);
- });
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 100, 100, [&bitmap](RecordingCanvas& canvas) {
+ SkPaint paint;
+ SkBitmap skBitmap;
+ bitmap->getSkBitmap(&skBitmap);
+ sk_sp<SkImage> image =
+ SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode);
+ sk_sp<SkShader> shader1 =
+ image->makeShader(SkShader::TileMode::kClamp_TileMode,
+ SkShader::TileMode::kClamp_TileMode, nullptr);
+
+ SkPoint center;
+ center.set(50, 50);
+ SkColor colors[2];
+ colors[0] = Color::Black;
+ colors[1] = Color::White;
+ sk_sp<SkShader> shader2 = SkGradientShader::MakeRadial(
+ center, 50, colors, nullptr, 2, SkShader::TileMode::kRepeat_TileMode);
+
+ sk_sp<SkShader> composeShader = SkShader::MakeComposeShader(
+ std::move(shader1), std::move(shader2), SkBlendMode::kMultiply);
+ paint.setShader(std::move(composeShader));
+ canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint);
+ });
auto& bitmaps = dl->getBitmapResources();
EXPECT_EQ(1u, bitmaps.size());
}
@@ -849,5 +850,5 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, drawTextInHighContrast) {
ASSERT_EQ(2, count);
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index d182d78da00a..dff259f81ec9 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -14,25 +14,24 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
#include <VectorDrawable.h>
+#include <gtest/gtest.h>
+#include <SkClipStack.h>
+#include <SkLiteRecorder.h>
+#include <SkSurface_Base.h>
+#include <string.h>
#include "AnimationContext.h"
#include "DamageAccumulator.h"
+#include "FatalTestCanvas.h"
#include "IContextFactory.h"
+#include "SkiaCanvas.h"
#include "pipeline/skia/SkiaDisplayList.h"
-#include "pipeline/skia/SkiaPipeline.h"
#include "pipeline/skia/SkiaOpenGLPipeline.h"
+#include "pipeline/skia/SkiaPipeline.h"
#include "pipeline/skia/SkiaRecordingCanvas.h"
#include "renderthread/CanvasContext.h"
#include "tests/common/TestUtils.h"
-#include "SkiaCanvas.h"
-#include <SkSurface_Base.h>
-#include <SkLiteRecorder.h>
-#include <SkClipStack.h>
-#include "FatalTestCanvas.h"
-#include <string.h>
-
using namespace android;
using namespace android::uirenderer;
@@ -40,8 +39,8 @@ using namespace android::uirenderer::renderthread;
using namespace android::uirenderer::skiapipeline;
TEST(RenderNodeDrawable, create) {
- auto rootNode = TestUtils::createNode(0, 0, 200, 400,
- [](RenderProperties& props, Canvas& canvas) {
+ auto rootNode =
+ TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
});
@@ -66,47 +65,50 @@ static void drawOrderedRect(Canvas* canvas, uint8_t expectedDrawOrder) {
}
static void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder, float z) {
- auto node = TestUtils::createSkiaNode(0, 0, 100, 100,
+ auto node = TestUtils::createSkiaNode(
+ 0, 0, 100, 100,
[expectedDrawOrder, z](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedRect(&canvas, expectedDrawOrder);
- props.setTranslationZ(z);
- });
- canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
+ drawOrderedRect(&canvas, expectedDrawOrder);
+ props.setTranslationZ(z);
+ });
+ canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
}
-static void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder,
+static void drawOrderedNode(
+ Canvas* canvas, uint8_t expectedDrawOrder,
std::function<void(RenderProperties& props, SkiaRecordingCanvas& canvas)> setup) {
- auto node = TestUtils::createSkiaNode(0, 0, 100, 100,
+ auto node = TestUtils::createSkiaNode(
+ 0, 0, 100, 100,
[expectedDrawOrder, setup](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedRect(&canvas, expectedDrawOrder);
- if (setup) {
- setup(props, canvas);
- }
- });
- canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
+ drawOrderedRect(&canvas, expectedDrawOrder);
+ if (setup) {
+ setup(props, canvas);
+ }
+ });
+ canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
}
class ZReorderCanvas : public SkCanvas {
public:
ZReorderCanvas(int width, int height) : SkCanvas(width, height) {}
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
- int expectedOrder = SkColorGetB(paint.getColor()); // extract order from blue channel
+ int expectedOrder = SkColorGetB(paint.getColor()); // extract order from blue channel
EXPECT_EQ(expectedOrder, mDrawCounter++) << "An op was drawn out of order";
}
int getIndex() { return mDrawCounter; }
+
protected:
int mDrawCounter = 0;
};
-} // end anonymous namespace
+} // end anonymous namespace
TEST(RenderNodeDrawable, zReorder) {
-
- auto parent = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ auto parent = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
canvas.insertReorderBarrier(true);
canvas.insertReorderBarrier(false);
- drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
+ drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
drawOrderedRect(&canvas, 1);
canvas.insertReorderBarrier(true);
drawOrderedNode(&canvas, 6, 2.0f);
@@ -117,37 +119,36 @@ TEST(RenderNodeDrawable, zReorder) {
drawOrderedNode(&canvas, 7, 2.0f);
canvas.insertReorderBarrier(false);
drawOrderedRect(&canvas, 8);
- drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
- canvas.insertReorderBarrier(true); //reorder a node ahead of drawrect op
+ drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
+ canvas.insertReorderBarrier(true); // reorder a node ahead of drawrect op
drawOrderedRect(&canvas, 11);
drawOrderedNode(&canvas, 10, -1.0f);
canvas.insertReorderBarrier(false);
- canvas.insertReorderBarrier(true); //test with two empty reorder sections
+ canvas.insertReorderBarrier(true); // test with two empty reorder sections
canvas.insertReorderBarrier(true);
canvas.insertReorderBarrier(false);
drawOrderedRect(&canvas, 12);
});
- //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
+ // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
ZReorderCanvas canvas(100, 100);
RenderNodeDrawable drawable(parent.get(), &canvas, false);
canvas.drawDrawable(&drawable);
EXPECT_EQ(13, canvas.getIndex());
}
-TEST(RenderNodeDrawable, composeOnLayer)
-{
+TEST(RenderNodeDrawable, composeOnLayer) {
auto surface = SkSurface::MakeRasterN32Premul(1, 1);
SkCanvas& canvas = *surface->getCanvas();
canvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
- auto rootNode = TestUtils::createSkiaNode(0, 0, 1, 1,
- [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
- recorder.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
- });
+ auto rootNode = TestUtils::createSkiaNode(
+ 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
+ recorder.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+ });
- //attach a layer to the render node
+ // attach a layer to the render node
auto surfaceLayer = SkSurface::MakeRasterN32Premul(1, 1);
auto canvas2 = surfaceLayer->getCanvas();
canvas2->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
@@ -182,39 +183,38 @@ static SkMatrix getRecorderMatrix(const SkiaRecordingCanvas& recorder) {
}
}
-TEST(RenderNodeDrawable, saveLayerClipAndMatrixRestore)
-{
+TEST(RenderNodeDrawable, saveLayerClipAndMatrixRestore) {
auto surface = SkSurface::MakeRasterN32Premul(400, 800);
SkCanvas& canvas = *surface->getCanvas();
canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
- auto rootNode = TestUtils::createSkiaNode(0, 0, 400, 800,
- [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
- SkPaint layerPaint;
- ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
- EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
+ auto rootNode = TestUtils::createSkiaNode(
+ 0, 0, 400, 800, [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
+ SkPaint layerPaint;
+ ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
+ EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
- //note we don't pass SaveFlags::MatrixClip, but matrix and clip will be saved
- recorder.saveLayer(0, 0, 400, 400, &layerPaint, SaveFlags::ClipToLayer);
- ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 400), getRecorderClipBounds(recorder));
- EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
+ // note we don't pass SaveFlags::MatrixClip, but matrix and clip will be saved
+ recorder.saveLayer(0, 0, 400, 400, &layerPaint, SaveFlags::ClipToLayer);
+ ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 400), getRecorderClipBounds(recorder));
+ EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
- recorder.clipRect(50, 50, 350, 350, SkClipOp::kIntersect);
- ASSERT_EQ(SkRect::MakeLTRB(50, 50, 350, 350), getRecorderClipBounds(recorder));
+ recorder.clipRect(50, 50, 350, 350, SkClipOp::kIntersect);
+ ASSERT_EQ(SkRect::MakeLTRB(50, 50, 350, 350), getRecorderClipBounds(recorder));
- recorder.translate(300.0f, 400.0f);
- EXPECT_EQ(SkMatrix::MakeTrans(300.0f, 400.0f), getRecorderMatrix(recorder));
+ recorder.translate(300.0f, 400.0f);
+ EXPECT_EQ(SkMatrix::MakeTrans(300.0f, 400.0f), getRecorderMatrix(recorder));
- recorder.restore();
- ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
- EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
+ recorder.restore();
+ ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
+ EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setColor(SK_ColorGREEN);
- recorder.drawRect(0.0f, 400.0f, 400.0f, 800.0f, paint);
- });
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(SK_ColorGREEN);
+ recorder.drawRect(0.0f, 400.0f, 400.0f, 800.0f, paint);
+ });
RenderNodeDrawable drawable(rootNode.get(), &canvas, true);
canvas.drawDrawable(&drawable);
@@ -228,7 +228,7 @@ public:
return new AnimationContext(clock);
}
};
-} // end anonymous namespace
+} // end anonymous namespace
RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorder) {
static const int SCROLL_X = 5;
@@ -238,33 +238,36 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorder) {
ProjectionTestCanvas(int width, int height) : SkCanvas(width, height) {}
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
const int index = mDrawCounter++;
- SkMatrix expectedMatrix;;
+ SkMatrix expectedMatrix;
+ ;
switch (index) {
- case 0: //this is node "B"
- EXPECT_EQ(SkRect::MakeWH(100, 100), rect);
- EXPECT_EQ(SK_ColorWHITE, paint.getColor());
- expectedMatrix.reset();
- EXPECT_EQ(SkRect::MakeLTRB(0, 0, 100, 100), TestUtils::getClipBounds(this));
- break;
- case 1: //this is node "P"
- EXPECT_EQ(SkRect::MakeLTRB(-10, -10, 60, 60), rect);
- EXPECT_EQ(SK_ColorDKGRAY, paint.getColor());
- expectedMatrix.setTranslate(50 - SCROLL_X, 50 - SCROLL_Y);
- EXPECT_EQ(SkRect::MakeLTRB(-35, -30, 45, 50), TestUtils::getLocalClipBounds(this));
- break;
- case 2: //this is node "C"
- EXPECT_EQ(SkRect::MakeWH(100, 50), rect);
- EXPECT_EQ(SK_ColorBLUE, paint.getColor());
- expectedMatrix.setTranslate(-SCROLL_X, 50 - SCROLL_Y);
- EXPECT_EQ(SkRect::MakeLTRB(0, 40, 95, 90), TestUtils::getClipBounds(this));
- break;
- default:
- ADD_FAILURE();
+ case 0: // this is node "B"
+ EXPECT_EQ(SkRect::MakeWH(100, 100), rect);
+ EXPECT_EQ(SK_ColorWHITE, paint.getColor());
+ expectedMatrix.reset();
+ EXPECT_EQ(SkRect::MakeLTRB(0, 0, 100, 100), TestUtils::getClipBounds(this));
+ break;
+ case 1: // this is node "P"
+ EXPECT_EQ(SkRect::MakeLTRB(-10, -10, 60, 60), rect);
+ EXPECT_EQ(SK_ColorDKGRAY, paint.getColor());
+ expectedMatrix.setTranslate(50 - SCROLL_X, 50 - SCROLL_Y);
+ EXPECT_EQ(SkRect::MakeLTRB(-35, -30, 45, 50),
+ TestUtils::getLocalClipBounds(this));
+ break;
+ case 2: // this is node "C"
+ EXPECT_EQ(SkRect::MakeWH(100, 50), rect);
+ EXPECT_EQ(SK_ColorBLUE, paint.getColor());
+ expectedMatrix.setTranslate(-SCROLL_X, 50 - SCROLL_Y);
+ EXPECT_EQ(SkRect::MakeLTRB(0, 40, 95, 90), TestUtils::getClipBounds(this));
+ break;
+ default:
+ ADD_FAILURE();
}
EXPECT_EQ(expectedMatrix, getTotalMatrix());
}
int getIndex() { return mDrawCounter; }
+
protected:
int mDrawCounter = 0;
};
@@ -277,59 +280,70 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorder) {
* The parent is scrolled by SCROLL_X/SCROLL_Y, but this does not affect the background
* (which isn't affected by scroll).
*/
- auto receiverBackground = TestUtils::createSkiaNode(0, 0, 100, 100,
+ auto receiverBackground = TestUtils::createSkiaNode(
+ 0, 0, 100, 100,
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- properties.setProjectionReceiver(true);
- // scroll doesn't apply to background, so undone via translationX/Y
- // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
- properties.setTranslationX(SCROLL_X);
- properties.setTranslationY(SCROLL_Y);
-
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- }, "B");
-
- auto projectingRipple = TestUtils::createSkiaNode(50, 0, 100, 50,
+ properties.setProjectionReceiver(true);
+ // scroll doesn't apply to background, so undone via translationX/Y
+ // NOTE: translationX/Y only! no other transform properties may be set for a proj
+ // receiver!
+ properties.setTranslationX(SCROLL_X);
+ properties.setTranslationY(SCROLL_Y);
+
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ },
+ "B");
+
+ auto projectingRipple = TestUtils::createSkiaNode(
+ 50, 0, 100, 50,
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- properties.setProjectBackwards(true);
- properties.setClipToBounds(false);
- SkPaint paint;
- paint.setColor(SK_ColorDKGRAY);
- canvas.drawRect(-10, -10, 60, 60, paint);
- }, "P");
- auto child = TestUtils::createSkiaNode(0, 50, 100, 100,
+ properties.setProjectBackwards(true);
+ properties.setClipToBounds(false);
+ SkPaint paint;
+ paint.setColor(SK_ColorDKGRAY);
+ canvas.drawRect(-10, -10, 60, 60, paint);
+ },
+ "P");
+ auto child = TestUtils::createSkiaNode(
+ 0, 50, 100, 100,
[&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- SkPaint paint;
- paint.setColor(SK_ColorBLUE);
- canvas.drawRect(0, 0, 100, 50, paint);
- canvas.drawRenderNode(projectingRipple.get());
- }, "C");
- auto parent = TestUtils::createSkiaNode(0, 0, 100, 100,
- [&receiverBackground, &child](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- // Set a rect outline for the projecting ripple to be masked against.
- properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
-
- canvas.save(SaveFlags::MatrixClip);
- canvas.translate(-SCROLL_X, -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
- canvas.drawRenderNode(receiverBackground.get());
- canvas.drawRenderNode(child.get());
- canvas.restore();
- }, "A");
+ SkPaint paint;
+ paint.setColor(SK_ColorBLUE);
+ canvas.drawRect(0, 0, 100, 50, paint);
+ canvas.drawRenderNode(projectingRipple.get());
+ },
+ "C");
+ auto parent = TestUtils::createSkiaNode(
+ 0, 0, 100, 100,
+ [&receiverBackground, &child](RenderProperties& properties,
+ SkiaRecordingCanvas& canvas) {
+ // Set a rect outline for the projecting ripple to be masked against.
+ properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
+
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.translate(-SCROLL_X,
+ -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
+ canvas.drawRenderNode(receiverBackground.get());
+ canvas.drawRenderNode(child.get());
+ canvas.restore();
+ },
+ "A");
ContextFactory contextFactory;
- std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
- renderThread, false, parent.get(), &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, 50], projectingRipple)
- //projectingRipple(P) -> (rect[-10, -10, 60, 60]) -> projects backwards
- //receiverBackground(B) -> (rect[0, 0, 100, 100]) -> projection receiver
+ // parent(A) -> (receiverBackground, child)
+ // child(C) -> (rect[0, 0, 100, 50], projectingRipple)
+ // projectingRipple(P) -> (rect[-10, -10, 60, 60]) -> projects backwards
+ // receiverBackground(B) -> (rect[0, 0, 100, 100]) -> projection receiver
- //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
+ // 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);
@@ -353,17 +367,17 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, projectionHwLayer) {
class ProjectionTestCanvas : public SkCanvas {
public:
ProjectionTestCanvas(int* drawCounter)
- : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT)
- , mDrawCounter(drawCounter)
- {}
+ : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT), mDrawCounter(drawCounter) {}
void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
- const SkPaint&) override {
- EXPECT_EQ(0, (*mDrawCounter)++); //part of painting the layer
- EXPECT_EQ(SkRect::MakeLTRB(0, 0, LAYER_WIDTH, LAYER_HEIGHT), TestUtils::getClipBounds(this));
+ const SkPaint&) override {
+ EXPECT_EQ(0, (*mDrawCounter)++); // part of painting the layer
+ EXPECT_EQ(SkRect::MakeLTRB(0, 0, LAYER_WIDTH, LAYER_HEIGHT),
+ TestUtils::getClipBounds(this));
}
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
EXPECT_EQ(1, (*mDrawCounter)++);
- EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), TestUtils::getClipBounds(this));
+ EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT),
+ TestUtils::getClipBounds(this));
}
void onDrawOval(const SkRect&, const SkPaint&) override {
EXPECT_EQ(2, (*mDrawCounter)++);
@@ -378,69 +392,73 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, projectionHwLayer) {
class ProjectionLayer : public SkSurface_Base {
public:
ProjectionLayer(int* drawCounter)
- : SkSurface_Base(SkImageInfo::MakeN32Premul(LAYER_WIDTH, LAYER_HEIGHT), nullptr)
- , mDrawCounter(drawCounter) {
- }
+ : SkSurface_Base(SkImageInfo::MakeN32Premul(LAYER_WIDTH, LAYER_HEIGHT), nullptr)
+ , mDrawCounter(drawCounter) {}
void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) 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()));
- }
- SkCanvas* onNewCanvas() override {
- return new ProjectionTestCanvas(mDrawCounter);
- }
- sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override {
- return nullptr;
- }
- sk_sp<SkImage> onNewImageSnapshot() override {
- return nullptr;
+ 300 - SCROLL_Y),
+ TestUtils::getClipBounds(this->getCanvas()));
}
+ 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;
};
- auto receiverBackground = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ auto receiverBackground = TestUtils::createSkiaNode(
+ 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- properties.setProjectionReceiver(true);
- // scroll doesn't apply to background, so undone via translationX/Y
- // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
- properties.setTranslationX(SCROLL_X);
- properties.setTranslationY(SCROLL_Y);
-
- canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
- }, "B"); //B
- auto projectingRipple = TestUtils::createSkiaNode(0, 0, LAYER_WIDTH, LAYER_HEIGHT,
+ properties.setProjectionReceiver(true);
+ // scroll doesn't apply to background, so undone via translationX/Y
+ // NOTE: translationX/Y only! no other transform properties may be set for a proj
+ // receiver!
+ properties.setTranslationX(SCROLL_X);
+ properties.setTranslationY(SCROLL_Y);
+
+ canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
+ },
+ "B"); // B
+ auto projectingRipple = TestUtils::createSkiaNode(
+ 0, 0, LAYER_WIDTH, LAYER_HEIGHT,
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- properties.setProjectBackwards(true);
- properties.setClipToBounds(false);
- canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
- }, "R"); //R
- auto child = TestUtils::createSkiaNode(100, 100, 300, 300,
+ properties.setProjectBackwards(true);
+ properties.setClipToBounds(false);
+ canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
+ },
+ "R"); // R
+ auto child = TestUtils::createSkiaNode(
+ 100, 100, 300, 300,
[&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- canvas.drawRenderNode(projectingRipple.get());
- canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, SkPaint());
- }, "C"); //C
- auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ canvas.drawRenderNode(projectingRipple.get());
+ canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, SkPaint());
+ },
+ "C"); // C
+ auto parent = TestUtils::createSkiaNode(
+ 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[&receiverBackground, &child](RenderProperties& properties,
- SkiaRecordingCanvas& canvas) {
- // Set a rect outline for the projecting ripple to be masked against.
- properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
- canvas.translate(-SCROLL_X, -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
- canvas.drawRenderNode(receiverBackground.get());
- canvas.drawRenderNode(child.get());
- }, "A"); //A
-
- //prepareTree is required to find, which receivers have backward projected nodes
+ SkiaRecordingCanvas& canvas) {
+ // Set a rect outline for the projecting ripple to be masked against.
+ properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
+ canvas.translate(-SCROLL_X,
+ -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
+ canvas.drawRenderNode(receiverBackground.get());
+ canvas.drawRenderNode(child.get());
+ },
+ "A"); // A
+
+ // prepareTree is required to find, which receivers have backward projected nodes
ContextFactory contextFactory;
- std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
- renderThread, false, parent.get(), &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);
int drawCounter = 0;
- //set a layer after prepareTree to avoid layer logic there
+ // set a layer after prepareTree to avoid layer logic there
child->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
sk_sp<SkSurface> surfaceLayer1(new ProjectionLayer(&drawCounter));
child->setLayerSurface(surfaceLayer1);
@@ -450,10 +468,10 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, projectionHwLayer) {
LayerUpdateQueue layerUpdateQueue;
layerUpdateQueue.enqueueLayerWithDamage(child.get(),
- android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT));
+ android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT));
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
pipeline->renderLayersImpl(layerUpdateQueue, true, false);
- EXPECT_EQ(1, drawCounter); //assert index 0 is drawn on the layer
+ EXPECT_EQ(1, drawCounter); // assert index 0 is drawn on the layer
RenderNodeDrawable drawable(parent.get(), surfaceLayer1->getCanvas(), true);
surfaceLayer1->getCanvas()->drawDrawable(&drawable);
@@ -490,40 +508,50 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionChildScroll) {
int mDrawCounter = 0;
};
- auto receiverBackground = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ auto receiverBackground = TestUtils::createSkiaNode(
+ 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- properties.setProjectionReceiver(true);
- canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
- }, "B"); //B
- auto projectingRipple = TestUtils::createSkiaNode(0, 0, 200, 200,
+ properties.setProjectionReceiver(true);
+ canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
+ },
+ "B"); // B
+ auto projectingRipple = TestUtils::createSkiaNode(
+ 0, 0, 200, 200,
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- // scroll doesn't apply to background, so undone via translationX/Y
- // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
- properties.setTranslationX(SCROLL_X);
- properties.setTranslationY(SCROLL_Y);
- properties.setProjectBackwards(true);
- properties.setClipToBounds(false);
- canvas.drawOval(0, 0, 200, 200, SkPaint());
- }, "R"); //R
- auto child = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ // scroll doesn't apply to background, so undone via translationX/Y
+ // NOTE: translationX/Y only! no other transform properties may be set for a proj
+ // receiver!
+ properties.setTranslationX(SCROLL_X);
+ properties.setTranslationY(SCROLL_Y);
+ properties.setProjectBackwards(true);
+ properties.setClipToBounds(false);
+ canvas.drawOval(0, 0, 200, 200, SkPaint());
+ },
+ "R"); // R
+ auto child = TestUtils::createSkiaNode(
+ 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- // Record time clip will be ignored by projectee
- canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
-
- canvas.translate(-SCROLL_X, -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
- canvas.drawRenderNode(projectingRipple.get());
- }, "C"); //C
- auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
- [&receiverBackground, &child](RenderProperties& properties,
- SkiaRecordingCanvas& canvas) {
- canvas.drawRenderNode(receiverBackground.get());
- canvas.drawRenderNode(child.get());
- }, "A"); //A
-
- //prepareTree is required to find, which receivers have backward projected nodes
+ // Record time clip will be ignored by projectee
+ canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
+
+ canvas.translate(-SCROLL_X,
+ -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
+ canvas.drawRenderNode(projectingRipple.get());
+ },
+ "C"); // C
+ auto parent =
+ TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ [&receiverBackground, &child](RenderProperties& properties,
+ SkiaRecordingCanvas& canvas) {
+ canvas.drawRenderNode(receiverBackground.get());
+ canvas.drawRenderNode(child.get());
+ },
+ "A"); // A
+
+ // prepareTree is required to find, which receivers have backward projected nodes
ContextFactory contextFactory;
- std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
- renderThread, false, parent.get(), &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;
@@ -536,17 +564,16 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionChildScroll) {
}
namespace {
-static int drawNode(RenderThread& renderThread, const sp<RenderNode>& renderNode)
-{
+static int drawNode(RenderThread& renderThread, const sp<RenderNode>& renderNode) {
ContextFactory contextFactory;
- std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
- renderThread, false, renderNode.get(), &contextFactory));
+ std::unique_ptr<CanvasContext> canvasContext(
+ CanvasContext::create(renderThread, false, renderNode.get(), &contextFactory));
TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
DamageAccumulator damageAccumulator;
info.damageAccumulator = &damageAccumulator;
renderNode->prepareTree(info);
- //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
+ // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
ZReorderCanvas canvas(100, 100);
RenderNodeDrawable drawable(renderNode.get(), &canvas, false);
canvas.drawDrawable(&drawable);
@@ -562,18 +589,18 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedInMiddle) {
|
R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectionReceiver(true);
- } ); //nodeB
+ }); // nodeB
drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectBackwards(true);
props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
EXPECT_EQ(3, drawNode(renderThread, nodeA));
}
@@ -586,19 +613,21 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectLast) {
|
R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, nullptr); //nodeB
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, nullptr); // nodeB
drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //drawn as 2
+ drawOrderedNode(&canvas, 3, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) { // drawn as 2
props.setProjectBackwards(true);
props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //drawn as 3
- props.setProjectionReceiver(true);
- } ); //nodeE
- }); //nodeA
+ }); // nodeR
+ }); // nodeC
+ drawOrderedNode(&canvas, 2,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // drawn as 3
+ props.setProjectionReceiver(true);
+ }); // nodeE
+ }); // nodeA
EXPECT_EQ(4, drawNode(renderThread, nodeA));
}
@@ -610,17 +639,17 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderNoReceivable) {
|
R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, nullptr); //nodeB
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, nullptr); // nodeB
drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- //not having a projection receiver is an undefined behavior
+ // not having a projection receiver is an undefined behavior
props.setProjectBackwards(true);
props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
EXPECT_EQ(2, drawNode(renderThread, nodeA));
}
@@ -632,17 +661,17 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderParentReceivable) {
|
R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, nullptr); //nodeB
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, nullptr); // nodeB
drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectionReceiver(true);
drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectBackwards(true);
props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
EXPECT_EQ(3, drawNode(renderThread, nodeA));
}
@@ -654,22 +683,22 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderSameNodeReceivable) {
|
R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, nullptr); //nodeB
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, nullptr); // nodeB
drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- //having a node that is projected on itself is an undefined/unexpected behavior
+ // having a node that is projected on itself is an undefined/unexpected behavior
props.setProjectionReceiver(true);
props.setProjectBackwards(true);
props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
EXPECT_EQ(2, drawNode(renderThread, nodeA));
}
-//Note: the outcome for this test is different in HWUI
+// Note: the outcome for this test is different in HWUI
RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling) {
/* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed.
A
@@ -677,18 +706,18 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling) {
/ | \
B C R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- } ); //nodeC
+ }); // nodeB
+ drawOrderedNode(&canvas, 1,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) {}); // nodeC
drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectBackwards(true);
props.setClipToBounds(false);
- } ); //nodeR
- }); //nodeA
+ }); // nodeR
+ }); // nodeA
EXPECT_EQ(2, drawNode(renderThread, nodeA));
}
@@ -701,20 +730,20 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling2) {
/ | \
B C R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- } ); //nodeC
+ }); // nodeB
+ drawOrderedNode(&canvas, 2,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) {}); // nodeC
drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectBackwards(true);
props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeG
- }); //nodeA
+ }); // nodeR
+ }); // nodeG
+ }); // nodeA
EXPECT_EQ(3, drawNode(renderThread, nodeA));
}
@@ -728,18 +757,19 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderGrandparentReceivable) {
|
R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectionReceiver(true);
drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- } ); //nodeB
- }); //nodeA
+ drawOrderedNode(&canvas, 2,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ }); // nodeB
+ }); // nodeA
EXPECT_EQ(3, drawNode(renderThread, nodeA));
}
@@ -751,21 +781,23 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivables) {
/ \
G R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //B
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B
props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //C
- drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //G
- props.setProjectionReceiver(true);
- } ); //nodeG
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //R
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ }); // nodeB
+ drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C
+ drawOrderedNode(&canvas, 3,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G
+ props.setProjectionReceiver(true);
+ }); // nodeG
+ drawOrderedNode(&canvas, 1,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // R
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
EXPECT_EQ(4, drawNode(renderThread, nodeA));
}
@@ -777,21 +809,23 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivablesLikelyScena
/ \
G R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //B
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B
props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //C
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //G
- props.setProjectionReceiver(true);
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeG
- drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //R
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ }); // nodeB
+ drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C
+ drawOrderedNode(&canvas, 1,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G
+ props.setProjectionReceiver(true);
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeG
+ drawOrderedNode(&canvas, 3,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // R
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
EXPECT_EQ(4, drawNode(renderThread, nodeA));
}
@@ -805,23 +839,26 @@ RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivablesDeeper) {
|
R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //B
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B
props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //C
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //G
- props.setProjectionReceiver(true);
- } ); //nodeG
- drawOrderedNode(&canvas, 4, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //D
- drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //R
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeD
- } ); //nodeC
- }); //nodeA
+ }); // nodeB
+ drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C
+ drawOrderedNode(&canvas, 2,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G
+ props.setProjectionReceiver(true);
+ }); // nodeG
+ drawOrderedNode(&canvas, 4,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // D
+ drawOrderedNode(&canvas, 3, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) { // R
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeD
+ }); // nodeC
+ }); // nodeA
EXPECT_EQ(5, drawNode(renderThread, nodeA));
}
@@ -830,8 +867,7 @@ RENDERTHREAD_TEST(RenderNodeDrawable, simple) {
static const int CANVAS_HEIGHT = 200;
class SimpleTestCanvas : public TestCanvasBase {
public:
- SimpleTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {
- }
+ SimpleTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
EXPECT_EQ(0, mDrawCounter++);
}
@@ -841,11 +877,12 @@ RENDERTHREAD_TEST(RenderNodeDrawable, simple) {
};
auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
- canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
- canvas.drawBitmap(*bitmap, 10, 10, nullptr);
- });
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
+ canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ SkPaint());
+ canvas.drawBitmap(*bitmap, 10, 10, nullptr);
+ });
SimpleTestCanvas canvas;
RenderNodeDrawable drawable(node.get(), &canvas, true);
@@ -858,33 +895,32 @@ RENDERTHREAD_TEST(RenderNodeDrawable, colorOp_unbounded) {
static const int CANVAS_HEIGHT = 200;
class ColorTestCanvas : public TestCanvasBase {
public:
- ColorTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {
- }
+ ColorTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
void onDrawPaint(const SkPaint&) {
switch (mDrawCounter++) {
- case 0:
- EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT),
- TestUtils::getClipBounds(this));
- break;
- case 1:
- EXPECT_EQ(SkRect::MakeWH(10, 10), TestUtils::getClipBounds(this));
- break;
- default:
- ADD_FAILURE();
+ case 0:
+ EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT),
+ TestUtils::getClipBounds(this));
+ break;
+ case 1:
+ EXPECT_EQ(SkRect::MakeWH(10, 10), TestUtils::getClipBounds(this));
+ break;
+ default:
+ ADD_FAILURE();
}
}
};
- auto unclippedColorView = TestUtils::createSkiaNode(0, 0, 10, 10,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- props.setClipToBounds(false);
- canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
- });
+ auto unclippedColorView = TestUtils::createSkiaNode(
+ 0, 0, 10, 10, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ props.setClipToBounds(false);
+ canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+ });
- auto clippedColorView = TestUtils::createSkiaNode(0, 0, 10, 10,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
- });
+ auto clippedColorView = TestUtils::createSkiaNode(
+ 0, 0, 10, 10, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+ });
ColorTestCanvas canvas;
RenderNodeDrawable drawable(unclippedColorView.get(), &canvas, true);
@@ -900,42 +936,43 @@ TEST(RenderNodeDrawable, renderNode) {
static const int CANVAS_HEIGHT = 200;
class RenderNodeTestCanvas : public TestCanvasBase {
public:
- RenderNodeTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {
- }
+ RenderNodeTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
- switch(mDrawCounter++) {
- case 0:
- EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), TestUtils::getClipBounds(this));
- EXPECT_EQ(SK_ColorDKGRAY, paint.getColor());
- break;
- case 1:
- EXPECT_EQ(SkRect::MakeLTRB(50, 50, 150, 150), TestUtils::getClipBounds(this));
- EXPECT_EQ(SK_ColorWHITE, paint.getColor());
- break;
- default:
- ADD_FAILURE();
+ switch (mDrawCounter++) {
+ case 0:
+ EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT),
+ TestUtils::getClipBounds(this));
+ EXPECT_EQ(SK_ColorDKGRAY, paint.getColor());
+ break;
+ case 1:
+ EXPECT_EQ(SkRect::MakeLTRB(50, 50, 150, 150), TestUtils::getClipBounds(this));
+ EXPECT_EQ(SK_ColorWHITE, paint.getColor());
+ break;
+ default:
+ ADD_FAILURE();
}
}
};
- auto child = TestUtils::createSkiaNode(10, 10, 110, 110,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
+ auto child = TestUtils::createSkiaNode(
+ 10, 10, 110, 110, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
- auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ auto parent = TestUtils::createSkiaNode(
+ 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[&child](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- SkPaint paint;
- paint.setColor(SK_ColorDKGRAY);
- canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
-
- canvas.save(SaveFlags::MatrixClip);
- canvas.translate(40, 40);
- canvas.drawRenderNode(child.get());
- canvas.restore();
- });
+ SkPaint paint;
+ paint.setColor(SK_ColorDKGRAY);
+ canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
+
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.translate(40, 40);
+ canvas.drawRenderNode(child.get());
+ canvas.restore();
+ });
RenderNodeTestCanvas canvas;
RenderNodeDrawable drawable(parent.get(), &canvas, true);
@@ -943,7 +980,6 @@ TEST(RenderNodeDrawable, renderNode) {
EXPECT_EQ(2, canvas.mDrawCounter);
}
-
TEST(ReorderBarrierDrawable, testShadowMatrix) {
static const int CANVAS_WIDTH = 100;
static const int CANVAS_HEIGHT = 100;
@@ -954,7 +990,6 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) {
static const float CASTER_WIDTH = 20.0f;
static const float CASTER_HEIGHT = 20.0f;
-
class ShadowTestCanvas : public SkCanvas {
public:
ShadowTestCanvas(int width, int height) : SkCanvas(width, height) {}
@@ -978,30 +1013,32 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) {
// matrix.
mDrawCounter++;
EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X, CASTER_Y), matrix);
- EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X+TRANSLATE_X, CASTER_Y+TRANSLATE_Y),
- getTotalMatrix());
+ EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
+ getTotalMatrix());
}
+
protected:
int mDrawCounter = 0;
};
- auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ auto parent = TestUtils::createSkiaNode(
+ 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- canvas.translate(TRANSLATE_X, TRANSLATE_Y);
- canvas.insertReorderBarrier(true);
-
- auto node = TestUtils::createSkiaNode(CASTER_X, CASTER_Y, CASTER_X + CASTER_WIDTH,
- CASTER_Y + CASTER_HEIGHT,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- props.setElevation(42);
- props.mutableOutline().setRoundRect(0, 0, 20, 20, 5, 1);
- props.mutableOutline().setShouldClip(true);
- });
- canvas.drawRenderNode(node.get());
- canvas.insertReorderBarrier(false);
- });
+ canvas.translate(TRANSLATE_X, TRANSLATE_Y);
+ canvas.insertReorderBarrier(true);
+
+ auto node = TestUtils::createSkiaNode(
+ CASTER_X, CASTER_Y, CASTER_X + CASTER_WIDTH, CASTER_Y + CASTER_HEIGHT,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ props.setElevation(42);
+ props.mutableOutline().setRoundRect(0, 0, 20, 20, 5, 1);
+ props.mutableOutline().setShouldClip(true);
+ });
+ canvas.drawRenderNode(node.get());
+ canvas.insertReorderBarrier(false);
+ });
- //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
+ // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
ShadowTestCanvas canvas(CANVAS_WIDTH, CANVAS_HEIGHT);
RenderNodeDrawable drawable(parent.get(), &canvas, false);
canvas.drawDrawable(&drawable);
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
index eda4a9de49ae..079520836bb5 100644
--- a/libs/hwui/tests/unit/RenderNodeTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
#include <VectorDrawable.h>
+#include <gtest/gtest.h>
#include "AnimationContext.h"
#include "DamageAccumulator.h"
@@ -32,21 +32,20 @@ using namespace android::uirenderer::renderthread;
class ContextFactory : public android::uirenderer::IContextFactory {
public:
- android::uirenderer::AnimationContext* createAnimationContext
- (android::uirenderer::renderthread::TimeLord& clock) override {
+ android::uirenderer::AnimationContext* createAnimationContext(
+ android::uirenderer::renderthread::TimeLord& clock) override {
return new android::uirenderer::AnimationContext(clock);
}
};
TEST(RenderNode, hasParents) {
- auto child = TestUtils::createNode(0, 0, 200, 400,
- [](RenderProperties& props, Canvas& canvas) {
+ auto child = TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
});
auto parent = TestUtils::createNode(0, 0, 200, 400,
- [&child](RenderProperties& props, Canvas& canvas) {
- canvas.drawRenderNode(child.get());
- });
+ [&child](RenderProperties& props, Canvas& canvas) {
+ canvas.drawRenderNode(child.get());
+ });
TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
@@ -67,14 +66,13 @@ TEST(RenderNode, hasParents) {
}
TEST(RenderNode, validity) {
- auto child = TestUtils::createNode(0, 0, 200, 400,
- [](RenderProperties& props, Canvas& canvas) {
+ auto child = TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
});
auto parent = TestUtils::createNode(0, 0, 200, 400,
- [&child](RenderProperties& props, Canvas& canvas) {
- canvas.drawRenderNode(child.get());
- });
+ [&child](RenderProperties& props, Canvas& canvas) {
+ canvas.drawRenderNode(child.get());
+ });
EXPECT_TRUE(child->isValid());
EXPECT_TRUE(parent->isValid());
@@ -111,9 +109,8 @@ TEST(RenderNode, validity) {
EXPECT_TRUE(child->isValid());
EXPECT_TRUE(child->nothingToDraw());
- TestUtils::recordNode(*parent, [&child](Canvas& canvas) {
- canvas.drawRenderNode(child.get());
- });
+ TestUtils::recordNode(*parent,
+ [&child](Canvas& canvas) { canvas.drawRenderNode(child.get()); });
TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
@@ -131,18 +128,17 @@ TEST(RenderNode, validity) {
}
TEST(RenderNode, multiTreeValidity) {
- auto child = TestUtils::createNode(0, 0, 200, 400,
- [](RenderProperties& props, Canvas& canvas) {
+ auto child = TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
});
auto parent1 = TestUtils::createNode(0, 0, 200, 400,
- [&child](RenderProperties& props, Canvas& canvas) {
- canvas.drawRenderNode(child.get());
- });
+ [&child](RenderProperties& props, Canvas& canvas) {
+ canvas.drawRenderNode(child.get());
+ });
auto parent2 = TestUtils::createNode(0, 0, 200, 400,
- [&child](RenderProperties& props, Canvas& canvas) {
- canvas.drawRenderNode(child.get());
- });
+ [&child](RenderProperties& props, Canvas& canvas) {
+ canvas.drawRenderNode(child.get());
+ });
EXPECT_TRUE(child->isValid());
EXPECT_TRUE(parent1->isValid());
@@ -200,14 +196,12 @@ TEST(RenderNode, multiTreeValidity) {
});
TestUtils::syncHierarchyPropertiesAndDisplayList(child);
- TestUtils::recordNode(*parent1, [&child](Canvas& canvas) {
- canvas.drawRenderNode(child.get());
- });
+ TestUtils::recordNode(*parent1,
+ [&child](Canvas& canvas) { canvas.drawRenderNode(child.get()); });
TestUtils::syncHierarchyPropertiesAndDisplayList(parent1);
- TestUtils::recordNode(*parent2, [&child](Canvas& canvas) {
- canvas.drawRenderNode(child.get());
- });
+ TestUtils::recordNode(*parent2,
+ [&child](Canvas& canvas) { canvas.drawRenderNode(child.get()); });
TestUtils::syncHierarchyPropertiesAndDisplayList(parent2);
EXPECT_TRUE(child->isValid());
@@ -240,9 +234,8 @@ TEST(RenderNode, releasedCallback) {
class DecRefOnReleased : public GlFunctorLifecycleListener {
public:
explicit DecRefOnReleased(int* refcnt) : mRefCnt(refcnt) {}
- void onGlFunctorReleased(Functor* functor) override {
- *mRefCnt -= 1;
- }
+ void onGlFunctorReleased(Functor* functor) override { *mRefCnt -= 1; }
+
private:
int* mRefCnt;
};
@@ -251,8 +244,7 @@ TEST(RenderNode, releasedCallback) {
sp<DecRefOnReleased> listener(new DecRefOnReleased(&refcnt));
Functor noopFunctor;
- auto node = TestUtils::createNode(0, 0, 200, 400,
- [&](RenderProperties& props, Canvas& canvas) {
+ auto node = TestUtils::createNode(0, 0, 200, 400, [&](RenderProperties& props, Canvas& canvas) {
refcnt++;
canvas.callDrawGLFunction(&noopFunctor, listener.get());
});
@@ -277,17 +269,17 @@ TEST(RenderNode, releasedCallback) {
RENDERTHREAD_TEST(RenderNode, prepareTree_nullableDisplayList) {
auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
ContextFactory contextFactory;
- std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
- renderThread, false, rootNode.get(), &contextFactory));
+ std::unique_ptr<CanvasContext> canvasContext(
+ CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory));
TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
DamageAccumulator damageAccumulator;
info.damageAccumulator = &damageAccumulator;
{
- auto nonNullDLNode = TestUtils::createNode(0, 0, 200, 400,
- [](RenderProperties& props, Canvas& canvas) {
- canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
- });
+ auto nonNullDLNode =
+ TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
+ });
TestUtils::syncHierarchyPropertiesAndDisplayList(nonNullDLNode);
EXPECT_TRUE(nonNullDLNode->getDisplayList());
nonNullDLNode->prepareTree(info);
@@ -304,17 +296,16 @@ RENDERTHREAD_TEST(RenderNode, prepareTree_nullableDisplayList) {
}
RENDERTHREAD_TEST(RenderNode, prepareTree_HwLayer_AVD_enqueueDamage) {
-
VectorDrawable::Group* group = new VectorDrawable::Group();
sp<VectorDrawableRoot> vectorDrawable(new VectorDrawableRoot(group));
- auto rootNode = TestUtils::createNode(0, 0, 200, 400,
- [&](RenderProperties& props, Canvas& canvas) {
- canvas.drawVectorDrawable(vectorDrawable.get());
- });
+ auto rootNode =
+ TestUtils::createNode(0, 0, 200, 400, [&](RenderProperties& props, Canvas& canvas) {
+ canvas.drawVectorDrawable(vectorDrawable.get());
+ });
ContextFactory contextFactory;
- std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
- renderThread, false, rootNode.get(), &contextFactory));
+ std::unique_ptr<CanvasContext> canvasContext(
+ CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory));
TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
DamageAccumulator damageAccumulator;
LayerUpdateQueue layerUpdateQueue;
diff --git a/libs/hwui/tests/unit/ShaderCacheTests.cpp b/libs/hwui/tests/unit/ShaderCacheTests.cpp
new file mode 100644
index 000000000000..43080a9460b3
--- /dev/null
+++ b/libs/hwui/tests/unit/ShaderCacheTests.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <gtest/gtest.h>
+#include <dirent.h>
+#include <cutils/properties.h>
+#include <cstdint>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+#include "pipeline/skia/ShaderCache.h"
+#include "FileBlobCache.h"
+
+using namespace android::uirenderer::skiapipeline;
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+class ShaderCacheTestUtils {
+public:
+ /**
+ * "setSaveDelay" sets the time in seconds to wait before saving newly inserted cache entries.
+ * If set to 0, then deferred save is disabled.
+ */
+ static void setSaveDelay(ShaderCache& cache, unsigned int saveDelay) {
+ cache.mDeferredSaveDelay = saveDelay;
+ }
+
+ /**
+ * "terminate" optionally stores the BlobCache on disk and release all in-memory cache.
+ * Next call to "initShaderDiskCache" will load again the in-memory cache from disk.
+ */
+ static void terminate(ShaderCache& cache, bool saveContent) {
+ std::lock_guard<std::mutex> lock(cache.mMutex);
+ if (cache.mInitialized && cache.mBlobCache && saveContent) {
+ cache.mBlobCache->writeToFile();
+ }
+ cache.mBlobCache = NULL;
+ }
+};
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
+
+
+namespace {
+
+std::string getExternalStorageFolder() {
+ return getenv("EXTERNAL_STORAGE");
+}
+
+bool folderExist(const std::string& folderName) {
+ DIR* dir = opendir(folderName.c_str());
+ if (dir) {
+ closedir(dir);
+ return true;
+ }
+ return false;
+}
+
+bool checkShader(const sk_sp<SkData>& shader, const char* program) {
+ sk_sp<SkData> shader2 = SkData::MakeWithCString(program);
+ return shader->size() == shader2->size()
+ && 0 == memcmp(shader->data(), shader2->data(), shader->size());
+}
+
+bool checkShader(const sk_sp<SkData>& shader, std::vector<char>& program) {
+ sk_sp<SkData> shader2 = SkData::MakeWithCopy(program.data(), program.size());
+ return shader->size() == shader2->size()
+ && 0 == memcmp(shader->data(), shader2->data(), shader->size());
+}
+
+void setShader(sk_sp<SkData>& shader, const char* program) {
+ shader = SkData::MakeWithCString(program);
+}
+
+void setShader(sk_sp<SkData>& shader, std::vector<char>& program) {
+ shader = SkData::MakeWithCopy(program.data(), program.size());
+}
+
+
+
+#define GrProgramDescTest(a) (*SkData::MakeWithCString(#a).get())
+
+TEST(ShaderCacheTest, testWriteAndRead) {
+ if (!folderExist(getExternalStorageFolder())) {
+ //don't run the test if external storage folder is not available
+ return;
+ }
+ std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1";
+ std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2";
+
+ //remove any test files from previous test run
+ int deleteFile = remove(cacheFile1.c_str());
+ ASSERT_TRUE(0 == deleteFile || ENOENT == errno);
+
+ //read the cache from a file that does not exist
+ ShaderCache::get().setFilename(cacheFile1.c_str());
+ ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); //disable deferred save
+ ShaderCache::get().initShaderDiskCache();
+
+ //read a key - should not be found since the cache is empty
+ sk_sp<SkData> outVS;
+ ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>());
+
+ //write to the in-memory cache without storing on disk and verify we read the same values
+ sk_sp<SkData> inVS;
+ setShader(inVS, "sassas");
+ ShaderCache::get().store(GrProgramDescTest(100), *inVS.get());
+ setShader(inVS, "someVS");
+ ShaderCache::get().store(GrProgramDescTest(432), *inVS.get());
+ ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(100))), sk_sp<SkData>());
+ ASSERT_TRUE(checkShader(outVS, "sassas"));
+ ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
+ ASSERT_TRUE(checkShader(outVS, "someVS"));
+
+ //store content to disk and release in-memory cache
+ ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
+
+ //change to a file that does not exist and verify load fails
+ ShaderCache::get().setFilename(cacheFile2.c_str());
+ ShaderCache::get().initShaderDiskCache();
+ ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>());
+ ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
+
+ //load again content from disk from an existing file and check the data is read correctly
+ ShaderCache::get().setFilename(cacheFile1.c_str());
+ ShaderCache::get().initShaderDiskCache();
+ sk_sp<SkData> outVS2;
+ ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
+ ASSERT_TRUE(checkShader(outVS2, "someVS"));
+
+ //change data, store to disk, read back again and verify data has been changed
+ setShader(inVS, "ewData1");
+ ShaderCache::get().store(GrProgramDescTest(432), *inVS.get());
+ ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
+ ShaderCache::get().initShaderDiskCache();
+ ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
+ ASSERT_TRUE(checkShader(outVS2, "ewData1"));
+
+
+ //write and read big data chunk (50K)
+ size_t dataSize = 50*1024;
+ std::vector<char> dataBuffer(dataSize);
+ for (size_t i = 0; i < dataSize; i++) {
+ dataBuffer[0] = dataSize % 256;
+ }
+ setShader(inVS, dataBuffer);
+ ShaderCache::get().store(GrProgramDescTest(432), *inVS.get());
+ ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
+ ShaderCache::get().initShaderDiskCache();
+ ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
+ ASSERT_TRUE(checkShader(outVS2, dataBuffer));
+
+ ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
+ remove(cacheFile1.c_str());
+}
+
+} // namespace
diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
index 85b12ba79a8c..bc742b0c5a63 100644
--- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
+++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
@@ -16,13 +16,13 @@
#include "tests/common/TestUtils.h"
-#include <gtest/gtest.h>
#include <SkBlurDrawLooper.h>
#include <SkColorMatrixFilter.h>
#include <SkColorSpace.h>
#include <SkImagePriv.h>
#include <SkPathOps.h>
#include <SkShader.h>
+#include <gtest/gtest.h>
using namespace android;
using namespace android::uirenderer;
@@ -42,15 +42,13 @@ SkBitmap createSkBitmap(int width, int height) {
TEST(SkiaBehavior, CreateBitmapShader1x1) {
SkBitmap origBitmap = createSkBitmap(1, 1);
sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(origBitmap, kNever_SkCopyPixelsMode);
- sk_sp<SkShader> s = image->makeShader(
- SkShader::kClamp_TileMode,
- SkShader::kRepeat_TileMode,
- nullptr);
+ sk_sp<SkShader> s =
+ image->makeShader(SkShader::kClamp_TileMode, SkShader::kRepeat_TileMode, nullptr);
SkBitmap bitmap;
SkShader::TileMode xy[2];
ASSERT_TRUE(s->isABitmap(&bitmap, nullptr, xy))
- << "1x1 bitmap shader must query as bitmap shader";
+ << "1x1 bitmap shader must query as bitmap shader";
EXPECT_EQ(origBitmap.pixelRef(), bitmap.pixelRef());
}
@@ -63,8 +61,7 @@ TEST(SkiaBehavior, genIds) {
TEST(SkiaBehavior, lightingColorFilter_simplify) {
{
- sk_sp<SkColorFilter> filter(
- SkColorMatrixFilter::MakeLightingFilter(0x11223344, 0));
+ sk_sp<SkColorFilter> filter(SkColorMatrixFilter::MakeLightingFilter(0x11223344, 0));
SkColor observedColor;
SkBlendMode observedMode;
@@ -74,8 +71,7 @@ TEST(SkiaBehavior, lightingColorFilter_simplify) {
}
{
- sk_sp<SkColorFilter> failFilter(
- SkColorMatrixFilter::MakeLightingFilter(0x11223344, 0x1));
+ sk_sp<SkColorFilter> failFilter(SkColorMatrixFilter::MakeLightingFilter(0x11223344, 0x1));
EXPECT_FALSE(failFilter->asColorMode(nullptr, nullptr));
}
}
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index d84b83d3f2dc..4138f595b091 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -16,12 +16,12 @@
#include "tests/common/TestUtils.h"
-#include <gtest/gtest.h>
#include <RecordingCanvas.h>
#include <SkBlurDrawLooper.h>
#include <SkCanvasStateUtils.h>
#include <SkPicture.h>
#include <SkPictureRecorder.h>
+#include <gtest/gtest.h>
using namespace android;
using namespace android::uirenderer;
@@ -88,7 +88,7 @@ TEST(SkiaCanvas, colorSpaceXform) {
sk_sp<Bitmap> adobeBitmap = Bitmap::allocateHeapBitmap(adobeInfo);
SkBitmap adobeSkBitmap;
adobeBitmap->getSkBitmap(&adobeSkBitmap);
- *adobeSkBitmap.getAddr32(0, 0) = 0xFF0000F0; // Opaque, almost fully-red
+ *adobeSkBitmap.getAddr32(0, 0) = 0xFF0000F0; // Opaque, almost fully-red
SkImageInfo info = adobeInfo.makeColorSpace(nullptr);
sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(info);
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index dd8f4b4ec8cc..88d6dcf990a5 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
#include <VectorDrawable.h>
+#include <gtest/gtest.h>
#include "AnimationContext.h"
#include "DamageAccumulator.h"
@@ -79,7 +79,7 @@ TEST(SkiaDisplayList, reuseDisplayList) {
// detach the list that you just attempted to reuse
availableList = renderNode->detachAvailableList();
ASSERT_EQ(availableList.get(), &skiaDL);
- availableList.release(); // prevents an invalid free since our DL is stack allocated
+ availableList.release(); // prevents an invalid free since our DL is stack allocated
// after detaching there should return no available list
availableList = renderNode->detachAvailableList();
@@ -115,8 +115,8 @@ public:
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) {
auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
ContextFactory contextFactory;
- std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
- renderThread, false, rootNode.get(), &contextFactory));
+ std::unique_ptr<CanvasContext> canvasContext(
+ CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory));
TreeInfo info(TreeInfo::MODE_FULL, *canvasContext.get());
DamageAccumulator damageAccumulator;
info.damageAccumulator = &damageAccumulator;
@@ -126,13 +126,13 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) {
// prepare with a clean VD
VectorDrawableRoot cleanVD(new VectorDrawable::Group());
skiaDL.mVectorDrawables.push_back(&cleanVD);
- cleanVD.getBitmapUpdateIfDirty(); // this clears the dirty bit
+ cleanVD.getBitmapUpdateIfDirty(); // this clears the dirty bit
ASSERT_FALSE(cleanVD.isDirty());
ASSERT_FALSE(cleanVD.getPropertyChangeWillBeConsumed());
TestUtils::MockTreeObserver observer;
ASSERT_FALSE(skiaDL.prepareListAndChildren(observer, info, false,
- [](RenderNode*, TreeObserver&, TreeInfo&, bool) {}));
+ [](RenderNode*, TreeObserver&, TreeInfo&, bool) {}));
ASSERT_TRUE(cleanVD.getPropertyChangeWillBeConsumed());
// prepare again this time adding a dirty VD
@@ -142,7 +142,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) {
ASSERT_TRUE(dirtyVD.isDirty());
ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed());
ASSERT_TRUE(skiaDL.prepareListAndChildren(observer, info, false,
- [](RenderNode*, TreeObserver&, TreeInfo&, bool) {}));
+ [](RenderNode*, TreeObserver&, TreeInfo&, bool) {}));
ASSERT_TRUE(dirtyVD.getPropertyChangeWillBeConsumed());
// prepare again this time adding a RenderNode and a callback
@@ -151,13 +151,15 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) {
SkCanvas dummyCanvas;
skiaDL.mChildNodes.emplace_back(renderNode.get(), &dummyCanvas);
bool hasRun = false;
- ASSERT_TRUE(skiaDL.prepareListAndChildren(observer, info, false,
- [&hasRun, renderNode, infoPtr](RenderNode* n, TreeObserver& observer, TreeInfo& i, bool r) {
- hasRun = true;
- ASSERT_EQ(renderNode.get(), n);
- ASSERT_EQ(infoPtr, &i);
- ASSERT_FALSE(r);
- }));
+ ASSERT_TRUE(skiaDL.prepareListAndChildren(
+ observer, info, false,
+ [&hasRun, renderNode, infoPtr](RenderNode* n, TreeObserver& observer, TreeInfo& i,
+ bool r) {
+ hasRun = true;
+ ASSERT_EQ(renderNode.get(), n);
+ ASSERT_EQ(infoPtr, &i);
+ ASSERT_FALSE(r);
+ }));
ASSERT_TRUE(hasRun);
canvasContext->destroy();
@@ -169,7 +171,5 @@ TEST(SkiaDisplayList, updateChildren) {
sp<RenderNode> renderNode = new RenderNode();
SkCanvas dummyCanvas;
skiaDL.mChildNodes.emplace_back(renderNode.get(), &dummyCanvas);
- skiaDL.updateChildren([renderNode](RenderNode* n) {
- ASSERT_EQ(renderNode.get(), n);
- });
+ skiaDL.updateChildren([renderNode](RenderNode* n) { ASSERT_EQ(renderNode.get(), n); });
}
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index f430ce633717..8fdb0e347afa 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -14,22 +14,22 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
#include <VectorDrawable.h>
+#include <gtest/gtest.h>
+#include <SkClipStack.h>
+#include <SkLiteRecorder.h>
+#include <SkSurface_Base.h>
+#include <string.h>
#include "AnimationContext.h"
#include "DamageAccumulator.h"
#include "IContextFactory.h"
+#include "SkiaCanvas.h"
#include "pipeline/skia/SkiaDisplayList.h"
-#include "pipeline/skia/SkiaRecordingCanvas.h"
#include "pipeline/skia/SkiaOpenGLPipeline.h"
+#include "pipeline/skia/SkiaRecordingCanvas.h"
#include "renderthread/CanvasContext.h"
#include "tests/common/TestUtils.h"
-#include "SkiaCanvas.h"
-#include <SkClipStack.h>
-#include <SkLiteRecorder.h>
-#include <SkSurface_Base.h>
-#include <string.h>
using namespace android;
using namespace android::uirenderer;
@@ -37,10 +37,10 @@ using namespace android::uirenderer::renderthread;
using namespace android::uirenderer::skiapipeline;
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrame) {
- auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
- [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
- redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
- });
+ auto redNode = TestUtils::createSkiaNode(
+ 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
+ redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+ });
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeLargest();
std::vector<sp<RenderNode>> renderNodes;
@@ -51,17 +51,16 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrame) {
auto surface = SkSurface::MakeRasterN32Premul(1, 1);
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes,
- opaque, false, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+ surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
}
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, testOnPrepareTree) {
-
- auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
- [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
- redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
- });
+ auto redNode = TestUtils::createSkiaNode(
+ 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
+ redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+ });
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeLargest();
@@ -71,33 +70,33 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, testOnPrepareTree) {
android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1);
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
{
- //add a pointer to a deleted vector drawable object in the pipeline
+ // add a pointer to a deleted vector drawable object in the pipeline
sp<VectorDrawableRoot> dirtyVD(new VectorDrawableRoot(new VectorDrawable::Group()));
- dirtyVD->mutateProperties()->setScaledSize(5,5);
+ dirtyVD->mutateProperties()->setScaledSize(5, 5);
pipeline->getVectorDrawables()->push_back(dirtyVD.get());
}
- //pipeline should clean list of dirty vector drawables before prepare tree
+ // pipeline should clean list of dirty vector drawables before prepare tree
pipeline->onPrepareTree();
auto surface = SkSurface::MakeRasterN32Premul(1, 1);
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
- //drawFrame will crash if "SkiaPipeline::onPrepareTree" did not clean invalid VD pointer
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes,
- opaque, false, contentDrawBounds, surface);
+ // drawFrame will crash if "SkiaPipeline::onPrepareTree" did not clean invalid VD pointer
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+ surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
}
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) {
- auto halfGreenNode = TestUtils::createSkiaNode(0, 0, 2, 2,
- [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {
- SkPaint greenPaint;
- greenPaint.setColor(SK_ColorGREEN);
- greenPaint.setStyle(SkPaint::kFill_Style);
- bottomHalfGreenCanvas.drawRect(0, 1, 2, 2, greenPaint);
- });
+ auto halfGreenNode = TestUtils::createSkiaNode(
+ 0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {
+ SkPaint greenPaint;
+ greenPaint.setColor(SK_ColorGREEN);
+ greenPaint.setStyle(SkPaint::kFill_Style);
+ bottomHalfGreenCanvas.drawRect(0, 1, 2, 2, greenPaint);
+ });
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeLargest();
std::vector<sp<RenderNode>> renderNodes;
@@ -107,21 +106,21 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) {
auto surface = SkSurface::MakeRasterN32Premul(2, 2);
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes,
- true, false, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, false, contentDrawBounds,
+ surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes,
- false, false, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, false, contentDrawBounds,
+ surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned int)SK_ColorTRANSPARENT);
ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
}
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckDirtyRect) {
- auto redNode = TestUtils::createSkiaNode(0, 0, 2, 2,
- [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
- redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
- });
+ auto redNode = TestUtils::createSkiaNode(
+ 0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
+ redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+ });
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeXYWH(0, 1, 2, 1);
std::vector<sp<RenderNode>> renderNodes;
@@ -131,8 +130,8 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckDirtyRect) {
auto surface = SkSurface::MakeRasterN32Premul(2, 2);
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes,
- true, false, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, false, contentDrawBounds,
+ surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
ASSERT_EQ(TestUtils::getColor(surface, 1, 0), SK_ColorBLUE);
ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorRED);
@@ -140,27 +139,27 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckDirtyRect) {
}
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderLayer) {
- auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
- [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
- redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
- });
+ auto redNode = TestUtils::createSkiaNode(
+ 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
+ redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+ });
auto surfaceLayer1 = SkSurface::MakeRasterN32Premul(1, 1);
surfaceLayer1->getCanvas()->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorWHITE);
redNode->setLayerSurface(surfaceLayer1);
- //create a 2nd 2x2 layer and add it to the queue as well.
- //make the layer's dirty area one half of the layer and verify only the dirty half is updated.
- auto blueNode = TestUtils::createSkiaNode(0, 0, 2, 2,
- [](RenderProperties& props, SkiaRecordingCanvas& blueCanvas) {
- blueCanvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
- });
+ // create a 2nd 2x2 layer and add it to the queue as well.
+ // make the layer's dirty area one half of the layer and verify only the dirty half is updated.
+ auto blueNode = TestUtils::createSkiaNode(
+ 0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& blueCanvas) {
+ blueCanvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
+ });
auto surfaceLayer2 = SkSurface::MakeRasterN32Premul(2, 2);
surfaceLayer2->getCanvas()->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 0), SK_ColorWHITE);
blueNode->setLayerSurface(surfaceLayer2);
- //attach both layers to the update queue
+ // attach both layers to the update queue
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeLargest();
layerUpdateQueue.enqueueLayerWithDamage(redNode.get(), dirty);
@@ -170,7 +169,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderLayer) {
bool opaque = true;
FrameBuilder::LightGeometry lightGeometry;
lightGeometry.radius = 1.0f;
- lightGeometry.center = { 0.0f, 0.0f, 0.0f };
+ lightGeometry.center = {0.0f, 0.0f, 0.0f};
BakedOpRenderer::LightInfo lightInfo;
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
pipeline->renderLayers(lightGeometry, &layerUpdateQueue, opaque, false, lightInfo);
@@ -185,16 +184,16 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderLayer) {
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderOverdraw) {
ScopedProperty<bool> prop(Properties::debugOverdraw, true);
- auto whiteNode = TestUtils::createSkiaNode(0, 0, 1, 1,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
- });
+ auto whiteNode = TestUtils::createSkiaNode(
+ 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+ });
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeXYWH(0, 0, 1, 1);
std::vector<sp<RenderNode>> renderNodes;
renderNodes.push_back(whiteNode);
bool opaque = true;
- //empty contentDrawBounds is avoiding backdrop/content logic, which would lead to less overdraw
+ // empty contentDrawBounds is avoiding backdrop/content logic, which would lead to less overdraw
android::uirenderer::Rect contentDrawBounds(0, 0, 0, 0);
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
auto surface = SkSurface::MakeRasterN32Premul(1, 1);
@@ -204,39 +203,39 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderOverdraw) {
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
// Single draw, should be white.
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
- false, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+ surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
// 1 Overdraw, should be blue blended onto white.
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
- false, contentDrawBounds, surface);
- ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0d0ff);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+ surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0d0ff);
// 2 Overdraw, should be green blended onto white
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
- false, contentDrawBounds, surface);
- ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0ffd0);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+ surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0ffd0);
// 3 Overdraw, should be pink blended onto white.
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
- false, contentDrawBounds, surface);
- ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffffc0c0);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+ surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffffc0c0);
// 4 Overdraw, should be red blended onto white.
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
- false, contentDrawBounds, surface);
- ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffff8080);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+ surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080);
// 5 Overdraw, should be red blended onto white.
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
- false, contentDrawBounds, surface);
- ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffff8080);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+ surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080);
}
namespace {
@@ -246,15 +245,9 @@ public:
DeferLayer() : SkSurface_Base(T().imageInfo(), nullptr) {}
virtual ~DeferLayer() {}
- SkCanvas* onNewCanvas() override {
- return new T();
- }
- sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override {
- return nullptr;
- }
- sk_sp<SkImage> onNewImageSnapshot() override {
- return nullptr;
- }
+ SkCanvas* onNewCanvas() override { return new T(); }
+ sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { return nullptr; }
+ sk_sp<SkImage> onNewImageSnapshot() override { return nullptr; }
T* canvas() { return static_cast<T*>(getCanvas()); }
void onCopyOnWrite(ContentChangeMode) override {}
};
@@ -267,28 +260,28 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, deferRenderNodeScene) {
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
SkMatrix expected;
switch (mDrawCounter++) {
- case 0:
- // background - left side
- EXPECT_EQ(SkRect::MakeLTRB(600, 100, 700, 500), TestUtils::getClipBounds(this));
- expected.setTranslate(100, 100);
- break;
- case 1:
- // background - top side
- EXPECT_EQ(SkRect::MakeLTRB(100, 400, 600, 500), TestUtils::getClipBounds(this));
- expected.setTranslate(100, 100);
- break;
- case 2:
- // content
- EXPECT_EQ(SkRect::MakeLTRB(100, 100, 700, 500), TestUtils::getClipBounds(this));
- expected.setTranslate(-50, -50);
- break;
- case 3:
- // overlay
- EXPECT_EQ(SkRect::MakeLTRB(0, 0, 800, 600), TestUtils::getClipBounds(this));
- expected.reset();
- break;
- default:
- ADD_FAILURE() << "Too many rects observed";
+ case 0:
+ // background - left side
+ EXPECT_EQ(SkRect::MakeLTRB(600, 100, 700, 500), TestUtils::getClipBounds(this));
+ expected.setTranslate(100, 100);
+ break;
+ case 1:
+ // background - top side
+ EXPECT_EQ(SkRect::MakeLTRB(100, 400, 600, 500), TestUtils::getClipBounds(this));
+ expected.setTranslate(100, 100);
+ break;
+ case 2:
+ // content
+ EXPECT_EQ(SkRect::MakeLTRB(100, 100, 700, 500), TestUtils::getClipBounds(this));
+ expected.setTranslate(-50, -50);
+ break;
+ case 3:
+ // overlay
+ EXPECT_EQ(SkRect::MakeLTRB(0, 0, 800, 600), TestUtils::getClipBounds(this));
+ expected.reset();
+ break;
+ default:
+ ADD_FAILURE() << "Too many rects observed";
}
EXPECT_EQ(expected, getTotalMatrix());
}
@@ -300,23 +293,26 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, deferRenderNodeScene) {
transparentPaint.setAlpha(128);
// backdrop
- nodes.push_back(TestUtils::createSkiaNode(100, 100, 700, 500, // 600x400
+ nodes.push_back(TestUtils::createSkiaNode(
+ 100, 100, 700, 500, // 600x400
[&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 600, 400, transparentPaint);
- }));
+ canvas.drawRect(0, 0, 600, 400, transparentPaint);
+ }));
// content
- android::uirenderer::Rect contentDrawBounds(150, 150, 650, 450); // 500x300
- nodes.push_back(TestUtils::createSkiaNode(0, 0, 800, 600,
+ android::uirenderer::Rect contentDrawBounds(150, 150, 650, 450); // 500x300
+ nodes.push_back(TestUtils::createSkiaNode(
+ 0, 0, 800, 600,
[&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 800, 600, transparentPaint);
- }));
+ canvas.drawRect(0, 0, 800, 600, transparentPaint);
+ }));
// overlay
- nodes.push_back(TestUtils::createSkiaNode(0, 0, 800, 600,
+ nodes.push_back(TestUtils::createSkiaNode(
+ 0, 0, 800, 600,
[&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 800, 200, transparentPaint);
- }));
+ canvas.drawRect(0, 0, 800, 200, transparentPaint);
+ }));
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeWH(800, 600);
@@ -331,8 +327,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clipped) {
static const int CANVAS_HEIGHT = 200;
class ClippedTestCanvas : public SkCanvas {
public:
- ClippedTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {
- }
+ ClippedTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {}
void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) override {
EXPECT_EQ(0, mDrawCounter++);
EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(this));
@@ -342,18 +337,19 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clipped) {
};
std::vector<sp<RenderNode>> nodes;
- nodes.push_back(TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ nodes.push_back(TestUtils::createSkiaNode(
+ 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- sk_sp<Bitmap> bitmap(TestUtils::createBitmap(CANVAS_WIDTH, CANVAS_HEIGHT));
- canvas.drawBitmap(*bitmap, 0, 0, nullptr);
- }));
+ sk_sp<Bitmap> bitmap(TestUtils::createBitmap(CANVAS_WIDTH, CANVAS_HEIGHT));
+ canvas.drawBitmap(*bitmap, 0, 0, nullptr);
+ }));
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeLTRB(10, 20, 30, 40);
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
sk_sp<DeferLayer<ClippedTestCanvas>> surface(new DeferLayer<ClippedTestCanvas>());
pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, false,
- SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
+ SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
EXPECT_EQ(1, surface->canvas()->mDrawCounter);
}
@@ -362,8 +358,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clip_replace) {
static const int CANVAS_HEIGHT = 50;
class ClipReplaceTestCanvas : public SkCanvas {
public:
- ClipReplaceTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {
- }
+ ClipReplaceTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {}
void onDrawPaint(const SkPaint&) {
EXPECT_EQ(0, mDrawCounter++);
EXPECT_EQ(SkRect::MakeLTRB(20, 10, 30, 40), TestUtils::getClipBounds(this))
@@ -373,17 +368,17 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clip_replace) {
};
std::vector<sp<RenderNode>> nodes;
- nodes.push_back(TestUtils::createSkiaNode(20, 20, 30, 30,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace_deprecated);
- canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
- }));
+ nodes.push_back(TestUtils::createSkiaNode(
+ 20, 20, 30, 30, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace_deprecated);
+ canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+ }));
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeLTRB(10, 10, 40, 40);
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
sk_sp<DeferLayer<ClipReplaceTestCanvas>> surface(new DeferLayer<ClipReplaceTestCanvas>());
pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, false,
- SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
+ SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
EXPECT_EQ(1, surface->canvas()->mDrawCounter);
}
diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
index 95c6ed6059b0..ad5fdacc8594 100644
--- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
@@ -14,23 +14,23 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
#include <VectorDrawable.h>
+#include <gtest/gtest.h>
+#include <SkClipStack.h>
+#include <SkLiteRecorder.h>
+#include <SkSurface_Base.h>
+#include <string.h>
#include "AnimationContext.h"
#include "DamageAccumulator.h"
+#include "FatalTestCanvas.h"
#include "IContextFactory.h"
+#include "SkiaCanvas.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "pipeline/skia/SkiaPipeline.h"
#include "pipeline/skia/SkiaRecordingCanvas.h"
#include "renderthread/CanvasContext.h"
#include "tests/common/TestUtils.h"
-#include "SkiaCanvas.h"
-#include <SkSurface_Base.h>
-#include <SkLiteRecorder.h>
-#include <SkClipStack.h>
-#include "FatalTestCanvas.h"
-#include <string.h>
using namespace android;
using namespace android::uirenderer;
@@ -40,7 +40,7 @@ using namespace android::uirenderer::skiapipeline;
namespace {
static void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
- std::function<void(const SkCanvas&)> opValidateCallback) {
+ std::function<void(const SkCanvas&)> opValidateCallback) {
static const int CANVAS_WIDTH = 100;
static const int CANVAS_HEIGHT = 100;
class PropertyTestCanvas : public TestCanvasBase {
@@ -57,79 +57,88 @@ static void testProperty(std::function<void(RenderProperties&)> propSetupCallbac
std::function<void(const SkCanvas&)> mCallback;
};
- auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ auto node = TestUtils::createSkiaNode(
+ 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[propSetupCallback](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- propSetupCallback(props);
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
- });
+ propSetupCallback(props);
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
+ });
PropertyTestCanvas canvas(opValidateCallback);
RenderNodeDrawable drawable(node.get(), &canvas, true);
canvas.drawDrawable(&drawable);
EXPECT_EQ(1, canvas.mDrawCounter);
}
-
}
TEST(RenderNodeDrawable, renderPropClipping) {
- testProperty([](RenderProperties& properties) {
- properties.setClipToBounds(true);
- properties.setClipBounds(android::uirenderer::Rect(10, 20, 300, 400));
- }, [](const SkCanvas& canvas) {
- EXPECT_EQ(SkRect::MakeLTRB(10, 20, 100, 100), TestUtils::getClipBounds(&canvas))
- << "Clip rect should be intersection of node bounds and clip bounds";
- });
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.setClipToBounds(true);
+ properties.setClipBounds(android::uirenderer::Rect(10, 20, 300, 400));
+ },
+ [](const SkCanvas& canvas) {
+ EXPECT_EQ(SkRect::MakeLTRB(10, 20, 100, 100), TestUtils::getClipBounds(&canvas))
+ << "Clip rect should be intersection of node bounds and clip bounds";
+ });
}
TEST(RenderNodeDrawable, renderPropRevealClip) {
- testProperty([](RenderProperties& properties) {
- properties.mutableRevealClip().set(true, 50, 50, 25);
- }, [](const SkCanvas& canvas) {
- EXPECT_EQ(SkRect::MakeLTRB(25, 25, 75, 75), TestUtils::getClipBounds(&canvas));
- });
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.mutableRevealClip().set(true, 50, 50, 25);
+ },
+ [](const SkCanvas& canvas) {
+ EXPECT_EQ(SkRect::MakeLTRB(25, 25, 75, 75), TestUtils::getClipBounds(&canvas));
+ });
}
TEST(RenderNodeDrawable, renderPropOutlineClip) {
- testProperty([](RenderProperties& properties) {
- properties.mutableOutline().setShouldClip(true);
- properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
- }, [](const SkCanvas& canvas) {
- EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(&canvas));
- });
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.mutableOutline().setShouldClip(true);
+ properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
+ },
+ [](const SkCanvas& canvas) {
+ EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(&canvas));
+ });
}
TEST(RenderNodeDrawable, renderPropTransform) {
- testProperty([](RenderProperties& properties) {
- properties.setLeftTopRightBottom(10, 10, 110, 110);
-
- SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
- properties.setStaticMatrix(&staticMatrix);
-
- // ignored, since static overrides animation
- SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
- properties.setAnimationMatrix(&animationMatrix);
-
- properties.setTranslationX(10);
- properties.setTranslationY(20);
- properties.setScaleX(0.5f);
- properties.setScaleY(0.7f);
- }, [](const SkCanvas& canvas) {
- Matrix4 matrix;
- matrix.loadTranslate(10, 10, 0); // left, top
- matrix.scale(1.2f, 1.2f, 1); // static matrix
- // ignore animation matrix, since static overrides it
-
- // translation xy
- matrix.translate(10, 20);
-
- // scale xy (from default pivot - center)
- matrix.translate(50, 50);
- matrix.scale(0.5f, 0.7f, 1);
- matrix.translate(-50, -50);
- Matrix4 actual(canvas.getTotalMatrix());
- EXPECT_MATRIX_APPROX_EQ(matrix, actual)
- << "Op draw matrix must match expected combination of transformation properties";
- });
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.setLeftTopRightBottom(10, 10, 110, 110);
+
+ SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
+ properties.setStaticMatrix(&staticMatrix);
+
+ // ignored, since static overrides animation
+ SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
+ properties.setAnimationMatrix(&animationMatrix);
+
+ properties.setTranslationX(10);
+ properties.setTranslationY(20);
+ properties.setScaleX(0.5f);
+ properties.setScaleY(0.7f);
+ },
+ [](const SkCanvas& canvas) {
+ Matrix4 matrix;
+ matrix.loadTranslate(10, 10, 0); // left, top
+ matrix.scale(1.2f, 1.2f, 1); // static matrix
+ // ignore animation matrix, since static overrides it
+
+ // translation xy
+ matrix.translate(10, 20);
+
+ // scale xy (from default pivot - center)
+ matrix.translate(50, 50);
+ matrix.scale(0.5f, 0.7f, 1);
+ matrix.translate(-50, -50);
+ Matrix4 actual(canvas.getTotalMatrix());
+ EXPECT_MATRIX_APPROX_EQ(matrix, actual) << "Op draw matrix must match expected "
+ "combination of transformation "
+ "properties";
+ });
}
diff --git a/libs/hwui/tests/unit/SnapshotTests.cpp b/libs/hwui/tests/unit/SnapshotTests.cpp
index 11797a8fc1db..9d673c82d4d0 100644
--- a/libs/hwui/tests/unit/SnapshotTests.cpp
+++ b/libs/hwui/tests/unit/SnapshotTests.cpp
@@ -32,16 +32,16 @@ TEST(Snapshot, serializeIntersectedClip) {
LinearAllocator allocator;
ClipRect rect(Rect(0, 0, 75, 75));
{
- auto intersectWithChild = child->serializeIntersectedClip(allocator,
- &rect, Matrix4::identity());
+ auto intersectWithChild =
+ child->serializeIntersectedClip(allocator, &rect, Matrix4::identity());
ASSERT_NE(nullptr, intersectWithChild);
EXPECT_EQ(Rect(50, 50, 75, 75), intersectWithChild->rect) << "Expect intersect with child";
}
rect.intersectWithRoot = true;
{
- auto intersectWithRoot = child->serializeIntersectedClip(allocator,
- &rect, Matrix4::identity());
+ auto intersectWithRoot =
+ child->serializeIntersectedClip(allocator, &rect, Matrix4::identity());
ASSERT_NE(nullptr, intersectWithRoot);
EXPECT_EQ(Rect(10, 10, 75, 75), intersectWithRoot->rect) << "Expect intersect with root";
}
diff --git a/libs/hwui/tests/unit/StringUtilsTests.cpp b/libs/hwui/tests/unit/StringUtilsTests.cpp
index b60e96c756ec..04fbb512e598 100644
--- a/libs/hwui/tests/unit/StringUtilsTests.cpp
+++ b/libs/hwui/tests/unit/StringUtilsTests.cpp
@@ -34,7 +34,7 @@ TEST(StringUtils, advancedBuildSet) {
auto collection = StringUtils::split("GL_ext1 GL_ext2 GL_ext3");
EXPECT_TRUE(collection.has("GL_ext1"));
- EXPECT_FALSE(collection.has("GL_ext")); // string present, but not in list
+ EXPECT_FALSE(collection.has("GL_ext")); // string present, but not in list
}
TEST(StringUtils, sizePrinter) {
diff --git a/libs/hwui/tests/unit/TestUtilsTests.cpp b/libs/hwui/tests/unit/TestUtilsTests.cpp
index 490595773724..742fe4210780 100644
--- a/libs/hwui/tests/unit/TestUtilsTests.cpp
+++ b/libs/hwui/tests/unit/TestUtilsTests.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include "tests/common/TestUtils.h"
#include "Properties.h"
+#include "tests/common/TestUtils.h"
#include <gtest/gtest.h>
diff --git a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
index 8312bda8d67d..78d75d65837c 100644
--- a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
+++ b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
@@ -18,8 +18,8 @@
#include "GammaFontRenderer.h"
#include "TextDropShadowCache.h"
-#include "utils/Blur.h"
#include "tests/common/TestUtils.h"
+#include "utils/Blur.h"
#include <SkPaint.h>
@@ -40,15 +40,15 @@ RENDERTHREAD_OPENGL_PIPELINE_TEST(TextDropShadowCache, addRemove) {
std::vector<float> positions;
float totalAdvance;
uirenderer::Rect bounds;
- TestUtils::layoutTextUnscaled(paint, "This is a test",
- &glyphs, &positions, &totalAdvance, &bounds);
+ TestUtils::layoutTextUnscaled(paint, "This is a test", &glyphs, &positions, &totalAdvance,
+ &bounds);
EXPECT_TRUE(bounds.contains(5, -10, 100, 0)) << "Expect input to be nontrivially sized";
ShadowTexture* texture = cache.get(&paint, glyphs.data(), glyphs.size(), 10, positions.data());
ASSERT_TRUE(texture);
ASSERT_FALSE(texture->cleanup);
- ASSERT_EQ((uint32_t) texture->objectSize(), cache.getSize());
+ ASSERT_EQ((uint32_t)texture->objectSize(), cache.getSize());
ASSERT_TRUE(cache.getSize());
cache.clear();
ASSERT_EQ(cache.getSize(), 0u);
diff --git a/libs/hwui/tests/unit/ThreadBaseTests.cpp b/libs/hwui/tests/unit/ThreadBaseTests.cpp
index 7aad34836bfe..1168ff211202 100644
--- a/libs/hwui/tests/unit/ThreadBaseTests.cpp
+++ b/libs/hwui/tests/unit/ThreadBaseTests.cpp
@@ -31,7 +31,8 @@ static ThreadBase& thread() {
sp<TestThread> ret{new TestThread};
ret->start("TestThread");
return ret;
- }();
+ }
+ ();
return *thread;
}
@@ -41,9 +42,7 @@ static WorkQueue& queue() {
TEST(ThreadBase, post) {
std::atomic_bool ran(false);
- queue().post([&ran]() {
- ran = true;
- });
+ queue().post([&ran]() { ran = true; });
for (int i = 0; !ran && i < 1000; i++) {
usleep(1);
}
@@ -55,9 +54,7 @@ TEST(ThreadBase, postDelay) {
std::promise<nsecs_t> ranAtPromise;
auto queuedAt = clock::now();
- queue().postDelayed(100_us, [&]() {
- ranAtPromise.set_value(clock::now());
- });
+ queue().postDelayed(100_us, [&]() { ranAtPromise.set_value(clock::now()); });
auto ranAt = ranAtPromise.get_future().get();
auto ranAfter = ranAt - queuedAt;
ASSERT_TRUE(ranAfter > 90_us) << "Ran after " << ns2us(ranAfter) << "us <= 90us";
@@ -80,15 +77,9 @@ TEST(ThreadBase, async) {
pid_t thisTid = gettid();
pid_t thisPid = getpid();
- auto otherTid = queue().async([]() -> auto {
- return gettid();
- });
- auto otherPid = queue().async([]() -> auto {
- return getpid();
- });
- auto result = queue().async([]() -> auto {
- return 42;
- });
+ auto otherTid = queue().async([]() -> auto { return gettid(); });
+ auto otherPid = queue().async([]() -> auto { return getpid(); });
+ auto result = queue().async([]() -> auto { return 42; });
ASSERT_NE(thisTid, otherTid.get());
ASSERT_EQ(thisPid, otherPid.get());
@@ -104,9 +95,7 @@ TEST(ThreadBase, lifecyclePerf) {
};
struct Counter {
- Counter(EventCount* count) : mCount(count) {
- mCount->construct++;
- }
+ Counter(EventCount* count) : mCount(count) { mCount->construct++; }
Counter(const Counter& other) : mCount(other.mCount) {
if (mCount) mCount->copy++;
@@ -149,17 +138,13 @@ TEST(ThreadBase, lifecyclePerf) {
}
int lifecycleTestHelper(const sp<VirtualLightRefBase>& test) {
- return queue().runSync([t = test]() -> int {
- return t->getStrongCount();
- });
+ return queue().runSync([t = test]()->int { return t->getStrongCount(); });
}
TEST(ThreadBase, lifecycle) {
sp<VirtualLightRefBase> dummyObject{new VirtualLightRefBase};
ASSERT_EQ(1, dummyObject->getStrongCount());
- ASSERT_EQ(2, queue().runSync([dummyObject]() -> int {
- return dummyObject->getStrongCount();
- }));
+ ASSERT_EQ(2, queue().runSync([dummyObject]() -> int { return dummyObject->getStrongCount(); }));
ASSERT_EQ(1, dummyObject->getStrongCount());
ASSERT_EQ(2, lifecycleTestHelper(dummyObject));
ASSERT_EQ(1, dummyObject->getStrongCount());
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
index 1f3eaef283ce..1fcc028b890f 100644
--- a/libs/hwui/tests/unit/TypefaceTests.cpp
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -57,17 +57,16 @@ std::shared_ptr<minikin::FontFamily> buildFamily(const char* fileName) {
std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
return std::make_shared<minikin::FontFamily>(
- std::vector<minikin::Font>({ minikin::Font(std::move(font), minikin::FontStyle()) }));
+ std::vector<minikin::Font>({minikin::Font(std::move(font), minikin::FontStyle())}));
}
std::vector<std::shared_ptr<minikin::FontFamily>> makeSingleFamlyVector(const char* fileName) {
- return std::vector<std::shared_ptr<minikin::FontFamily>>({ buildFamily(fileName) });
+ return std::vector<std::shared_ptr<minikin::FontFamily>>({buildFamily(fileName)});
}
TEST(TypefaceTest, resolveDefault_and_setDefaultTest) {
- std::unique_ptr<Typeface> regular(
- Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoRegular),
- RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+ std::unique_ptr<Typeface> regular(Typeface::createFromFamilies(
+ makeSingleFamlyVector(kRobotoRegular), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
EXPECT_EQ(regular.get(), Typeface::resolveDefault(regular.get()));
// Keep the original to restore it later.
@@ -82,128 +81,139 @@ TEST(TypefaceTest, resolveDefault_and_setDefaultTest) {
TEST(TypefaceTest, createWithDifferentBaseWeight) {
std::unique_ptr<Typeface> bold(Typeface::createWithDifferentBaseWeight(nullptr, 700));
- EXPECT_EQ(7, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(700, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, bold->fAPIStyle);
std::unique_ptr<Typeface> light(Typeface::createWithDifferentBaseWeight(nullptr, 300));
- EXPECT_EQ(3, light->fStyle.getWeight());
- EXPECT_FALSE(light->fStyle.getItalic());
+ EXPECT_EQ(300, light->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, light->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, light->fAPIStyle);
}
TEST(TypefaceTest, createRelativeTest_fromRegular) {
// In Java, Typeface.create(Typeface.DEFAULT, Typeface.NORMAL);
std::unique_ptr<Typeface> normal(Typeface::createRelative(nullptr, Typeface::kNormal));
- EXPECT_EQ(4, normal->fStyle.getWeight());
- EXPECT_FALSE(normal->fStyle.getItalic());
+ EXPECT_EQ(400, normal->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, normal->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, normal->fAPIStyle);
// In Java, Typeface.create(Typeface.DEFAULT, Typeface.BOLD);
std::unique_ptr<Typeface> bold(Typeface::createRelative(nullptr, Typeface::kBold));
- EXPECT_EQ(7, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(700, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
// In Java, Typeface.create(Typeface.DEFAULT, Typeface.ITALIC);
std::unique_ptr<Typeface> italic(Typeface::createRelative(nullptr, Typeface::kItalic));
- EXPECT_EQ(4, italic->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(400, italic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
// In Java, Typeface.create(Typeface.DEFAULT, Typeface.BOLD_ITALIC);
- std::unique_ptr<Typeface> boldItalic(
- Typeface::createRelative(nullptr, Typeface::kBoldItalic));
- EXPECT_EQ(7, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ std::unique_ptr<Typeface> boldItalic(Typeface::createRelative(nullptr, Typeface::kBoldItalic));
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kBoldItalic, boldItalic->fAPIStyle);
}
TEST(TypefaceTest, createRelativeTest_BoldBase) {
std::unique_ptr<Typeface> base(Typeface::createWithDifferentBaseWeight(nullptr, 700));
- // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.NORMAL);
+ // In Java, Typeface.create(Typeface.create("sans-serif-bold"),
+ // Typeface.NORMAL);
std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), Typeface::kNormal));
- EXPECT_EQ(7, normal->fStyle.getWeight());
- EXPECT_FALSE(normal->fStyle.getItalic());
+ EXPECT_EQ(700, normal->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, normal->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, normal->fAPIStyle);
- // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.BOLD);
+ // In Java, Typeface.create(Typeface.create("sans-serif-bold"),
+ // Typeface.BOLD);
std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), Typeface::kBold));
- EXPECT_EQ(10, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(1000, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
- // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.ITALIC);
+ // In Java, Typeface.create(Typeface.create("sans-serif-bold"),
+ // Typeface.ITALIC);
std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), Typeface::kItalic));
- EXPECT_EQ(7, italic->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(700, italic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
- // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.BOLD_ITALIC);
- std::unique_ptr<Typeface>
- boldItalic(Typeface::createRelative(base.get(), Typeface::kBoldItalic));
- EXPECT_EQ(10, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ // In Java, Typeface.create(Typeface.create("sans-serif-bold"),
+ // Typeface.BOLD_ITALIC);
+ std::unique_ptr<Typeface> boldItalic(
+ Typeface::createRelative(base.get(), Typeface::kBoldItalic));
+ EXPECT_EQ(1000, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kBoldItalic, boldItalic->fAPIStyle);
}
TEST(TypefaceTest, createRelativeTest_LightBase) {
std::unique_ptr<Typeface> base(Typeface::createWithDifferentBaseWeight(nullptr, 300));
- // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.NORMAL);
+ // In Java, Typeface.create(Typeface.create("sans-serif-light"),
+ // Typeface.NORMAL);
std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), Typeface::kNormal));
- EXPECT_EQ(3, normal->fStyle.getWeight());
- EXPECT_FALSE(normal->fStyle.getItalic());
+ EXPECT_EQ(300, normal->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, normal->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, normal->fAPIStyle);
- // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.BOLD);
+ // In Java, Typeface.create(Typeface.create("sans-serif-light"),
+ // Typeface.BOLD);
std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), Typeface::kBold));
- EXPECT_EQ(6, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(600, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
- // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.ITLIC);
+ // In Java, Typeface.create(Typeface.create("sans-serif-light"),
+ // Typeface.ITLIC);
std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), Typeface::kItalic));
- EXPECT_EQ(3, italic->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(300, italic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
- // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.BOLD_ITALIC);
- std::unique_ptr<Typeface>
- boldItalic(Typeface::createRelative(base.get(), Typeface::kBoldItalic));
- EXPECT_EQ(6, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ // In Java, Typeface.create(Typeface.create("sans-serif-light"),
+ // Typeface.BOLD_ITALIC);
+ std::unique_ptr<Typeface> boldItalic(
+ Typeface::createRelative(base.get(), Typeface::kBoldItalic));
+ EXPECT_EQ(600, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kBoldItalic, boldItalic->fAPIStyle);
}
TEST(TypefaceTest, createRelativeTest_fromBoldStyled) {
std::unique_ptr<Typeface> base(Typeface::createRelative(nullptr, Typeface::kBold));
- // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.NORMAL);
+ // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD),
+ // Typeface.NORMAL);
std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), Typeface::kNormal));
- EXPECT_EQ(4, normal->fStyle.getWeight());
- EXPECT_FALSE(normal->fStyle.getItalic());
+ EXPECT_EQ(400, normal->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, normal->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, normal->fAPIStyle);
- // In Java Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.BOLD);
+ // In Java Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD),
+ // Typeface.BOLD);
std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), Typeface::kBold));
- EXPECT_EQ(7, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(700, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
- // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.ITALIC);
+ // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD),
+ // Typeface.ITALIC);
std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), Typeface::kItalic));
- EXPECT_EQ(4, normal->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(400, normal->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
// In Java,
- // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.BOLD_ITALIC);
- std::unique_ptr<Typeface>
- boldItalic(Typeface::createRelative(base.get(), Typeface::kBoldItalic));
- EXPECT_EQ(7, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD),
+ // Typeface.BOLD_ITALIC);
+ std::unique_ptr<Typeface> boldItalic(
+ Typeface::createRelative(base.get(), Typeface::kBoldItalic));
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kBoldItalic, boldItalic->fAPIStyle);
}
@@ -211,31 +221,35 @@ TEST(TypefaceTest, createRelativeTest_fromItalicStyled) {
std::unique_ptr<Typeface> base(Typeface::createRelative(nullptr, Typeface::kItalic));
// In Java,
- // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.NORMAL);
+ // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC),
+ // Typeface.NORMAL);
std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), Typeface::kNormal));
- EXPECT_EQ(4, normal->fStyle.getWeight());
- EXPECT_FALSE(normal->fStyle.getItalic());
+ EXPECT_EQ(400, normal->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, normal->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, normal->fAPIStyle);
- // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.BOLD);
+ // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT,
+ // Typeface.ITALIC), Typeface.BOLD);
std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), Typeface::kBold));
- EXPECT_EQ(7, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(700, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
// In Java,
- // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.ITALIC);
+ // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC),
+ // Typeface.ITALIC);
std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), Typeface::kItalic));
- EXPECT_EQ(4, italic->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(400, italic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
// In Java,
- // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.BOLD_ITALIC);
- std::unique_ptr<Typeface>
- boldItalic(Typeface::createRelative(base.get(), Typeface::kBoldItalic));
- EXPECT_EQ(7, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC),
+ // Typeface.BOLD_ITALIC);
+ std::unique_ptr<Typeface> boldItalic(
+ Typeface::createRelative(base.get(), Typeface::kBoldItalic));
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kBoldItalic, boldItalic->fAPIStyle);
}
@@ -247,8 +261,8 @@ TEST(TypefaceTest, createRelativeTest_fromSpecifiedStyled) {
// .setWeight(700).setItalic(false).build();
// Typeface.create(typeface, Typeface.NORMAL);
std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), Typeface::kNormal));
- EXPECT_EQ(4, normal->fStyle.getWeight());
- EXPECT_FALSE(normal->fStyle.getItalic());
+ EXPECT_EQ(400, normal->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, normal->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, normal->fAPIStyle);
// In Java,
@@ -256,8 +270,8 @@ TEST(TypefaceTest, createRelativeTest_fromSpecifiedStyled) {
// .setWeight(700).setItalic(false).build();
// Typeface.create(typeface, Typeface.BOLD);
std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), Typeface::kBold));
- EXPECT_EQ(7, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(700, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
// In Java,
@@ -265,155 +279,160 @@ TEST(TypefaceTest, createRelativeTest_fromSpecifiedStyled) {
// .setWeight(700).setItalic(false).build();
// Typeface.create(typeface, Typeface.ITALIC);
std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), Typeface::kItalic));
- EXPECT_EQ(4, italic->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(400, italic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
// In Java,
// Typeface typeface = new Typeface.Builder(invalid).setFallback("sans-serif")
// .setWeight(700).setItalic(false).build();
// Typeface.create(typeface, Typeface.BOLD_ITALIC);
- std::unique_ptr<Typeface>
- boldItalic(Typeface::createRelative(base.get(), Typeface::kBoldItalic));
- EXPECT_EQ(7, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ std::unique_ptr<Typeface> boldItalic(
+ Typeface::createRelative(base.get(), Typeface::kBoldItalic));
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kBoldItalic, boldItalic->fAPIStyle);
}
TEST(TypefaceTest, createAbsolute) {
// In Java,
- // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(400).setItalic(false)
+ // new
+ // Typeface.Builder(invalid).setFallback("sans-serif").setWeight(400).setItalic(false)
// .build();
std::unique_ptr<Typeface> regular(Typeface::createAbsolute(nullptr, 400, false));
- EXPECT_EQ(4, regular->fStyle.getWeight());
- EXPECT_FALSE(regular->fStyle.getItalic());
+ EXPECT_EQ(400, regular->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, regular->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, regular->fAPIStyle);
// In Java,
- // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(700).setItalic(false)
+ // new
+ // Typeface.Builder(invalid).setFallback("sans-serif").setWeight(700).setItalic(false)
// .build();
std::unique_ptr<Typeface> bold(Typeface::createAbsolute(nullptr, 700, false));
- EXPECT_EQ(7, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(700, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
// In Java,
- // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(400).setItalic(true)
+ // new
+ // Typeface.Builder(invalid).setFallback("sans-serif").setWeight(400).setItalic(true)
// .build();
std::unique_ptr<Typeface> italic(Typeface::createAbsolute(nullptr, 400, true));
- EXPECT_EQ(4, italic->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(400, italic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
// In Java,
- // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(700).setItalic(true)
+ // new
+ // Typeface.Builder(invalid).setFallback("sans-serif").setWeight(700).setItalic(true)
// .build();
std::unique_ptr<Typeface> boldItalic(Typeface::createAbsolute(nullptr, 700, true));
- EXPECT_EQ(7, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kBoldItalic, boldItalic->fAPIStyle);
// In Java,
- // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(1100).setItalic(true)
+ // new
+ // Typeface.Builder(invalid).setFallback("sans-serif").setWeight(1100).setItalic(true)
// .build();
std::unique_ptr<Typeface> over1000(Typeface::createAbsolute(nullptr, 1100, false));
- EXPECT_EQ(10, over1000->fStyle.getWeight());
- EXPECT_FALSE(over1000->fStyle.getItalic());
+ EXPECT_EQ(1000, over1000->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, over1000->fStyle.slant);
EXPECT_EQ(Typeface::kBold, over1000->fAPIStyle);
}
TEST(TypefaceTest, createFromFamilies_Single) {
- // In Java, new Typeface.Builder("Roboto-Regular.ttf").setWeight(400).setItalic(false).build();
+ // In Java, new
+ // Typeface.Builder("Roboto-Regular.ttf").setWeight(400).setItalic(false).build();
std::unique_ptr<Typeface> regular(
Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoRegular), 400, false));
- EXPECT_EQ(4, regular->fStyle.getWeight());
- EXPECT_FALSE(regular->fStyle.getItalic());
+ EXPECT_EQ(400, regular->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, regular->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, regular->fAPIStyle);
- // In Java, new Typeface.Builder("Roboto-Bold.ttf").setWeight(700).setItalic(false).build();
+ // In Java, new
+ // Typeface.Builder("Roboto-Bold.ttf").setWeight(700).setItalic(false).build();
std::unique_ptr<Typeface> bold(
Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBold), 700, false));
- EXPECT_EQ(7, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(700, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
- // In Java, new Typeface.Builder("Roboto-Italic.ttf").setWeight(400).setItalic(true).build();
+ // In Java, new
+ // Typeface.Builder("Roboto-Italic.ttf").setWeight(400).setItalic(true).build();
std::unique_ptr<Typeface> italic(
Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoItalic), 400, true));
- EXPECT_EQ(4, italic->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(400, italic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
// In Java,
- // new Typeface.Builder("Roboto-BoldItalic.ttf").setWeight(700).setItalic(true).build();
+ // new
+ // Typeface.Builder("Roboto-BoldItalic.ttf").setWeight(700).setItalic(true).build();
std::unique_ptr<Typeface> boldItalic(
Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBoldItalic), 700, true));
- EXPECT_EQ(7, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
// In Java,
- // new Typeface.Builder("Roboto-BoldItalic.ttf").setWeight(1100).setItalic(false).build();
+ // new
+ // Typeface.Builder("Roboto-BoldItalic.ttf").setWeight(1100).setItalic(false).build();
std::unique_ptr<Typeface> over1000(
Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBold), 1100, false));
- EXPECT_EQ(10, over1000->fStyle.getWeight());
- EXPECT_FALSE(over1000->fStyle.getItalic());
+ EXPECT_EQ(1000, over1000->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, over1000->fStyle.slant);
EXPECT_EQ(Typeface::kBold, over1000->fAPIStyle);
}
TEST(TypefaceTest, createFromFamilies_Single_resolveByTable) {
// In Java, new Typeface.Builder("Roboto-Regular.ttf").build();
- std::unique_ptr<Typeface> regular(
- Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoRegular),
- RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
- EXPECT_EQ(4, regular->fStyle.getWeight());
- EXPECT_FALSE(regular->fStyle.getItalic());
+ std::unique_ptr<Typeface> regular(Typeface::createFromFamilies(
+ makeSingleFamlyVector(kRobotoRegular), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+ EXPECT_EQ(400, regular->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, regular->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, regular->fAPIStyle);
// In Java, new Typeface.Builder("Roboto-Bold.ttf").build();
- std::unique_ptr<Typeface> bold(
- Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBold),
- RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
- EXPECT_EQ(7, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ std::unique_ptr<Typeface> bold(Typeface::createFromFamilies(
+ makeSingleFamlyVector(kRobotoBold), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+ EXPECT_EQ(700, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
// In Java, new Typeface.Builder("Roboto-Italic.ttf").build();
- std::unique_ptr<Typeface> italic(
- Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoItalic),
- RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
- EXPECT_EQ(4, italic->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ std::unique_ptr<Typeface> italic(Typeface::createFromFamilies(
+ makeSingleFamlyVector(kRobotoItalic), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+ EXPECT_EQ(400, italic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
// In Java, new Typeface.Builder("Roboto-BoldItalic.ttf").build();
std::unique_ptr<Typeface> boldItalic(
Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBoldItalic),
- RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
- EXPECT_EQ(7, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
}
TEST(TypefaceTest, createFromFamilies_Family) {
std::vector<std::shared_ptr<minikin::FontFamily>> families = {
buildFamily(kRobotoRegular), buildFamily(kRobotoBold), buildFamily(kRobotoItalic),
- buildFamily(kRobotoBoldItalic)
- };
- std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies(std::move(families),
- RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
- EXPECT_EQ(4, typeface->fStyle.getWeight());
- EXPECT_FALSE(typeface->fStyle.getItalic());
+ buildFamily(kRobotoBoldItalic)};
+ std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies(
+ std::move(families), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+ EXPECT_EQ(400, typeface->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, typeface->fStyle.slant);
}
TEST(TypefaceTest, createFromFamilies_Family_withoutRegular) {
std::vector<std::shared_ptr<minikin::FontFamily>> families = {
- buildFamily(kRobotoBold), buildFamily(kRobotoItalic), buildFamily(kRobotoBoldItalic)
- };
- std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies(std::move(families),
- RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
- EXPECT_EQ(7, typeface->fStyle.getWeight());
- EXPECT_FALSE(typeface->fStyle.getItalic());
+ buildFamily(kRobotoBold), buildFamily(kRobotoItalic), buildFamily(kRobotoBoldItalic)};
+ std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies(
+ std::move(families), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+ EXPECT_EQ(700, typeface->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, typeface->fStyle.slant);
}
} // namespace
diff --git a/libs/hwui/tests/unit/VectorDrawableAtlasTests.cpp b/libs/hwui/tests/unit/VectorDrawableAtlasTests.cpp
index 17f8176bcfdc..0c95fdd42851 100644
--- a/libs/hwui/tests/unit/VectorDrawableAtlasTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableAtlasTests.cpp
@@ -16,9 +16,9 @@
#include <gtest/gtest.h>
-#include "tests/common/TestUtils.h"
#include <GrRectanizer.h>
#include "pipeline/skia/VectorDrawableAtlas.h"
+#include "tests/common/TestUtils.h"
using namespace android;
using namespace android::uirenderer;
@@ -26,16 +26,16 @@ using namespace android::uirenderer::renderthread;
using namespace android::uirenderer::skiapipeline;
RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, addGetRemove) {
- VectorDrawableAtlas atlas(100*100);
+ VectorDrawableAtlas atlas(100 * 100);
atlas.prepareForDraw(renderThread.getGrContext());
- //create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects)
+ // create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects)
const int MAX_RECTS = 150;
AtlasEntry VDRects[MAX_RECTS];
sk_sp<SkSurface> atlasSurface;
- //check we are able to allocate new rects
- //check that rects in the atlas do not intersect
+ // check we are able to allocate new rects
+ // check that rects in the atlas do not intersect
for (uint32_t i = 0; i < MAX_RECTS; i++) {
VDRects[i] = atlas.requestNewEntry(10, 10, renderThread.getGrContext());
if (0 == i) {
@@ -45,7 +45,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, addGetRemove) {
ASSERT_TRUE(VDRects[i].surface.get() != nullptr);
ASSERT_TRUE(VDRects[i].rect.width() == 10 && VDRects[i].rect.height() == 10);
- //nothing in the atlas should intersect
+ // nothing in the atlas should intersect
if (atlasSurface.get() == VDRects[i].surface.get()) {
for (uint32_t j = 0; j < i; j++) {
if (atlasSurface.get() == VDRects[j].surface.get()) {
@@ -55,16 +55,16 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, addGetRemove) {
}
}
- //first 1/3 rects should all be in the same surface
- for (uint32_t i = 1; i < MAX_RECTS/3; i++) {
+ // first 1/3 rects should all be in the same surface
+ for (uint32_t i = 1; i < MAX_RECTS / 3; i++) {
ASSERT_NE(VDRects[i].key, VDRects[0].key);
ASSERT_EQ(VDRects[i].surface.get(), atlasSurface.get());
}
- //first rect is using atlas and last is a standalone surface
- ASSERT_NE(VDRects[0].surface.get(), VDRects[MAX_RECTS-1].surface.get());
+ // first rect is using atlas and last is a standalone surface
+ ASSERT_NE(VDRects[0].surface.get(), VDRects[MAX_RECTS - 1].surface.get());
- //check getEntry returns the same surfaces that we had created
+ // check getEntry returns the same surfaces that we had created
for (uint32_t i = 0; i < MAX_RECTS; i++) {
auto VDRect = atlas.getEntry(VDRects[i].key);
ASSERT_TRUE(VDRect.key != INVALID_ATLAS_KEY);
@@ -74,9 +74,9 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, addGetRemove) {
atlas.releaseEntry(VDRect.key);
}
- //check that any new rects will be allocated in the atlas, even that rectanizer is full.
- //rects in the atlas should not intersect.
- for (uint32_t i = 0; i < MAX_RECTS/3; i++) {
+ // check that any new rects will be allocated in the atlas, even that rectanizer is full.
+ // rects in the atlas should not intersect.
+ for (uint32_t i = 0; i < MAX_RECTS / 3; i++) {
VDRects[i] = atlas.requestNewEntry(10, 10, renderThread.getGrContext());
ASSERT_TRUE(VDRects[i].key != INVALID_ATLAS_KEY);
ASSERT_EQ(VDRects[i].surface.get(), atlasSurface.get());
@@ -87,25 +87,24 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, addGetRemove) {
}
}
-
RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, disallowSharedSurface) {
- VectorDrawableAtlas atlas(100*100);
- //don't allow to use a shared surface
+ VectorDrawableAtlas atlas(100 * 100);
+ // don't allow to use a shared surface
atlas.setStorageMode(VectorDrawableAtlas::StorageMode::disallowSharedSurface);
atlas.prepareForDraw(renderThread.getGrContext());
- //create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects)
+ // create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects)
const int MAX_RECTS = 150;
AtlasEntry VDRects[MAX_RECTS];
- //check we are able to allocate new rects
- //check that rects in the atlas use unique surfaces
+ // check we are able to allocate new rects
+ // check that rects in the atlas use unique surfaces
for (uint32_t i = 0; i < MAX_RECTS; i++) {
VDRects[i] = atlas.requestNewEntry(10, 10, renderThread.getGrContext());
ASSERT_TRUE(VDRects[i].key != INVALID_ATLAS_KEY);
ASSERT_TRUE(VDRects[i].surface.get() != nullptr);
ASSERT_TRUE(VDRects[i].rect.width() == 10 && VDRects[i].rect.height() == 10);
- //nothing in the atlas should use the same surface
+ // nothing in the atlas should use the same surface
for (uint32_t j = 0; j < i; j++) {
ASSERT_NE(VDRects[i].surface.get(), VDRects[j].surface.get());
}
@@ -113,17 +112,17 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, disallowSharedSurface) {
}
RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, repack) {
- VectorDrawableAtlas atlas(100*100);
+ VectorDrawableAtlas atlas(100 * 100);
ASSERT_FALSE(atlas.isFragmented());
atlas.prepareForDraw(renderThread.getGrContext());
ASSERT_FALSE(atlas.isFragmented());
- //create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects)
+ // create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects)
const int MAX_RECTS = 150;
AtlasEntry VDRects[MAX_RECTS];
sk_sp<SkSurface> atlasSurface;
- //fill the atlas with check we are able to allocate new rects
+ // fill the atlas with check we are able to allocate new rects
for (uint32_t i = 0; i < MAX_RECTS; i++) {
VDRects[i] = atlas.requestNewEntry(10, 10, renderThread.getGrContext());
if (0 == i) {
@@ -134,13 +133,13 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, repack) {
ASSERT_FALSE(atlas.isFragmented());
- //first 1/3 rects should all be in the same surface
- for (uint32_t i = 1; i < MAX_RECTS/3; i++) {
+ // first 1/3 rects should all be in the same surface
+ for (uint32_t i = 1; i < MAX_RECTS / 3; i++) {
ASSERT_NE(VDRects[i].key, VDRects[0].key);
ASSERT_EQ(VDRects[i].surface.get(), atlasSurface.get());
}
- //release all entries
+ // release all entries
for (uint32_t i = 0; i < MAX_RECTS; i++) {
auto VDRect = atlas.getEntry(VDRects[i].key);
ASSERT_TRUE(VDRect.key != INVALID_ATLAS_KEY);
@@ -149,9 +148,9 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, repack) {
ASSERT_FALSE(atlas.isFragmented());
- //allocate 4x4 rects, which will fragment the atlas badly, because each entry occupies a 10x10
- //area
- for (uint32_t i = 0; i < 4*MAX_RECTS; i++) {
+ // allocate 4x4 rects, which will fragment the atlas badly, because each entry occupies a 10x10
+ // area
+ for (uint32_t i = 0; i < 4 * MAX_RECTS; i++) {
AtlasEntry entry = atlas.requestNewEntry(4, 4, renderThread.getGrContext());
ASSERT_TRUE(entry.key != INVALID_ATLAS_KEY);
}
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 1c2156765fe6..a92cbfdf6757 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -33,195 +33,239 @@ struct TestData {
};
const static TestData sTestDataSet[] = {
- // TestData with scientific notation -2e3 etc.
- {
- // Path
- "M2.000000,22.000000l20.000000,0.000000 1e0-2e3z",
- {
- // Verbs
- {'M', 'l', 'z'},
- // Verb sizes
- {2, 4, 0},
- // Points
- {2, 22, 20, 0, 1, -2000},
- },
- [](SkPath* outPath) {
- outPath->moveTo(2, 22);
- outPath->rLineTo(20, 0);
- outPath->rLineTo(1, -2000);
- outPath->close();
- outPath->moveTo(2, 22);
- }
- },
-
- // Comprehensive data, containing all the verbs possible.
- {
- // Path
- "M 1 1 m 2 2, l 3 3 L 3 3 H 4 h4 V5 v5, Q6 6 6 6 q 6 6 6 6t 7 7 T 7 7 C 8 8 8 8 8 8 c 8 8 8 8 8 8 S 9 9 9 9 s 9 9 9 9 A 10 10 0 1 1 10 10 a 10 10 0 1 1 10 10",
- {
- // Verbs
- {'M', 'm', 'l', 'L', 'H', 'h', 'V', 'v', 'Q', 'q', 't', 'T', 'C', 'c', 'S', 's', 'A', 'a'},
- // VerbSizes
- {2, 2, 2, 2, 1, 1, 1, 1, 4, 4, 2, 2, 6, 6, 4, 4, 7, 7},
- // Points
- {1.0, 1.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 5.0, 5.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 7.0, 7.0, 7.0, 7.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 10.0, 10.0, 0.0, 1.0, 1.0, 10.0, 10.0, 10.0, 10.0, 0.0, 1.0, 1.0, 10.0, 10.0, }
- },
- [](SkPath* outPath) {
- outPath->moveTo(1.0, 1.0);
- outPath->rMoveTo(2.0, 2.0);
- outPath->rLineTo(3.0, 3.0);
- outPath->lineTo(3.0, 3.0);
- outPath->lineTo(4.0, 3.0);
- outPath->rLineTo(4.0, 0);
- outPath->lineTo(8.0, 5.0);
- outPath->rLineTo(0, 5.0);
- outPath->quadTo(6.0, 6.0, 6.0, 6.0);
- outPath->rQuadTo(6.0, 6.0, 6.0, 6.0);
- outPath->rQuadTo(0.0, 0.0, 7.0, 7.0);
- outPath->quadTo(26.0, 26.0, 7.0, 7.0);
- outPath->cubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0);
- 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);
- }
- },
-
- // Check box VectorDrawable path data
- {
- // Path
- "M 0.0,-1.0 l 0.0,0.0 c 0.5522847498,0.0 1.0,0.4477152502 1.0,1.0 l 0.0,0.0 c 0.0,0.5522847498 -0.4477152502,1.0 -1.0,1.0 l 0.0,0.0 c -0.5522847498,0.0 -1.0,-0.4477152502 -1.0,-1.0 l 0.0,0.0 c 0.0,-0.5522847498 0.4477152502,-1.0 1.0,-1.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z",
- {
- {'M', 'l', 'c', 'l', 'c', 'l', 'c', 'l', 'c', 'Z', 'M', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'Z'},
- {2, 2, 6, 2, 6, 2, 6, 2, 6, 0, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0},
- {0.0, -1.0, 0.0, 0.0, 0.5522848, 0.0, 1.0, 0.44771525, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5522848, -0.44771525, 1.0, -1.0, 1.0, 0.0, 0.0, -0.5522848, 0.0, -1.0, -0.44771525, -1.0, -1.0, 0.0, 0.0, 0.0, -0.5522848, 0.44771525, -1.0, 1.0, -1.0, 7.0, -9.0, 0.0, 0.0, -14.0, 0.0, -14.0, 0.0, -1.1044922, 0.0, -2.0, 0.8955078, -2.0, 2.0, 0.0, 0.0, 0.0, 14.0, 0.0, 14.0, 0.0, 1.1044922, 0.8955078, 2.0, 2.0, 2.0, 0.0, 0.0, 14.0, 0.0, 14.0, 0.0, 1.1044922, 0.0, 2.0, -0.8955078, 2.0, -2.0, 0.0, 0.0, 0.0, -14.0, 0.0, -14.0, 0.0, -1.1044922, -0.8955078, -2.0, -2.0, -2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
- },
- [](SkPath* outPath) {
- outPath->moveTo(0.0, -1.0);
- outPath->rLineTo(0.0, 0.0);
- outPath->rCubicTo(0.5522848, 0.0, 1.0, 0.44771525, 1.0, 1.0);
- outPath->rLineTo(0.0, 0.0);
- outPath->rCubicTo(0.0, 0.5522848, -0.44771525, 1.0, -1.0, 1.0);
- outPath->rLineTo(0.0, 0.0);
- outPath->rCubicTo(-0.5522848, 0.0, -1.0, -0.44771525, -1.0, -1.0);
- outPath->rLineTo(0.0, 0.0);
- outPath->rCubicTo(0.0, -0.5522848, 0.44771525, -1.0, 1.0, -1.0);
- outPath->close();
- outPath->moveTo(0.0, -1.0);
- outPath->moveTo(7.0, -9.0);
- outPath->rCubicTo(0.0, 0.0, -14.0, 0.0, -14.0, 0.0);
- outPath->rCubicTo(-1.1044922, 0.0, -2.0, 0.8955078, -2.0, 2.0);
- outPath->rCubicTo(0.0, 0.0, 0.0, 14.0, 0.0, 14.0);
- outPath->rCubicTo(0.0, 1.1044922, 0.8955078, 2.0, 2.0, 2.0);
- outPath->rCubicTo(0.0, 0.0, 14.0, 0.0, 14.0, 0.0);
- outPath->rCubicTo(1.1044922, 0.0, 2.0, -0.8955078, 2.0, -2.0);
- outPath->rCubicTo(0.0, 0.0, 0.0, -14.0, 0.0, -14.0);
- outPath->rCubicTo(0.0, -1.1044922, -0.8955078, -2.0, -2.0, -2.0);
- outPath->rCubicTo(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
- outPath->close();
- outPath->moveTo(7.0, -9.0);
- }
- },
-
- // pie1 in progress bar
- {
- "M300,70 a230,230 0 1,0 1,0 z",
- {
- {'M', 'a', 'z', },
- {2, 7, 0, },
- {300.0, 70.0, 230.0, 230.0, 0.0, 1.0, 0.0, 1.0, 0.0, },
- },
- [](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->close();
- outPath->moveTo(300.0, 70.0);
- }
- },
-
- // Random long data
- {
- // Path
- "M5.3,13.2c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,-0.2 -0.4,-0.7 -0.2,-1.0c1.3,-1.9 2.9,-3.4 4.9,-4.5c4.1,-2.2 9.3,-2.2 13.4,0.0c1.9,1.1 3.6,2.5 4.9,4.4c0.2,0.3 0.1,0.8 -0.2,1.0c-0.3,0.2 -0.8,0.1 -1.0,-0.2c-1.2,-1.7 -2.6,-3.0 -4.3,-4.0c-3.7,-2.0 -8.3,-2.0 -12.0,0.0c-1.7,0.9 -3.2,2.3 -4.3,4.0C5.7,13.1 5.5,13.2 5.3,13.2z",
- {
- // Verbs
- {'M', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'C', 'z'},
- // Verb sizes
- {2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0},
- // Points
- {5.3, 13.2, -0.1, 0, -0.3, 0, -0.4, -0.1, -0.3, -0.2, -0.4, -0.7, -0.2, -1, 1.3, -1.9, 2.9, -3.4, 4.9, -4.5, 4.1, -2.2, 9.3, -2.2, 13.4, 0, 1.9, 1.1, 3.6, 2.5, 4.9, 4.4, 0.2, 0.3, 0.1, 0.8, -0.2, 1, -0.3, 0.2, -0.8, 0.1, -1, -0.2, -1.2, -1.7, -2.6, -3, -4.3, -4, -3.7, -2, -8.3, -2, -12, 0, -1.7, 0.9, -3.2, 2.3, -4.3, 4, 5.7, 13.1, 5.5, 13.2, 5.3, 13.2},
- },
- [](SkPath* outPath) {
- outPath->moveTo(5.3, 13.2);
- outPath->rCubicTo(-0.1, 0.0, -0.3, 0.0, -0.4, -0.1);
- outPath->rCubicTo(-0.3, -0.2, -0.4, -0.7, -0.2, -1.0);
- outPath->rCubicTo(1.3, -1.9, 2.9, -3.4, 4.9, -4.5);
- outPath->rCubicTo(4.1, -2.2, 9.3, -2.2, 13.4, 0.0);
- outPath->rCubicTo(1.9, 1.1, 3.6, 2.5, 4.9, 4.4);
- outPath->rCubicTo(0.2, 0.3, 0.1, 0.8, -0.2, 1.0);
- outPath->rCubicTo(-0.3, 0.2, -0.8, 0.1, -1.0, -0.2);
- outPath->rCubicTo(-1.2, -1.7, -2.6, -3.0, -4.3, -4.0);
- outPath->rCubicTo(-3.7, -2.0, -8.3, -2.0, -12.0, 0.0);
- outPath->rCubicTo(-1.7, 0.9, -3.2, 2.3, -4.3, 4.0);
- outPath->cubicTo(5.7, 13.1, 5.5, 13.2, 5.3, 13.2);
- outPath->close();
- outPath->moveTo(5.3, 13.2);
- }
- },
-
- // Extreme case with numbers and decimal points crunched together
- {
- // Path
- "l0.0.0.5.0.0.5-0.5.0.0-.5z",
- {
- // Verbs
- {'l', 'z'},
- // Verb sizes
- {10, 0},
- // Points
- {0, 0, 0.5, 0, 0, 0.5, -0.5, 0, 0, -0.5},
- },
- [](SkPath* outPath) {
- outPath->rLineTo(0.0, 0.0);
- outPath->rLineTo(0.5, 0.0);
- outPath->rLineTo(0.0, 0.5);
- outPath->rLineTo(-0.5, 0.0);
- outPath->rLineTo(0.0, -0.5);
- outPath->close();
- outPath->moveTo(0.0, 0.0);
- }
- },
-
- // Empty test data
- {
- "",
- {
- // Verbs
- {},
- {},
- {},
- },
- [](SkPath* outPath) {}
- }
+ // TestData with scientific notation -2e3 etc.
+ {// Path
+ "M2.000000,22.000000l20.000000,0.000000 1e0-2e3z",
+ {
+ // Verbs
+ {'M', 'l', 'z'},
+ // Verb sizes
+ {2, 4, 0},
+ // Points
+ {2, 22, 20, 0, 1, -2000},
+ },
+ [](SkPath* outPath) {
+ outPath->moveTo(2, 22);
+ outPath->rLineTo(20, 0);
+ outPath->rLineTo(1, -2000);
+ outPath->close();
+ outPath->moveTo(2, 22);
+ }},
+
+ // Comprehensive data, containing all the verbs possible.
+ {// Path
+ "M 1 1 m 2 2, l 3 3 L 3 3 H 4 h4 V5 v5, Q6 6 6 6 q 6 6 6 6t 7 7 T 7 7 C 8 8 8 8 8 8 c 8 8 "
+ "8 8 8 8 S 9 9 9 9 s 9 9 9 9 A 10 10 0 1 1 10 10 a 10 10 0 1 1 10 10",
+ {// Verbs
+ {'M', 'm', 'l', 'L', 'H', 'h', 'V', 'v', 'Q', 'q', 't', 'T', 'C', 'c', 'S', 's', 'A',
+ 'a'},
+ // VerbSizes
+ {2, 2, 2, 2, 1, 1, 1, 1, 4, 4, 2, 2, 6, 6, 4, 4, 7, 7},
+ // Points
+ {
+ 1.0, 1.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 5.0, 5.0, 6.0, 6.0, 6.0,
+ 6.0, 6.0, 6.0, 6.0, 6.0, 7.0, 7.0, 7.0, 7.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0,
+ 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 10.0,
+ 10.0, 0.0, 1.0, 1.0, 10.0, 10.0, 10.0, 10.0, 0.0, 1.0, 1.0, 10.0, 10.0,
+ }},
+ [](SkPath* outPath) {
+ outPath->moveTo(1.0, 1.0);
+ outPath->rMoveTo(2.0, 2.0);
+ outPath->rLineTo(3.0, 3.0);
+ outPath->lineTo(3.0, 3.0);
+ outPath->lineTo(4.0, 3.0);
+ outPath->rLineTo(4.0, 0);
+ outPath->lineTo(8.0, 5.0);
+ outPath->rLineTo(0, 5.0);
+ outPath->quadTo(6.0, 6.0, 6.0, 6.0);
+ outPath->rQuadTo(6.0, 6.0, 6.0, 6.0);
+ outPath->rQuadTo(0.0, 0.0, 7.0, 7.0);
+ outPath->quadTo(26.0, 26.0, 7.0, 7.0);
+ outPath->cubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0);
+ 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);
+ }},
+
+ // Check box VectorDrawable path data
+ {// Path
+ "M 0.0,-1.0 l 0.0,0.0 c 0.5522847498,0.0 1.0,0.4477152502 1.0,1.0 l 0.0,0.0 c "
+ "0.0,0.5522847498 -0.4477152502,1.0 -1.0,1.0 l 0.0,0.0 c -0.5522847498,0.0 "
+ "-1.0,-0.4477152502 -1.0,-1.0 l 0.0,0.0 c 0.0,-0.5522847498 0.4477152502,-1.0 1.0,-1.0 Z "
+ "M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 "
+ "c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 "
+ "14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 "
+ "0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z",
+ {
+ {'M', 'l', 'c', 'l', 'c', 'l', 'c', 'l', 'c', 'Z', 'M',
+ 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'Z'},
+ {2, 2, 6, 2, 6, 2, 6, 2, 6, 0, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0},
+ {0.0, -1.0, 0.0, 0.0, 0.5522848, 0.0, 1.0,
+ 0.44771525, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5522848,
+ -0.44771525, 1.0, -1.0, 1.0, 0.0, 0.0, -0.5522848,
+ 0.0, -1.0, -0.44771525, -1.0, -1.0, 0.0, 0.0,
+ 0.0, -0.5522848, 0.44771525, -1.0, 1.0, -1.0, 7.0,
+ -9.0, 0.0, 0.0, -14.0, 0.0, -14.0, 0.0,
+ -1.1044922, 0.0, -2.0, 0.8955078, -2.0, 2.0, 0.0,
+ 0.0, 0.0, 14.0, 0.0, 14.0, 0.0, 1.1044922,
+ 0.8955078, 2.0, 2.0, 2.0, 0.0, 0.0, 14.0,
+ 0.0, 14.0, 0.0, 1.1044922, 0.0, 2.0, -0.8955078,
+ 2.0, -2.0, 0.0, 0.0, 0.0, -14.0, 0.0,
+ -14.0, 0.0, -1.1044922, -0.8955078, -2.0, -2.0, -2.0,
+ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+ },
+ [](SkPath* outPath) {
+ outPath->moveTo(0.0, -1.0);
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rCubicTo(0.5522848, 0.0, 1.0, 0.44771525, 1.0, 1.0);
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rCubicTo(0.0, 0.5522848, -0.44771525, 1.0, -1.0, 1.0);
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rCubicTo(-0.5522848, 0.0, -1.0, -0.44771525, -1.0, -1.0);
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rCubicTo(0.0, -0.5522848, 0.44771525, -1.0, 1.0, -1.0);
+ outPath->close();
+ outPath->moveTo(0.0, -1.0);
+ outPath->moveTo(7.0, -9.0);
+ outPath->rCubicTo(0.0, 0.0, -14.0, 0.0, -14.0, 0.0);
+ outPath->rCubicTo(-1.1044922, 0.0, -2.0, 0.8955078, -2.0, 2.0);
+ outPath->rCubicTo(0.0, 0.0, 0.0, 14.0, 0.0, 14.0);
+ outPath->rCubicTo(0.0, 1.1044922, 0.8955078, 2.0, 2.0, 2.0);
+ outPath->rCubicTo(0.0, 0.0, 14.0, 0.0, 14.0, 0.0);
+ outPath->rCubicTo(1.1044922, 0.0, 2.0, -0.8955078, 2.0, -2.0);
+ outPath->rCubicTo(0.0, 0.0, 0.0, -14.0, 0.0, -14.0);
+ outPath->rCubicTo(0.0, -1.1044922, -0.8955078, -2.0, -2.0, -2.0);
+ outPath->rCubicTo(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+ outPath->close();
+ outPath->moveTo(7.0, -9.0);
+ }},
+
+ // pie1 in progress bar
+ {"M300,70 a230,230 0 1,0 1,0 z",
+ {
+ {
+ 'M', 'a', 'z',
+ },
+ {
+ 2, 7, 0,
+ },
+ {
+ 300.0, 70.0, 230.0, 230.0, 0.0, 1.0, 0.0, 1.0, 0.0,
+ },
+ },
+ [](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->close();
+ outPath->moveTo(300.0, 70.0);
+ }},
+
+ // Random long data
+ {// Path
+ "M5.3,13.2c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,-0.2 -0.4,-0.7 -0.2,-1.0c1.3,-1.9 2.9,-3.4 "
+ "4.9,-4.5c4.1,-2.2 9.3,-2.2 13.4,0.0c1.9,1.1 3.6,2.5 4.9,4.4c0.2,0.3 0.1,0.8 "
+ "-0.2,1.0c-0.3,0.2 -0.8,0.1 -1.0,-0.2c-1.2,-1.7 -2.6,-3.0 -4.3,-4.0c-3.7,-2.0 -8.3,-2.0 "
+ "-12.0,0.0c-1.7,0.9 -3.2,2.3 -4.3,4.0C5.7,13.1 5.5,13.2 5.3,13.2z",
+ {
+ // Verbs
+ {'M', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'C', 'z'},
+ // Verb sizes
+ {2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0},
+ // Points
+ {5.3, 13.2, -0.1, 0, -0.3, 0, -0.4, -0.1, -0.3, -0.2, -0.4, -0.7, -0.2, -1,
+ 1.3, -1.9, 2.9, -3.4, 4.9, -4.5, 4.1, -2.2, 9.3, -2.2, 13.4, 0, 1.9, 1.1,
+ 3.6, 2.5, 4.9, 4.4, 0.2, 0.3, 0.1, 0.8, -0.2, 1, -0.3, 0.2, -0.8, 0.1,
+ -1, -0.2, -1.2, -1.7, -2.6, -3, -4.3, -4, -3.7, -2, -8.3, -2, -12, 0,
+ -1.7, 0.9, -3.2, 2.3, -4.3, 4, 5.7, 13.1, 5.5, 13.2, 5.3, 13.2},
+ },
+ [](SkPath* outPath) {
+ outPath->moveTo(5.3, 13.2);
+ outPath->rCubicTo(-0.1, 0.0, -0.3, 0.0, -0.4, -0.1);
+ outPath->rCubicTo(-0.3, -0.2, -0.4, -0.7, -0.2, -1.0);
+ outPath->rCubicTo(1.3, -1.9, 2.9, -3.4, 4.9, -4.5);
+ outPath->rCubicTo(4.1, -2.2, 9.3, -2.2, 13.4, 0.0);
+ outPath->rCubicTo(1.9, 1.1, 3.6, 2.5, 4.9, 4.4);
+ outPath->rCubicTo(0.2, 0.3, 0.1, 0.8, -0.2, 1.0);
+ outPath->rCubicTo(-0.3, 0.2, -0.8, 0.1, -1.0, -0.2);
+ outPath->rCubicTo(-1.2, -1.7, -2.6, -3.0, -4.3, -4.0);
+ outPath->rCubicTo(-3.7, -2.0, -8.3, -2.0, -12.0, 0.0);
+ outPath->rCubicTo(-1.7, 0.9, -3.2, 2.3, -4.3, 4.0);
+ outPath->cubicTo(5.7, 13.1, 5.5, 13.2, 5.3, 13.2);
+ outPath->close();
+ outPath->moveTo(5.3, 13.2);
+ }},
+
+ // Extreme case with numbers and decimal points crunched together
+ {// Path
+ "l0.0.0.5.0.0.5-0.5.0.0-.5z",
+ {
+ // Verbs
+ {'l', 'z'},
+ // Verb sizes
+ {10, 0},
+ // Points
+ {0, 0, 0.5, 0, 0, 0.5, -0.5, 0, 0, -0.5},
+ },
+ [](SkPath* outPath) {
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rLineTo(0.5, 0.0);
+ outPath->rLineTo(0.0, 0.5);
+ outPath->rLineTo(-0.5, 0.0);
+ outPath->rLineTo(0.0, -0.5);
+ outPath->close();
+ outPath->moveTo(0.0, 0.0);
+ }},
+
+ // Empty test data
+ {"",
+ {
+ // Verbs
+ {},
+ {},
+ {},
+ },
+ [](SkPath* outPath) {}}
};
@@ -231,22 +275,21 @@ struct StringPath {
};
const StringPath sStringPaths[] = {
- {"3e...3", false}, // Not starting with a verb and ill-formatted float
- {"L.M.F.A.O", false}, // No floats following verbs
- {"m 1 1", true}, // Valid path data
- {"\n \t z", true}, // Valid path data with leading spaces
- {"1-2e34567", false}, // Not starting with a verb and ill-formatted float
- {"f 4 5", false}, // Invalid verb
- {"\r ", false} // Empty string
+ {"3e...3", false}, // Not starting with a verb and ill-formatted float
+ {"L.M.F.A.O", false}, // No floats following verbs
+ {"m 1 1", true}, // Valid path data
+ {"\n \t z", true}, // Valid path data with leading spaces
+ {"1-2e34567", false}, // Not starting with a verb and ill-formatted float
+ {"f 4 5", false}, // Invalid verb
+ {"\r ", false} // Empty string
};
-
static bool hasSameVerbs(const PathData& from, const PathData& to) {
return from.verbs == to.verbs && from.verbSizes == to.verbSizes;
}
TEST(PathParser, parseStringForData) {
- for (TestData testData: sTestDataSet) {
+ for (TestData testData : sTestDataSet) {
PathParser::ParseResult result;
// Test generated path data against the given data.
PathData pathData;
@@ -259,14 +302,14 @@ TEST(PathParser, parseStringForData) {
PathParser::ParseResult result;
PathData pathData;
SkPath skPath;
- PathParser::getPathDataFromAsciiString(&pathData, &result,
- stringPath.stringPath, strlen(stringPath.stringPath));
+ PathParser::getPathDataFromAsciiString(&pathData, &result, stringPath.stringPath,
+ strlen(stringPath.stringPath));
EXPECT_EQ(stringPath.isValid, !result.failureOccurred);
}
}
TEST(VectorDrawableUtils, createSkPathFromPathData) {
- for (TestData testData: sTestDataSet) {
+ for (TestData testData : sTestDataSet) {
SkPath expectedPath;
testData.skPathLamda(&expectedPath);
SkPath actualPath;
@@ -276,7 +319,7 @@ TEST(VectorDrawableUtils, createSkPathFromPathData) {
}
TEST(PathParser, parseAsciiStringForSkPath) {
- for (TestData testData: sTestDataSet) {
+ for (TestData testData : sTestDataSet) {
PathParser::ParseResult result;
size_t length = strlen(testData.pathString);
// Check the return value as well as the SkPath generated.
@@ -293,14 +336,14 @@ TEST(PathParser, parseAsciiStringForSkPath) {
PathParser::ParseResult result;
SkPath skPath;
PathParser::parseAsciiStringForSkPath(&skPath, &result, stringPath.stringPath,
- strlen(stringPath.stringPath));
+ strlen(stringPath.stringPath));
EXPECT_EQ(stringPath.isValid, !result.failureOccurred);
}
}
TEST(VectorDrawableUtils, morphPathData) {
- for (TestData fromData: sTestDataSet) {
- for (TestData toData: sTestDataSet) {
+ for (TestData fromData : sTestDataSet) {
+ for (TestData toData : sTestDataSet) {
bool canMorph = VectorDrawableUtils::canMorph(fromData.pathData, toData.pathData);
if (fromData.pathData == toData.pathData) {
EXPECT_TRUE(canMorph);
@@ -314,11 +357,11 @@ TEST(VectorDrawableUtils, morphPathData) {
TEST(VectorDrawableUtils, interpolatePathData) {
// Interpolate path data with itself and every other path data
- for (TestData fromData: sTestDataSet) {
- for (TestData toData: sTestDataSet) {
+ for (TestData fromData : sTestDataSet) {
+ for (TestData toData : sTestDataSet) {
PathData outData;
bool success = VectorDrawableUtils::interpolatePathData(&outData, fromData.pathData,
- toData.pathData, 0.5);
+ toData.pathData, 0.5);
bool expectedToMorph = hasSameVerbs(fromData.pathData, toData.pathData);
EXPECT_EQ(expectedToMorph, success);
}
@@ -335,12 +378,12 @@ TEST(VectorDrawableUtils, interpolatePathData) {
PathData outData;
// Interpolate the two path data with different fractions
for (float fraction : fractions) {
- bool success = VectorDrawableUtils::interpolatePathData(
- &outData, fromPathData, toPathData, fraction);
+ bool success = VectorDrawableUtils::interpolatePathData(&outData, fromPathData,
+ toPathData, fraction);
EXPECT_TRUE(success);
for (size_t i = 0; i < outData.points.size(); i++) {
- float expectedResult = fromPathData.points[i] * (1.0 - fraction) +
- toPathData.points[i] * fraction;
+ float expectedResult =
+ fromPathData.points[i] * (1.0 - fraction) + toPathData.points[i] * fraction;
EXPECT_TRUE(MathUtils::areEqual(expectedResult, outData.points[i]));
}
}
@@ -348,7 +391,7 @@ TEST(VectorDrawableUtils, interpolatePathData) {
}
TEST(VectorDrawable, groupProperties) {
- //TODO: Also need to test property sync and dirty flag when properties change.
+ // TODO: Also need to test property sync and dirty flag when properties change.
VectorDrawable::Group group;
VectorDrawable::Group::GroupProperties* properties = group.mutateProperties();
// Test default values, change values through setters and verify the change through getters.
@@ -379,7 +422,6 @@ TEST(VectorDrawable, groupProperties) {
EXPECT_EQ(0.0f, properties->getPivotY());
properties->setPivotY(1.0f);
EXPECT_EQ(1.0f, properties->getPivotY());
-
}
TEST(VectorDrawable, drawPathWithoutIncrementingShaderRefCount) {
@@ -402,5 +444,5 @@ TEST(VectorDrawable, drawPathWithoutIncrementingShaderRefCount) {
EXPECT_TRUE(shader->unique());
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp
index cea84c057b63..406255d61d25 100644
--- a/libs/hwui/tests/unit/main.cpp
+++ b/libs/hwui/tests/unit/main.cpp
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-#include "gtest/gtest.h"
#include "gmock/gmock.h"
+#include "gtest/gtest.h"
#include "Caches.h"
#include "debug/GlesDriver.h"
#include "debug/NullGlesDriver.h"
#include "hwui/Typeface.h"
-#include "thread/TaskManager.h"
#include "tests/common/LeakChecker.h"
+#include "thread/TaskManager.h"
#include <signal.h>
@@ -31,17 +31,14 @@ using namespace android;
using namespace android::uirenderer;
static auto CRASH_SIGNALS = {
- SIGABRT,
- SIGSEGV,
- SIGBUS,
+ SIGABRT, SIGSEGV, SIGBUS,
};
static map<int, struct sigaction> gSigChain;
static void gtestSigHandler(int sig, siginfo_t* siginfo, void* context) {
auto testinfo = ::testing::UnitTest::GetInstance()->current_test_info();
- printf("[ FAILED ] %s.%s\n", testinfo->test_case_name(),
- testinfo->name());
+ printf("[ FAILED ] %s.%s\n", testinfo->test_case_name(), testinfo->name());
printf("[ FATAL! ] Process crashed, aborting tests!\n");
fflush(stdout);
@@ -53,9 +50,7 @@ static void gtestSigHandler(int sig, siginfo_t* siginfo, void* context) {
class TypefaceEnvironment : public testing::Environment {
public:
- virtual void SetUp() {
- Typeface::setRobotoTypefaceForTest();
- }
+ virtual void SetUp() { Typeface::setRobotoTypefaceForTest(); }
};
int main(int argc, char* argv[]) {
@@ -83,4 +78,3 @@ int main(int argc, char* argv[]) {
test::LeakChecker::checkForLeaks();
return ret;
}
-
diff --git a/libs/hwui/thread/Barrier.h b/libs/hwui/thread/Barrier.h
index 17f82ba9d67d..8faeee6b391a 100644
--- a/libs/hwui/thread/Barrier.h
+++ b/libs/hwui/thread/Barrier.h
@@ -24,8 +24,9 @@ namespace uirenderer {
class Barrier {
public:
- explicit Barrier(Condition::WakeUpType type = Condition::WAKE_UP_ALL) : mType(type), mOpened(false) { }
- ~Barrier() { }
+ explicit Barrier(Condition::WakeUpType type = Condition::WAKE_UP_ALL)
+ : mType(type), mOpened(false) {}
+ ~Barrier() {}
void open() {
Mutex::Autolock l(mLock);
@@ -47,7 +48,7 @@ private:
mutable Condition mCondition;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_BARRIER_H
+#endif // ANDROID_HWUI_BARRIER_H
diff --git a/libs/hwui/thread/Future.h b/libs/hwui/thread/Future.h
index 177eebd9b85f..45f3102492e3 100644
--- a/libs/hwui/thread/Future.h
+++ b/libs/hwui/thread/Future.h
@@ -24,11 +24,12 @@
namespace android {
namespace uirenderer {
-template<typename T>
-class Future: public LightRefBase<Future<T> > {
+template <typename T>
+class Future : public LightRefBase<Future<T> > {
public:
- explicit Future(Condition::WakeUpType type = Condition::WAKE_UP_ONE): mBarrier(type), mResult() { }
- ~Future() { }
+ explicit Future(Condition::WakeUpType type = Condition::WAKE_UP_ONE)
+ : mBarrier(type), mResult() {}
+ ~Future() {}
/**
* Returns the result of this future, blocking if
@@ -52,7 +53,7 @@ private:
T mResult;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_FUTURE_H
+#endif // ANDROID_HWUI_FUTURE_H
diff --git a/libs/hwui/thread/Signal.h b/libs/hwui/thread/Signal.h
index 93e6f4c27535..ffcd4b675a85 100644
--- a/libs/hwui/thread/Signal.h
+++ b/libs/hwui/thread/Signal.h
@@ -26,8 +26,9 @@ namespace uirenderer {
class Signal {
public:
- explicit Signal(Condition::WakeUpType type = Condition::WAKE_UP_ALL) : mType(type), mSignaled(false) { }
- ~Signal() { }
+ explicit Signal(Condition::WakeUpType type = Condition::WAKE_UP_ALL)
+ : mType(type), mSignaled(false) {}
+ ~Signal() {}
void signal() {
{
@@ -52,7 +53,7 @@ private:
mutable Condition mCondition;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_SIGNAL_H
+#endif // ANDROID_HWUI_SIGNAL_H
diff --git a/libs/hwui/thread/Task.h b/libs/hwui/thread/Task.h
index 7fcf5931c4b4..276a22f941fe 100644
--- a/libs/hwui/thread/Task.h
+++ b/libs/hwui/thread/Task.h
@@ -25,36 +25,30 @@
namespace android {
namespace uirenderer {
-class TaskBase: public RefBase {
+class TaskBase : public RefBase {
public:
- TaskBase() { }
- virtual ~TaskBase() { }
+ TaskBase() {}
+ virtual ~TaskBase() {}
};
-template<typename T>
-class Task: public TaskBase {
+template <typename T>
+class Task : public TaskBase {
public:
- Task(): mFuture(new Future<T>()) { }
- virtual ~Task() { }
+ Task() : mFuture(new Future<T>()) {}
+ virtual ~Task() {}
- T getResult() const {
- return mFuture->get();
- }
+ T getResult() const { return mFuture->get(); }
- void setResult(T result) {
- mFuture->produce(result);
- }
+ void setResult(T result) { mFuture->produce(result); }
protected:
- const sp<Future<T> >& future() const {
- return mFuture;
- }
+ const sp<Future<T> >& future() const { return mFuture; }
private:
sp<Future<T> > mFuture;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_TASK_H
+#endif // ANDROID_HWUI_TASK_H
diff --git a/libs/hwui/thread/TaskManager.cpp b/libs/hwui/thread/TaskManager.cpp
index d346b859526e..54b55e472095 100644
--- a/libs/hwui/thread/TaskManager.cpp
+++ b/libs/hwui/thread/TaskManager.cpp
@@ -17,8 +17,8 @@
#include <sys/resource.h>
#include <sys/sysinfo.h>
-#include "TaskManager.h"
#include "Task.h"
+#include "TaskManager.h"
#include "TaskProcessor.h"
#include "utils/MathUtils.h"
@@ -129,5 +129,5 @@ void TaskManager::WorkerThread::exit() {
mSignal.signal();
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/thread/TaskManager.h b/libs/hwui/thread/TaskManager.h
index c9d12bc6044b..29b4fcdbfde9 100644
--- a/libs/hwui/thread/TaskManager.h
+++ b/libs/hwui/thread/TaskManager.h
@@ -58,7 +58,7 @@ private:
template <typename T>
friend class TaskProcessor;
- template<typename T>
+ template <typename T>
bool addTask(const sp<Task<T> >& task, const sp<TaskProcessor<T> >& processor) {
return addTaskBase(sp<TaskBase>(task), sp<TaskProcessorBase>(processor));
}
@@ -66,19 +66,18 @@ private:
bool addTaskBase(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor);
struct TaskWrapper {
- TaskWrapper(): mTask(), mProcessor() { }
+ TaskWrapper() : mTask(), mProcessor() {}
- TaskWrapper(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor):
- mTask(task), mProcessor(processor) {
- }
+ TaskWrapper(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor)
+ : mTask(task), mProcessor(processor) {}
sp<TaskBase> mTask;
sp<TaskProcessorBase> mProcessor;
};
- class WorkerThread: public Thread {
+ class WorkerThread : public Thread {
public:
- explicit WorkerThread(const String8& name): mSignal(Condition::WAKE_UP_ONE), mName(name) { }
+ explicit WorkerThread(const String8& name) : mSignal(Condition::WAKE_UP_ONE), mName(name) {}
bool addTask(const TaskWrapper& task);
size_t getTaskCount() const;
@@ -102,7 +101,7 @@ private:
std::vector<sp<WorkerThread> > mThreads;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_TASK_MANAGER_H
+#endif // ANDROID_HWUI_TASK_MANAGER_H
diff --git a/libs/hwui/thread/TaskProcessor.h b/libs/hwui/thread/TaskProcessor.h
index 58674505c457..8117ae6409c4 100644
--- a/libs/hwui/thread/TaskProcessor.h
+++ b/libs/hwui/thread/TaskProcessor.h
@@ -25,19 +25,19 @@
namespace android {
namespace uirenderer {
-class TaskProcessorBase: public RefBase {
+class TaskProcessorBase : public RefBase {
public:
- TaskProcessorBase() { }
- virtual ~TaskProcessorBase() { };
+ TaskProcessorBase() {}
+ virtual ~TaskProcessorBase(){};
virtual void process(const sp<TaskBase>& task) = 0;
};
-template<typename T>
-class TaskProcessor: public TaskProcessorBase {
+template <typename T>
+class TaskProcessor : public TaskProcessorBase {
public:
- explicit TaskProcessor(TaskManager* manager): mManager(manager) { }
- virtual ~TaskProcessor() { }
+ explicit TaskProcessor(TaskManager* manager) : mManager(manager) {}
+ virtual ~TaskProcessor() {}
void add(const sp<Task<T> >& task) {
if (!addImpl(task)) {
@@ -52,7 +52,7 @@ private:
bool addImpl(const sp<Task<T> >& task);
virtual void process(const sp<TaskBase>& task) override {
- sp<Task<T> > realTask = static_cast<Task<T>* >(task.get());
+ sp<Task<T> > realTask = static_cast<Task<T>*>(task.get());
// This is the right way to do it but sp<> doesn't play nice
// sp<Task<T> > realTask = static_cast<sp<Task<T> > >(task);
onProcess(realTask);
@@ -61,7 +61,7 @@ private:
TaskManager* mManager;
};
-template<typename T>
+template <typename T>
bool TaskProcessor<T>::addImpl(const sp<Task<T> >& task) {
if (mManager) {
sp<TaskProcessor<T> > self(this);
@@ -70,7 +70,7 @@ bool TaskProcessor<T>::addImpl(const sp<Task<T> >& task) {
return false;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_TASK_PROCESSOR_H
+#endif // ANDROID_HWUI_TASK_PROCESSOR_H
diff --git a/libs/hwui/thread/ThreadBase.h b/libs/hwui/thread/ThreadBase.h
index 402fd1efca9a..b3fec1fb36c3 100644
--- a/libs/hwui/thread/ThreadBase.h
+++ b/libs/hwui/thread/ThreadBase.h
@@ -31,10 +31,7 @@ class ThreadBase : protected Thread {
PREVENT_COPY_AND_ASSIGN(ThreadBase);
public:
- ThreadBase()
- : mLooper(new Looper(false))
- , mQueue([this](){ mLooper->wake(); }, mLock)
- {}
+ ThreadBase() : mLooper(new Looper(false)), mQueue([this]() { mLooper->wake(); }, mLock) {}
WorkQueue& queue() { return mQueue; }
@@ -43,13 +40,9 @@ public:
mLooper->wake();
}
- void start(const char* name = "ThreadBase") {
- Thread::run(name);
- }
+ void start(const char* name = "ThreadBase") { Thread::run(name); }
- void join() {
- Thread::join();
- }
+ void join() { Thread::join(); }
protected:
void waitForWork() {
@@ -64,13 +57,10 @@ protected:
if (timeout < 0) timeout = 0;
}
int result = mLooper->pollOnce(timeout);
- LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR,
- "RenderThread Looper POLL_ERROR!");
+ LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR, "RenderThread Looper POLL_ERROR!");
}
- void processQueue() {
- mQueue.process();
- }
+ void processQueue() { mQueue.process(); }
virtual bool threadLoop() override {
while (!exitPending()) {
@@ -87,7 +77,6 @@ private:
std::mutex mLock;
};
-} // namespace android::uirenderer
-
+} // namespace android::uirenderer
-#endif //HWUI_THREADBASE_H
+#endif // HWUI_THREADBASE_H
diff --git a/libs/hwui/thread/WorkQueue.h b/libs/hwui/thread/WorkQueue.h
index fbb24bb9b964..7a6e638e0568 100644
--- a/libs/hwui/thread/WorkQueue.h
+++ b/libs/hwui/thread/WorkQueue.h
@@ -37,6 +37,7 @@ struct MonotonicClock {
class WorkQueue {
PREVENT_COPY_AND_ASSIGN(WorkQueue);
+
public:
using clock = MonotonicClock;
@@ -57,8 +58,7 @@ private:
public:
WorkQueue(std::function<void()>&& wakeFunc, std::mutex& lock)
- : mWakeFunc(move(wakeFunc))
- , mLock(lock) {}
+ : mWakeFunc(move(wakeFunc)), mLock(lock) {}
void process() {
auto now = clock::now();
@@ -68,9 +68,7 @@ public:
if (mWorkQueue.empty()) return;
toProcess = std::move(mWorkQueue);
auto moveBack = find_if(std::begin(toProcess), std::end(toProcess),
- [&now](WorkItem& item) {
- return item.runAt > now;
- });
+ [&now](WorkItem& item) { return item.runAt > now; });
if (moveBack != std::end(toProcess)) {
mWorkQueue.reserve(std::distance(moveBack, std::end(toProcess)) + 5);
std::move(moveBack, std::end(toProcess), std::back_inserter(mWorkQueue));
@@ -82,22 +80,22 @@ public:
}
}
- template<class F>
+ template <class F>
void postAt(nsecs_t time, F&& func) {
enqueue(WorkItem{time, std::function<void()>(std::forward<F>(func))});
}
- template<class F>
+ template <class F>
void postDelayed(nsecs_t delay, F&& func) {
enqueue(WorkItem{clock::now() + delay, std::function<void()>(std::forward<F>(func))});
}
- template<class F>
+ template <class F>
void post(F&& func) {
postAt(0, std::forward<F>(func));
}
- template<class F>
+ template <class F>
auto async(F&& func) -> std::future<decltype(func())> {
typedef std::packaged_task<decltype(func())()> task_t;
auto task = std::make_shared<task_t>(std::forward<F>(func));
@@ -105,14 +103,14 @@ public:
return task->get_future();
}
- template<class F>
+ template <class F>
auto runSync(F&& func) -> decltype(func()) {
std::packaged_task<decltype(func())()> task{std::forward<F>(func)};
post([&task]() { std::invoke(task); });
return task.get_future().get();
};
- nsecs_t nextWakeup(std::unique_lock<std::mutex> &lock) {
+ nsecs_t nextWakeup(std::unique_lock<std::mutex>& lock) {
if (mWorkQueue.empty()) {
return std::numeric_limits<nsecs_t>::max();
} else {
@@ -125,10 +123,9 @@ private:
bool needsWakeup;
{
std::unique_lock _lock{mLock};
- auto insertAt = std::find_if(std::begin(mWorkQueue), std::end(mWorkQueue),
- [time = item.runAt](WorkItem& item) {
- return item.runAt > time;
- });
+ auto insertAt = std::find_if(
+ std::begin(mWorkQueue), std::end(mWorkQueue),
+ [time = item.runAt](WorkItem & item) { return item.runAt > time; });
needsWakeup = std::begin(mWorkQueue) == insertAt;
mWorkQueue.emplace(insertAt, std::move(item));
}
@@ -143,6 +140,6 @@ private:
std::vector<WorkItem> mWorkQueue;
};
-} // namespace android::uirenderer
+} // namespace android::uirenderer
-#endif //HWUI_WORKQUEUE_H
+#endif // HWUI_WORKQUEUE_H
diff --git a/libs/hwui/utils/Blur.cpp b/libs/hwui/utils/Blur.cpp
index 9b70765ee8ad..1bc5646993c9 100644
--- a/libs/hwui/utils/Blur.cpp
+++ b/libs/hwui/utils/Blur.cpp
@@ -38,7 +38,7 @@ float Blur::convertSigmaToRadius(float sigma) {
// is within the conversion error tolerance then we attempt to snap to the
// original integer boundary.
uint32_t Blur::convertRadiusToInt(float radius) {
- const float radiusCeil = ceilf(radius);
+ const float radiusCeil = ceilf(radius);
if (MathUtils::areEqual(radiusCeil, radius)) {
return radiusCeil;
}
@@ -75,46 +75,45 @@ void Blur::generateGaussianWeights(float* weights, float radius) {
// the blur calculations
// precompute some values
float coeff1 = 1.0f / (sqrt(2.0f * pi) * sigma);
- float coeff2 = - 1.0f / (2.0f * sigma * sigma);
+ float coeff2 = -1.0f / (2.0f * sigma * sigma);
float normalizeFactor = 0.0f;
- for (int32_t r = -intRadius; r <= intRadius; r ++) {
- float floatR = (float) r;
+ for (int32_t r = -intRadius; r <= intRadius; r++) {
+ float floatR = (float)r;
weights[r + intRadius] = coeff1 * pow(e, floatR * floatR * coeff2);
normalizeFactor += weights[r + intRadius];
}
- //Now we need to normalize the weights because all our coefficients need to add up to one
+ // Now we need to normalize the weights because all our coefficients need to add up to one
normalizeFactor = 1.0f / normalizeFactor;
- for (int32_t r = -intRadius; r <= intRadius; r ++) {
+ for (int32_t r = -intRadius; r <= intRadius; r++) {
weights[r + intRadius] *= normalizeFactor;
}
}
-void Blur::horizontal(float* weights, int32_t radius,
- const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
+void Blur::horizontal(float* weights, int32_t radius, const uint8_t* source, uint8_t* dest,
+ int32_t width, int32_t height) {
float blurredPixel = 0.0f;
float currentPixel = 0.0f;
- for (int32_t y = 0; y < height; y ++) {
-
+ for (int32_t y = 0; y < height; y++) {
const uint8_t* input = source + y * width;
uint8_t* output = dest + y * width;
- for (int32_t x = 0; x < width; x ++) {
+ for (int32_t x = 0; x < width; x++) {
blurredPixel = 0.0f;
const float* gPtr = weights;
// Optimization for non-border pixels
if (x > radius && x < (width - radius)) {
- const uint8_t *i = input + (x - radius);
- for (int r = -radius; r <= radius; r ++) {
- currentPixel = (float) (*i);
+ const uint8_t* i = input + (x - radius);
+ for (int r = -radius; r <= radius; r++) {
+ currentPixel = (float)(*i);
blurredPixel += currentPixel * gPtr[0];
gPtr++;
i++;
}
} else {
- for (int32_t r = -radius; r <= radius; r ++) {
+ for (int32_t r = -radius; r <= radius; r++) {
// Stepping left and right away from the pixel
int validW = x + r;
if (validW < 0) {
@@ -124,40 +123,40 @@ void Blur::horizontal(float* weights, int32_t radius,
validW = width - 1;
}
- currentPixel = (float) input[validW];
+ currentPixel = (float)input[validW];
blurredPixel += currentPixel * gPtr[0];
gPtr++;
}
}
*output = (uint8_t)blurredPixel;
- output ++;
+ output++;
}
}
}
-void Blur::vertical(float* weights, int32_t radius,
- const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
+void Blur::vertical(float* weights, int32_t radius, const uint8_t* source, uint8_t* dest,
+ int32_t width, int32_t height) {
float blurredPixel = 0.0f;
float currentPixel = 0.0f;
- for (int32_t y = 0; y < height; y ++) {
+ for (int32_t y = 0; y < height; y++) {
uint8_t* output = dest + y * width;
- for (int32_t x = 0; x < width; x ++) {
+ for (int32_t x = 0; x < width; x++) {
blurredPixel = 0.0f;
const float* gPtr = weights;
const uint8_t* input = source + x;
// Optimization for non-border pixels
if (y > radius && y < (height - radius)) {
- const uint8_t *i = input + ((y - radius) * width);
- for (int32_t r = -radius; r <= radius; r ++) {
- currentPixel = (float) (*i);
+ const uint8_t* i = input + ((y - radius) * width);
+ for (int32_t r = -radius; r <= radius; r++) {
+ currentPixel = (float)(*i);
blurredPixel += currentPixel * gPtr[0];
gPtr++;
i += width;
}
} else {
- for (int32_t r = -radius; r <= radius; r ++) {
+ for (int32_t r = -radius; r <= radius; r++) {
int validH = y + r;
// Clamp to zero and width
if (validH < 0) {
@@ -167,17 +166,17 @@ void Blur::vertical(float* weights, int32_t radius,
validH = height - 1;
}
- const uint8_t *i = input + validH * width;
- currentPixel = (float) (*i);
+ const uint8_t* i = input + validH * width;
+ currentPixel = (float)(*i);
blurredPixel += currentPixel * gPtr[0];
gPtr++;
}
}
- *output = (uint8_t) blurredPixel;
+ *output = (uint8_t)blurredPixel;
output++;
}
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/Blur.h b/libs/hwui/utils/Blur.h
index 3f21832bf2b5..bec3837106e8 100644
--- a/libs/hwui/utils/Blur.h
+++ b/libs/hwui/utils/Blur.h
@@ -17,8 +17,8 @@
#ifndef ANDROID_HWUI_BLUR_H
#define ANDROID_HWUI_BLUR_H
-#include <stdint.h>
#include <cutils/compiler.h>
+#include <stdint.h>
namespace android {
namespace uirenderer {
@@ -35,13 +35,13 @@ public:
static uint32_t convertRadiusToInt(float radius);
static void generateGaussianWeights(float* weights, float radius);
- static void horizontal(float* weights, int32_t radius, const uint8_t* source,
- uint8_t* dest, int32_t width, int32_t height);
- static void vertical(float* weights, int32_t radius, const uint8_t* source,
- uint8_t* dest, int32_t width, int32_t height);
+ static void horizontal(float* weights, int32_t radius, const uint8_t* source, uint8_t* dest,
+ int32_t width, int32_t height);
+ static void vertical(float* weights, int32_t radius, const uint8_t* source, uint8_t* dest,
+ int32_t width, int32_t height);
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_BLUR_H
+#endif // ANDROID_HWUI_BLUR_H
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index 7d234b06b8ca..c2af867657bf 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -41,18 +41,17 @@ bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace) {
const float sRGBParamG = 2.4f;
// This comparison will catch Display P3
- return
- almostEqual(sRGBParamA, transferFunction.fA)
- && almostEqual(sRGBParamB, transferFunction.fB)
- && almostEqual(sRGBParamC, transferFunction.fC)
- && almostEqual(sRGBParamD, transferFunction.fD)
- && almostEqual(sRGBParamE, transferFunction.fE)
- && almostEqual(sRGBParamF, transferFunction.fF)
- && almostEqual(sRGBParamG, transferFunction.fG);
+ return almostEqual(sRGBParamA, transferFunction.fA) &&
+ almostEqual(sRGBParamB, transferFunction.fB) &&
+ almostEqual(sRGBParamC, transferFunction.fC) &&
+ almostEqual(sRGBParamD, transferFunction.fD) &&
+ almostEqual(sRGBParamE, transferFunction.fE) &&
+ almostEqual(sRGBParamF, transferFunction.fF) &&
+ almostEqual(sRGBParamG, transferFunction.fG);
}
return false;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 9c096601c826..4857a87ff97b 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -23,114 +23,94 @@
namespace android {
namespace uirenderer {
- namespace Color {
- enum Color {
- Red_500 = 0xFFF44336,
- Pink_500 = 0xFFE91E63,
- Purple_500 = 0xFF9C27B0,
- DeepPurple_500 = 0xFF673AB7,
- Indigo_500 = 0xFF3F51B5,
- Blue_500 = 0xFF2196F3,
- LightBlue_300 = 0xFF4FC3F7,
- LightBlue_500 = 0xFF03A9F4,
- Cyan_500 = 0xFF00BCD4,
- Teal_500 = 0xFF009688,
- Teal_700 = 0xFF00796B,
- Green_500 = 0xFF4CAF50,
- Green_700 = 0xFF388E3C,
- LightGreen_500 = 0xFF8BC34A,
- LightGreen_700 = 0xFF689F38,
- Lime_500 = 0xFFCDDC39,
- Yellow_500 = 0xFFFFEB3B,
- Amber_500 = 0xFFFFC107,
- Orange_500 = 0xFFFF9800,
- DeepOrange_500 = 0xFFFF5722,
- Brown_500 = 0xFF795548,
- Grey_200 = 0xFFEEEEEE,
- Grey_500 = 0xFF9E9E9E,
- Grey_700 = 0xFF616161,
- BlueGrey_500 = 0xFF607D8B,
- Transparent = 0x00000000,
- Black = 0xFF000000,
- White = 0xFFFFFFFF,
- };
- }
+namespace Color {
+enum Color {
+ Red_500 = 0xFFF44336,
+ Pink_500 = 0xFFE91E63,
+ Purple_500 = 0xFF9C27B0,
+ DeepPurple_500 = 0xFF673AB7,
+ Indigo_500 = 0xFF3F51B5,
+ Blue_500 = 0xFF2196F3,
+ LightBlue_300 = 0xFF4FC3F7,
+ LightBlue_500 = 0xFF03A9F4,
+ Cyan_500 = 0xFF00BCD4,
+ Teal_500 = 0xFF009688,
+ Teal_700 = 0xFF00796B,
+ Green_500 = 0xFF4CAF50,
+ Green_700 = 0xFF388E3C,
+ LightGreen_500 = 0xFF8BC34A,
+ LightGreen_700 = 0xFF689F38,
+ Lime_500 = 0xFFCDDC39,
+ Yellow_500 = 0xFFFFEB3B,
+ Amber_500 = 0xFFFFC107,
+ Orange_500 = 0xFFFF9800,
+ DeepOrange_500 = 0xFFFF5722,
+ Brown_500 = 0xFF795548,
+ Grey_200 = 0xFFEEEEEE,
+ Grey_500 = 0xFF9E9E9E,
+ Grey_700 = 0xFF616161,
+ BlueGrey_500 = 0xFF607D8B,
+ Transparent = 0x00000000,
+ Black = 0xFF000000,
+ White = 0xFFFFFFFF,
+};
+}
- static_assert(Color::White == SK_ColorWHITE, "color format has changed");
- static_assert(Color::Black == SK_ColorBLACK, "color format has changed");
+static_assert(Color::White == SK_ColorWHITE, "color format has changed");
+static_assert(Color::Black == SK_ColorBLACK, "color format has changed");
- // Array of bright (500 intensity) colors for synthetic content
- static const Color::Color BrightColors[] = {
- Color::Red_500,
- Color::Pink_500,
- Color::Purple_500,
- Color::DeepPurple_500,
- Color::Indigo_500,
- Color::Blue_500,
- Color::LightBlue_500,
- Color::Cyan_500,
- Color::Teal_500,
- Color::Green_500,
- Color::LightGreen_500,
- Color::Lime_500,
- Color::Yellow_500,
- Color::Amber_500,
- Color::Orange_500,
- Color::DeepOrange_500,
- Color::Brown_500,
- Color::Grey_500,
- Color::BlueGrey_500,
- };
- static constexpr int BrightColorsCount = sizeof(BrightColors) / sizeof(Color::Color);
+// Array of bright (500 intensity) colors for synthetic content
+static const Color::Color BrightColors[] = {
+ Color::Red_500, Color::Pink_500, Color::Purple_500, Color::DeepPurple_500,
+ Color::Indigo_500, Color::Blue_500, Color::LightBlue_500, Color::Cyan_500,
+ Color::Teal_500, Color::Green_500, Color::LightGreen_500, Color::Lime_500,
+ Color::Yellow_500, Color::Amber_500, Color::Orange_500, Color::DeepOrange_500,
+ Color::Brown_500, Color::Grey_500, Color::BlueGrey_500,
+};
+static constexpr int BrightColorsCount = sizeof(BrightColors) / sizeof(Color::Color);
- enum class TransferFunctionType : int8_t {
- None = 0,
- Full,
- Limited,
- Gamma
- };
+enum class TransferFunctionType : int8_t { None = 0, Full, Limited, Gamma };
- // Opto-electronic conversion function for the sRGB color space
- // Takes a linear sRGB value and converts it to a gamma-encoded sRGB value
- static constexpr float OECF_sRGB(float linear) {
- // IEC 61966-2-1:1999
- return linear <= 0.0031308f ?
- linear * 12.92f : (powf(linear, 1.0f / 2.4f) * 1.055f) - 0.055f;
- }
+// Opto-electronic conversion function for the sRGB color space
+// Takes a linear sRGB value and converts it to a gamma-encoded sRGB value
+static constexpr float OECF_sRGB(float linear) {
+ // IEC 61966-2-1:1999
+ return linear <= 0.0031308f ? linear * 12.92f : (powf(linear, 1.0f / 2.4f) * 1.055f) - 0.055f;
+}
- // Opto-electronic conversion function for the sRGB color space
- // Takes a linear sRGB value and converts it to a gamma-encoded sRGB value
- // This function returns the input unmodified if linear blending is not enabled
- static constexpr float OECF(float linear) {
+// Opto-electronic conversion function for the sRGB color space
+// Takes a linear sRGB value and converts it to a gamma-encoded sRGB value
+// This function returns the input unmodified if linear blending is not enabled
+static constexpr float OECF(float linear) {
#ifdef ANDROID_ENABLE_LINEAR_BLENDING
- return OECF_sRGB(linear);
+ return OECF_sRGB(linear);
#else
- return linear;
+ return linear;
#endif
- }
+}
- // Electro-optical conversion function for the sRGB color space
- // Takes a gamma-encoded sRGB value and converts it to a linear sRGB value
- static constexpr float EOCF_sRGB(float srgb) {
- // IEC 61966-2-1:1999
- return srgb <= 0.04045f ? srgb / 12.92f : powf((srgb + 0.055f) / 1.055f, 2.4f);
- }
+// Electro-optical conversion function for the sRGB color space
+// Takes a gamma-encoded sRGB value and converts it to a linear sRGB value
+static constexpr float EOCF_sRGB(float srgb) {
+ // IEC 61966-2-1:1999
+ return srgb <= 0.04045f ? srgb / 12.92f : powf((srgb + 0.055f) / 1.055f, 2.4f);
+}
- // Electro-optical conversion function for the sRGB color space
- // Takes a gamma-encoded sRGB value and converts it to a linear sRGB value
- // This function returns the input unmodified if linear blending is not enabled
- static constexpr float EOCF(float srgb) {
+// Electro-optical conversion function for the sRGB color space
+// Takes a gamma-encoded sRGB value and converts it to a linear sRGB value
+// This function returns the input unmodified if linear blending is not enabled
+static constexpr float EOCF(float srgb) {
#ifdef ANDROID_ENABLE_LINEAR_BLENDING
- return EOCF_sRGB(srgb);
+ return EOCF_sRGB(srgb);
#else
- return srgb;
+ return srgb;
#endif
- }
+}
- // Returns whether the specified color space's transfer function can be
- // approximated with the native sRGB transfer function. This method
- // returns true for sRGB, gamma 2.2 and Display P3 for instance
- bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
+// Returns whether the specified color space's transfer function can be
+// approximated with the native sRGB transfer function. This method
+// returns true for sRGB, gamma 2.2 and Display P3 for instance
+bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/utils/FatVector.h b/libs/hwui/utils/FatVector.h
index df8cb076e763..eafe2f13c16d 100644
--- a/libs/hwui/utils/FatVector.h
+++ b/libs/hwui/utils/FatVector.h
@@ -30,8 +30,8 @@
#include <stddef.h>
#include <stdlib.h>
-#include <type_traits>
#include <utils/Log.h>
+#include <type_traits>
#include <vector>
@@ -43,28 +43,27 @@ class InlineStdAllocator {
public:
struct Allocation {
PREVENT_COPY_AND_ASSIGN(Allocation);
+
public:
- Allocation() {};
+ Allocation(){};
// char array instead of T array, so memory is uninitialized, with no destructors run
char array[sizeof(T) * SIZE];
bool inUse = false;
};
- typedef T value_type; // needed to implement std::allocator
- typedef T* pointer; // needed to implement std::allocator
+ typedef T value_type; // needed to implement std::allocator
+ typedef T* pointer; // needed to implement std::allocator
- explicit InlineStdAllocator(Allocation& allocation)
- : mAllocation(allocation) {}
- InlineStdAllocator(const InlineStdAllocator& other)
- : mAllocation(other.mAllocation) {}
+ explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {}
+ InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {}
~InlineStdAllocator() {}
T* allocate(size_t num, const void* = 0) {
if (!mAllocation.inUse && num <= SIZE) {
mAllocation.inUse = true;
- return (T*) mAllocation.array;
+ return (T*)mAllocation.array;
} else {
- return (T*) malloc(num * sizeof(T));
+ return (T*)malloc(num * sizeof(T));
}
}
@@ -88,20 +87,19 @@ public:
template <typename T, size_t SIZE>
class FatVector : public std::vector<T, InlineStdAllocator<T, SIZE>> {
public:
- FatVector() : std::vector<T, InlineStdAllocator<T, SIZE>>(
- InlineStdAllocator<T, SIZE>(mAllocation)) {
+ FatVector()
+ : std::vector<T, InlineStdAllocator<T, SIZE>>(
+ InlineStdAllocator<T, SIZE>(mAllocation)) {
this->reserve(SIZE);
}
- explicit FatVector(size_t capacity) : FatVector() {
- this->resize(capacity);
- }
+ explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); }
private:
typename InlineStdAllocator<T, SIZE>::Allocation mAllocation;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_FAT_VECTOR_H
+#endif // ANDROID_FAT_VECTOR_H
diff --git a/libs/hwui/utils/GLUtils.cpp b/libs/hwui/utils/GLUtils.cpp
index 332097593c86..bf27300029c6 100644
--- a/libs/hwui/utils/GLUtils.cpp
+++ b/libs/hwui/utils/GLUtils.cpp
@@ -39,25 +39,25 @@ bool GLUtils::dumpGLErrors() {
while ((status = glGetError()) != GL_NO_ERROR) {
errorObserved = true;
switch (status) {
- case GL_INVALID_ENUM:
- ALOGE("GL error: GL_INVALID_ENUM");
- break;
- case GL_INVALID_VALUE:
- ALOGE("GL error: GL_INVALID_VALUE");
- break;
- case GL_INVALID_OPERATION:
- ALOGE("GL error: GL_INVALID_OPERATION");
- break;
- case GL_OUT_OF_MEMORY:
- ALOGE("GL error: Out of memory!");
- break;
- default:
- ALOGE("GL error: 0x%x", status);
+ case GL_INVALID_ENUM:
+ ALOGE("GL error: GL_INVALID_ENUM");
+ break;
+ case GL_INVALID_VALUE:
+ ALOGE("GL error: GL_INVALID_VALUE");
+ break;
+ case GL_INVALID_OPERATION:
+ ALOGE("GL error: GL_INVALID_OPERATION");
+ break;
+ case GL_OUT_OF_MEMORY:
+ ALOGE("GL error: Out of memory!");
+ break;
+ default:
+ ALOGE("GL error: 0x%x", status);
}
}
return errorObserved;
#endif
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/GLUtils.h b/libs/hwui/utils/GLUtils.h
index c12747805293..debfb5d06944 100644
--- a/libs/hwui/utils/GLUtils.h
+++ b/libs/hwui/utils/GLUtils.h
@@ -23,13 +23,14 @@
namespace android {
namespace uirenderer {
-
#if DEBUG_OPENGL
-#define GL_CHECKPOINT(LEVEL) \
- do { if (DEBUG_OPENGL >= DEBUG_LEVEL_##LEVEL) {\
- LOG_ALWAYS_FATAL_IF(android::uirenderer::GLUtils::dumpGLErrors(),\
- "GL errors! %s:%d", __FILE__, __LINE__);\
- } } while (0)
+#define GL_CHECKPOINT(LEVEL) \
+ do { \
+ if (DEBUG_OPENGL >= DEBUG_LEVEL_##LEVEL) { \
+ LOG_ALWAYS_FATAL_IF(android::uirenderer::GLUtils::dumpGLErrors(), "GL errors! %s:%d", \
+ __FILE__, __LINE__); \
+ } \
+ } while (0)
#else
#define GL_CHECKPOINT(LEVEL)
#endif
@@ -42,7 +43,7 @@ public:
*/
static bool dumpGLErrors();
-}; // class GLUtils
+}; // class GLUtils
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/utils/LinearAllocator.cpp b/libs/hwui/utils/LinearAllocator.cpp
index d92bc0cd1fca..5a59de8b922a 100644
--- a/libs/hwui/utils/LinearAllocator.cpp
+++ b/libs/hwui/utils/LinearAllocator.cpp
@@ -30,10 +30,9 @@
#include <stdlib.h>
#include <utils/Log.h>
-
// The ideal size of a page allocation (these need to be multiples of 8)
-#define INITIAL_PAGE_SIZE ((size_t)512) // 512b
-#define MAX_PAGE_SIZE ((size_t)131072) // 128kb
+#define INITIAL_PAGE_SIZE ((size_t)512) // 512b
+#define MAX_PAGE_SIZE ((size_t)131072) // 128kb
// The maximum amount of wasted space we can have per page
// Allocations exceeding this will have their own dedicated page
@@ -48,7 +47,7 @@
#define ALIGN_SZ (sizeof(int))
#endif
-#define ALIGN(x) (((x) + ALIGN_SZ - 1 ) & ~(ALIGN_SZ - 1))
+#define ALIGN(x) (((x) + ALIGN_SZ - 1) & ~(ALIGN_SZ - 1))
#define ALIGN_PTR(p) ((void*)(ALIGN((size_t)(p))))
#if LOG_NDEBUG
@@ -79,7 +78,7 @@ static void _addAllocation(int count) {
#define RM_ALLOCATION(size) _addAllocation(-1);
#endif
-#define min(x,y) (((x) < (y)) ? (x) : (y))
+#define min(x, y) (((x) < (y)) ? (x) : (y))
namespace android {
namespace uirenderer {
@@ -89,19 +88,13 @@ public:
Page* next() { return mNextPage; }
void setNext(Page* next) { mNextPage = next; }
- Page()
- : mNextPage(0)
- {}
+ Page() : mNextPage(0) {}
void* operator new(size_t /*size*/, void* buf) { return buf; }
- void* start() {
- return (void*) (((size_t)this) + sizeof(Page));
- }
+ void* start() { return (void*)(((size_t)this) + sizeof(Page)); }
- void* end(int pageSize) {
- return (void*) (((size_t)start()) + pageSize);
- }
+ void* end(int pageSize) { return (void*)(((size_t)start()) + pageSize); }
private:
Page(const Page& /*other*/) {}
@@ -109,15 +102,15 @@ private:
};
LinearAllocator::LinearAllocator()
- : mPageSize(INITIAL_PAGE_SIZE)
- , mMaxAllocSize(INITIAL_PAGE_SIZE * MAX_WASTE_RATIO)
- , mNext(0)
- , mCurrentPage(0)
- , mPages(0)
- , mTotalAllocated(0)
- , mWastedSpace(0)
- , mPageCount(0)
- , mDedicatedPageCount(0) {}
+ : mPageSize(INITIAL_PAGE_SIZE)
+ , mMaxAllocSize(INITIAL_PAGE_SIZE * MAX_WASTE_RATIO)
+ , mNext(0)
+ , mCurrentPage(0)
+ , mPages(0)
+ , mTotalAllocated(0)
+ , mWastedSpace(0)
+ , mPageCount(0)
+ , mDedicatedPageCount(0) {}
LinearAllocator::~LinearAllocator(void) {
while (mDtorList) {
@@ -176,8 +169,7 @@ void* LinearAllocator::allocImpl(size_t size) {
mDedicatedPageCount++;
page->setNext(mPages);
mPages = page;
- if (!mCurrentPage)
- mCurrentPage = mPages;
+ if (!mCurrentPage) mCurrentPage = mPages;
return start(page);
}
ensureNext(size);
@@ -225,8 +217,8 @@ void LinearAllocator::rewindIfLastAlloc(void* ptr, size_t allocSize) {
runDestructorFor(ptr);
// Don't bother rewinding across pages
allocSize = ALIGN(allocSize);
- if (ptr >= start(mCurrentPage) && ptr < end(mCurrentPage)
- && ptr == ((char*)mNext - allocSize)) {
+ if (ptr >= start(mCurrentPage) && ptr < end(mCurrentPage) &&
+ ptr == ((char*)mNext - allocSize)) {
mWastedSpace += allocSize;
mNext = ptr;
}
@@ -261,9 +253,9 @@ void LinearAllocator::dumpMemoryStats(const char* prefix) {
ALOGD("%sTotal allocated: %.2f%s", prefix, prettySize, prettySuffix);
prettySuffix = toSize(mWastedSpace, prettySize);
ALOGD("%sWasted space: %.2f%s (%.1f%%)", prefix, prettySize, prettySuffix,
- (float) mWastedSpace / (float) mTotalAllocated * 100.0f);
+ (float)mWastedSpace / (float)mTotalAllocated * 100.0f);
ALOGD("%sPages %zu (dedicated %zu)", prefix, mPageCount, mDedicatedPageCount);
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
index f95a6fe5060e..03f685e8aca8 100644
--- a/libs/hwui/utils/LinearAllocator.h
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -56,10 +56,10 @@ public:
* Note that unlike create, for alloc the type is purely for compile-time error
* checking and does not affect size.
*/
- template<class T>
+ template <class T>
void* alloc(size_t size) {
static_assert(std::is_trivially_destructible<T>::value,
- "Error, type is non-trivial! did you mean to use create()?");
+ "Error, type is non-trivial! did you mean to use create()?");
return allocImpl(size);
}
@@ -67,7 +67,7 @@ public:
* Allocates an instance of the template type with the given construction parameters
* and adds it to the automatic destruction list.
*/
- template<class T, typename... Params>
+ template <class T, typename... Params>
T* create(Params&&... params) {
T* ret = new (allocImpl(sizeof(T))) T(std::forward<Params>(params)...);
if (!std::is_trivially_destructible<T>::value) {
@@ -77,17 +77,17 @@ public:
return ret;
}
- template<class T, typename... Params>
+ template <class T, typename... Params>
T* create_trivial(Params&&... params) {
static_assert(std::is_trivially_destructible<T>::value,
- "Error, called create_trivial on a non-trivial type");
+ "Error, called create_trivial on a non-trivial type");
return new (allocImpl(sizeof(T))) T(std::forward<Params>(params)...);
}
- template<class T>
+ template <class T>
T* create_trivial_array(int count) {
static_assert(std::is_trivially_destructible<T>::value,
- "Error, called create_trivial_array on a non-trivial type");
+ "Error, called create_trivial_array on a non-trivial type");
return reinterpret_cast<T*>(allocImpl(sizeof(T) * count));
}
@@ -100,7 +100,7 @@ public:
/**
* Same as rewindIfLastAlloc(void*, size_t)
*/
- template<class T>
+ template <class T>
void rewindIfLastAlloc(T* ptr) {
rewindIfLastAlloc((void*)ptr, sizeof(T));
}
@@ -134,7 +134,7 @@ private:
Page* newPage(size_t pageSize);
bool fitsInCurrentPage(size_t size);
void ensureNext(size_t size);
- void* start(Page *p);
+ void* start(Page* p);
void* end(Page* p);
size_t mPageSize;
@@ -154,13 +154,11 @@ private:
template <class T>
class LinearStdAllocator {
public:
- typedef T value_type; // needed to implement std::allocator
- typedef T* pointer; // needed to implement std::allocator
+ typedef T value_type; // needed to implement std::allocator
+ typedef T* pointer; // needed to implement std::allocator
- explicit LinearStdAllocator(LinearAllocator& allocator)
- : linearAllocator(allocator) {}
- LinearStdAllocator(const LinearStdAllocator& other)
- : linearAllocator(other.linearAllocator) {}
+ explicit LinearStdAllocator(LinearAllocator& allocator) : linearAllocator(allocator) {}
+ LinearStdAllocator(const LinearStdAllocator& other) : linearAllocator(other.linearAllocator) {}
~LinearStdAllocator() {}
// rebind marks that allocators can be rebound to different types
@@ -188,9 +186,13 @@ public:
// return that all specializations of LinearStdAllocator are interchangeable
template <class T1, class T2>
-bool operator== (const LinearStdAllocator<T1>&, const LinearStdAllocator<T2>&) { return true; }
+bool operator==(const LinearStdAllocator<T1>&, const LinearStdAllocator<T2>&) {
+ return true;
+}
template <class T1, class T2>
-bool operator!= (const LinearStdAllocator<T1>&, const LinearStdAllocator<T2>&) { return false; }
+bool operator!=(const LinearStdAllocator<T1>&, const LinearStdAllocator<T2>&) {
+ return false;
+}
template <class T>
class LsaVector : public std::vector<T, LinearStdAllocator<T>> {
@@ -199,7 +201,7 @@ public:
: std::vector<T, LinearStdAllocator<T>>(allocator) {}
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_LINEARALLOCATOR_H
+#endif // ANDROID_LINEARALLOCATOR_H
diff --git a/libs/hwui/utils/Macros.h b/libs/hwui/utils/Macros.h
index 7212897bf5d3..d758f29d6dcb 100644
--- a/libs/hwui/utils/Macros.h
+++ b/libs/hwui/utils/Macros.h
@@ -19,21 +19,19 @@
#include <type_traits>
#define PREVENT_COPY_AND_ASSIGN(Type) \
- private: \
- Type(const Type&) = delete; \
- void operator=(const Type&) = delete
+private: \
+ Type(const Type&) = delete; \
+ void operator=(const Type&) = delete
-#define HASHABLE_TYPE(Type) \
- bool operator==(const Type& other) const; \
- hash_t hash() const; \
- bool operator!=(const Type& other) const { return !(*this == other); } \
- friend inline hash_t hash_type(const Type& entry) { return entry.hash(); }
+#define HASHABLE_TYPE(Type) \
+ bool operator==(const Type& other) const; \
+ hash_t hash() const; \
+ bool operator!=(const Type& other) const { return !(*this == other); } \
+ friend inline hash_t hash_type(const Type& entry) { return entry.hash(); }
#define REQUIRE_COMPATIBLE_LAYOUT(Type) \
- static_assert(std::is_standard_layout<Type>::value, \
- #Type " must have standard layout")
+ static_assert(std::is_standard_layout<Type>::value, #Type " must have standard layout")
-#define WARN_UNUSED_RESULT \
- __attribute__((warn_unused_result))
+#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#endif /* MACROS_H */
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
index 8d20f2142e73..5475898bff28 100644
--- a/libs/hwui/utils/MathUtils.h
+++ b/libs/hwui/utils/MathUtils.h
@@ -16,8 +16,8 @@
#ifndef MATHUTILS_H
#define MATHUTILS_H
-#include <algorithm>
#include <math.h>
+#include <algorithm>
namespace android {
namespace uirenderer {
@@ -34,9 +34,7 @@ public:
return (value >= -NON_ZERO_EPSILON) && (value <= NON_ZERO_EPSILON);
}
- inline static bool isPositive(float value) {
- return value >= NON_ZERO_EPSILON;
- }
+ inline static bool isPositive(float value) { return value >= NON_ZERO_EPSILON; }
/**
* Clamps alpha value, and snaps when very near 0 or 1
@@ -69,28 +67,24 @@ public:
* Returns the number of points (beyond two, the start and end) needed to form a polygonal
* approximation of an arc, with a given threshold value.
*/
- inline static int divisionsNeededToApproximateArc(float radius,
- float angleInRads, float threshold) {
+ inline static int divisionsNeededToApproximateArc(float radius, float angleInRads,
+ float threshold) {
const float errConst = (-threshold / radius + 1);
const float targetCosVal = 2 * errConst * errConst - 1;
// needed divisions are rounded up from approximation
- return (int)(ceilf(angleInRads / acos(targetCosVal)/2)) * 2;
+ return (int)(ceilf(angleInRads / acos(targetCosVal) / 2)) * 2;
}
- inline static bool areEqual(float valueA, float valueB) {
- return isZero(valueA - valueB);
- }
+ inline static bool areEqual(float valueA, float valueB) { return isZero(valueA - valueB); }
- template<typename T>
+ template <typename T>
static inline T clamp(T a, T minValue, T maxValue) {
return std::min(std::max(a, minValue), maxValue);
}
- inline static float lerp(float v1, float v2, float t) {
- return v1 + ((v2 - v1) * t);
- }
-}; // class MathUtils
+ inline static float lerp(float v1, float v2, float t) { return v1 + ((v2 - v1) * t); }
+}; // class MathUtils
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h
index 2673be1cb6fa..233adae1df24 100644
--- a/libs/hwui/utils/PaintUtils.h
+++ b/libs/hwui/utils/PaintUtils.h
@@ -31,7 +31,6 @@ namespace uirenderer {
*/
class PaintUtils {
public:
-
static inline GLenum getFilter(const SkPaint* paint) {
if (!paint || paint->getFilterQuality() != kNone_SkFilterQuality) {
return GL_LINEAR;
@@ -40,18 +39,16 @@ public:
}
static bool isOpaquePaint(const SkPaint* paint) {
- if (!paint) return true; // default (paintless) behavior is SrcOver, black
+ if (!paint) return true; // default (paintless) behavior is SrcOver, black
- if (paint->getAlpha() != 0xFF
- || PaintUtils::isBlendedShader(paint->getShader())
- || PaintUtils::isBlendedColorFilter(paint->getColorFilter())) {
+ if (paint->getAlpha() != 0xFF || PaintUtils::isBlendedShader(paint->getShader()) ||
+ PaintUtils::isBlendedColorFilter(paint->getColorFilter())) {
return false;
}
// Only let simple srcOver / src blending modes declare opaque, since behavior is clear.
SkBlendMode mode = paint->getBlendMode();
- return mode == SkBlendMode::kSrcOver
- || mode == SkBlendMode::kSrc;
+ return mode == SkBlendMode::kSrcOver || mode == SkBlendMode::kSrc;
}
static bool isBlendedShader(const SkShader* shader) {
@@ -89,9 +86,7 @@ public:
return false;
}
- static inline bool hasTextShadow(const SkPaint* paint) {
- return getTextShadow(paint, nullptr);
- }
+ static inline bool hasTextShadow(const SkPaint* paint) { return getTextShadow(paint, nullptr); }
static inline SkBlendMode getBlendModeDirect(const SkPaint* paint) {
return paint ? paint->getBlendMode() : SkBlendMode::kSrcOver;
@@ -101,7 +96,7 @@ public:
return paint ? paint->getAlpha() : 255;
}
-}; // class PaintUtils
+}; // class PaintUtils
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/utils/Pair.h b/libs/hwui/utils/Pair.h
index 0db3aa38d8b1..4bcd57629e0c 100644
--- a/libs/hwui/utils/Pair.h
+++ b/libs/hwui/utils/Pair.h
@@ -27,34 +27,34 @@ struct Pair {
F first;
S second;
- Pair() { }
- Pair(const Pair& o) : first(o.first), second(o.second) { }
- Pair(const F& f, const S& s) : first(f), second(s) { }
+ Pair() {}
+ Pair(const Pair& o) : first(o.first), second(o.second) {}
+ Pair(const F& f, const S& s) : first(f), second(s) {}
- inline const F& getFirst() const {
- return first;
- }
+ inline const F& getFirst() const { return first; }
- inline const S& getSecond() const {
- return second;
- }
+ inline const S& getSecond() const { return second; }
};
-}; // namespace uirenderer
+}; // namespace uirenderer
template <typename F, typename S>
-struct trait_trivial_ctor< uirenderer::Pair<F, S> >
-{ enum { value = aggregate_traits<F, S>::has_trivial_ctor }; };
+struct trait_trivial_ctor<uirenderer::Pair<F, S> > {
+ enum { value = aggregate_traits<F, S>::has_trivial_ctor };
+};
template <typename F, typename S>
-struct trait_trivial_dtor< uirenderer::Pair<F, S> >
-{ enum { value = aggregate_traits<F, S>::has_trivial_dtor }; };
+struct trait_trivial_dtor<uirenderer::Pair<F, S> > {
+ enum { value = aggregate_traits<F, S>::has_trivial_dtor };
+};
template <typename F, typename S>
-struct trait_trivial_copy< uirenderer::Pair<F, S> >
-{ enum { value = aggregate_traits<F, S>::has_trivial_copy }; };
+struct trait_trivial_copy<uirenderer::Pair<F, S> > {
+ enum { value = aggregate_traits<F, S>::has_trivial_copy };
+};
template <typename F, typename S>
-struct trait_trivial_move< uirenderer::Pair<F, S> >
-{ enum { value = aggregate_traits<F, S>::has_trivial_move }; };
+struct trait_trivial_move<uirenderer::Pair<F, S> > {
+ enum { value = aggregate_traits<F, S>::has_trivial_move };
+};
-}; // namespace android
+}; // namespace android
-#endif // ANDROID_HWUI_PAIR_H
+#endif // ANDROID_HWUI_PAIR_H
diff --git a/libs/hwui/utils/RingBuffer.h b/libs/hwui/utils/RingBuffer.h
index 06bcdcd7d84b..b3e893139cf8 100644
--- a/libs/hwui/utils/RingBuffer.h
+++ b/libs/hwui/utils/RingBuffer.h
@@ -23,7 +23,7 @@
namespace android {
namespace uirenderer {
-template<class T, size_t SIZE>
+template <class T, size_t SIZE>
class RingBuffer {
PREVENT_COPY_AND_ASSIGN(RingBuffer);
@@ -42,21 +42,13 @@ public:
return mBuffer[mHead];
}
- T& front() {
- return (*this)[0];
- }
+ T& front() { return (*this)[0]; }
- T& back() {
- return (*this)[size() - 1];
- }
+ T& back() { return (*this)[size() - 1]; }
- T& operator[](size_t index) {
- return mBuffer[(mHead + index + 1) % mCount];
- }
+ T& operator[](size_t index) { return mBuffer[(mHead + index + 1) % mCount]; }
- const T& operator[](size_t index) const {
- return mBuffer[(mHead + index + 1) % mCount];
- }
+ const T& operator[](size_t index) const { return mBuffer[(mHead + index + 1) % mCount]; }
void clear() {
mCount = 0;
@@ -69,7 +61,7 @@ private:
size_t mCount = 0;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
#endif /* RINGBUFFER_H_ */
diff --git a/libs/hwui/utils/StringUtils.cpp b/libs/hwui/utils/StringUtils.cpp
index 64a59705028a..5304b762f3dc 100644
--- a/libs/hwui/utils/StringUtils.cpp
+++ b/libs/hwui/utils/StringUtils.cpp
@@ -34,5 +34,5 @@ unordered_string_set StringUtils::split(const char* spacedList) {
return set;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/StringUtils.h b/libs/hwui/utils/StringUtils.h
index af5d10f8522b..a10610a3d0da 100644
--- a/libs/hwui/utils/StringUtils.h
+++ b/libs/hwui/utils/StringUtils.h
@@ -30,9 +30,7 @@ namespace uirenderer {
class unordered_string_set : public std::unordered_set<std::string> {
public:
- bool has(const char* str) {
- return find(std::string(str)) != end();
- }
+ bool has(const char* str) { return find(std::string(str)) != end(); }
};
class StringUtils {
@@ -55,8 +53,8 @@ struct SizePrinter {
}
};
-class LogcatStream: public std::ostream {
- class LogcatStreamBuf: public std::stringbuf {
+class LogcatStream : public std::ostream {
+ class LogcatStreamBuf : public std::stringbuf {
virtual int sync() {
ALOGD("%s", str().c_str());
str("");
@@ -65,10 +63,9 @@ class LogcatStream: public std::ostream {
};
LogcatStreamBuf buffer;
+
public:
- LogcatStream()
- :std::ostream(&buffer) {
- }
+ LogcatStream() : std::ostream(&buffer) {}
};
} /* namespace uirenderer */
diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp
index 492ca7fe62fa..700d3b3cf000 100644
--- a/libs/hwui/utils/TestWindowContext.cpp
+++ b/libs/hwui/utils/TestWindowContext.cpp
@@ -36,13 +36,13 @@ namespace {
*/
class ContextFactory : public android::uirenderer::IContextFactory {
public:
- android::uirenderer::AnimationContext* createAnimationContext
- (android::uirenderer::renderthread::TimeLord& clock) override {
+ android::uirenderer::AnimationContext* createAnimationContext(
+ android::uirenderer::renderthread::TimeLord& clock) override {
return new android::uirenderer::AnimationContext(clock);
}
};
-} // anonymous namespace
+} // anonymous namespace
namespace android {
namespace uirenderer {
@@ -54,45 +54,38 @@ namespace uirenderer {
*/
class TestWindowContext::TestWindowData {
-
public:
-
explicit TestWindowData(SkISize size) : mSize(size) {
android::BufferQueue::createBufferQueue(&mProducer, &mConsumer);
mCpuConsumer = new android::CpuConsumer(mConsumer, 1);
mCpuConsumer->setName(android::String8("TestWindowContext"));
mCpuConsumer->setDefaultBufferSize(mSize.width(), mSize.height());
mAndroidSurface = new android::Surface(mProducer);
- native_window_set_buffers_dimensions(mAndroidSurface.get(),
- mSize.width(), mSize.height());
- native_window_set_buffers_format(mAndroidSurface.get(),
- android::PIXEL_FORMAT_RGBA_8888);
- native_window_set_usage(mAndroidSurface.get(),
- GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_SW_WRITE_NEVER |
- GRALLOC_USAGE_HW_RENDER);
+ native_window_set_buffers_dimensions(mAndroidSurface.get(), mSize.width(), mSize.height());
+ native_window_set_buffers_format(mAndroidSurface.get(), android::PIXEL_FORMAT_RGBA_8888);
+ native_window_set_usage(mAndroidSurface.get(), GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_NEVER |
+ GRALLOC_USAGE_HW_RENDER);
mRootNode.reset(new android::uirenderer::RenderNode());
mRootNode->incStrong(nullptr);
- mRootNode->mutateStagingProperties().setLeftTopRightBottom
- (0, 0, mSize.width(), mSize.height());
+ mRootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, mSize.width(),
+ mSize.height());
mRootNode->mutateStagingProperties().setClipToBounds(false);
mRootNode->setPropertyFieldsDirty(android::uirenderer::RenderNode::GENERIC);
ContextFactory factory;
- mProxy.reset
- (new android::uirenderer::renderthread::RenderProxy(false,
- mRootNode.get(),
- &factory));
+ mProxy.reset(new android::uirenderer::renderthread::RenderProxy(false, mRootNode.get(),
+ &factory));
mProxy->loadSystemProperties();
mProxy->initialize(mAndroidSurface.get());
float lightX = mSize.width() / 2.0f;
- android::uirenderer::Vector3 lightVector { lightX, -200.0f, 800.0f };
+ android::uirenderer::Vector3 lightVector{lightX, -200.0f, 800.0f};
mProxy->setup(800.0f, 255 * 0.075f, 255 * 0.15f);
mProxy->setLightCenter(lightVector);
mCanvas.reset(new android::uirenderer::RecordingCanvas(mSize.width(), mSize.height()));
}
SkCanvas* prepareToDraw() {
- //mCanvas->reset(mSize.width(), mSize.height());
+ // mCanvas->reset(mSize.width(), mSize.height());
mCanvas->clipRect(0, 0, mSize.width(), mSize.height(), SkClipOp::kReplace_deprecated);
return mCanvas->asSkCanvas();
}
@@ -104,17 +97,15 @@ public:
// the timings we record.
}
- void fence() {
- mProxy->fence();
- }
+ void fence() { mProxy->fence(); }
bool capturePixels(SkBitmap* bmp) {
sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeSRGB();
SkImageInfo destinationConfig =
- SkImageInfo::Make(mSize.width(), mSize.height(),
- kRGBA_8888_SkColorType, kPremul_SkAlphaType, colorSpace);
+ SkImageInfo::Make(mSize.width(), mSize.height(), kRGBA_8888_SkColorType,
+ kPremul_SkAlphaType, colorSpace);
bmp->allocPixels(destinationConfig);
- android_memset32((uint32_t*) bmp->getPixels(), SK_ColorRED,
+ android_memset32((uint32_t*)bmp->getPixels(), SK_ColorRED,
mSize.width() * mSize.height() * 4);
android::CpuConsumer::LockedBuffer nativeBuffer;
@@ -135,14 +126,13 @@ public:
LOG_ALWAYS_FATAL_IF(nativeBuffer.format != android::PIXEL_FORMAT_RGBA_8888,
"Native buffer not RGBA!");
- SkImageInfo nativeConfig =
- SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
- kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+ SkImageInfo nativeConfig = SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
+ kRGBA_8888_SkColorType, kPremul_SkAlphaType);
// Android stride is in pixels, Skia stride is in bytes
SkBitmap nativeWrapper;
- bool success =
- nativeWrapper.installPixels(nativeConfig, nativeBuffer.data, nativeBuffer.stride * 4);
+ bool success = nativeWrapper.installPixels(nativeConfig, nativeBuffer.data,
+ nativeBuffer.stride * 4);
if (!success) {
SkDebugf("Failed to wrap HWUI buffer in a SkBitmap");
return false;
@@ -150,8 +140,8 @@ public:
LOG_ALWAYS_FATAL_IF(bmp->colorType() != kRGBA_8888_SkColorType,
"Destination buffer not RGBA!");
- success =
- nativeWrapper.readPixels(destinationConfig, bmp->getPixels(), bmp->rowBytes(), 0, 0);
+ success = nativeWrapper.readPixels(destinationConfig, bmp->getPixels(), bmp->rowBytes(), 0,
+ 0);
if (!success) {
SkDebugf("Failed to extract pixels from HWUI buffer");
return false;
@@ -163,7 +153,6 @@ public:
}
private:
-
std::unique_ptr<android::uirenderer::RenderNode> mRootNode;
std::unique_ptr<android::uirenderer::renderthread::RenderProxy> mProxy;
std::unique_ptr<android::uirenderer::RecordingCanvas> mCanvas;
@@ -174,15 +163,13 @@ private:
SkISize mSize;
};
-
-TestWindowContext::TestWindowContext() :
- mData (nullptr) { }
+TestWindowContext::TestWindowContext() : mData(nullptr) {}
TestWindowContext::~TestWindowContext() {
delete mData;
}
-void TestWindowContext::initialize(int width, int height) {
+void TestWindowContext::initialize(int width, int height) {
mData = new TestWindowData(SkISize::Make(width, height));
}
@@ -206,6 +193,5 @@ bool TestWindowContext::capturePixels(SkBitmap* bmp) {
return mData ? mData->capturePixels(bmp) : false;
}
-} // namespace uirenderer
-} // namespace android
-
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/utils/TestWindowContext.h b/libs/hwui/utils/TestWindowContext.h
index 48ec95216b14..17ad1e3fef55 100644
--- a/libs/hwui/utils/TestWindowContext.h
+++ b/libs/hwui/utils/TestWindowContext.h
@@ -31,9 +31,7 @@ namespace uirenderer {
*/
class ANDROID_API TestWindowContext {
-
public:
-
TestWindowContext();
~TestWindowContext();
@@ -58,11 +56,9 @@ private:
class TestWindowData;
TestWindowData* mData;
-
};
} // namespace uirenderer
} // namespace android
#endif // TESTWINDOWCONTEXT_H_
-
diff --git a/libs/hwui/utils/TimeUtils.h b/libs/hwui/utils/TimeUtils.h
index ce181b766841..f66edeaa2a4e 100644
--- a/libs/hwui/utils/TimeUtils.h
+++ b/libs/hwui/utils/TimeUtils.h
@@ -21,15 +21,15 @@
namespace android {
namespace uirenderer {
-constexpr nsecs_t operator"" _s (unsigned long long s) {
+constexpr nsecs_t operator"" _s(unsigned long long s) {
return seconds_to_nanoseconds(s);
}
-constexpr nsecs_t operator"" _ms (unsigned long long ms) {
+constexpr nsecs_t operator"" _ms(unsigned long long ms) {
return milliseconds_to_nanoseconds(ms);
}
-constexpr nsecs_t operator"" _us (unsigned long long us) {
+constexpr nsecs_t operator"" _us(unsigned long long us) {
return microseconds_to_nanoseconds(us);
}
diff --git a/libs/hwui/utils/Timing.h b/libs/hwui/utils/Timing.h
index 4b1fabe42c35..978c7bcf7a57 100644
--- a/libs/hwui/utils/Timing.h
+++ b/libs/hwui/utils/Timing.h
@@ -22,18 +22,16 @@
#define TIME_METHOD() MethodTimer __method_timer(__func__)
class MethodTimer {
public:
- explicit MethodTimer(const char* name)
- : mMethodName(name) {
- gettimeofday(&mStart, nullptr);
- }
+ explicit MethodTimer(const char* name) : mMethodName(name) { gettimeofday(&mStart, nullptr); }
~MethodTimer() {
struct timeval stop;
gettimeofday(&stop, nullptr);
- long long elapsed = (stop.tv_sec * 1000000) - (mStart.tv_sec * 1000000)
- + (stop.tv_usec - mStart.tv_usec);
+ long long elapsed = (stop.tv_sec * 1000000) - (mStart.tv_sec * 1000000) +
+ (stop.tv_usec - mStart.tv_usec);
ALOGD("%s took %.2fms", mMethodName, elapsed / 1000.0);
}
+
private:
const char* mMethodName;
struct timeval mStart;
diff --git a/libs/hwui/utils/TraceUtils.h b/libs/hwui/utils/TraceUtils.h
index ddc272c64851..1869d00396c0 100644
--- a/libs/hwui/utils/TraceUtils.h
+++ b/libs/hwui/utils/TraceUtils.h
@@ -18,11 +18,11 @@
#include <utils/Trace.h>
-#define ATRACE_FORMAT(fmt, ...) \
- TraceUtils::TraceEnder __traceEnder = (TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__), TraceUtils::TraceEnder())
+#define ATRACE_FORMAT(fmt, ...) \
+ TraceUtils::TraceEnder __traceEnder = \
+ (TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__), TraceUtils::TraceEnder())
-#define ATRACE_FORMAT_BEGIN(fmt, ...) \
- TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__)
+#define ATRACE_FORMAT_BEGIN(fmt, ...) TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__)
namespace android {
namespace uirenderer {
@@ -48,7 +48,7 @@ public:
ATRACE_BEGIN(buf);
}
-}; // class TraceUtils
+}; // class TraceUtils
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/utils/VectorDrawableUtils.cpp b/libs/hwui/utils/VectorDrawableUtils.cpp
index 6f0c96db4b1e..1931d646fa4a 100644
--- a/libs/hwui/utils/VectorDrawableUtils.cpp
+++ b/libs/hwui/utils/VectorDrawableUtils.cpp
@@ -32,8 +32,8 @@ public:
float ctrlPointY = 0;
float currentSegmentStartX = 0;
float currentSegmentStartY = 0;
- void addCommand(SkPath* outPath, char previousCmd,
- char cmd, const std::vector<float>* points, size_t start, size_t end);
+ void addCommand(SkPath* outPath, char previousCmd, char cmd, const std::vector<float>* points,
+ size_t start, size_t end);
};
bool VectorDrawableUtils::canMorph(const PathData& morphFrom, const PathData& morphTo) {
@@ -42,8 +42,8 @@ bool VectorDrawableUtils::canMorph(const PathData& morphFrom, const PathData& mo
}
for (unsigned int i = 0; i < morphFrom.verbs.size(); i++) {
- if (morphFrom.verbs[i] != morphTo.verbs[i]
- || morphFrom.verbSizes[i] != morphTo.verbSizes[i]) {
+ if (morphFrom.verbs[i] != morphTo.verbs[i] ||
+ morphFrom.verbSizes[i] != morphTo.verbSizes[i]) {
return false;
}
}
@@ -51,7 +51,7 @@ bool VectorDrawableUtils::canMorph(const PathData& morphFrom, const PathData& mo
}
bool VectorDrawableUtils::interpolatePathData(PathData* outData, const PathData& morphFrom,
- const PathData& morphTo, float fraction) {
+ const PathData& morphTo, float fraction) {
if (!canMorph(morphFrom, morphTo)) {
return false;
}
@@ -59,9 +59,9 @@ bool VectorDrawableUtils::interpolatePathData(PathData* outData, const PathData&
return true;
}
- /**
- * Convert an array of PathVerb to Path.
- */
+/**
+* Convert an array of PathVerb to Path.
+*/
void VectorDrawableUtils::verbsToPath(SkPath* outPath, const PathData& data) {
PathResolver resolver;
char previousCommand = 'm';
@@ -70,7 +70,7 @@ void VectorDrawableUtils::verbsToPath(SkPath* outPath, const PathData& data) {
for (unsigned int i = 0; i < data.verbs.size(); i++) {
size_t verbSize = data.verbSizes[i];
resolver.addCommand(outPath, previousCommand, data.verbs[i], &data.points, start,
- start + verbSize);
+ start + verbSize);
previousCommand = data.verbs[i];
start += verbSize;
}
@@ -85,8 +85,8 @@ void VectorDrawableUtils::verbsToPath(SkPath* outPath, const PathData& data) {
* @param nodeTo The end value as a PathVerb
* @param fraction The fraction to interpolate.
*/
-void VectorDrawableUtils::interpolatePaths(PathData* outData,
- const PathData& from, const PathData& to, float fraction) {
+void VectorDrawableUtils::interpolatePaths(PathData* outData, const PathData& from,
+ const PathData& to, float fraction) {
outData->points.resize(from.points.size());
outData->verbSizes = from.verbSizes;
outData->verbs = from.verbs;
@@ -110,16 +110,8 @@ void VectorDrawableUtils::interpolatePaths(PathData* outData,
* @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) {
+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
@@ -144,19 +136,13 @@ static void arcToBezier(SkPath* p,
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 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);
+ p->cubicTo((float)q1x, (float)q1y, (float)q2x, (float)q2y, (float)e2x, (float)e2y);
eta1 = eta2;
e1x = e2x;
e1y = e2y;
@@ -165,19 +151,12 @@ static void arcToBezier(SkPath* p,
}
}
-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) {
+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 */
@@ -204,9 +183,8 @@ static void drawArc(SkPath* p,
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);
+ 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);
@@ -244,248 +222,232 @@ static void drawArc(SkPath* p,
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) {
-
+void PathResolver::addCommand(SkPath* outPath, char previousCmd, char cmd,
+ const std::vector<float>* points, size_t start, size_t end) {
int incr = 2;
float reflectiveCtrlPointX;
float reflectiveCtrlPointY;
switch (cmd) {
- case 'z':
- case 'Z':
- outPath->close();
- // Path is closed here, but we need to move the pen to the
- // closed position. So we cache the segment's starting position,
- // and restore it here.
- currentX = currentSegmentStartX;
- currentY = currentSegmentStartY;
- ctrlPointX = currentSegmentStartX;
- ctrlPointY = currentSegmentStartY;
- outPath->moveTo(currentX, currentY);
- break;
- case 'm':
- case 'M':
- case 'l':
- case 'L':
- case 't':
- case 'T':
- incr = 2;
- break;
- case 'h':
- case 'H':
- case 'v':
- case 'V':
- incr = 1;
- break;
- case 'c':
- case 'C':
- incr = 6;
- break;
- case 's':
- case 'S':
- case 'q':
- case 'Q':
- incr = 4;
- break;
- case 'a':
- case 'A':
- incr = 7;
- break;
- }
-
- for (unsigned int k = start; k < end; k += incr) {
- switch (cmd) {
- case 'm': // moveto - Start a new sub-path (relative)
- currentX += points->at(k + 0);
- currentY += points->at(k + 1);
- if (k > start) {
- // According to the spec, if a moveto is followed by multiple
- // pairs of coordinates, the subsequent pairs are treated as
- // implicit lineto commands.
- outPath->rLineTo(points->at(k + 0), points->at(k + 1));
- } else {
- outPath->rMoveTo(points->at(k + 0), points->at(k + 1));
- currentSegmentStartX = currentX;
- currentSegmentStartY = currentY;
- }
+ case 'z':
+ case 'Z':
+ outPath->close();
+ // Path is closed here, but we need to move the pen to the
+ // closed position. So we cache the segment's starting position,
+ // and restore it here.
+ currentX = currentSegmentStartX;
+ currentY = currentSegmentStartY;
+ ctrlPointX = currentSegmentStartX;
+ ctrlPointY = currentSegmentStartY;
+ outPath->moveTo(currentX, currentY);
break;
- case 'M': // moveto - Start a new sub-path
- currentX = points->at(k + 0);
- currentY = points->at(k + 1);
- if (k > start) {
- // According to the spec, if a moveto is followed by multiple
- // pairs of coordinates, the subsequent pairs are treated as
- // implicit lineto commands.
- outPath->lineTo(points->at(k + 0), points->at(k + 1));
- } else {
- outPath->moveTo(points->at(k + 0), points->at(k + 1));
- currentSegmentStartX = currentX;
- currentSegmentStartY = currentY;
- }
- break;
- case 'l': // lineto - Draw a line from the current point (relative)
- outPath->rLineTo(points->at(k + 0), points->at(k + 1));
- currentX += points->at(k + 0);
- currentY += points->at(k + 1);
+ case 'm':
+ case 'M':
+ case 'l':
+ case 'L':
+ case 't':
+ case 'T':
+ incr = 2;
break;
- case 'L': // lineto - Draw a line from the current point
- outPath->lineTo(points->at(k + 0), points->at(k + 1));
- currentX = points->at(k + 0);
- currentY = points->at(k + 1);
+ case 'h':
+ case 'H':
+ case 'v':
+ case 'V':
+ incr = 1;
break;
- case 'h': // horizontal lineto - Draws a horizontal line (relative)
- outPath->rLineTo(points->at(k + 0), 0);
- currentX += points->at(k + 0);
+ case 'c':
+ case 'C':
+ incr = 6;
break;
- case 'H': // horizontal lineto - Draws a horizontal line
- outPath->lineTo(points->at(k + 0), currentY);
- currentX = points->at(k + 0);
+ case 's':
+ case 'S':
+ case 'q':
+ case 'Q':
+ incr = 4;
break;
- case 'v': // vertical lineto - Draws a vertical line from the current point (r)
- outPath->rLineTo(0, points->at(k + 0));
- currentY += points->at(k + 0);
+ case 'a':
+ case 'A':
+ incr = 7;
break;
- case 'V': // vertical lineto - Draws a vertical line from the current point
- outPath->lineTo(currentX, points->at(k + 0));
- currentY = points->at(k + 0);
- break;
- case 'c': // curveto - Draws a cubic Bézier curve (relative)
- outPath->rCubicTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3),
- points->at(k + 4), points->at(k + 5));
-
- ctrlPointX = currentX + points->at(k + 2);
- ctrlPointY = currentY + points->at(k + 3);
- currentX += points->at(k + 4);
- currentY += points->at(k + 5);
+ }
- break;
- case 'C': // curveto - Draws a cubic Bézier curve
- outPath->cubicTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3),
- points->at(k + 4), points->at(k + 5));
- currentX = points->at(k + 4);
- currentY = points->at(k + 5);
- ctrlPointX = points->at(k + 2);
- ctrlPointY = points->at(k + 3);
- break;
- case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
- reflectiveCtrlPointX = 0;
- reflectiveCtrlPointY = 0;
- if (previousCmd == 'c' || previousCmd == 's'
- || previousCmd == 'C' || previousCmd == 'S') {
- reflectiveCtrlPointX = currentX - ctrlPointX;
- reflectiveCtrlPointY = currentY - ctrlPointY;
- }
- outPath->rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
- points->at(k + 0), points->at(k + 1),
- points->at(k + 2), points->at(k + 3));
- ctrlPointX = currentX + points->at(k + 0);
- ctrlPointY = currentY + points->at(k + 1);
- currentX += points->at(k + 2);
- currentY += points->at(k + 3);
- break;
- case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
- reflectiveCtrlPointX = currentX;
- reflectiveCtrlPointY = currentY;
- if (previousCmd == 'c' || previousCmd == 's'
- || previousCmd == 'C' || previousCmd == 'S') {
- reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
- reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
- }
- outPath->cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
- points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3));
- ctrlPointX = points->at(k + 0);
- ctrlPointY = points->at(k + 1);
- currentX = points->at(k + 2);
- currentY = points->at(k + 3);
- break;
- case 'q': // Draws a quadratic Bézier (relative)
- outPath->rQuadTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3));
- ctrlPointX = currentX + points->at(k + 0);
- ctrlPointY = currentY + points->at(k + 1);
- currentX += points->at(k + 2);
- currentY += points->at(k + 3);
- break;
- case 'Q': // Draws a quadratic Bézier
- outPath->quadTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3));
- ctrlPointX = points->at(k + 0);
- ctrlPointY = points->at(k + 1);
- currentX = points->at(k + 2);
- currentY = points->at(k + 3);
- break;
- case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
- reflectiveCtrlPointX = 0;
- reflectiveCtrlPointY = 0;
- if (previousCmd == 'q' || previousCmd == 't'
- || previousCmd == 'Q' || previousCmd == 'T') {
- reflectiveCtrlPointX = currentX - ctrlPointX;
- reflectiveCtrlPointY = currentY - ctrlPointY;
- }
- outPath->rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
- points->at(k + 0), points->at(k + 1));
- ctrlPointX = currentX + reflectiveCtrlPointX;
- ctrlPointY = currentY + reflectiveCtrlPointY;
- currentX += points->at(k + 0);
- currentY += points->at(k + 1);
- break;
- case 'T': // Draws a quadratic Bézier curve (reflective control point)
- reflectiveCtrlPointX = currentX;
- reflectiveCtrlPointY = currentY;
- if (previousCmd == 'q' || previousCmd == 't'
- || previousCmd == 'Q' || previousCmd == 'T') {
- reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
- reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
- }
- outPath->quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
- points->at(k + 0), points->at(k + 1));
- ctrlPointX = reflectiveCtrlPointX;
- ctrlPointY = reflectiveCtrlPointY;
- currentX = points->at(k + 0);
- currentY = points->at(k + 1);
- 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);
- 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);
- currentX = points->at(k + 5);
- currentY = points->at(k + 6);
- ctrlPointX = currentX;
- ctrlPointY = currentY;
- break;
- default:
- LOG_ALWAYS_FATAL("Unsupported command: %c", cmd);
- break;
+ for (unsigned int k = start; k < end; k += incr) {
+ switch (cmd) {
+ case 'm': // moveto - Start a new sub-path (relative)
+ currentX += points->at(k + 0);
+ currentY += points->at(k + 1);
+ if (k > start) {
+ // According to the spec, if a moveto is followed by multiple
+ // pairs of coordinates, the subsequent pairs are treated as
+ // implicit lineto commands.
+ outPath->rLineTo(points->at(k + 0), points->at(k + 1));
+ } else {
+ outPath->rMoveTo(points->at(k + 0), points->at(k + 1));
+ currentSegmentStartX = currentX;
+ currentSegmentStartY = currentY;
+ }
+ break;
+ case 'M': // moveto - Start a new sub-path
+ currentX = points->at(k + 0);
+ currentY = points->at(k + 1);
+ if (k > start) {
+ // According to the spec, if a moveto is followed by multiple
+ // pairs of coordinates, the subsequent pairs are treated as
+ // implicit lineto commands.
+ outPath->lineTo(points->at(k + 0), points->at(k + 1));
+ } else {
+ outPath->moveTo(points->at(k + 0), points->at(k + 1));
+ currentSegmentStartX = currentX;
+ currentSegmentStartY = currentY;
+ }
+ break;
+ case 'l': // lineto - Draw a line from the current point (relative)
+ outPath->rLineTo(points->at(k + 0), points->at(k + 1));
+ currentX += points->at(k + 0);
+ currentY += points->at(k + 1);
+ break;
+ case 'L': // lineto - Draw a line from the current point
+ outPath->lineTo(points->at(k + 0), points->at(k + 1));
+ currentX = points->at(k + 0);
+ currentY = points->at(k + 1);
+ break;
+ case 'h': // horizontal lineto - Draws a horizontal line (relative)
+ outPath->rLineTo(points->at(k + 0), 0);
+ currentX += points->at(k + 0);
+ break;
+ case 'H': // horizontal lineto - Draws a horizontal line
+ outPath->lineTo(points->at(k + 0), currentY);
+ currentX = points->at(k + 0);
+ break;
+ case 'v': // vertical lineto - Draws a vertical line from the current point (r)
+ outPath->rLineTo(0, points->at(k + 0));
+ currentY += points->at(k + 0);
+ break;
+ case 'V': // vertical lineto - Draws a vertical line from the current point
+ outPath->lineTo(currentX, points->at(k + 0));
+ currentY = points->at(k + 0);
+ break;
+ case 'c': // curveto - Draws a cubic Bézier curve (relative)
+ outPath->rCubicTo(points->at(k + 0), points->at(k + 1), points->at(k + 2),
+ points->at(k + 3), points->at(k + 4), points->at(k + 5));
+
+ ctrlPointX = currentX + points->at(k + 2);
+ ctrlPointY = currentY + points->at(k + 3);
+ currentX += points->at(k + 4);
+ currentY += points->at(k + 5);
+
+ break;
+ case 'C': // curveto - Draws a cubic Bézier curve
+ outPath->cubicTo(points->at(k + 0), points->at(k + 1), points->at(k + 2),
+ points->at(k + 3), points->at(k + 4), points->at(k + 5));
+ currentX = points->at(k + 4);
+ currentY = points->at(k + 5);
+ ctrlPointX = points->at(k + 2);
+ ctrlPointY = points->at(k + 3);
+ break;
+ case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
+ reflectiveCtrlPointX = 0;
+ reflectiveCtrlPointY = 0;
+ if (previousCmd == 'c' || previousCmd == 's' || previousCmd == 'C' ||
+ previousCmd == 'S') {
+ reflectiveCtrlPointX = currentX - ctrlPointX;
+ reflectiveCtrlPointY = currentY - ctrlPointY;
+ }
+ outPath->rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, points->at(k + 0),
+ points->at(k + 1), points->at(k + 2), points->at(k + 3));
+ ctrlPointX = currentX + points->at(k + 0);
+ ctrlPointY = currentY + points->at(k + 1);
+ currentX += points->at(k + 2);
+ currentY += points->at(k + 3);
+ break;
+ case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
+ reflectiveCtrlPointX = currentX;
+ reflectiveCtrlPointY = currentY;
+ if (previousCmd == 'c' || previousCmd == 's' || previousCmd == 'C' ||
+ previousCmd == 'S') {
+ reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
+ reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
+ }
+ outPath->cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, points->at(k + 0),
+ points->at(k + 1), points->at(k + 2), points->at(k + 3));
+ ctrlPointX = points->at(k + 0);
+ ctrlPointY = points->at(k + 1);
+ currentX = points->at(k + 2);
+ currentY = points->at(k + 3);
+ break;
+ case 'q': // Draws a quadratic Bézier (relative)
+ outPath->rQuadTo(points->at(k + 0), points->at(k + 1), points->at(k + 2),
+ points->at(k + 3));
+ ctrlPointX = currentX + points->at(k + 0);
+ ctrlPointY = currentY + points->at(k + 1);
+ currentX += points->at(k + 2);
+ currentY += points->at(k + 3);
+ break;
+ case 'Q': // Draws a quadratic Bézier
+ outPath->quadTo(points->at(k + 0), points->at(k + 1), points->at(k + 2),
+ points->at(k + 3));
+ ctrlPointX = points->at(k + 0);
+ ctrlPointY = points->at(k + 1);
+ currentX = points->at(k + 2);
+ currentY = points->at(k + 3);
+ break;
+ case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
+ reflectiveCtrlPointX = 0;
+ reflectiveCtrlPointY = 0;
+ if (previousCmd == 'q' || previousCmd == 't' || previousCmd == 'Q' ||
+ previousCmd == 'T') {
+ reflectiveCtrlPointX = currentX - ctrlPointX;
+ reflectiveCtrlPointY = currentY - ctrlPointY;
+ }
+ outPath->rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, points->at(k + 0),
+ points->at(k + 1));
+ ctrlPointX = currentX + reflectiveCtrlPointX;
+ ctrlPointY = currentY + reflectiveCtrlPointY;
+ currentX += points->at(k + 0);
+ currentY += points->at(k + 1);
+ break;
+ case 'T': // Draws a quadratic Bézier curve (reflective control point)
+ reflectiveCtrlPointX = currentX;
+ reflectiveCtrlPointY = currentY;
+ if (previousCmd == 'q' || previousCmd == 't' || previousCmd == 'Q' ||
+ previousCmd == 'T') {
+ reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
+ reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
+ }
+ outPath->quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, points->at(k + 0),
+ points->at(k + 1));
+ ctrlPointX = reflectiveCtrlPointX;
+ ctrlPointY = reflectiveCtrlPointY;
+ currentX = points->at(k + 0);
+ currentY = points->at(k + 1);
+ 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);
+ 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);
+ currentX = points->at(k + 5);
+ currentY = points->at(k + 6);
+ ctrlPointX = currentX;
+ ctrlPointY = currentY;
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unsupported command: %c", cmd);
+ break;
}
previousCmd = cmd;
}
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/utils/VectorDrawableUtils.h b/libs/hwui/utils/VectorDrawableUtils.h
index b5ef5102d219..4be48fb942fc 100644
--- a/libs/hwui/utils/VectorDrawableUtils.h
+++ b/libs/hwui/utils/VectorDrawableUtils.h
@@ -20,8 +20,8 @@
#include "VectorDrawable.h"
#include <cutils/compiler.h>
-#include "SkPath.h"
#include <vector>
+#include "SkPath.h"
namespace android {
namespace uirenderer {
@@ -30,11 +30,11 @@ class VectorDrawableUtils {
public:
ANDROID_API static bool canMorph(const PathData& morphFrom, const PathData& morphTo);
ANDROID_API static bool interpolatePathData(PathData* outData, const PathData& morphFrom,
- const PathData& morphTo, float fraction);
+ const PathData& morphTo, float fraction);
ANDROID_API static void verbsToPath(SkPath* outPath, const PathData& data);
static void interpolatePaths(PathData* outPathData, const PathData& from, const PathData& to,
- float fraction);
+ float fraction);
};
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
#endif /* ANDROID_HWUI_VECTORDRAWABLE_UTILS_H*/
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 20405d3b725c..7afe267f9c15 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -244,6 +244,7 @@ public final class AudioAttributes implements Parcelable {
SUPPRESSIBLE_USAGES.put(USAGE_GAME, SUPPRESSIBLE_MEDIA_SYSTEM_OTHER);
SUPPRESSIBLE_USAGES.put(USAGE_VOICE_COMMUNICATION_SIGNALLING, SUPPRESSIBLE_MEDIA_SYSTEM_OTHER);
SUPPRESSIBLE_USAGES.put(USAGE_ASSISTANT, SUPPRESSIBLE_MEDIA_SYSTEM_OTHER);
+ SUPPRESSIBLE_USAGES.put(USAGE_UNKNOWN, SUPPRESSIBLE_MEDIA_SYSTEM_OTHER);
}
/**
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index dab7632a0e53..58976ca0d5cc 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -43,17 +43,16 @@ import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.Log;
-import android.util.Pair;
+import android.util.Slog;
import android.view.KeyEvent;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
@@ -1966,9 +1965,28 @@ public class AudioManager {
*/
private boolean querySoundEffectsEnabled(int user) {
return Settings.System.getIntForUser(getContext().getContentResolver(),
- Settings.System.SOUND_EFFECTS_ENABLED, 0, user) != 0;
+ Settings.System.SOUND_EFFECTS_ENABLED, 0, user) != 0
+ && !areSystemSoundsZenModeBlocked(getContext());
}
+ private boolean areSystemSoundsZenModeBlocked(Context context) {
+ int zenMode = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.ZEN_MODE, 0);
+
+ switch (zenMode) {
+ case Settings.Global.ZEN_MODE_NO_INTERRUPTIONS:
+ case Settings.Global.ZEN_MODE_ALARMS:
+ return true;
+ case Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+ final NotificationManager noMan = (NotificationManager) context
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+ return (noMan.getNotificationPolicy().priorityCategories
+ & NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER) == 0;
+ case Settings.Global.ZEN_MODE_OFF:
+ default:
+ return false;
+ }
+ }
/**
* Load Sound effects.
diff --git a/media/java/android/media/BufferingParams.java b/media/java/android/media/BufferingParams.java
index 681271b1a6f0..521e89756f5d 100644
--- a/media/java/android/media/BufferingParams.java
+++ b/media/java/android/media/BufferingParams.java
@@ -26,170 +26,68 @@ import java.lang.annotation.RetentionPolicy;
/**
* Structure for source buffering management params.
*
- * Used by {@link MediaPlayer#getDefaultBufferingParams()},
- * {@link MediaPlayer#getBufferingParams()} and
+ * Used by {@link MediaPlayer#getBufferingParams()} and
* {@link MediaPlayer#setBufferingParams(BufferingParams)}
* to control source buffering behavior.
*
* <p>There are two stages of source buffering in {@link MediaPlayer}: initial buffering
* (when {@link MediaPlayer} is being prepared) and rebuffering (when {@link MediaPlayer}
- * is playing back source). {@link BufferingParams} includes mode and corresponding
- * watermarks for each stage of source buffering. The watermarks could be either size
- * based (in milliseconds), or time based (in kilobytes) or both, depending on the mode.
+ * is playing back source). {@link BufferingParams} includes corresponding marks for each
+ * stage of source buffering. The marks are time based (in milliseconds).
*
- * <p>There are 4 buffering modes: {@link #BUFFERING_MODE_NONE},
- * {@link #BUFFERING_MODE_TIME_ONLY}, {@link #BUFFERING_MODE_SIZE_ONLY} and
- * {@link #BUFFERING_MODE_TIME_THEN_SIZE}.
- * {@link MediaPlayer} source component has default buffering modes which can be queried
- * by calling {@link MediaPlayer#getDefaultBufferingParams()}.
- * Users should always use those default modes or their downsized version when trying to
- * change buffering params. For example, {@link #BUFFERING_MODE_TIME_THEN_SIZE} can be
- * downsized to {@link #BUFFERING_MODE_NONE}, {@link #BUFFERING_MODE_TIME_ONLY} or
- * {@link #BUFFERING_MODE_SIZE_ONLY}. But {@link #BUFFERING_MODE_TIME_ONLY} can not be
- * downsized to {@link #BUFFERING_MODE_SIZE_ONLY}.
+ * <p>{@link MediaPlayer} source component has default marks which can be queried by
+ * calling {@link MediaPlayer#getBufferingParams()} before any change is made by
+ * {@link MediaPlayer#setBufferingParams()}.
* <ul>
- * <li><strong>initial buffering stage:</strong> has one watermark which is used when
- * {@link MediaPlayer} is being prepared. When cached data amount exceeds this watermark,
- * {@link MediaPlayer} is prepared.</li>
- * <li><strong>rebuffering stage:</strong> has two watermarks, low and high, which are
- * used when {@link MediaPlayer} is playing back content.
+ * <li><strong>initial buffering:</strong> initialMarkMs is used when
+ * {@link MediaPlayer} is being prepared. When cached data amount exceeds this mark
+ * {@link MediaPlayer} is prepared. </li>
+ * <li><strong>rebuffering during playback:</strong> resumePlaybackMarkMs is used when
+ * {@link MediaPlayer} is playing back content.
* <ul>
- * <li> When cached data amount exceeds high watermark, {@link MediaPlayer} will pause
- * buffering. Buffering will resume when cache runs below some limit which could be low
- * watermark or some intermediate value decided by the source component.</li>
- * <li> When cached data amount runs below low watermark, {@link MediaPlayer} will paused
- * playback. Playback will resume when cached data amount exceeds high watermark
- * or reaches end of stream.</li>
- * </ul>
+ * <li> {@link MediaPlayer} has internal mark, namely pausePlaybackMarkMs, to decide when
+ * to pause playback if cached data amount runs low. This internal mark varies based on
+ * type of data source. </li>
+ * <li> When cached data amount exceeds resumePlaybackMarkMs, {@link MediaPlayer} will
+ * resume playback if it has been paused due to low cached data amount. The internal mark
+ * pausePlaybackMarkMs shall be less than resumePlaybackMarkMs. </li>
+ * <li> {@link MediaPlayer} has internal mark, namely pauseRebufferingMarkMs, to decide
+ * when to pause rebuffering. Apparently, this internal mark shall be no less than
+ * resumePlaybackMarkMs. </li>
+ * <li> {@link MediaPlayer} has internal mark, namely resumeRebufferingMarkMs, to decide
+ * when to resume buffering. This internal mark varies based on type of data source. This
+ * mark shall be larger than pausePlaybackMarkMs, and less than pauseRebufferingMarkMs.
+ * </li>
+ * </ul> </li>
* </ul>
* <p>Users should use {@link Builder} to change {@link BufferingParams}.
* @hide
*/
public final class BufferingParams implements Parcelable {
- /**
- * This mode indicates that source buffering is not supported.
- */
- public static final int BUFFERING_MODE_NONE = 0;
- /**
- * This mode indicates that only time based source buffering is supported. This means
- * the watermark(s) are time based.
- */
- public static final int BUFFERING_MODE_TIME_ONLY = 1;
- /**
- * This mode indicates that only size based source buffering is supported. This means
- * the watermark(s) are size based.
- */
- public static final int BUFFERING_MODE_SIZE_ONLY = 2;
- /**
- * This mode indicates that both time and size based source buffering are supported,
- * and time based calculation precedes size based. Size based calculation will be used
- * only when time information is not available from the source.
- */
- public static final int BUFFERING_MODE_TIME_THEN_SIZE = 3;
-
- /** @hide */
- @IntDef(
- value = {
- BUFFERING_MODE_NONE,
- BUFFERING_MODE_TIME_ONLY,
- BUFFERING_MODE_SIZE_ONLY,
- BUFFERING_MODE_TIME_THEN_SIZE,
- }
- )
- @Retention(RetentionPolicy.SOURCE)
- public @interface BufferingMode {}
-
- private static final int BUFFERING_NO_WATERMARK = -1;
+ private static final int BUFFERING_NO_MARK = -1;
// params
- private int mInitialBufferingMode = BUFFERING_MODE_NONE;
- private int mRebufferingMode = BUFFERING_MODE_NONE;
-
- private int mInitialWatermarkMs = BUFFERING_NO_WATERMARK;
- private int mInitialWatermarkKB = BUFFERING_NO_WATERMARK;
+ private int mInitialMarkMs = BUFFERING_NO_MARK;
- private int mRebufferingWatermarkLowMs = BUFFERING_NO_WATERMARK;
- private int mRebufferingWatermarkHighMs = BUFFERING_NO_WATERMARK;
- private int mRebufferingWatermarkLowKB = BUFFERING_NO_WATERMARK;
- private int mRebufferingWatermarkHighKB = BUFFERING_NO_WATERMARK;
+ private int mResumePlaybackMarkMs = BUFFERING_NO_MARK;
private BufferingParams() {
}
/**
- * Return the initial buffering mode used when {@link MediaPlayer} is being prepared.
- * @return one of the values that can be set in {@link Builder#setInitialBufferingMode(int)}
- */
- public int getInitialBufferingMode() {
- return mInitialBufferingMode;
- }
-
- /**
- * Return the rebuffering mode used when {@link MediaPlayer} is playing back source.
- * @return one of the values that can be set in {@link Builder#setRebufferingMode(int)}
- */
- public int getRebufferingMode() {
- return mRebufferingMode;
- }
-
- /**
- * Return the time based initial buffering watermark in milliseconds.
- * It is meaningful only when initial buffering mode obatined from
- * {@link #getInitialBufferingMode()} is time based.
- * @return time based initial buffering watermark in milliseconds
- */
- public int getInitialBufferingWatermarkMs() {
- return mInitialWatermarkMs;
- }
-
- /**
- * Return the size based initial buffering watermark in kilobytes.
- * It is meaningful only when initial buffering mode obatined from
- * {@link #getInitialBufferingMode()} is size based.
- * @return size based initial buffering watermark in kilobytes
+ * Return initial buffering mark in milliseconds.
+ * @return initial buffering mark in milliseconds
*/
- public int getInitialBufferingWatermarkKB() {
- return mInitialWatermarkKB;
+ public int getInitialMarkMs() {
+ return mInitialMarkMs;
}
/**
- * Return the time based low watermark in milliseconds for rebuffering.
- * It is meaningful only when rebuffering mode obatined from
- * {@link #getRebufferingMode()} is time based.
- * @return time based low watermark for rebuffering in milliseconds
+ * Return the mark in milliseconds for resuming playback.
+ * @return the mark for resuming playback in milliseconds
*/
- public int getRebufferingWatermarkLowMs() {
- return mRebufferingWatermarkLowMs;
- }
-
- /**
- * Return the time based high watermark in milliseconds for rebuffering.
- * It is meaningful only when rebuffering mode obatined from
- * {@link #getRebufferingMode()} is time based.
- * @return time based high watermark for rebuffering in milliseconds
- */
- public int getRebufferingWatermarkHighMs() {
- return mRebufferingWatermarkHighMs;
- }
-
- /**
- * Return the size based low watermark in kilobytes for rebuffering.
- * It is meaningful only when rebuffering mode obatined from
- * {@link #getRebufferingMode()} is size based.
- * @return size based low watermark for rebuffering in kilobytes
- */
- public int getRebufferingWatermarkLowKB() {
- return mRebufferingWatermarkLowKB;
- }
-
- /**
- * Return the size based high watermark in kilobytes for rebuffering.
- * It is meaningful only when rebuffering mode obatined from
- * {@link #getRebufferingMode()} is size based.
- * @return size based high watermark for rebuffering in kilobytes
- */
- public int getRebufferingWatermarkHighKB() {
- return mRebufferingWatermarkHighKB;
+ public int getResumePlaybackMarkMs() {
+ return mResumePlaybackMarkMs;
}
/**
@@ -200,27 +98,19 @@ public final class BufferingParams implements Parcelable {
* <pre class="prettyprint">
* BufferingParams myParams = mediaplayer.getDefaultBufferingParams();
* myParams = new BufferingParams.Builder(myParams)
- * .setInitialBufferingWatermarkMs(10000)
- * .build();
+ * .setInitialMarkMs(10000)
+ * .setResumePlaybackMarkMs(15000)
+ * .build();
* mediaplayer.setBufferingParams(myParams);
* </pre>
*/
public static class Builder {
- private int mInitialBufferingMode = BUFFERING_MODE_NONE;
- private int mRebufferingMode = BUFFERING_MODE_NONE;
-
- private int mInitialWatermarkMs = BUFFERING_NO_WATERMARK;
- private int mInitialWatermarkKB = BUFFERING_NO_WATERMARK;
-
- private int mRebufferingWatermarkLowMs = BUFFERING_NO_WATERMARK;
- private int mRebufferingWatermarkHighMs = BUFFERING_NO_WATERMARK;
- private int mRebufferingWatermarkLowKB = BUFFERING_NO_WATERMARK;
- private int mRebufferingWatermarkHighKB = BUFFERING_NO_WATERMARK;
+ private int mInitialMarkMs = BUFFERING_NO_MARK;
+ private int mResumePlaybackMarkMs = BUFFERING_NO_MARK;
/**
* Constructs a new Builder with the defaults.
- * By default, both initial buffering mode and rebuffering mode are
- * {@link BufferingParams#BUFFERING_MODE_NONE}, and all watermarks are -1.
+ * By default, all marks are -1.
*/
public Builder() {
}
@@ -231,16 +121,8 @@ public final class BufferingParams implements Parcelable {
* in the new Builder.
*/
public Builder(BufferingParams bp) {
- mInitialBufferingMode = bp.mInitialBufferingMode;
- mRebufferingMode = bp.mRebufferingMode;
-
- mInitialWatermarkMs = bp.mInitialWatermarkMs;
- mInitialWatermarkKB = bp.mInitialWatermarkKB;
-
- mRebufferingWatermarkLowMs = bp.mRebufferingWatermarkLowMs;
- mRebufferingWatermarkHighMs = bp.mRebufferingWatermarkHighMs;
- mRebufferingWatermarkLowKB = bp.mRebufferingWatermarkLowKB;
- mRebufferingWatermarkHighKB = bp.mRebufferingWatermarkHighKB;
+ mInitialMarkMs = bp.mInitialMarkMs;
+ mResumePlaybackMarkMs = bp.mResumePlaybackMarkMs;
}
/**
@@ -250,179 +132,37 @@ public final class BufferingParams implements Parcelable {
* @return a new {@link BufferingParams} object
*/
public BufferingParams build() {
- if (isTimeBasedMode(mRebufferingMode)
- && mRebufferingWatermarkLowMs > mRebufferingWatermarkHighMs) {
- throw new IllegalStateException("Illegal watermark:"
- + mRebufferingWatermarkLowMs + " : " + mRebufferingWatermarkHighMs);
- }
- if (isSizeBasedMode(mRebufferingMode)
- && mRebufferingWatermarkLowKB > mRebufferingWatermarkHighKB) {
- throw new IllegalStateException("Illegal watermark:"
- + mRebufferingWatermarkLowKB + " : " + mRebufferingWatermarkHighKB);
- }
-
BufferingParams bp = new BufferingParams();
- bp.mInitialBufferingMode = mInitialBufferingMode;
- bp.mRebufferingMode = mRebufferingMode;
-
- bp.mInitialWatermarkMs = mInitialWatermarkMs;
- bp.mInitialWatermarkKB = mInitialWatermarkKB;
+ bp.mInitialMarkMs = mInitialMarkMs;
+ bp.mResumePlaybackMarkMs = mResumePlaybackMarkMs;
- bp.mRebufferingWatermarkLowMs = mRebufferingWatermarkLowMs;
- bp.mRebufferingWatermarkHighMs = mRebufferingWatermarkHighMs;
- bp.mRebufferingWatermarkLowKB = mRebufferingWatermarkLowKB;
- bp.mRebufferingWatermarkHighKB = mRebufferingWatermarkHighKB;
return bp;
}
- private boolean isTimeBasedMode(int mode) {
- return (mode == BUFFERING_MODE_TIME_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE);
- }
-
- private boolean isSizeBasedMode(int mode) {
- return (mode == BUFFERING_MODE_SIZE_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE);
- }
-
/**
- * Sets the initial buffering mode.
- * @param mode one of {@link BufferingParams#BUFFERING_MODE_NONE},
- * {@link BufferingParams#BUFFERING_MODE_TIME_ONLY},
- * {@link BufferingParams#BUFFERING_MODE_SIZE_ONLY},
- * {@link BufferingParams#BUFFERING_MODE_TIME_THEN_SIZE},
+ * Sets the time based mark in milliseconds for initial buffering.
+ * @param markMs time based mark in milliseconds
* @return the same Builder instance.
*/
- public Builder setInitialBufferingMode(@BufferingMode int mode) {
- switch (mode) {
- case BUFFERING_MODE_NONE:
- case BUFFERING_MODE_TIME_ONLY:
- case BUFFERING_MODE_SIZE_ONLY:
- case BUFFERING_MODE_TIME_THEN_SIZE:
- mInitialBufferingMode = mode;
- break;
- default:
- throw new IllegalArgumentException("Illegal buffering mode " + mode);
- }
+ public Builder setInitialMarkMs(int markMs) {
+ mInitialMarkMs = markMs;
return this;
}
/**
- * Sets the rebuffering mode.
- * @param mode one of {@link BufferingParams#BUFFERING_MODE_NONE},
- * {@link BufferingParams#BUFFERING_MODE_TIME_ONLY},
- * {@link BufferingParams#BUFFERING_MODE_SIZE_ONLY},
- * {@link BufferingParams#BUFFERING_MODE_TIME_THEN_SIZE},
+ * Sets the time based mark in milliseconds for resuming playback.
+ * @param markMs time based mark in milliseconds for resuming playback
* @return the same Builder instance.
*/
- public Builder setRebufferingMode(@BufferingMode int mode) {
- switch (mode) {
- case BUFFERING_MODE_NONE:
- case BUFFERING_MODE_TIME_ONLY:
- case BUFFERING_MODE_SIZE_ONLY:
- case BUFFERING_MODE_TIME_THEN_SIZE:
- mRebufferingMode = mode;
- break;
- default:
- throw new IllegalArgumentException("Illegal buffering mode " + mode);
- }
- return this;
- }
-
- /**
- * Sets the time based watermark in milliseconds for initial buffering.
- * @param watermarkMs time based watermark in milliseconds
- * @return the same Builder instance.
- */
- public Builder setInitialBufferingWatermarkMs(int watermarkMs) {
- mInitialWatermarkMs = watermarkMs;
- return this;
- }
-
- /**
- * Sets the size based watermark in kilobytes for initial buffering.
- * @param watermarkKB size based watermark in kilobytes
- * @return the same Builder instance.
- */
- public Builder setInitialBufferingWatermarkKB(int watermarkKB) {
- mInitialWatermarkKB = watermarkKB;
- return this;
- }
-
- /**
- * Sets the time based low watermark in milliseconds for rebuffering.
- * @param watermarkMs time based low watermark in milliseconds
- * @return the same Builder instance.
- */
- public Builder setRebufferingWatermarkLowMs(int watermarkMs) {
- mRebufferingWatermarkLowMs = watermarkMs;
- return this;
- }
-
- /**
- * Sets the time based high watermark in milliseconds for rebuffering.
- * @param watermarkMs time based high watermark in milliseconds
- * @return the same Builder instance.
- */
- public Builder setRebufferingWatermarkHighMs(int watermarkMs) {
- mRebufferingWatermarkHighMs = watermarkMs;
- return this;
- }
-
- /**
- * Sets the size based low watermark in milliseconds for rebuffering.
- * @param watermarkKB size based low watermark in milliseconds
- * @return the same Builder instance.
- */
- public Builder setRebufferingWatermarkLowKB(int watermarkKB) {
- mRebufferingWatermarkLowKB = watermarkKB;
- return this;
- }
-
- /**
- * Sets the size based high watermark in milliseconds for rebuffering.
- * @param watermarkKB size based high watermark in milliseconds
- * @return the same Builder instance.
- */
- public Builder setRebufferingWatermarkHighKB(int watermarkKB) {
- mRebufferingWatermarkHighKB = watermarkKB;
- return this;
- }
-
- /**
- * Sets the time based low and high watermarks in milliseconds for rebuffering.
- * @param lowWatermarkMs time based low watermark in milliseconds
- * @param highWatermarkMs time based high watermark in milliseconds
- * @return the same Builder instance.
- */
- public Builder setRebufferingWatermarksMs(int lowWatermarkMs, int highWatermarkMs) {
- mRebufferingWatermarkLowMs = lowWatermarkMs;
- mRebufferingWatermarkHighMs = highWatermarkMs;
- return this;
- }
-
- /**
- * Sets the size based low and high watermarks in kilobytes for rebuffering.
- * @param lowWatermarkKB size based low watermark in kilobytes
- * @param highWatermarkKB size based high watermark in kilobytes
- * @return the same Builder instance.
- */
- public Builder setRebufferingWatermarksKB(int lowWatermarkKB, int highWatermarkKB) {
- mRebufferingWatermarkLowKB = lowWatermarkKB;
- mRebufferingWatermarkHighKB = highWatermarkKB;
+ public Builder setResumePlaybackMarkMs(int markMs) {
+ mResumePlaybackMarkMs = markMs;
return this;
}
}
private BufferingParams(Parcel in) {
- mInitialBufferingMode = in.readInt();
- mRebufferingMode = in.readInt();
-
- mInitialWatermarkMs = in.readInt();
- mInitialWatermarkKB = in.readInt();
-
- mRebufferingWatermarkLowMs = in.readInt();
- mRebufferingWatermarkHighMs = in.readInt();
- mRebufferingWatermarkLowKB = in.readInt();
- mRebufferingWatermarkHighKB = in.readInt();
+ mInitialMarkMs = in.readInt();
+ mResumePlaybackMarkMs = in.readInt();
}
public static final Parcelable.Creator<BufferingParams> CREATOR =
@@ -446,15 +186,7 @@ public final class BufferingParams implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mInitialBufferingMode);
- dest.writeInt(mRebufferingMode);
-
- dest.writeInt(mInitialWatermarkMs);
- dest.writeInt(mInitialWatermarkKB);
-
- dest.writeInt(mRebufferingWatermarkLowMs);
- dest.writeInt(mRebufferingWatermarkHighMs);
- dest.writeInt(mRebufferingWatermarkLowKB);
- dest.writeInt(mRebufferingWatermarkHighKB);
+ dest.writeInt(mInitialMarkMs);
+ dest.writeInt(mResumePlaybackMarkMs);
}
}
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 88b1c5ffcc7e..1feea8907cd4 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -994,7 +994,6 @@ public final class MediaDrm {
* {@link #PROPERTY_VENDOR}, {@link #PROPERTY_VERSION},
* {@link #PROPERTY_DESCRIPTION}, {@link #PROPERTY_ALGORITHMS}
*/
- /* FIXME this throws IllegalStateException for invalid property names */
@NonNull
public native String getPropertyString(@NonNull @StringProperty String propertyName);
@@ -1002,7 +1001,6 @@ public final class MediaDrm {
* Byte array property name: the device unique identifier is established during
* device provisioning and provides a means of uniquely identifying each device.
*/
- /* FIXME this throws IllegalStateException for invalid property names */
public static final String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
/** @hide */
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 62757e2ec248..649c091b1fd4 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -43,6 +43,7 @@ import android.system.Os;
import android.system.OsConstants;
import android.util.Log;
import android.util.Pair;
+import android.util.ArrayMap;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.widget.VideoView;
@@ -58,6 +59,7 @@ import android.media.SubtitleData;
import android.media.SubtitleTrack.RenderingWidget;
import android.media.SyncParams;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import libcore.io.IoBridge;
@@ -577,6 +579,7 @@ import java.util.Vector;
public class MediaPlayer extends PlayerBase
implements SubtitleController.Listener
, VolumeAutomation
+ , AudioRouting
{
/**
Constant to retrieve only the new metadata since the last
@@ -1417,6 +1420,155 @@ public class MediaPlayer extends PlayerBase
private native @Nullable VolumeShaper.State native_getVolumeShaperState(int id);
+ //--------------------------------------------------------------------------
+ // Explicit Routing
+ //--------------------
+ private AudioDeviceInfo mPreferredDevice = null;
+
+ /**
+ * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
+ * the output from this MediaPlayer.
+ * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio sink or source.
+ * If deviceInfo is null, default routing is restored.
+ * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
+ * does not correspond to a valid audio device.
+ */
+ @Override
+ public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
+ if (deviceInfo != null && !deviceInfo.isSink()) {
+ return false;
+ }
+ int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0;
+ boolean status = native_setOutputDevice(preferredDeviceId);
+ if (status == true) {
+ synchronized (this) {
+ mPreferredDevice = deviceInfo;
+ }
+ }
+ return status;
+ }
+
+ /**
+ * Returns the selected output specified by {@link #setPreferredDevice}. Note that this
+ * is not guaranteed to correspond to the actual device being used for playback.
+ */
+ @Override
+ public AudioDeviceInfo getPreferredDevice() {
+ synchronized (this) {
+ return mPreferredDevice;
+ }
+ }
+
+ /**
+ * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaPlayer
+ * Note: The query is only valid if the MediaPlayer is currently playing.
+ * If the player is not playing, the returned device can be null or correspond to previously
+ * selected device when the player was last active.
+ */
+ @Override
+ public AudioDeviceInfo getRoutedDevice() {
+ int deviceId = native_getRoutedDeviceId();
+ if (deviceId == 0) {
+ return null;
+ }
+ AudioDeviceInfo[] devices =
+ AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
+ for (int i = 0; i < devices.length; i++) {
+ if (devices[i].getId() == deviceId) {
+ return devices[i];
+ }
+ }
+ return null;
+ }
+
+ /*
+ * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
+ */
+ private void enableNativeRoutingCallbacksLocked(boolean enabled) {
+ if (mRoutingChangeListeners.size() == 0) {
+ native_enableDeviceCallback(enabled);
+ }
+ }
+
+ /**
+ * The list of AudioRouting.OnRoutingChangedListener interfaces added (with
+ * {@link #addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, Handler)}
+ * by an app to receive (re)routing notifications.
+ */
+ @GuardedBy("mRoutingChangeListeners")
+ private ArrayMap<AudioRouting.OnRoutingChangedListener,
+ NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
+
+ /**
+ * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
+ * changes on this MediaPlayer.
+ * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
+ * notifications of rerouting events.
+ * @param handler Specifies the {@link Handler} object for the thread on which to execute
+ * the callback. If <code>null</code>, the handler on the main looper will be used.
+ */
+ @Override
+ public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
+ Handler handler) {
+ synchronized (mRoutingChangeListeners) {
+ if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
+ enableNativeRoutingCallbacksLocked(true);
+ mRoutingChangeListeners.put(
+ listener, new NativeRoutingEventHandlerDelegate(this, listener, handler));
+ }
+ }
+ }
+
+ /**
+ * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
+ * to receive rerouting notifications.
+ * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
+ * to remove.
+ */
+ @Override
+ public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
+ synchronized (mRoutingChangeListeners) {
+ if (mRoutingChangeListeners.containsKey(listener)) {
+ mRoutingChangeListeners.remove(listener);
+ enableNativeRoutingCallbacksLocked(false);
+ }
+ }
+ }
+
+ /**
+ * Helper class to handle the forwarding of native events to the appropriate listener
+ * (potentially) handled in a different thread
+ */
+ private class NativeRoutingEventHandlerDelegate {
+ private 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);
+
/**
* Set the low-level power management behavior for this MediaPlayer. This
* can be used when the MediaPlayer is not playing through a SurfaceHolder
@@ -1546,21 +1698,9 @@ public class MediaPlayer extends PlayerBase
public native boolean isPlaying();
/**
- * Gets the default buffering management params.
- * Calling it only after {@code setDataSource} has been called.
- * Each type of data source might have different set of default params.
- *
- * @return the default buffering management params supported by the source component.
- * @throws IllegalStateException if the internal player engine has not been
- * initialized, or {@code setDataSource} has not been called.
- * @hide
- */
- @NonNull
- public native BufferingParams getDefaultBufferingParams();
-
- /**
* Gets the current buffering management params used by the source component.
* Calling it only after {@code setDataSource} has been called.
+ * Each type of data source might have different set of default params.
*
* @return the current buffering management params used by the source component.
* @throws IllegalStateException if the internal player engine has not been
@@ -1575,8 +1715,7 @@ public class MediaPlayer extends PlayerBase
* The object sets its internal BufferingParams to the input, except that the input is
* invalid or not supported.
* Call it only after {@code setDataSource} has been called.
- * Users should only use supported mode returned by {@link #getDefaultBufferingParams()}
- * or its downsized version as described in {@link BufferingParams}.
+ * The input is a hint to MediaPlayer.
*
* @param params the buffering management params.
*
@@ -3176,6 +3315,7 @@ public class MediaPlayer extends PlayerBase
private static final int MEDIA_SUBTITLE_DATA = 201;
private static final int MEDIA_META_DATA = 202;
private static final int MEDIA_DRM_INFO = 210;
+ private static final int MEDIA_AUDIO_ROUTING_CHANGED = 10000;
private TimeProvider mTimeProvider;
@@ -3414,6 +3554,16 @@ public class MediaPlayer extends PlayerBase
case MEDIA_NOP: // interface test message - ignore
break;
+ case MEDIA_AUDIO_ROUTING_CHANGED:
+ AudioManager.resetAudioPortGeneration();
+ synchronized (mRoutingChangeListeners) {
+ for (NativeRoutingEventHandlerDelegate delegate
+ : mRoutingChangeListeners.values()) {
+ delegate.notifyClient();
+ }
+ }
+ return;
+
default:
Log.e(TAG, "Unknown message type " + msg.what);
return;
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 1d85c97239ac..597336bc5fae 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -35,6 +35,7 @@ cc_library_shared {
"libutils",
"libbinder",
"libmedia",
+ "libmedia_omx",
"libmediametrics",
"libmediadrm",
"libmidi",
diff --git a/media/jni/android_media_BufferingParams.h b/media/jni/android_media_BufferingParams.h
index 24c51f5f00d4..b0046720174b 100644
--- a/media/jni/android_media_BufferingParams.h
+++ b/media/jni/android_media_BufferingParams.h
@@ -29,14 +29,8 @@ struct BufferingParams {
jclass clazz;
jmethodID constructID;
- jfieldID initial_buffering_mode;
- jfieldID rebuffering_mode;
- jfieldID initial_watermark_ms;
- jfieldID initial_watermark_kb;
- jfieldID rebuffering_watermark_low_ms;
- jfieldID rebuffering_watermark_high_ms;
- jfieldID rebuffering_watermark_low_kb;
- jfieldID rebuffering_watermark_high_kb;
+ jfieldID initial_mark_ms;
+ jfieldID resume_playback_mark_ms;
void init(JNIEnv *env) {
jclass lclazz = env->FindClass("android/media/BufferingParams");
@@ -51,14 +45,8 @@ struct BufferingParams {
constructID = env->GetMethodID(clazz, "<init>", "()V");
- initial_buffering_mode = env->GetFieldID(clazz, "mInitialBufferingMode", "I");
- rebuffering_mode = env->GetFieldID(clazz, "mRebufferingMode", "I");
- initial_watermark_ms = env->GetFieldID(clazz, "mInitialWatermarkMs", "I");
- initial_watermark_kb = env->GetFieldID(clazz, "mInitialWatermarkKB", "I");
- rebuffering_watermark_low_ms = env->GetFieldID(clazz, "mRebufferingWatermarkLowMs", "I");
- rebuffering_watermark_high_ms = env->GetFieldID(clazz, "mRebufferingWatermarkHighMs", "I");
- rebuffering_watermark_low_kb = env->GetFieldID(clazz, "mRebufferingWatermarkLowKB", "I");
- rebuffering_watermark_high_kb = env->GetFieldID(clazz, "mRebufferingWatermarkHighKB", "I");
+ initial_mark_ms = env->GetFieldID(clazz, "mInitialMarkMs", "I");
+ resume_playback_mark_ms = env->GetFieldID(clazz, "mResumePlaybackMarkMs", "I");
env->DeleteLocalRef(lclazz);
}
@@ -70,22 +58,10 @@ struct BufferingParams {
};
void fillFromJobject(JNIEnv *env, const fields_t& fields, jobject params) {
- settings.mInitialBufferingMode =
- (BufferingMode)env->GetIntField(params, fields.initial_buffering_mode);
- settings.mRebufferingMode =
- (BufferingMode)env->GetIntField(params, fields.rebuffering_mode);
- settings.mInitialWatermarkMs =
- env->GetIntField(params, fields.initial_watermark_ms);
- settings.mInitialWatermarkKB =
- env->GetIntField(params, fields.initial_watermark_kb);
- settings.mRebufferingWatermarkLowMs =
- env->GetIntField(params, fields.rebuffering_watermark_low_ms);
- settings.mRebufferingWatermarkHighMs =
- env->GetIntField(params, fields.rebuffering_watermark_high_ms);
- settings.mRebufferingWatermarkLowKB =
- env->GetIntField(params, fields.rebuffering_watermark_low_kb);
- settings.mRebufferingWatermarkHighKB =
- env->GetIntField(params, fields.rebuffering_watermark_high_kb);
+ settings.mInitialMarkMs =
+ env->GetIntField(params, fields.initial_mark_ms);
+ settings.mResumePlaybackMarkMs =
+ env->GetIntField(params, fields.resume_playback_mark_ms);
}
jobject asJobject(JNIEnv *env, const fields_t& fields) {
@@ -93,14 +69,8 @@ struct BufferingParams {
if (params == NULL) {
return NULL;
}
- env->SetIntField(params, fields.initial_buffering_mode, (jint)settings.mInitialBufferingMode);
- env->SetIntField(params, fields.rebuffering_mode, (jint)settings.mRebufferingMode);
- env->SetIntField(params, fields.initial_watermark_ms, (jint)settings.mInitialWatermarkMs);
- env->SetIntField(params, fields.initial_watermark_kb, (jint)settings.mInitialWatermarkKB);
- env->SetIntField(params, fields.rebuffering_watermark_low_ms, (jint)settings.mRebufferingWatermarkLowMs);
- env->SetIntField(params, fields.rebuffering_watermark_high_ms, (jint)settings.mRebufferingWatermarkHighMs);
- env->SetIntField(params, fields.rebuffering_watermark_low_kb, (jint)settings.mRebufferingWatermarkLowKB);
- env->SetIntField(params, fields.rebuffering_watermark_high_kb, (jint)settings.mRebufferingWatermarkHighKB);
+ env->SetIntField(params, fields.initial_mark_ms, (jint)settings.mInitialMarkMs);
+ env->SetIntField(params, fields.resume_playback_mark_ms, (jint)settings.mResumePlaybackMarkMs);
return params;
}
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index d0c2aea1affc..51c9e5f1c7da 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -282,7 +282,7 @@ static bool throwExceptionAsNecessary(
drmMessage = "Decrypt error";
break;
case ERROR_DRM_CANNOT_HANDLE:
- drmMessage = "Unsupported scheme or data format";
+ drmMessage = "Invalid parameter or data format";
break;
case ERROR_DRM_TAMPER_DETECTED:
drmMessage = "Invalid state";
@@ -297,7 +297,7 @@ static bool throwExceptionAsNecessary(
drmMessage = vendorMessage.string();
}
- if (err == BAD_VALUE) {
+ if (err == BAD_VALUE || err == ERROR_DRM_CANNOT_HANDLE) {
jniThrowException(env, "java/lang/IllegalArgumentException", msg);
return true;
} else if (err == ERROR_DRM_NOT_PROVISIONED) {
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 28827e64cf96..eda22d574fd7 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -371,25 +371,6 @@ android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsu
}
static jobject
-android_media_MediaPlayer_getDefaultBufferingParams(JNIEnv *env, jobject thiz)
-{
- sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
- if (mp == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
- return NULL;
- }
-
- BufferingParams bp;
- BufferingSettings &settings = bp.settings;
- process_media_player_call(
- env, thiz, mp->getDefaultBufferingSettings(&settings),
- "java/lang/IllegalStateException", "unexpected error");
- ALOGV("getDefaultBufferingSettings:{%s}", settings.toString().string());
-
- return bp.asJobject(env, gBufferingParamsFields);
-}
-
-static jobject
android_media_MediaPlayer_getBufferingParams(JNIEnv *env, jobject thiz)
{
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
@@ -1387,6 +1368,44 @@ static void android_media_MediaPlayer_releaseDrm(JNIEnv *env, jobject thiz)
// Modular DRM end
// ----------------------------------------------------------------------------
+/////////////////////////////////////////////////////////////////////////////////////
+// AudioRouting begin
+static jboolean android_media_MediaPlayer_setOutputDevice(JNIEnv *env, jobject thiz, jint device_id)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ return false;
+ }
+ return mp->setOutputDevice(device_id) == NO_ERROR;
+}
+
+static jint android_media_MediaPlayer_getRoutedDeviceId(JNIEnv *env, jobject thiz)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ return AUDIO_PORT_HANDLE_NONE;
+ }
+ return mp->getRoutedDeviceId();
+}
+
+static void android_media_MediaPlayer_enableDeviceCallback(
+ JNIEnv* env, jobject thiz, jboolean enabled)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ return;
+ }
+
+ status_t status = mp->enableAudioDeviceCallback(enabled);
+ if (status != NO_ERROR) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ ALOGE("enable device callback failed: %d", status);
+ }
+}
+
+// AudioRouting end
+// ----------------------------------------------------------------------------
+
static const JNINativeMethod gMethods[] = {
{
"nativeSetDataSource",
@@ -1398,7 +1417,6 @@ static const JNINativeMethod gMethods[] = {
{"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},
{"_setDataSource", "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback },
{"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer_setVideoSurface},
- {"getDefaultBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer_getDefaultBufferingParams},
{"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer_getBufferingParams},
{"setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer_setBufferingParams},
{"_prepare", "()V", (void *)android_media_MediaPlayer_prepare},
@@ -1448,6 +1466,11 @@ static const JNINativeMethod gMethods[] = {
// Modular DRM
{ "_prepareDrm", "([B[B)V", (void *)android_media_MediaPlayer_prepareDrm },
{ "_releaseDrm", "()V", (void *)android_media_MediaPlayer_releaseDrm },
+
+ // AudioRouting
+ {"native_setOutputDevice", "(I)Z", (void *)android_media_MediaPlayer_setOutputDevice},
+ {"native_getRoutedDeviceId", "()I", (void *)android_media_MediaPlayer_getRoutedDeviceId},
+ {"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaPlayer_enableDeviceCallback},
};
// This function only registers the native methods
diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java
index fa50943343e9..478297f2a3c9 100644
--- a/obex/javax/obex/ObexHelper.java
+++ b/obex/javax/obex/ObexHelper.java
@@ -80,6 +80,9 @@ public final class ObexHelper {
// The minimum allowed max packet size is 255 according to the OBEX specification
public static final int LOWER_LIMIT_MAX_PACKET_SIZE = 255;
+ // The length of OBEX Byte Sequency Header Id according to the OBEX specification
+ public static final int OBEX_BYTE_SEQ_HEADER_LEN = 0x03;
+
/**
* Temporary workaround to be able to push files to Windows 7.
* TODO: Should be removed as soon as Microsoft updates their driver.
@@ -205,12 +208,15 @@ public final class ObexHelper {
case 0x40:
boolean trimTail = true;
index++;
- length = 0xFF & headerArray[index];
- length = length << 8;
- index++;
- length += 0xFF & headerArray[index];
- length -= 3;
- index++;
+ length = ((0xFF & headerArray[index]) << 8) +
+ (0xFF & headerArray[index + 1]);
+ index += 2;
+ if (length <= OBEX_BYTE_SEQ_HEADER_LEN) {
+ Log.e(TAG, "Remote sent an OBEX packet with " +
+ "incorrect header length = " + length);
+ break;
+ }
+ length -= OBEX_BYTE_SEQ_HEADER_LEN;
value = new byte[length];
System.arraycopy(headerArray, index, value, 0, length);
if (length == 0 || (length > 0 && (value[length - 1] != 0))) {
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index f535368bd356..6fe8975577a4 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -23,16 +23,37 @@ import static android.service.notification.NotificationListenerService.Ranking
import android.app.INotificationManager;
import android.content.Context;
import android.ext.services.R;
+import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.Environment;
+import android.os.storage.StorageManager;
import android.service.notification.Adjustment;
import android.service.notification.NotificationAssistantService;
import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
+import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
+import android.util.Xml;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Map;
/**
* Notification assistant that provides guidance on notification channel blocking
@@ -41,19 +62,112 @@ public class Assistant extends NotificationAssistantService {
private static final String TAG = "ExtAssistant";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private static final ArrayList<Integer> DISMISS_WITH_PREJUDICE = new ArrayList<>();
+ private static final String TAG_ASSISTANT = "assistant";
+ private static final String TAG_IMPRESSION = "impression-set";
+ private static final String ATT_KEY = "key";
+ private static final int DB_VERSION = 1;
+ private static final String ATTR_VERSION = "version";
+
+ private static final ArrayList<Integer> PREJUDICAL_DISMISSALS = new ArrayList<>();
static {
- DISMISS_WITH_PREJUDICE.add(REASON_CANCEL);
- DISMISS_WITH_PREJUDICE.add(REASON_LISTENER_CANCEL);
+ PREJUDICAL_DISMISSALS.add(REASON_CANCEL);
+ PREJUDICAL_DISMISSALS.add(REASON_LISTENER_CANCEL);
}
// key : impressions tracker
- // TODO: persist across reboots
+ // TODO: prune deleted channels and apps
ArrayMap<String, ChannelImpressions> mkeyToImpressions = new ArrayMap<>();
// SBN key : channel id
ArrayMap<String, String> mLiveNotifications = new ArrayMap<>();
private Ranking mFakeRanking = null;
+ private AtomicFile mFile = null;
+
+ public Assistant() {
+ }
+
+ private void loadFile() {
+ if (DEBUG) Slog.d(TAG, "loadFile");
+ AsyncTask.execute(() -> {
+ InputStream infile = null;
+ try {
+ infile = mFile.openRead();
+ readXml(infile);
+ } catch (FileNotFoundException e) {
+ // No data yet
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to read channel impressions", e);
+ } catch (NumberFormatException | XmlPullParserException e) {
+ Log.e(TAG, "Unable to parse channel impressions", e);
+ } finally {
+ IoUtils.closeQuietly(infile);
+ }
+ });
+ }
+
+ protected void readXml(InputStream stream)
+ throws XmlPullParserException, NumberFormatException, IOException {
+ final XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, StandardCharsets.UTF_8.name());
+ final int outerDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (!TAG_ASSISTANT.equals(parser.getName())) {
+ continue;
+ }
+ final int impressionOuterDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, impressionOuterDepth)) {
+ if (!TAG_IMPRESSION.equals(parser.getName())) {
+ continue;
+ }
+ String key = parser.getAttributeValue(null, ATT_KEY);
+ ChannelImpressions ci = new ChannelImpressions();
+ ci.populateFromXml(parser);
+ synchronized (mkeyToImpressions) {
+ ci.append(mkeyToImpressions.get(key));
+ mkeyToImpressions.put(key, ci);
+ }
+ }
+ }
+ }
+
+ private void saveFile() throws IOException {
+ AsyncTask.execute(() -> {
+ final FileOutputStream stream;
+ try {
+ stream = mFile.startWrite();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to save policy file", e);
+ return;
+ }
+ try {
+ final XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, StandardCharsets.UTF_8.name());
+ writeXml(out);
+ mFile.finishWrite(stream);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to save impressions file, restoring backup", e);
+ mFile.failWrite(stream);
+ }
+ });
+ }
+
+ protected void writeXml(XmlSerializer out) throws IOException {
+ out.startDocument(null, true);
+ out.startTag(null, TAG_ASSISTANT);
+ out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
+ synchronized (mkeyToImpressions) {
+ for (Map.Entry<String, ChannelImpressions> entry
+ : mkeyToImpressions.entrySet()) {
+ // TODO: ensure channel still exists
+ out.startTag(null, TAG_IMPRESSION);
+ out.attribute(null, ATT_KEY, entry.getKey());
+ entry.getValue().writeXml(out);
+ out.endTag(null, TAG_IMPRESSION);
+ }
+ }
+ out.endTag(null, TAG_ASSISTANT);
+ out.endDocument();
+ }
@Override
public Adjustment onNotificationEnqueued(StatusBarNotification sbn) {
@@ -87,26 +201,38 @@ public class Assistant extends NotificationAssistantService {
public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap,
NotificationStats stats, int reason) {
try {
+ boolean updatedImpressions = false;
String channelId = mLiveNotifications.remove(sbn.getKey());
String key = getKey(sbn.getPackageName(), sbn.getUserId(), channelId);
- ChannelImpressions ci = mkeyToImpressions.getOrDefault(key, new ChannelImpressions());
- if (stats.hasSeen()) {
- ci.incrementViews();
+ synchronized (mkeyToImpressions) {
+ ChannelImpressions ci = mkeyToImpressions.getOrDefault(key,
+ new ChannelImpressions());
+ if (stats.hasSeen()) {
+ ci.incrementViews();
+ updatedImpressions = true;
+ }
+ if (PREJUDICAL_DISMISSALS.contains(reason)) {
+ if ((!sbn.isAppGroup() || sbn.getNotification().isGroupChild())
+ && !stats.hasInteracted()
+ && stats.getDismissalSurface() != NotificationStats.DISMISSAL_AOD
+ && stats.getDismissalSurface() != NotificationStats.DISMISSAL_PEEK
+ && stats.getDismissalSurface() != NotificationStats.DISMISSAL_OTHER) {
+ if (DEBUG) Log.i(TAG, "increment dismissals " + key);
+ ci.incrementDismissals();
+ updatedImpressions = true;
+ } else {
+ if (DEBUG) Slog.i(TAG, "reset streak " + key);
+ if (ci.getStreak() > 0) {
+ updatedImpressions = true;
+ }
+ ci.resetStreak();
+ }
+ }
+ mkeyToImpressions.put(key, ci);
}
- if (DISMISS_WITH_PREJUDICE.contains(reason)
- && !sbn.isAppGroup()
- && !sbn.getNotification().isGroupChild()
- && !stats.hasInteracted()
- && stats.getDismissalSurface() != NotificationStats.DISMISSAL_AOD
- && stats.getDismissalSurface() != NotificationStats.DISMISSAL_PEEK
- && stats.getDismissalSurface() != NotificationStats.DISMISSAL_OTHER) {
- if (DEBUG) Log.i(TAG, "increment dismissals");
- ci.incrementDismissals();
- } else {
- if (DEBUG) Slog.i(TAG, "reset streak");
- ci.resetStreak();
+ if (updatedImpressions) {
+ saveFile();
}
- mkeyToImpressions.put(key, ci);
} catch (Throwable e) {
Slog.e(TAG, "Error occurred processing removal", e);
}
@@ -121,6 +247,11 @@ public class Assistant extends NotificationAssistantService {
public void onListenerConnected() {
if (DEBUG) Log.i(TAG, "CONNECTED");
try {
+ mFile = new AtomicFile(new File(new File(
+ Environment.getDataUserCePackageDirectory(
+ StorageManager.UUID_PRIVATE_INTERNAL, getUserId(), getPackageName()),
+ "assistant"), "block_stats.xml"));
+ loadFile();
for (StatusBarNotification sbn : getActiveNotifications()) {
onNotificationPosted(sbn);
}
@@ -129,7 +260,7 @@ public class Assistant extends NotificationAssistantService {
}
}
- private String getKey(String pkg, int userId, String channelId) {
+ protected String getKey(String pkg, int userId, String channelId) {
return pkg + "|" + userId + "|" + channelId;
}
@@ -151,6 +282,11 @@ public class Assistant extends NotificationAssistantService {
}
// for testing
+
+ protected void setFile(AtomicFile file) {
+ mFile = file;
+ }
+
protected void setFakeRanking(Ranking ranking) {
mFakeRanking = ranking;
}
@@ -162,4 +298,16 @@ public class Assistant extends NotificationAssistantService {
protected void setContext(Context context) {
mSystemContext = context;
}
+
+ protected ChannelImpressions getImpressions(String key) {
+ synchronized (mkeyToImpressions) {
+ return mkeyToImpressions.get(key);
+ }
+ }
+
+ protected void insertImpressions(String key, ChannelImpressions ci) {
+ synchronized (mkeyToImpressions) {
+ mkeyToImpressions.put(key, ci);
+ }
+ }
} \ No newline at end of file
diff --git a/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java b/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java
index 30567ccdd074..4ad4b2415735 100644
--- a/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java
+++ b/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java
@@ -18,14 +18,23 @@ package android.ext.services.notification;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import android.util.Log;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+
public final class ChannelImpressions implements Parcelable {
private static final String TAG = "ExtAssistant.CI";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
static final double DISMISS_TO_VIEW_RATIO_LIMIT = .8;
static final int STREAK_LIMIT = 2;
+ static final String ATT_DISMISSALS = "dismisses";
+ static final String ATT_VIEWS = "views";
+ static final String ATT_STREAK = "streak";
private int mDismissals = 0;
private int mViews = 0;
@@ -62,6 +71,14 @@ public final class ChannelImpressions implements Parcelable {
mStreak++;
}
+ public void append(ChannelImpressions additionalImpressions) {
+ if (additionalImpressions != null) {
+ mViews += additionalImpressions.getViews();
+ mStreak += additionalImpressions.getStreak();
+ mDismissals += additionalImpressions.getDismissals();
+ }
+ }
+
public void incrementViews() {
mViews++;
}
@@ -134,4 +151,36 @@ public final class ChannelImpressions implements Parcelable {
sb.append('}');
return sb.toString();
}
+
+ protected void populateFromXml(XmlPullParser parser) {
+ mDismissals = safeInt(parser, ATT_DISMISSALS, 0);
+ mStreak = safeInt(parser, ATT_STREAK, 0);
+ mViews = safeInt(parser, ATT_VIEWS, 0);
+ }
+
+ protected void writeXml(XmlSerializer out) throws IOException {
+ if (mDismissals != 0) {
+ out.attribute(null, ATT_DISMISSALS, String.valueOf(mDismissals));
+ }
+ if (mStreak != 0) {
+ out.attribute(null, ATT_STREAK, String.valueOf(mStreak));
+ }
+ if (mViews != 0) {
+ out.attribute(null, ATT_VIEWS, String.valueOf(mViews));
+ }
+ }
+
+ private static int safeInt(XmlPullParser parser, String att, int defValue) {
+ final String val = parser.getAttributeValue(null, att);
+ return tryParseInt(val, defValue);
+ }
+
+ private static int tryParseInt(String value, int defValue) {
+ if (TextUtils.isEmpty(value)) return defValue;
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ return defValue;
+ }
+ }
}
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java
index 4e5e9f9d1e00..7c35b48310f2 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantTest.java
@@ -31,7 +31,6 @@ import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.content.Intent;
-import android.ext.services.R;
import android.os.UserHandle;
import android.service.notification.Adjustment;
import android.service.notification.NotificationListenerService;
@@ -42,6 +41,10 @@ import android.service.notification.StatusBarNotification;
import android.support.test.InstrumentationRegistry;
import android.test.ServiceTestCase;
import android.testing.TestableContext;
+import android.util.AtomicFile;
+import android.util.Xml;
+
+import com.android.internal.util.FastXmlSerializer;
import org.junit.Before;
import org.junit.Rule;
@@ -49,6 +52,14 @@ import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
public class AssistantTest extends ServiceTestCase<Assistant> {
@@ -67,6 +78,8 @@ public class AssistantTest extends ServiceTestCase<Assistant> {
new NotificationChannel("one", "", IMPORTANCE_LOW);
@Mock INotificationManager mNoMan;
+ @Mock
+ AtomicFile mFile;
Assistant mAssistant;
@@ -88,6 +101,8 @@ public class AssistantTest extends ServiceTestCase<Assistant> {
bindService(startIntent);
mAssistant = getService();
mAssistant.setNoMan(mNoMan);
+ mAssistant.setFile(mFile);
+ when(mFile.startWrite()).thenReturn(mock(FileOutputStream.class));
}
private StatusBarNotification generateSbn(String pkg, int uid, NotificationChannel channel,
@@ -170,18 +185,43 @@ public class AssistantTest extends ServiceTestCase<Assistant> {
}
@Test
- public void testGroupCannotTriggerAdjustment() throws Exception {
+ public void testGroupChildCanTriggerAdjustment() throws Exception {
almostBlockChannel(PKG1, UID1, P1C1);
StatusBarNotification sbn = generateSbn(PKG1, UID1, P1C1, "no", "I HAVE A GROUP");
- mAssistant.setFakeRanking(mock(Ranking.class));
+ mAssistant.setFakeRanking(generateRanking(sbn, P1C1));
NotificationStats stats = new NotificationStats();
stats.setDismissalSurface(NotificationStats.DISMISSAL_SHADE);
stats.setSeen();
+ mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
mAssistant.onNotificationRemoved(
sbn, mock(RankingMap.class), stats, NotificationListenerService.REASON_CANCEL);
- sbn = generateSbn(PKG1, UID1, P1C1, "new one!", null);
+ sbn = generateSbn(PKG1, UID1, P1C1, "new one!", "group");
+ mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
+
+ ArgumentCaptor<Adjustment> captor = ArgumentCaptor.forClass(Adjustment.class);
+ verify(mNoMan, times(1)).applyAdjustmentFromAssistant(any(), captor.capture());
+ assertEquals(sbn.getKey(), captor.getValue().getKey());
+ assertEquals(Ranking.USER_SENTIMENT_NEGATIVE,
+ captor.getValue().getSignals().getInt(Adjustment.KEY_USER_SENTIMENT));
+ }
+
+ @Test
+ public void testGroupSummaryCannotTriggerAdjustment() throws Exception {
+ almostBlockChannel(PKG1, UID1, P1C1);
+
+ StatusBarNotification sbn = generateSbn(PKG1, UID1, P1C1, "no", "I HAVE A GROUP");
+ sbn.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
+ mAssistant.setFakeRanking(generateRanking(sbn, P1C1));
+ NotificationStats stats = new NotificationStats();
+ stats.setDismissalSurface(NotificationStats.DISMISSAL_SHADE);
+ stats.setSeen();
+ mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
+ mAssistant.onNotificationRemoved(
+ sbn, mock(RankingMap.class), stats, NotificationListenerService.REASON_CANCEL);
+
+ sbn = generateSbn(PKG1, UID1, P1C1, "new one!", "group");
mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
verify(mNoMan, never()).applyAdjustmentFromAssistant(any(), any());
@@ -192,10 +232,11 @@ public class AssistantTest extends ServiceTestCase<Assistant> {
almostBlockChannel(PKG1, UID1, P1C1);
StatusBarNotification sbn = generateSbn(PKG1, UID1, P1C1, "no", null);
- mAssistant.setFakeRanking(mock(Ranking.class));
+ mAssistant.setFakeRanking(generateRanking(sbn, P1C1));
NotificationStats stats = new NotificationStats();
stats.setDismissalSurface(NotificationStats.DISMISSAL_AOD);
stats.setSeen();
+ mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
mAssistant.onNotificationRemoved(
sbn, mock(RankingMap.class), stats, NotificationListenerService.REASON_CANCEL);
@@ -208,13 +249,13 @@ public class AssistantTest extends ServiceTestCase<Assistant> {
@Test
public void testInteractedCannotTriggerAdjustment() throws Exception {
almostBlockChannel(PKG1, UID1, P1C1);
-
StatusBarNotification sbn = generateSbn(PKG1, UID1, P1C1, "no", null);
- mAssistant.setFakeRanking(mock(Ranking.class));
+ mAssistant.setFakeRanking(generateRanking(sbn, P1C1));
NotificationStats stats = new NotificationStats();
stats.setDismissalSurface(NotificationStats.DISMISSAL_SHADE);
stats.setSeen();
stats.setExpanded();
+ mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
mAssistant.onNotificationRemoved(
sbn, mock(RankingMap.class), stats, NotificationListenerService.REASON_CANCEL);
@@ -229,10 +270,11 @@ public class AssistantTest extends ServiceTestCase<Assistant> {
almostBlockChannel(PKG1, UID1, P1C1);
StatusBarNotification sbn = generateSbn(PKG1, UID1, P1C1, "no", null);
- mAssistant.setFakeRanking(mock(Ranking.class));
+ mAssistant.setFakeRanking(generateRanking(sbn, P1C1));
NotificationStats stats = new NotificationStats();
stats.setDismissalSurface(NotificationStats.DISMISSAL_SHADE);
stats.setSeen();
+ mAssistant.onNotificationPosted(sbn, mock(RankingMap.class));
mAssistant.onNotificationRemoved(
sbn, mock(RankingMap.class), stats, NotificationListenerService.REASON_APP_CANCEL);
@@ -265,4 +307,88 @@ public class AssistantTest extends ServiceTestCase<Assistant> {
verify(mNoMan, never()).applyAdjustmentFromAssistant(any(), any());
}
+
+ @Test
+ public void testReadXml() throws Exception {
+ String key1 = mAssistant.getKey("pkg1", 1, "channel1");
+ int streak1 = 2;
+ int views1 = 5;
+ int dismiss1 = 9;
+
+ int streak1a = 3;
+ int views1a = 10;
+ int dismiss1a = 99;
+ String key1a = mAssistant.getKey("pkg1", 1, "channel1a");
+
+ int streak2 = 7;
+ int views2 = 77;
+ int dismiss2 = 777;
+ String key2 = mAssistant.getKey("pkg2", 2, "channel2");
+
+ String xml = "<assistant version=\"1\">\n"
+ + "<impression-set key=\"" + key1 + "\" "
+ + "dismisses=\"" + dismiss1 + "\" views=\"" + views1
+ + "\" streak=\"" + streak1 + "\"/>\n"
+ + "<impression-set key=\"" + key1a + "\" "
+ + "dismisses=\"" + dismiss1a + "\" views=\"" + views1a
+ + "\" streak=\"" + streak1a + "\"/>\n"
+ + "<impression-set key=\"" + key2 + "\" "
+ + "dismisses=\"" + dismiss2 + "\" views=\"" + views2
+ + "\" streak=\"" + streak2 + "\"/>\n"
+ + "</assistant>\n";
+ mAssistant.readXml(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())));
+
+ ChannelImpressions c1 = mAssistant.getImpressions(key1);
+ assertEquals(2, c1.getStreak());
+ assertEquals(5, c1.getViews());
+ assertEquals(9, c1.getDismissals());
+
+ ChannelImpressions c1a = mAssistant.getImpressions(key1a);
+ assertEquals(3, c1a.getStreak());
+ assertEquals(10, c1a.getViews());
+ assertEquals(99, c1a.getDismissals());
+
+ ChannelImpressions c2 = mAssistant.getImpressions(key2);
+ assertEquals(7, c2.getStreak());
+ assertEquals(77, c2.getViews());
+ assertEquals(777, c2.getDismissals());
+ }
+
+ @Test
+ public void testRoundTripXml() throws Exception {
+ String key1 = mAssistant.getKey("pkg1", 1, "channel1");
+ ChannelImpressions ci1 = new ChannelImpressions(9, 10);
+ String key2 = mAssistant.getKey("pkg1", 1, "channel2");
+ ChannelImpressions ci2 = new ChannelImpressions();
+ for (int i = 0; i < 3; i++) {
+ ci2.incrementViews();
+ ci2.incrementDismissals();
+ }
+ ChannelImpressions ci3 = new ChannelImpressions();
+ String key3 = mAssistant.getKey("pkg3", 3, "channel2");
+ for (int i = 0; i < 9; i++) {
+ ci3.incrementViews();
+ if (i % 3 == 0) {
+ ci3.incrementDismissals();
+ }
+ }
+
+ mAssistant.insertImpressions(key1, ci1);
+ mAssistant.insertImpressions(key2, ci2);
+ mAssistant.insertImpressions(key3, ci3);
+
+
+ XmlSerializer serializer = new FastXmlSerializer();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+ mAssistant.writeXml(serializer);
+
+ Assistant assistant = new Assistant();
+ assistant.readXml(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())));
+
+ assertEquals(ci1, assistant.getImpressions(key1));
+ assertEquals(ci2, assistant.getImpressions(key2));
+ assertEquals(ci3, assistant.getImpressions(key3));
+ }
+
}
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/ChannelImpressionsTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/ChannelImpressionsTest.java
index a8c9fa35e678..d28e2ac0cffe 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/ChannelImpressionsTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/ChannelImpressionsTest.java
@@ -21,6 +21,8 @@ import static android.ext.services.notification.ChannelImpressions.STREAK_LIMIT;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
import org.junit.Test;
public class ChannelImpressionsTest {
@@ -82,4 +84,28 @@ public class ChannelImpressionsTest {
assertFalse(ci.shouldTriggerBlock());
}
+
+ @Test
+ public void testAppend() {
+ ChannelImpressions ci = new ChannelImpressions();
+ ci.incrementViews();
+ ci.incrementDismissals();
+
+ ChannelImpressions ci2 = new ChannelImpressions();
+ ci2.incrementViews();
+ ci2.incrementDismissals();
+ ci2.incrementViews();
+
+ ci.append(ci2);
+ assertEquals(3, ci.getViews());
+ assertEquals(2, ci.getDismissals());
+ assertEquals(2, ci.getStreak());
+
+ assertEquals(2, ci2.getViews());
+ assertEquals(1, ci2.getDismissals());
+ assertEquals(1, ci2.getStreak());
+
+ // no crash
+ ci.append(null);
+ }
}
diff --git a/packages/MtpDocumentsProvider/res/values-mr/strings.xml b/packages/MtpDocumentsProvider/res/values-mr/strings.xml
index 89a9d14243d9..d581e10f6a1d 100644
--- a/packages/MtpDocumentsProvider/res/values-mr/strings.xml
+++ b/packages/MtpDocumentsProvider/res/values-mr/strings.xml
@@ -19,7 +19,7 @@
<string name="app_label" msgid="6271216747302322594">"MTP होस्ट"</string>
<string name="downloads_app_label" msgid="7120690641874849726">"डाउनलोड"</string>
<string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
- <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> मधून फायलींंमध्ये प्रवेश करीत आहे"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> मधून फायलींंमध्ये प्रवेश करत आहे"</string>
<string name="error_busy_device" msgid="3997316850357386589">"दुसरे डिव्हाइस व्यस्त आहे. ते उपलब्‍ध होईपर्यंत तुम्ही फायली ट्रांसफर करू शकत नाही."</string>
<string name="error_locked_device" msgid="7557872102188356147">"कोणत्याही फायली आढळल्या नाहीत. दुसरे डिव्हाइस कदाचित बंद असू शकते. तसे असल्यास, ते अनलॉक करा आणि पुन्हा प्रयत्न करा."</string>
</resources>
diff --git a/packages/PrintSpooler/res/drawable/ic_print.xml b/packages/PrintSpooler/res/drawable/ic_print.xml
deleted file mode 100644
index e5e4d075f019..000000000000
--- a/packages/PrintSpooler/res/drawable/ic_print.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@*android:drawable/ic_print"
- android:tint="?android:attr/colorAccent" />
diff --git a/packages/PrintSpooler/res/values-mr/strings.xml b/packages/PrintSpooler/res/values-mr/strings.xml
index 05eb8539444f..862d19305d91 100644
--- a/packages/PrintSpooler/res/values-mr/strings.xml
+++ b/packages/PrintSpooler/res/values-mr/strings.xml
@@ -34,7 +34,7 @@
<string name="print_preview" msgid="8010217796057763343">"मुद्रण पूर्वावलोकन"</string>
<string name="install_for_print_preview" msgid="6366303997385509332">"पूर्वावलोकनासाठी पीडीएफ व्ह्यूअर इंस्टॉल करा"</string>
<string name="printing_app_crashed" msgid="854477616686566398">"प्रिंटिंग अ‍ॅप क्रॅश झाले"</string>
- <string name="generating_print_job" msgid="3119608742651698916">"मुद्रण कार्य व्‍युत्‍पन्न करीत आहे"</string>
+ <string name="generating_print_job" msgid="3119608742651698916">"मुद्रण कार्य व्‍युत्‍पन्न करत आहे"</string>
<string name="save_as_pdf" msgid="5718454119847596853">"पीडीएफ म्‍हणून सेव्ह करा"</string>
<string name="all_printers" msgid="5018829726861876202">"सर्व प्रिंटर..."</string>
<string name="print_dialog" msgid="32628687461331979">"मुद्रण संवाद"</string>
@@ -79,8 +79,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर शोधण्यासाठी इंस्टॉल करा</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर शोधण्यासाठी इंस्टॉल करा</item>
</plurals>
- <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> मुद्रण करीत आहे"</string>
- <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द करीत आहे"</string>
+ <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> मुद्रण करत आहे"</string>
+ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द करत आहे"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर एरर <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="blocked_notification_title_template" msgid="1175435827331588646">"प्रिंटरने <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> अवरोधित केले"</string>
<string name="cancel" msgid="4373674107267141885">"रद्द करा"</string>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
index a9a6cbd47699..7c2e55f35cde 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
@@ -122,7 +122,7 @@ public final class SelectPrinterActivity extends Activity implements
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- getActionBar().setIcon(R.drawable.ic_print);
+ getActionBar().setIcon(com.android.internal.R.drawable.ic_print);
setContentView(R.layout.select_printer_activity);
diff --git a/packages/SettingsLib/Android.mk b/packages/SettingsLib/Android.mk
index 1ad4fea5e0a5..99f7f719be99 100644
--- a/packages/SettingsLib/Android.mk
+++ b/packages/SettingsLib/Android.mk
@@ -5,14 +5,20 @@ LOCAL_USE_AAPT2 := true
LOCAL_MODULE := SettingsLib
+LOCAL_JAVA_LIBRARIES := \
+ android-support-annotations
+
LOCAL_SHARED_ANDROID_LIBRARIES := \
- android-support-annotations \
android-support-v4 \
android-support-v7-recyclerview \
android-support-v7-preference \
android-support-v7-appcompat \
android-support-v14-preference
+LOCAL_SHARED_JAVA_LIBRARIES := \
+ apptoolkit-lifecycle-common \
+ apptoolkit-lifecycle-runtime
+
LOCAL_STATIC_JAVA_LIBRARY := legacy-android-test
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
diff --git a/packages/SettingsLib/common.mk b/packages/SettingsLib/common.mk
index 46b66c4900e6..b9abde2e61d9 100644
--- a/packages/SettingsLib/common.mk
+++ b/packages/SettingsLib/common.mk
@@ -14,8 +14,10 @@
#
ifeq ($(LOCAL_USE_AAPT2),true)
+LOCAL_STATIC_JAVA_LIBRARIES += \
+ android-support-annotations
+
LOCAL_STATIC_ANDROID_LIBRARIES += \
- android-support-annotations \
android-support-v4 \
SettingsLib
else
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 2dc8dc9bf22d..ec3425338b06 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -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">"نظام أسماء النطاقات عبر طبقة النقل الآمنة"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"عند تمكينه، يمكن استخدام نظام أسماء النطاقات عبر طبقة النقل الآمنة على المنفذ 853."</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، وعرض لكل SSID RSSI في منتقي Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"‏عند تمكينه، سيكون Wi-Fi أكثر حدة في تسليم اتصال البيانات إلى الجوّال، وذلك عندما تكون إشارة WiFi منخفضة"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index e855f9b141ad..3efe3bf669c7 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Не атрымалася спалучыцца з прыладай <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, таму што PIN-код або пароль няправiльныя."</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">"Адзiн слупок 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 у залежн. ад SSID RSSI у Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Калі гэта функцыя ўключана, Wi-Fi будзе больш інтэнсіўна імкнуцца перайсці на падключ. маб. перад. даных пры слабым сігнале Wi‑Fi"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 24a90847cdbc..b2afcb55cd5b 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -78,7 +78,7 @@
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"মিডিয়া অডিওতে সংযুক্ত রয়েছে"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ফোন অডিওতে সংযুক্ত"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ফাইল স্থানান্তর সার্ভারের সঙ্গে সংযুক্ত"</string>
- <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"মানচিত্রে সংযুক্ত"</string>
+ <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"ম্যাপে সংযুক্ত"</string>
<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>
@@ -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">"ওয়াই ফাই বন্ধ৷"</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"ওয়াই ফাই এর সংযোগ বিচ্ছিন্ন হয়েছে৷"</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"ওয়াই ফাই এ একটি দণ্ড৷"</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 এ ডিএনএস"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"যদি সক্ষম করা থাকে তাহলে পোর্ট ৮৫৩ তে 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">"ওয়াই-ফাই লগিং স্তর বাড়ান, ওয়াই-ফাই চয়নকারীতে SSID RSSI অনুযায়ী দেখান"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"সক্ষম করা থাকলে, ওয়াই ফাই সিগন্যালের মান খারাপ হলে ডেটা সংযোগ মোবাইলের কাছে হস্তান্তর করার জন্য ওয়াই ফাই আরো বেশি তৎপর হবে।"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 0ee111a97839..fc81c76ed207 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"No s\'ha pogut vincular amb <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, perquè el PIN o la contrasenya són incorrectes."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"No es pot comunicar amb <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Vinculació rebutjada per <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Ordinador"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Auriculars"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telèfon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Imatges"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Auricular"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Perifèric d\'entrada"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi desactivada."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desconnectada."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Senyal Wi-Fi: una barra."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Còdec LDAC d\'àudio per Bluetooth: qualitat de reproducció"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Selecciona el còdec LDAC d\'àudio per Bluetooth:\nQualitat de reproducció"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"S\'està reproduint en temps real: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS per TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Si s\'ha activat, prova d\'utilitzar DNS per TLS al port 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS privat"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selecciona el mode de DNS privat"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Desactivat"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunista"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Nom d\'amfitrió del proveïdor de DNS privat"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Introdueix el nom d\'amfitrió del proveïdor de DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra les opcions de certificació de pantalla sense fil"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Augmenta nivell de registre Wi‑Fi i mostra\'l per SSID RSSI al Selector de Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Quan s\'activa, la Wi-Fi és més agressiva en transferir la connexió de dades al mòbil quan el senyal de la Wi-Fi sigui dèbil"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index e85242a87736..e9fa0862fbd8 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Couldn\'t pair with <xliff:g id="DEVICE_NAME">%1$s</xliff:g> because of an incorrect PIN or passkey."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Can\'t communicate with <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Pairing rejected by <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">"Telephone"</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">"Wi-Fi off."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi disconnected."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi one bar."</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 over TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"If enabled, attempt DNS over TLS on port 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Private DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Select private DNS mode"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Off"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistic"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Private DNS provider hostname"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Enter hostname of DNS provider"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to mobile, when Wi‑Fi signal is low"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index e85242a87736..e9fa0862fbd8 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Couldn\'t pair with <xliff:g id="DEVICE_NAME">%1$s</xliff:g> because of an incorrect PIN or passkey."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Can\'t communicate with <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Pairing rejected by <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">"Telephone"</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">"Wi-Fi off."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi disconnected."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi one bar."</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 over TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"If enabled, attempt DNS over TLS on port 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Private DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Select private DNS mode"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Off"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistic"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Private DNS provider hostname"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Enter hostname of DNS provider"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to mobile, when Wi‑Fi signal is low"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index e85242a87736..e9fa0862fbd8 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Couldn\'t pair with <xliff:g id="DEVICE_NAME">%1$s</xliff:g> because of an incorrect PIN or passkey."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Can\'t communicate with <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Pairing rejected by <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">"Telephone"</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">"Wi-Fi off."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi disconnected."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi one bar."</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 over TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"If enabled, attempt DNS over TLS on port 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Private DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Select private DNS mode"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Off"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistic"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Private DNS provider hostname"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Enter hostname of DNS provider"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to mobile, when Wi‑Fi signal is low"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index e85242a87736..e9fa0862fbd8 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Couldn\'t pair with <xliff:g id="DEVICE_NAME">%1$s</xliff:g> because of an incorrect PIN or passkey."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Can\'t communicate with <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Pairing rejected by <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">"Telephone"</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">"Wi-Fi off."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi disconnected."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi one bar."</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 over TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"If enabled, attempt DNS over TLS on port 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Private DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Select private DNS mode"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Off"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistic"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Private DNS provider hostname"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Enter hostname of DNS provider"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to mobile, when Wi‑Fi signal is low"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index a3430fc8e98e..88fba49dcd55 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‎‏‏‏‏‎‎‏‏‏‎‏‏‏‎‏‏‎‏‏‎‏‎‎‎‎‎‏‎‎‎‏‎‏‎‏‎‎‎‏‎‏‏‎‏‎‏‏‎‏‎‎Couldn\'t pair with ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ because of an incorrect PIN or passkey.‎‏‎‎‏‎"</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‎‏‎‎‏‏‎‏‏‎‎‎‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎Can\'t communicate with ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎.‎‏‎‎‏‎"</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‏‏‏‏‎‏‏‎‏‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‏‏‎‎Pairing rejected by ‎‏‎‎‏‏‎<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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‎Phone‎‏‎‎‏‎"</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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‎‎‎‏‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‎‎‎‎‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‎Wifi off.‎‏‎‎‏‎"</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‎‏‏‎‏‎‏‏‏‏‎‎‏‎‎‎‎‏‏‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‎‎‎Wifi disconnected.‎‏‎‎‏‎"</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‎‏‎‎‏‏‎‏‎‏‎‏‎‏‎‎‏‎‎‏‏‏‏‏‎‎‎Wifi one bar.‎‏‎‎‏‎"</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:‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Playback 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 over TLS‎‏‎‎‏‎"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‎‎‏‏‏‎‏‏‎‎‎‏‎‎‎‏‏‏‏‎‎‏‎‏‎‎‎If enabled, attempt DNS over TLS on port 853.‎‏‎‎‏‎"</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‏‏‎‏‎‏‎‏‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‎‎‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‎Private DNS‎‏‎‎‏‎"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‏‎‏‏‏‎‏‎‏‏‎‎‏‏‏‏‏‎‏‏‎Select Private DNS Mode‎‏‎‎‏‎"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‏‏‏‎‎‎‏‏‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‎Off‎‏‎‎‏‎"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‏‏‎‏‎‎‎‎‎‎‎‎‏‎‏‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‏‎‎Opportunistic‎‏‎‎‏‎"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‎‎‏‎‎‎‏‏‏‏‎‎‏‎‎‏‎‎‎Private DNS provider hostname‎‏‎‎‏‎"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‎‎‎‏‎‏‎‏‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‎‎‎‏‎‏‎‏‏‏‎‎‏‎‎‎‎‎‎‎‏‎‎‎‎‎‎‏‏‏‏‎Enter hostname of DNS provider‎‏‎‎‏‎"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‎‎‎‎‎‏‎‎‎‎‎‎‎‏‎‎‎‎‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‏‎‏‏‎‎‏‏‎‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎Show options for wireless display certification‎‏‎‎‏‎"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎‎‏‎‏‏‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎‏‏‏‏‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker‎‏‎‎‏‎"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‏‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‎‎‏‏‎‏‎‎‏‏‏‎‏‏‎When enabled, Wi‑Fi will be more aggressive in handing over the data connection to mobile, when Wi‑Fi signal is low‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index ea62383fe9a5..f351e708cfa1 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"No se pudo sincronizar con <xliff:g id="DEVICE_NAME">%1$s</xliff:g> debido a que el PIN o la clave de acceso son incorrectos."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"No se puede establecer la comunicación con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Vínculo rechazado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Computadora"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Auriculares"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Teléfono"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Imágenes"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Auriculares"</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 inhabilitado"</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desconectado"</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Una barra de Wi-Fi"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 8474c4941e10..a5929e257950 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"No se ha podido vincular con <xliff:g id="DEVICE_NAME">%1$s</xliff:g> porque la clave de acceso o el PIN son incorrectos."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"No se puede establecer comunicación con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Vinculación rechazada por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Ordenador"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Cascos"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Teléfono"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Escáner"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Auriculares"</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 desactivado."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desconectado."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Una barra de Wi-Fi."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Selecciona el códec LDAC por Bluetooth: calidad de reproducción"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Selecciona el códec LDAC de audio por Bluetooth:\nCalidad de reproducción"</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 a través de TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Si esta opción está inhabilitada, prueba DNS a través de 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">"No"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunista"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Nombre de host de proveedor de DNS privado"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Introduce el nombre de host del proveedor de DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opciones para la certificación de la pantalla inalámbrica"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar el nivel de registro de Wi-Fi, mostrar por SSID RSSI en el selector Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Si se activa esta opción, la conexión Wi-Fi será más agresiva al pasar la conexión a datos móviles (si la señal Wi-Fi es débil)"</string>
@@ -382,10 +393,10 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Ayuda y sugerencias"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
- <string name="retail_demo_reset_message" msgid="118771671364131297">"Escribe una contraseña para restablecer datos de fábrica en modo demostración"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"Escribe una contraseña para restablecer estado de fábrica en modo demostración"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"Siguiente"</string>
<string name="retail_demo_reset_title" msgid="696589204029930100">"Contraseña obligatoria"</string>
- <string name="active_input_method_subtypes" msgid="3596398805424733238">"Métodos de introducción activos"</string>
+ <string name="active_input_method_subtypes" msgid="3596398805424733238">"Métodos de introducción de texto activos"</string>
<string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"Usar idiomas del sistema"</string>
<string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"Error al abrir los ajustes de <xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g>"</string>
<string name="ime_security_warning" msgid="4135828934735934248">"Este método de entrada puede registrar todo lo que escribas, incluidos datos personales, como las contraseñas y los números de las tarjetas de crédito. Procede de la aplicación <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. ¿Quieres usar este método de entrada?"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 29b1e2b22ed0..a8d3cca8d033 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Non se puido sincronizar con <xliff:g id="DEVICE_NAME">%1$s</xliff:g> debido a que se introduciu un contrasinal ou PIN incorrecto."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Non se pode comunicar con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Sincronización rexeitada por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Ordenador"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Auriculares con micrófono"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Teléfono"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Imaxes"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Auriculares"</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">"Wifi desactivada."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi desconectada."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Unha barra de wifi."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Códec LDAC de audio por Bluetooth: calidade de reprodución"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Seleccionar códec LDAC de audio por Bluetooth:\ncalidade de reprodución"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Reprodución en tempo real: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS a través de TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Se se activa esta opción, téntase utilizar o método DNS a través de TLS no porto 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 o modo de DNS privado"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Desactivar"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunista"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Nome de host de provedor de DNS privado"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Introduce o nome de host de provedor de DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra opcións para o certificado de visualización sen fíos"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nivel de rexistro da wifi, mostrar por SSID RSSI no selector de wifi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Cando estea activada esta función, a wifi será máis agresiva ao transferir a conexión de datos ao móbil cando o sinal wifi sexa feble"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index cbaa414ebddc..e3f9746d8493 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -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">"ખાનગી 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">"વાઇ-ફાઇ લોગિંગ સ્તર વધારો, વાઇ-ફાઇ પીકરમાં SSID RSSI દીઠ બતાવો"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"જ્યારે સક્ષમ કરેલ હોય, ત્યારે વાઇ-ફાઇ સિગ્નલ નબળું હોવા પર, વાઇ-ફાઇ વધુ ઝડપથી ડેટા કનેક્શનને મોબાઇલ પર મોકલશે"</string>
diff --git a/packages/SettingsLib/res/values-hi/arrays.xml b/packages/SettingsLib/res/values-hi/arrays.xml
index a41c4f239b8f..1a765b34e4d7 100644
--- a/packages/SettingsLib/res/values-hi/arrays.xml
+++ b/packages/SettingsLib/res/values-hi/arrays.xml
@@ -49,14 +49,14 @@
<item msgid="1805837518286731242">"खराब कनेक्शन को अस्थायी रूप से अनदेखा कर रहा है"</item>
</string-array>
<string-array name="hdcp_checking_titles">
- <item msgid="441827799230089869">"कभी नही जांचें"</item>
- <item msgid="6042769699089883931">"केवल DRM सामग्री जांचें"</item>
- <item msgid="9174900380056846820">"हमेशा जांचें"</item>
+ <item msgid="441827799230089869">"कभी नही जाँचें"</item>
+ <item msgid="6042769699089883931">"केवल DRM सामग्री जाँचें"</item>
+ <item msgid="9174900380056846820">"हमेशा जाँचें"</item>
</string-array>
<string-array name="hdcp_checking_summaries">
- <item msgid="505558545611516707">"कभी भी HDCP जांच का उपयोग न करें"</item>
- <item msgid="3878793616631049349">"HDCP जांच का उपयोग केवल DRM सामग्री के लिए करें"</item>
- <item msgid="45075631231212732">"हमेशा HDCP जांच का उपयोग करें"</item>
+ <item msgid="505558545611516707">"कभी भी HDCP जाँच का उपयोग न करें"</item>
+ <item msgid="3878793616631049349">"HDCP जाँच का उपयोग केवल DRM सामग्री के लिए करें"</item>
+ <item msgid="45075631231212732">"हमेशा HDCP जाँच का उपयोग करें"</item>
</string-array>
<string-array name="bluetooth_avrcp_versions">
<item msgid="5347678900838034763">"AVRCP 1.4 (डिफ़ॉल्ट)"</item>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 5d25d2096abe..3b5ea2d846f7 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -30,7 +30,7 @@
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"प्रमाणीकरण समस्या"</string>
<string name="wifi_cant_connect" msgid="5410016875644565884">"कनेक्ट नहीं हो पा रहा है"</string>
<string name="wifi_cant_connect_to_ap" msgid="1222553274052685331">"\'<xliff:g id="AP_NAME">%1$s</xliff:g>\' से कनेक्ट नहीं हो पा रहा है"</string>
- <string name="wifi_check_password_try_again" msgid="516958988102584767">"पासवर्ड जांचें और दोबारा कोशिश करें"</string>
+ <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>
@@ -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">"वाई-फ़ाई बंद है."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"वाई-फ़ाई डिसकनेक्ट है."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"वाई-फ़ाई का एक बार है."</string>
@@ -142,7 +149,7 @@
<string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> पूरी तरह से समर्थित है"</string>
<string name="tts_status_requires_network" msgid="6042500821503226892">"<xliff:g id="LOCALE">%1$s</xliff:g> के लिए नेटवर्क कनेक्शन की आवश्यकता है"</string>
<string name="tts_status_not_supported" msgid="4491154212762472495">"<xliff:g id="LOCALE">%1$s</xliff:g> समर्थित नहीं है"</string>
- <string name="tts_status_checking" msgid="5339150797940483592">"जांच की जा रही है..."</string>
+ <string name="tts_status_checking" msgid="5339150797940483592">"जाँच की जा रही है..."</string>
<string name="tts_engine_settings_title" msgid="3499112142425680334">"<xliff:g id="TTS_ENGINE_NAME">%s</xliff:g> के लिए सेटिंग"</string>
<string name="tts_engine_settings_button" msgid="1030512042040722285">"इंजन सेटिंग लॉन्‍च करें"</string>
<string name="tts_engine_preference_section_title" msgid="448294500990971413">"पसंदीदा इंजन"</string>
@@ -209,10 +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>
- <!-- no translation found for dns_tls (6773814174391131955) -->
- <skip />
- <!-- no translation found for dns_tls_summary (3692494150251071380) -->
- <skip />
+ <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">"वाई-फ़ाई प्रवेश स्तर बढ़ाएं, वाई-फ़ाई पिकर में प्रति SSID RSSI दिखाएं"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"इसके सक्षम होने पर, जब वाई-फ़ाई संकेत कमज़ोर हों तो वाई-फ़ाई, डेटा कनेक्शन को मोबाइल पर ज़्यादा तेज़ी से भेजेगा"</string>
@@ -236,14 +245,14 @@
<string name="dev_settings_warning_title" msgid="7244607768088540165">"विकास सेटिंग की अनुमति दें?"</string>
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ये सेटिंग केवल विकास संबंधी उपयोग के प्रयोजन से हैं. वे आपके डिवाइस और उस पर स्‍थित ऐप्स को खराब कर सकती हैं या उनके दुर्व्यवहार का कारण हो सकती हैं."</string>
<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="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_enable_inband_ringing_summary" msgid="2787866074741784975">"फ़ोन की रिंगटोन को ब्लूटूथ हेडसेट पर बजने दें"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"स्थानीय टर्मिनल"</string>
<string name="enable_terminal_summary" msgid="67667852659359206">"लोकल शेल तक पहुंचने की सुविधा देने वाले टर्मिनल ऐप को चालू करें"</string>
- <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP जांच"</string>
- <string name="hdcp_checking_dialog_title" msgid="5141305530923283">"HDCP जांच व्‍यवहार सेट करें"</string>
+ <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP जाँच"</string>
+ <string name="hdcp_checking_dialog_title" msgid="5141305530923283">"HDCP जाँच व्‍यवहार सेट करें"</string>
<string name="debug_debugging_category" msgid="6781250159513471316">"डीबग करना"</string>
<string name="debug_app" msgid="8349591734751384446">"डीबग ऐप्स को चुनें"</string>
<string name="debug_app_not_set" msgid="718752499586403499">"कोई डीबग ऐप्स सेट नहीं है"</string>
@@ -304,7 +313,7 @@
<string name="force_resizable_activities" msgid="8615764378147824985">"आकार बदले जाने के लिए गतिविधियों को बाध्य करें"</string>
<string name="force_resizable_activities_summary" msgid="6667493494706124459">"सभी गतिविधियों को मल्टी-विंडो (एक से ज़्यादा ऐप, एक साथ) के लिए आकार बदलने लायक बनाएं, चाहे उनकी मेनिफ़ेस्ट वैल्यू कुछ भी हो."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"फ़्रीफ़ॉर्म विंडो (एक साथ कई विंडो दिखाना) चालू करें"</string>
- <string name="enable_freeform_support_summary" msgid="8247310463288834487">"जांच के लिए बनी फ़्रीफ़ॉर्म विंडो के लिए सहायता चालू करें."</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>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 2365058bb8db..34f471bf9ee7 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -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">"Բարձրացնել մակարդակը, Wi‑Fi ընտրիչում ամեն մի SSID-ի համար ցույց տալ RSSI"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Եթե այս գործառույթը միացված է, Wi-Fi-ի թույլ ազդանշանի դեպքում Wi‑Fi ինտերնետից բջջային ինտերնետի անցումը ավելի կտրուկ կկատարվի"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 435abbb908da..c5f4f85af808 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -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">"‏Codec אודיו LDAC ל-Bluetooth: איכות נגינה"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"‏בחירת Codec אודיו 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">"‏הצג אפשרויות עבור אישור של תצוגת WiFi"</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>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 8d9a7e150f87..d7ab9feaf55e 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -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">"ವೈಫೈ ಆಫ್."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"ವೈಫೈ ಸಂಪರ್ಕ ಕಡಿತಗೊಂಡಿದೆ."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"ವೈಫೈ ಒಂದು ಪಟ್ಟಿ."</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">"ಇದು ಸಕ್ರಿಯಗೊಂಡರೆ, ವೈ-ಫೈ ಸಿಗ್ನಲ್ ದುರ್ಬಲವಾಗಿದ್ದಾಗ, ಮೊಬೈಲ್‌ಗೆ ಡೇಟಾ ಸಂಪರ್ಕವನ್ನು ಹಸ್ತಾಂತರಿಸುವಲ್ಲಿ ವೈ-ಫೈ ಹೆಚ್ಚು ಆಕ್ರಮಣಕಾರಿಯಾಗಿರುತ್ತದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index a2a10f273092..a96fbcf3cbe5 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -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">"വൈഫൈ ഓഫാണ്."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"വൈഫൈ വിച്ഛേദിച്ചു."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"വൈഫൈ സിഗ്നൽ ഒരു ബാർ."</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-ലെ 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">"വൈഫൈ പിക്കറിൽ ഓരോ SSID RSSI പ്രകാരം കാണിക്കാൻ വൈഫൈ ലോഗിംഗ് നില വർദ്ധിപ്പിക്കുക"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"പ്രവർത്തനക്ഷമമായിരിക്കുമ്പോൾ, വൈഫൈ സിഗ്‌നൽ കുറവായിരിക്കുന്ന സമയത്ത് മൊബൈലിലേക്ക് ഡാറ്റ കണക്ഷൻ വഴി കൈമാറുന്നതിൽ വൈഫൈ കൂടുതൽ സക്രിയമായിരിക്കും"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 42ee5817e341..3ac692335b40 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -22,7 +22,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="wifi_fail_to_scan" msgid="1265540342578081461">"नेटवर्कसाठी स्कॅन करू शकत नाही"</string>
<string name="wifi_security_none" msgid="7985461072596594400">"काहीही नाही"</string>
- <string name="wifi_remembered" msgid="4955746899347821096">"जतन केले"</string>
+ <string name="wifi_remembered" msgid="4955746899347821096">"सेव्ह केले"</string>
<string name="wifi_disabled_generic" msgid="4259794910584943386">"अक्षम"</string>
<string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP कॉन्फिगरेशन अयशस्वी"</string>
<string name="wifi_disabled_by_recommendation_provider" msgid="5168315140978066096">"कमी दर्जाच्या नेटवर्कमुळे कनेक्ट केलेले नाही"</string>
@@ -34,7 +34,7 @@
<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="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारे जतन केले"</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>
@@ -52,7 +52,7 @@
<string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
<string name="bluetooth_disconnected" msgid="6557104142667339895">"डिस्कनेक्ट केले"</string>
<string name="bluetooth_disconnecting" msgid="8913264760027764974">"डिस्कनेक्ट करत आहे..."</string>
- <string name="bluetooth_connecting" msgid="8555009514614320497">"कनेक्ट करीत आहे..."</string>
+ <string name="bluetooth_connecting" msgid="8555009514614320497">"कनेक्ट करत आहे..."</string>
<string name="bluetooth_connected" msgid="6038755206916626419">"कनेक्ट केले"</string>
<string name="bluetooth_pairing" msgid="1426882272690346242">"जोडत आहे…"</string>
<string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"कनेक्ट केले (फोन नाही)"</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">"वाय फाय बंद."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"वाय फाय डिस्कनेक्ट झाले."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"वाय फाय एक बार."</string>
@@ -135,7 +142,7 @@
<string name="tts_play_example_summary" msgid="8029071615047894486">"उच्चार संश्लेषणाचे एक छोटेसे प्रात्यक्षिक प्ले करा"</string>
<string name="tts_install_data_title" msgid="4264378440508149986">"व्हॉइस डेटा इंस्टॉल करा"</string>
<string name="tts_install_data_summary" msgid="5742135732511822589">"उच्चार संश्लेषणासाठी आवश्यक आवाज डेटा इंस्टॉल करा"</string>
- <string name="tts_engine_security_warning" msgid="8786238102020223650">"हे उच्चार संश्लेषण इंजिन संकेतशब्द आणि क्रेडिट कार्ड नंबर यासारख्या वैयक्तिक मजकुरासह, बोलला जाणारा सर्व मजकूर संकलित करण्यात सक्षम होऊ शकते. हे <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> इंजिनवरून येते. या उच्चार संश्लेषण इंजिनचा वापर सक्षम करायचा?"</string>
+ <string name="tts_engine_security_warning" msgid="8786238102020223650">"हे उच्चार संश्लेषण इंजिन पासवर्ड आणि क्रेडिट कार्ड नंबर यासारख्या वैयक्तिक मजकुरासह, बोलला जाणारा सर्व मजकूर संकलित करण्यात सक्षम होऊ शकते. हे <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> इंजिनवरून येते. या उच्चार संश्लेषण इंजिनचा वापर सक्षम करायचा?"</string>
<string name="tts_engine_network_required" msgid="1190837151485314743">"या भाषेस टेक्‍स्‍ट टू स्‍पीचसाठी एका नेटवर्क कनेक्शनची आवश्यकता आहे."</string>
<string name="tts_default_sample_string" msgid="4040835213373086322">"हे उच्चार संश्लेषणाचे एक उदाहरण आहे"</string>
<string name="tts_status_title" msgid="7268566550242584413">"डीफॉल्ट भाषा स्थिती"</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">"खाजगी 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">"वाय-फाय लॉगिंग स्‍तर वाढवा, वाय-फाय सिलेक्टरमध्‍ये प्रति SSID RSSI दर्शवा"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"सक्षम केले असताना, वाय-फाय सिग्‍नल कमी असताना, मोबाइलकडे डेटा कनेक्‍शन सोपवण्यासाठी वाय-फाय अधिक अॅग्रेसिव्ह असेल."</string>
@@ -245,7 +256,7 @@
<string name="debug_debugging_category" msgid="6781250159513471316">"डीबग करणे"</string>
<string name="debug_app" msgid="8349591734751384446">"डीबग अॅप निवडा"</string>
<string name="debug_app_not_set" msgid="718752499586403499">"कोणतेही डीबग अॅप्लिकेशन सेट नाही"</string>
- <string name="debug_app_set" msgid="2063077997870280017">"अॅप्लिकेशन डीबग करीत आहे: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="debug_app_set" msgid="2063077997870280017">"अॅप्लिकेशन डीबग करत आहे: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="select_application" msgid="5156029161289091703">"अॅप्लिकेशन निवडा"</string>
<string name="no_application" msgid="2813387563129153880">"काहीही नाही"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"डीबगरची प्रतीक्षा करा"</string>
@@ -303,11 +314,11 @@
<string name="force_resizable_activities_summary" msgid="6667493494706124459">"manifest मूल्यांकडे दुर्लक्ष करून, एकाधिक-विंडोसाठी सर्व क्रियाकलापांचा आकार बदलण्यायोग्य करा."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"freeform विंडो सक्षम करा"</string>
<string name="enable_freeform_support_summary" msgid="8247310463288834487">"प्रायोगिक मुक्तस्वरूपाच्या विंडोसाठी समर्थन सक्षम करा."</string>
- <string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटॉप बॅकअप संकेतशब्द"</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_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_confirmation_mismatch" msgid="7805892532752708288">"नवीन पासवर्ड आणि पुष्टीकरण जुळत नाही"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"बॅक अप पासवर्ड सेट करणे अयशस्वी"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"सशक्त (डीफॉल्ट)"</item>
@@ -382,13 +393,13 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"सानुकूल करा (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"मदत आणि अभिप्राय"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"मेनू"</string>
- <string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोडमध्ये फॅक्टरी रीसेट करण्यासाठी पासवर्ड प्रविष्ट करा"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोडमध्ये फॅक्टरी रीसेट करण्यासाठी पासवर्ड एंटर करा"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"पुढील"</string>
- <string name="retail_demo_reset_title" msgid="696589204029930100">"संकेतशब्द आवश्यक"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"पासवर्ड आवश्यक"</string>
<string name="active_input_method_subtypes" msgid="3596398805424733238">"सक्रिय इनपुट पद्धती"</string>
<string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"सिस्टम भाषा वापरा"</string>
<string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> साठी सेटिंग्ज उघडण्यात अयशस्वी"</string>
- <string name="ime_security_warning" msgid="4135828934735934248">"ही इनपुट पद्धत संकेतशब्द आणि क्रेडिट कार्ड नंबर यासह, आपण टाइप करता तो सर्व मजकूर संकलित करण्यात सक्षम होऊ शकते. ही <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> अॅपवरून येते. ही इनपुट पद्धत वापरायची?"</string>
+ <string name="ime_security_warning" msgid="4135828934735934248">"ही इनपुट पद्धत पासवर्ड आणि क्रेडिट कार्ड नंबर यासह, आपण टाइप करता तो सर्व मजकूर संकलित करण्यात सक्षम होऊ शकते. ही <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> अॅपवरून येते. ही इनपुट पद्धत वापरायची?"</string>
<string name="direct_boot_unaware_dialog_message" msgid="7870273558547549125">"टीप: रीबूट केल्यानंतर, तुम्ही आपला फोन अनलॉक करे पर्यंत हे अॅप सुरू होऊ शकत नाही"</string>
<string name="ims_reg_title" msgid="7609782759207241443">"IMS नोंदणी स्थिती"</string>
<string name="ims_reg_status_registered" msgid="933003316932739188">"नोंदवलेले"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 7d166b403f3f..c1892c3ee322 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -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 over TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"ဖွင့်ထားပါက DNS over 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 လွှင့်အား နည်းချိန်တွင် Wi‑Fi မှ မိုဘိုင်းသို့ ဒေတာချိတ်ဆက်မှုကို လွှဲပြောင်းရာ၌ ပိုမိုထိရောက်ပါသည်"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index a3875a6a2026..172fed1a14e9 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -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">"सक्षम पारिएको खण्डमा पोर्ट ८५३ मा 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>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 4d0d7fe8d932..38853f09bd82 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Kan niet koppelen aan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> vanwege een onjuiste pincode of toegangscode."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Kan niet communiceren met <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Koppeling geweigerd door <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">"Telefoon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Replicatieapparaat"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Hoofdtelefoon"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Randapparaat voor invoer"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi: uitgeschakeld."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi-verbinding verbroken."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi: één streepje."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"LDAC-codec voor Bluetooth-audio: afspeelkwaliteit"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"LDAC-codec voor Bluetooth-audio selecteren:\nafspeelkwaliteit"</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">"Als deze optie is ingeschakeld, wordt geprobeerd om DNS via TLS uit te voeren via poort 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Privé-DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selecteer de modus Privé-DNS"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Uit"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Opportunistisch"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Hostnaam van privé-DNS-provider"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Geef hostnaam van DNS-provider op"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Opties weergeven voor certificering van draadloze weergave"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Logniveau voor wifi verhogen, weergeven per SSID RSSI in wifi-kiezer"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Indien ingeschakeld, is wifi agressiever bij het overgeven van de gegevensverbinding aan mobiel wanneer het wifi-signaal zwak is"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 56e361f20e08..be4fa8d6a727 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -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">"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">"ਵਾਈ‑ਫਾਈ ਲੌਗਿੰਗ ਪੱਧਰ ਵਧਾਓ, ਵਾਈ‑ਫਾਈ Picker ਵਿੱਚ ਪ੍ਰਤੀ SSID RSSI ਦਿਖਾਓ"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"ਜਦੋਂ ਯੋਗ ਬਣਾਇਆ ਹੋਵੇ, ਤਾਂ ਵਾਈ‑ਫਾਈ ਸਿਗਨਲ ਘੱਟ ਹੋਣ \'ਤੇ ਵਾਈ‑ਫਾਈ ਡਾਟਾ ਕਨੈਕਸ਼ਨ ਮੋਬਾਈਲ ਨੂੰ ਹੈਂਡ ਓਵਰ ਕਰਨ ਵਿੱਚ ਵੱਧ ਆਕਰਮਣਸ਼ੀਲ ਹੋਵੇਗਾ।"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 7be64e41f302..89a18ef5c014 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nu s-a putut împerechea cu <xliff:g id="DEVICE_NAME">%1$s</xliff:g> din cauza unui cod PIN sau al unei chei de acces incorecte."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Nu se poate comunica cu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Împerechere respinsă de <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">"Set căști-microfon"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Dispozitiv pentru imagini"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Căști"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Dispozitiv periferic de intrare"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi dezactivat."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi deconectat."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Semnal Wi-Fi: o bară."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Codecul LDAC audio pentru Bluetooth: calitatea redării"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Selectați codecul LDAC audio pentru Bluetooth:\ncalitatea redării"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Transmitere în flux: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS prin TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Dacă opțiunea este activată, încercați DNS prin TLS pe portul 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS privat"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selectați modul DNS privat"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Dezactivat"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Oportunist"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Nume de gazdă al furnizorului de DNS privat"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Introduceți numele de gazdă al furnizorului de DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afișați opțiunile pentru certificarea Ecran wireless"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Măriți niv. de înr. prin Wi‑Fi, afișați în fcț. de SSID RSSI în Selectorul Wi‑Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Când este activată, Wi-Fi va fi mai agresivă la predarea conexiunii de date către rețeaua mobilă când semnalul Wi-Fi este slab"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 756254b98c1c..a1beef68d8cd 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Haikuweza kulingana na <xliff:g id="DEVICE_NAME">%1$s</xliff:g> kwa sababu ya PIN isiyo sahihi au msimbo ya kuingia."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Haiwezi kuanzisha mawasiliano na <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Ulinganishaji umekataliwa na <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Kompyuta"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Vifaa vya sauti"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Simu"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Kupiga picha"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Kifaa cha sauti"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Vifaa vya Ziada vya Kuingiza Data"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi imezimwa."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi imeondolewa."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Kipima mtandao kimoja cha Wifi."</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Kodeki ya LDAC ya Sauti ya Bluetooth: Ubora wa Kucheza"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"Chagua Kodeki ya LDAC ya Sauti ya Bluetooth:\nUbora wa Kucheza"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Kutiririsha: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"DNS kupitia TLS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Ukiwasha mipangilio hii, jaribu kutumia DNS kupitia TLS kwenye mlango wa 853."</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS ya Faragha"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Chagua Hali ya DNS ya Faragha"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Imezimwa"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Inayojitokeza"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Jina la mpangishi wa huduma za DNS ya faragha"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"Weka jina la mpangishi wa huduma za DNS"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Onyesha chaguo za cheti cha kuonyesha pasiwaya"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Ongeza hatua ya uwekaji kumbukumbu ya Wi-Fi, onyesha kwa kila SSID RSSI kwenye Kichukuzi cha Wi-Fi"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Ikiwashwa, Wi-Fi itakabidhi kwa hima muunganisho wa data kwa mtandao wa simu, wakati mtandao wa Wi-Fi si thabiti"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index e31e3e0a4377..3a8b17518afa 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -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">"வைஃபை முடக்கப்பட்டது."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"வைஃபை துண்டிக்கப்பட்டது."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"வைஃபை சிக்னல்: ஒரு கோடு."</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">"Wifi நுழைவு அளவை அதிகரித்து, வைஃபை தேர்வியில் ஒவ்வொன்றிற்கும் SSID RSSI ஐ காட்டுக"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"இயக்கப்பட்டதும், வைஃபை சிக்னல் குறையும் போது, வைஃபை முழுமையாக ஒத்துழைக்காமல் இருந்தால் மொபைல் தரவிற்கு மாறும்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 0c28ef218b8d..b6f1bd2c8139 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -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">"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 ఎంపికలో SSID RSSI ప్రకారం చూపబడే Wi‑Fi లాగింగ్ స్థాయిని పెంచండి"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"ప్రారంభించబడినప్పుడు, Wi‑Fi సిగ్నల్ బలహీనంగా ఉంటే డేటా కనెక్షన్‌ను మొబైల్‌కి మార్చేలా Wi‑Fi చురుగ్గా వ్యవహరిస్తుంది"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 782bb6fc4230..3b6ab4a53748 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -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>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 95e4455e2d1d..4b3d2d47b4bc 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> qurilmasiga ulanib bo‘lmadi, chunki PIN-kod yoki parol noto‘g‘ri kiritildi."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>” qurilmasi bilan aloqa o‘rnatib bo‘lmayapti."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> biriktirish so‘rovini rad qildi."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Kompyuter"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Audio moslama"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Telefon"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Kamera"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Quloqchin"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Kiritish qurilmasi"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi o‘chiq."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi o‘chiq."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi: bitta ustun"</string>
@@ -209,8 +216,12 @@
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"LDAC audiokodeki bilan ijro etish sifati (Bluetooth orqali)"</string>
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3181967377574368400">"LDAC audiokodeki:\nijro sifati"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Translatsiya: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
- <string name="dns_tls" msgid="6773814174391131955">"TLS orqali DNS"</string>
- <string name="dns_tls_summary" msgid="3692494150251071380">"Yoqilgan bo‘lsa, TLS orqali DNS serverini 853-port yordamida sozlab ko‘ring"</string>
+ <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Shaxsiy DNS"</string>
+ <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Shaxsiy DNS rejimini tanlang"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"O‘chiq"</string>
+ <string name="private_dns_mode_opportunistic" msgid="7608409735589131766">"Moslashuvchan"</string>
+ <string name="private_dns_mode_provider" msgid="8354935160639360804">"Shaxsiy DNS provayderining host nomi"</string>
+ <string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS provayderining host nomini kiriting"</string>
<string name="wifi_display_certification_summary" msgid="1155182309166746973">"Simsiz monitorlarni sertifikatlash parametrini ko‘rsatish"</string>
<string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi ulanishini tanlashda har bir SSID uchun jurnalda ko‘rsatilsin"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"Agar ushbu funksiya yoqilsa, Wi-Fi signali past bo‘lganda internetga ulanish majburiy ravishda mobil internetga o‘tkaziladi"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 094bb906a3c0..dd58cc941dce 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -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">"WLAN 已关闭。"</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"WLAN 连接已断开。"</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"WLAN 信号强度为一格。"</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">"提升WLAN日志记录级别(在WLAN选择器中显示每个SSID的RSSI)"</string>
<string name="wifi_aggressive_handover_summary" msgid="7266329646559808827">"开启此设置后,系统会在 WLAN 信号较弱时,主动将网络模式从 WLAN 网络切换到移动数据网络"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 360848f72ddd..4bb16ffe597e 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -546,11 +546,13 @@
<!-- [CHAR LIMIT=NONE] Label for displaying Bluetooth Audio Codec Parameters while streaming -->
<string name="bluetooth_select_a2dp_codec_streaming_label">Streaming: <xliff:g id="streaming_parameter">%1$s</xliff:g></string>
- <!-- Title of the developer option for DNS over TLS. -->
- <string name="dns_tls">DNS over TLS</string>
- <!-- Summary to explain the developer option for DNS over TLS. This allows the user to
- request that the system attempt TLS with all DNS servers, or none. -->
- <string name="dns_tls_summary">If enabled, attempt DNS over TLS on port 853.</string>
+ <!-- Developer option setting for Private DNS -->
+ <string name="select_private_dns_configuration_title">Private DNS</string>
+ <string name="select_private_dns_configuration_dialog_title">Select Private DNS Mode</string>
+ <string name="private_dns_mode_off">Off</string>
+ <string name="private_dns_mode_opportunistic">Opportunistic</string>
+ <string name="private_dns_mode_provider">Private DNS provider hostname</string>
+ <string name="private_dns_mode_provider_hostname_hint">Enter hostname of DNS provider</string>
<!-- setting Checkbox summary whether to show options for wireless display certification -->
<string name="wifi_display_certification_summary">Show options for wireless display certification</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
index 90124f1f558f..8e29e50fc848 100644
--- a/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
@@ -49,8 +49,13 @@ public class CustomEditTextPreference extends EditTextPreference {
}
public EditText getEditText() {
- return mFragment != null ? (EditText) mFragment.getDialog().findViewById(android.R.id.edit)
- : null;
+ if (mFragment != null) {
+ final Dialog dialog = mFragment.getDialog();
+ if (dialog != null) {
+ return (EditText) dialog.findViewById(android.R.id.edit);
+ }
+ }
+ return null;
}
public boolean isDialogOpen() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java b/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java
index 78a9064f1400..f2cd1033cd38 100644
--- a/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java
@@ -22,12 +22,15 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
+import android.system.Os;
+import android.system.StructUtsname;
import android.telephony.PhoneNumberUtils;
import android.telephony.SubscriptionInfo;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.Log;
+import android.support.annotation.VisibleForTesting;
import java.io.BufferedReader;
import java.io.FileReader;
@@ -45,7 +48,6 @@ import static android.content.Context.TELEPHONY_SERVICE;
public class DeviceInfoUtils {
private static final String TAG = "DeviceInfoUtils";
- private static final String FILENAME_PROC_VERSION = "/proc/version";
private static final String FILENAME_MSV = "/sys/board_properties/soc/msv";
/**
@@ -63,43 +65,36 @@ public class DeviceInfoUtils {
}
}
- public static String getFormattedKernelVersion() {
- try {
- return formatKernelVersion(readLine(FILENAME_PROC_VERSION));
- } catch (IOException e) {
- Log.e(TAG, "IO Exception when getting kernel version for Device Info screen",
- e);
-
- return "Unavailable";
- }
+ public static String getFormattedKernelVersion(Context context) {
+ return formatKernelVersion(context, Os.uname());
}
- public static String formatKernelVersion(String rawKernelVersion) {
- // Example (see tests for more):
- // Linux version 4.9.29-g958411d (android-build@xyz) (Android clang version 3.8.256229 \
- // (based on LLVM 3.8.256229)) #1 SMP PREEMPT Wed Jun 7 00:06:03 CST 2017
- // Linux version 4.9.29-geb63318482a7 (android-build@xyz) (gcc version 4.9.x 20150123 \
- // (prerelease) (GCC) ) #1 SMP PREEMPT Thu Jun 1 03:41:57 UTC 2017
- final String PROC_VERSION_REGEX =
- "Linux version (\\S+) " + /* group 1: "3.0.31-g6fb96c9" */
- "\\((\\S+?)\\) " + /* group 2: "(x@y.com) " */
- "\\((.+?)\\) " + /* group 3: kernel toolchain version information */
- "(#\\d+) " + /* group 4: "#1" */
+ @VisibleForTesting
+ static String formatKernelVersion(Context context, StructUtsname uname) {
+ if (uname == null) {
+ return context.getString(R.string.status_unavailable);
+ }
+ // Example:
+ // 4.9.29-g958411d
+ // #1 SMP PREEMPT Wed Jun 7 00:06:03 CST 2017
+ final String VERSION_REGEX =
+ "(#\\d+) " + /* group 1: "#1" */
"(?:.*?)?" + /* ignore: optional SMP, PREEMPT, and any CONFIG_FLAGS */
- "((Sun|Mon|Tue|Wed|Thu|Fri|Sat).+)"; /* group 5: "Thu Jun 28 11:02:39 PDT 2012" */
-
- Matcher m = Pattern.compile(PROC_VERSION_REGEX).matcher(rawKernelVersion);
+ "((Sun|Mon|Tue|Wed|Thu|Fri|Sat).+)"; /* group 2: "Thu Jun 28 11:02:39 PDT 2012" */
+ Matcher m = Pattern.compile(VERSION_REGEX).matcher(uname.version);
if (!m.matches()) {
- Log.e(TAG, "Regex did not match on /proc/version: " + rawKernelVersion);
- return "Unavailable";
- } else if (m.groupCount() < 4) {
- Log.e(TAG, "Regex match on /proc/version only returned " + m.groupCount()
- + " groups");
- return "Unavailable";
+ Log.e(TAG, "Regex did not match on uname version " + uname.version);
+ return context.getString(R.string.status_unavailable);
}
- return m.group(1) + " ("+ m.group(3) + ")\n" + // 3.0.31-g6fb96c9 (toolchain version)
- m.group(2) + " " + m.group(4) + "\n" + // x@y.com #1
- m.group(5); // Thu Jun 28 11:02:39 PDT 2012
+
+ // Example output:
+ // 4.9.29-g958411d
+ // #1 Wed Jun 7 00:06:03 CST 2017
+ return new StringBuilder().append(uname.release)
+ .append("\n")
+ .append(m.group(1))
+ .append(" ")
+ .append(m.group(2)).toString();
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index d90386f904ec..218616929e0d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -94,7 +94,7 @@ public class Utils {
public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) {
final int iconSize = UserIconDrawable.getSizeForList(context);
if (user.isManagedProfile()) {
- Drawable drawable = context.getDrawable(com.android.internal.R.drawable.ic_corp_icon);
+ Drawable drawable = context.getDrawable(com.android.internal.R.drawable.ic_corp_badge);
drawable.setBounds(0, 0, iconSize, iconSize);
return drawable;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
index 38fe8790e4d0..88f0d2be311f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
@@ -10,79 +10,63 @@ import android.support.v7.preference.PreferenceScreen;
*/
public abstract class AbstractPreferenceController {
- protected final Context mContext;
+ protected final Context mContext;
- public AbstractPreferenceController(Context context) {
- mContext = context;
- }
+ public AbstractPreferenceController(Context context) {
+ mContext = context;
+ }
- /**
- * Displays preference in this controller.
- */
- public void displayPreference(PreferenceScreen screen) {
- if (isAvailable()) {
- if (this instanceof Preference.OnPreferenceChangeListener) {
- final Preference preference = screen.findPreference(getPreferenceKey());
- preference.setOnPreferenceChangeListener(
- (Preference.OnPreferenceChangeListener) this);
- }
- } else {
- removePreference(screen, getPreferenceKey());
- }
- }
+ /**
+ * Displays preference in this controller.
+ */
+ public void displayPreference(PreferenceScreen screen) {
+ final String prefKey = getPreferenceKey();
+ if (isAvailable()) {
+ setVisible(screen, prefKey, true /* visible */);
+ if (this instanceof Preference.OnPreferenceChangeListener) {
+ final Preference preference = screen.findPreference(prefKey);
+ preference.setOnPreferenceChangeListener(
+ (Preference.OnPreferenceChangeListener) this);
+ }
+ } else {
+ setVisible(screen, prefKey, false /* visible */);
+ }
+ }
- /**
- * Updates the current status of preference (summary, switch state, etc)
- */
- public void updateState(Preference preference) {
+ /**
+ * Updates the current status of preference (summary, switch state, etc)
+ */
+ public void updateState(Preference preference) {
- }
+ }
- /**
- * Returns true if preference is available (should be displayed)
- */
- public abstract boolean isAvailable();
+ /**
+ * Returns true if preference is available (should be displayed)
+ */
+ public abstract boolean isAvailable();
- /**
- * Handles preference tree click
- *
- * @param preference the preference being clicked
- * @return true if click is handled
- */
- public boolean handlePreferenceTreeClick(Preference preference) {
- return false;
- }
+ /**
+ * Handles preference tree click
+ *
+ * @param preference the preference being clicked
+ * @return true if click is handled
+ */
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ return false;
+ }
- /**
- * Returns the key for this preference.
- */
- public abstract String getPreferenceKey();
-
- /**
- * Removes preference from screen.
- */
- protected final void removePreference(PreferenceScreen screen, String key) {
- findAndRemovePreference(screen, key);
- }
-
- // finds the preference recursively and removes it from its parent
- private boolean findAndRemovePreference(PreferenceGroup prefGroup, String key) {
- final int preferenceCount = prefGroup.getPreferenceCount();
- for (int i = 0; i < preferenceCount; i++) {
- final Preference preference = prefGroup.getPreference(i);
- final String curKey = preference.getKey();
-
- if (curKey != null && curKey.equals(key)) {
- return prefGroup.removePreference(preference);
- }
-
- if (preference instanceof PreferenceGroup) {
- if (findAndRemovePreference((PreferenceGroup) preference, key)) {
- return true;
- }
- }
- }
- return false;
- }
+ /**
+ * Returns the key for this preference.
+ */
+ public abstract String getPreferenceKey();
+ /**
+ * Show/hide a preference.
+ */
+ protected final void setVisible(PreferenceGroup group, String key, boolean isVisible) {
+ final Preference pref = group.findPreference(key);
+ if (pref != null) {
+ pref.setVisible(isVisible);
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java
index b2351a9ee0e4..451e5611979a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java
@@ -15,11 +15,18 @@
*/
package com.android.settingslib.core.lifecycle;
+import static android.arch.lifecycle.Lifecycle.Event.ON_ANY;
+
import android.annotation.UiThread;
+import android.arch.lifecycle.LifecycleOwner;
+import android.arch.lifecycle.LifecycleRegistry;
+import android.arch.lifecycle.OnLifecycleEvent;
import android.content.Context;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.preference.PreferenceScreen;
+import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -44,18 +51,46 @@ import java.util.List;
/**
* Dispatcher for lifecycle events.
*/
-public class Lifecycle {
+public class Lifecycle extends LifecycleRegistry {
+ private static final String TAG = "LifecycleObserver";
+
+ private final List<LifecycleObserver> mObservers = new ArrayList<>();
+ private final LifecycleProxy mProxy = new LifecycleProxy();
- protected final List<LifecycleObserver> mObservers = new ArrayList<>();
+ /**
+ * Creates a new LifecycleRegistry for the given provider.
+ * <p>
+ * You should usually create this inside your LifecycleOwner class's constructor and hold
+ * onto the same instance.
+ *
+ * @param provider The owner LifecycleOwner
+ */
+ public Lifecycle(@NonNull LifecycleOwner provider) {
+ super(provider);
+ addObserver(mProxy);
+ }
/**
* Registers a new observer of lifecycle events.
*/
@UiThread
- public <T extends LifecycleObserver> T addObserver(T observer) {
+ @Override
+ public void addObserver(android.arch.lifecycle.LifecycleObserver observer) {
ThreadUtils.ensureMainThread();
- mObservers.add(observer);
- return observer;
+ super.addObserver(observer);
+ if (observer instanceof LifecycleObserver) {
+ mObservers.add((LifecycleObserver) observer);
+ }
+ }
+
+ @UiThread
+ @Override
+ public void removeObserver(android.arch.lifecycle.LifecycleObserver observer) {
+ ThreadUtils.ensureMainThread();
+ super.removeObserver(observer);
+ if (observer instanceof LifecycleObserver) {
+ mObservers.remove(observer);
+ }
}
public void onAttach(Context context) {
@@ -67,6 +102,8 @@ public class Lifecycle {
}
}
+ // This method is not called from the proxy because it does not have access to the
+ // savedInstanceState
public void onCreate(Bundle savedInstanceState) {
for (int i = 0, size = mObservers.size(); i < size; i++) {
final LifecycleObserver observer = mObservers.get(i);
@@ -76,7 +113,7 @@ public class Lifecycle {
}
}
- public void onStart() {
+ private void onStart() {
for (int i = 0, size = mObservers.size(); i < size; i++) {
final LifecycleObserver observer = mObservers.get(i);
if (observer instanceof OnStart) {
@@ -94,7 +131,7 @@ public class Lifecycle {
}
}
- public void onResume() {
+ private void onResume() {
for (int i = 0, size = mObservers.size(); i < size; i++) {
final LifecycleObserver observer = mObservers.get(i);
if (observer instanceof OnResume) {
@@ -103,7 +140,7 @@ public class Lifecycle {
}
}
- public void onPause() {
+ private void onPause() {
for (int i = 0, size = mObservers.size(); i < size; i++) {
final LifecycleObserver observer = mObservers.get(i);
if (observer instanceof OnPause) {
@@ -121,7 +158,7 @@ public class Lifecycle {
}
}
- public void onStop() {
+ private void onStop() {
for (int i = 0, size = mObservers.size(); i < size; i++) {
final LifecycleObserver observer = mObservers.get(i);
if (observer instanceof OnStop) {
@@ -130,7 +167,7 @@ public class Lifecycle {
}
}
- public void onDestroy() {
+ private void onDestroy() {
for (int i = 0, size = mObservers.size(); i < size; i++) {
final LifecycleObserver observer = mObservers.get(i);
if (observer instanceof OnDestroy) {
@@ -168,4 +205,34 @@ public class Lifecycle {
}
return false;
}
+
+ private class LifecycleProxy
+ implements android.arch.lifecycle.LifecycleObserver {
+ @OnLifecycleEvent(ON_ANY)
+ public void onLifecycleEvent(LifecycleOwner owner, Event event) {
+ switch (event) {
+ case ON_CREATE:
+ // onCreate is called directly since we don't have savedInstanceState here
+ break;
+ case ON_START:
+ onStart();
+ break;
+ case ON_RESUME:
+ onResume();
+ break;
+ case ON_PAUSE:
+ onPause();
+ break;
+ case ON_STOP:
+ onStop();
+ break;
+ case ON_DESTROY:
+ onDestroy();
+ break;
+ case ON_ANY:
+ Log.wtf(TAG, "Should not receive an 'ANY' event!");
+ break;
+ }
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/LifecycleObserver.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/LifecycleObserver.java
index 6c4107290274..ec8a8b537f48 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/LifecycleObserver.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/LifecycleObserver.java
@@ -17,6 +17,9 @@ package com.android.settingslib.core.lifecycle;
/**
* Observer of lifecycle events.
+ * @deprecated use {@link android.arch.lifecycle.LifecycleObserver} instead
*/
-public interface LifecycleObserver {
+@Deprecated
+public interface LifecycleObserver extends
+ android.arch.lifecycle.LifecycleObserver {
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservableActivity.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservableActivity.java
index 727bec75c204..8b062f8447b0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservableActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservableActivity.java
@@ -15,8 +15,16 @@
*/
package com.android.settingslib.core.lifecycle;
+import static android.arch.lifecycle.Lifecycle.Event.ON_CREATE;
+import static android.arch.lifecycle.Lifecycle.Event.ON_DESTROY;
+import static android.arch.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static android.arch.lifecycle.Lifecycle.Event.ON_RESUME;
+import static android.arch.lifecycle.Lifecycle.Event.ON_START;
+import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
+
import android.annotation.Nullable;
import android.app.Activity;
+import android.arch.lifecycle.LifecycleOwner;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.view.Menu;
@@ -25,17 +33,19 @@ import android.view.MenuItem;
/**
* {@link Activity} that has hooks to observe activity lifecycle events.
*/
-public class ObservableActivity extends Activity {
+public class ObservableActivity extends Activity implements LifecycleOwner {
- private final Lifecycle mLifecycle = new Lifecycle();
+ private final Lifecycle mLifecycle = new Lifecycle(this);
- protected Lifecycle getLifecycle() {
+ public Lifecycle getLifecycle() {
return mLifecycle;
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
mLifecycle.onAttach(this);
+ mLifecycle.onCreate(savedInstanceState);
+ mLifecycle.handleLifecycleEvent(ON_CREATE);
super.onCreate(savedInstanceState);
}
@@ -43,36 +53,38 @@ public class ObservableActivity extends Activity {
public void onCreate(@Nullable Bundle savedInstanceState,
@Nullable PersistableBundle persistentState) {
mLifecycle.onAttach(this);
+ mLifecycle.onCreate(savedInstanceState);
+ mLifecycle.handleLifecycleEvent(ON_CREATE);
super.onCreate(savedInstanceState, persistentState);
}
@Override
protected void onStart() {
- mLifecycle.onStart();
+ mLifecycle.handleLifecycleEvent(ON_START);
super.onStart();
}
@Override
protected void onResume() {
- mLifecycle.onResume();
+ mLifecycle.handleLifecycleEvent(ON_RESUME);
super.onResume();
}
@Override
protected void onPause() {
- mLifecycle.onPause();
+ mLifecycle.handleLifecycleEvent(ON_PAUSE);
super.onPause();
}
@Override
protected void onStop() {
- mLifecycle.onStop();
+ mLifecycle.handleLifecycleEvent(ON_STOP);
super.onStop();
}
@Override
protected void onDestroy() {
- mLifecycle.onDestroy();
+ mLifecycle.handleLifecycleEvent(ON_DESTROY);
super.onDestroy();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservableDialogFragment.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservableDialogFragment.java
index 315bedc168bb..dc95384b26a5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservableDialogFragment.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservableDialogFragment.java
@@ -15,9 +15,17 @@
*/
package com.android.settingslib.core.lifecycle;
+import static android.arch.lifecycle.Lifecycle.Event.ON_CREATE;
+import static android.arch.lifecycle.Lifecycle.Event.ON_DESTROY;
+import static android.arch.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static android.arch.lifecycle.Lifecycle.Event.ON_RESUME;
+import static android.arch.lifecycle.Lifecycle.Event.ON_START;
+import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
+
import android.app.DialogFragment;
+import android.arch.lifecycle.LifecycleOwner;
import android.content.Context;
-import android.support.annotation.VisibleForTesting;
+import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -25,9 +33,9 @@ import android.view.MenuItem;
/**
* {@link DialogFragment} that has hooks to observe fragment lifecycle events.
*/
-public class ObservableDialogFragment extends DialogFragment {
+public class ObservableDialogFragment extends DialogFragment implements LifecycleOwner {
- protected final Lifecycle mLifecycle = createLifecycle();
+ protected final Lifecycle mLifecycle = new Lifecycle(this);
@Override
public void onAttach(Context context) {
@@ -36,32 +44,39 @@ public class ObservableDialogFragment extends DialogFragment {
}
@Override
+ public void onCreate(Bundle savedInstanceState) {
+ mLifecycle.onCreate(savedInstanceState);
+ mLifecycle.handleLifecycleEvent(ON_CREATE);
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
public void onStart() {
- mLifecycle.onStart();
+ mLifecycle.handleLifecycleEvent(ON_START);
super.onStart();
}
@Override
public void onResume() {
- mLifecycle.onResume();
+ mLifecycle.handleLifecycleEvent(ON_RESUME);
super.onResume();
}
@Override
public void onPause() {
- mLifecycle.onPause();
+ mLifecycle.handleLifecycleEvent(ON_PAUSE);
super.onPause();
}
@Override
public void onStop() {
- mLifecycle.onStop();
+ mLifecycle.handleLifecycleEvent(ON_STOP);
super.onStop();
}
@Override
public void onDestroy() {
- mLifecycle.onDestroy();
+ mLifecycle.handleLifecycleEvent(ON_DESTROY);
super.onDestroy();
}
@@ -86,9 +101,8 @@ public class ObservableDialogFragment extends DialogFragment {
return lifecycleHandled;
}
- @VisibleForTesting(otherwise = VisibleForTesting.NONE)
- /** @return a new lifecycle. */
- public static Lifecycle createLifecycle() {
- return new Lifecycle();
+ @Override
+ public Lifecycle getLifecycle() {
+ return mLifecycle;
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservableFragment.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservableFragment.java
index 3a00eba664c4..925eda6ef9d5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservableFragment.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservableFragment.java
@@ -16,19 +16,27 @@
package com.android.settingslib.core.lifecycle;
+import static android.arch.lifecycle.Lifecycle.Event.ON_CREATE;
+import static android.arch.lifecycle.Lifecycle.Event.ON_DESTROY;
+import static android.arch.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static android.arch.lifecycle.Lifecycle.Event.ON_RESUME;
+import static android.arch.lifecycle.Lifecycle.Event.ON_START;
+import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
+
import android.annotation.CallSuper;
import android.app.Fragment;
+import android.arch.lifecycle.LifecycleOwner;
import android.content.Context;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
-public class ObservableFragment extends Fragment {
+public class ObservableFragment extends Fragment implements LifecycleOwner {
- private final Lifecycle mLifecycle = new Lifecycle();
+ private final Lifecycle mLifecycle = new Lifecycle(this);
- protected Lifecycle getLifecycle() {
+ public Lifecycle getLifecycle() {
return mLifecycle;
}
@@ -43,6 +51,7 @@ public class ObservableFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
mLifecycle.onCreate(savedInstanceState);
+ mLifecycle.handleLifecycleEvent(ON_CREATE);
super.onCreate(savedInstanceState);
}
@@ -56,35 +65,35 @@ public class ObservableFragment extends Fragment {
@CallSuper
@Override
public void onStart() {
- mLifecycle.onStart();
+ mLifecycle.handleLifecycleEvent(ON_START);
super.onStart();
}
@CallSuper
@Override
- public void onStop() {
- mLifecycle.onStop();
- super.onStop();
- }
-
- @CallSuper
- @Override
public void onResume() {
- mLifecycle.onResume();
+ mLifecycle.handleLifecycleEvent(ON_RESUME);
super.onResume();
}
@CallSuper
@Override
public void onPause() {
- mLifecycle.onPause();
+ mLifecycle.handleLifecycleEvent(ON_PAUSE);
super.onPause();
}
@CallSuper
@Override
+ public void onStop() {
+ mLifecycle.handleLifecycleEvent(ON_STOP);
+ super.onStop();
+ }
+
+ @CallSuper
+ @Override
public void onDestroy() {
- mLifecycle.onDestroy();
+ mLifecycle.handleLifecycleEvent(ON_DESTROY);
super.onDestroy();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservablePreferenceFragment.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservablePreferenceFragment.java
index 76e5c8579f05..abd77559612e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservablePreferenceFragment.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservablePreferenceFragment.java
@@ -16,7 +16,15 @@
package com.android.settingslib.core.lifecycle;
+import static android.arch.lifecycle.Lifecycle.Event.ON_CREATE;
+import static android.arch.lifecycle.Lifecycle.Event.ON_DESTROY;
+import static android.arch.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static android.arch.lifecycle.Lifecycle.Event.ON_RESUME;
+import static android.arch.lifecycle.Lifecycle.Event.ON_START;
+import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
+
import android.annotation.CallSuper;
+import android.arch.lifecycle.LifecycleOwner;
import android.content.Context;
import android.os.Bundle;
import android.support.v14.preference.PreferenceFragment;
@@ -28,11 +36,12 @@ import android.view.MenuItem;
/**
* {@link PreferenceFragment} that has hooks to observe fragment lifecycle events.
*/
-public abstract class ObservablePreferenceFragment extends PreferenceFragment {
+public abstract class ObservablePreferenceFragment extends PreferenceFragment
+ implements LifecycleOwner {
- private final Lifecycle mLifecycle = new Lifecycle();
+ private final Lifecycle mLifecycle = new Lifecycle(this);
- protected Lifecycle getLifecycle() {
+ public Lifecycle getLifecycle() {
return mLifecycle;
}
@@ -47,6 +56,7 @@ public abstract class ObservablePreferenceFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
mLifecycle.onCreate(savedInstanceState);
+ mLifecycle.handleLifecycleEvent(ON_CREATE);
super.onCreate(savedInstanceState);
}
@@ -66,35 +76,35 @@ public abstract class ObservablePreferenceFragment extends PreferenceFragment {
@CallSuper
@Override
public void onStart() {
- mLifecycle.onStart();
+ mLifecycle.handleLifecycleEvent(ON_START);
super.onStart();
}
@CallSuper
@Override
- public void onStop() {
- mLifecycle.onStop();
- super.onStop();
- }
-
- @CallSuper
- @Override
public void onResume() {
- mLifecycle.onResume();
+ mLifecycle.handleLifecycleEvent(ON_RESUME);
super.onResume();
}
@CallSuper
@Override
public void onPause() {
- mLifecycle.onPause();
+ mLifecycle.handleLifecycleEvent(ON_PAUSE);
super.onPause();
}
@CallSuper
@Override
+ public void onStop() {
+ mLifecycle.handleLifecycleEvent(ON_STOP);
+ super.onStop();
+ }
+
+ @CallSuper
+ @Override
public void onDestroy() {
- mLifecycle.onDestroy();
+ mLifecycle.handleLifecycleEvent(ON_DESTROY);
super.onDestroy();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnAttach.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnAttach.java
index 152cbac3ad3d..e28c38736639 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnAttach.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnAttach.java
@@ -17,6 +17,10 @@ package com.android.settingslib.core.lifecycle.events;
import android.content.Context;
+/**
+ * @deprecated pass {@link Context} in constructor instead
+ */
+@Deprecated
public interface OnAttach {
void onAttach(Context context);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnCreate.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnCreate.java
index 44cbf8d26757..ad7068e2f9fb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnCreate.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnCreate.java
@@ -16,8 +16,14 @@
package com.android.settingslib.core.lifecycle.events;
+import android.arch.lifecycle.Lifecycle;
+import android.arch.lifecycle.OnLifecycleEvent;
import android.os.Bundle;
+/**
+ * @deprecated use {@link OnLifecycleEvent(Lifecycle.Event) }
+ */
+@Deprecated
public interface OnCreate {
void onCreate(Bundle savedInstanceState);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnDestroy.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnDestroy.java
index ffa3d168b904..c37286e1efaa 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnDestroy.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnDestroy.java
@@ -15,6 +15,13 @@
*/
package com.android.settingslib.core.lifecycle.events;
+import android.arch.lifecycle.Lifecycle;
+import android.arch.lifecycle.OnLifecycleEvent;
+
+/**
+ * @deprecated use {@link OnLifecycleEvent(Lifecycle.Event) }
+ */
+@Deprecated
public interface OnDestroy {
void onDestroy();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnPause.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnPause.java
index 4a711058df21..a5ab39c46ab1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnPause.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnPause.java
@@ -15,6 +15,13 @@
*/
package com.android.settingslib.core.lifecycle.events;
+import android.arch.lifecycle.Lifecycle;
+import android.arch.lifecycle.OnLifecycleEvent;
+
+/**
+ * @deprecated use {@link OnLifecycleEvent(Lifecycle.Event) }
+ */
+@Deprecated
public interface OnPause {
void onPause();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnResume.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnResume.java
index 8dd24e98401d..1effba4a750d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnResume.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnResume.java
@@ -15,6 +15,13 @@
*/
package com.android.settingslib.core.lifecycle.events;
+import android.arch.lifecycle.Lifecycle;
+import android.arch.lifecycle.OnLifecycleEvent;
+
+/**
+ * @deprecated use {@link OnLifecycleEvent(Lifecycle.Event)}
+ */
+@Deprecated
public interface OnResume {
void onResume();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnStart.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnStart.java
index c88ddaa1d8de..07b8460367c1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnStart.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnStart.java
@@ -15,7 +15,13 @@
*/
package com.android.settingslib.core.lifecycle.events;
-public interface OnStart {
+import android.arch.lifecycle.Lifecycle;
+import android.arch.lifecycle.OnLifecycleEvent;
+/**
+ * @deprecated use {@link OnLifecycleEvent(Lifecycle.Event) }
+ */
+@Deprecated
+public interface OnStart {
void onStart();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnStop.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnStop.java
index 32f61d98e4ad..d6a5967116be 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnStop.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnStop.java
@@ -15,7 +15,13 @@
*/
package com.android.settingslib.core.lifecycle.events;
-public interface OnStop {
+import android.arch.lifecycle.Lifecycle;
+import android.arch.lifecycle.OnLifecycleEvent;
+/**
+ * @deprecated use {@link OnLifecycleEvent(Lifecycle.Event) }
+ */
+@Deprecated
+public interface OnStop {
void onStop();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
index 1cb255bf8973..a8262c8cc4c8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.res.XmlResourceParser;
import android.icu.text.TimeZoneFormat;
import android.icu.text.TimeZoneNames;
+import android.support.annotation.VisibleForTesting;
import android.support.v4.text.BidiFormatter;
import android.support.v4.text.TextDirectionHeuristicsCompat;
import android.text.SpannableString;
@@ -32,6 +33,8 @@ import android.view.View;
import com.android.settingslib.R;
+import libcore.util.TimeZoneFinder;
+
import org.xmlpull.v1.XmlPullParserException;
import java.util.ArrayList;
@@ -43,7 +46,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
-import libcore.util.TimeZoneFinder;
/**
* ZoneGetter is the utility class to get time zone and zone list, and both of them have display
@@ -350,7 +352,8 @@ public class ZoneGetter {
return gmtText;
}
- private static final class ZoneGetterData {
+ @VisibleForTesting
+ public static final class ZoneGetterData {
public final String[] olsonIdsToDisplay;
public final CharSequence[] gmtOffsetTexts;
public final TimeZone[] timeZones;
@@ -377,9 +380,13 @@ public class ZoneGetter {
}
// Create a lookup of local zone IDs.
- List<String> zoneIds =
- TimeZoneFinder.getInstance().lookupTimeZoneIdsByCountry(locale.getCountry());
+ final List<String> zoneIds = lookupTimeZoneIdsByCountry(locale.getCountry());
localZoneIds = new HashSet<>(zoneIds);
}
+
+ @VisibleForTesting
+ public List<String> lookupTimeZoneIdsByCountry(String country) {
+ return TimeZoneFinder.getInstance().lookupTimeZoneIdsByCountry(country);
+ }
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractSerialNumberPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractSerialNumberPreferenceController.java
index ff7536adb808..90f14ef4c32c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractSerialNumberPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractSerialNumberPreferenceController.java
@@ -18,18 +18,20 @@ package com.android.settingslib.deviceinfo;
import android.content.Context;
import android.os.Build;
+import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.text.TextUtils;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.core.AbstractPreferenceController;
/**
* Preference controller for displaying device serial number. Wraps {@link Build#getSerial()}.
*/
public class AbstractSerialNumberPreferenceController extends AbstractPreferenceController {
- private static final String KEY_SERIAL_NUMBER = "serial_number";
+
+ @VisibleForTesting
+ static final String KEY_SERIAL_NUMBER = "serial_number";
private final String mSerialNumber;
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/UserAdapter.java b/packages/SettingsLib/src/com/android/settingslib/drawer/UserAdapter.java
index 750601d82ce5..b27d8235563a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/UserAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/UserAdapter.java
@@ -57,7 +57,7 @@ public class UserAdapter implements SpinnerAdapter, ListAdapter {
if (userInfo.isManagedProfile()) {
mName = context.getString(R.string.managed_user_title);
icon = context.getDrawable(
- com.android.internal.R.drawable.ic_corp_icon);
+ com.android.internal.R.drawable.ic_corp_badge);
} else {
mName = userInfo.name;
final int userId = userInfo.id;
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index f4c9bb31f01a..4fe9d56a4179 100755
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -16,7 +16,6 @@
package com.android.settingslib.graph;
-import android.animation.ArgbEvaluator;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
@@ -100,7 +99,7 @@ public class BatteryMeterDrawableBase extends Drawable {
final int N = levels.length();
mColors = new int[2 * N];
- for (int i=0; i < N; i++) {
+ for (int i = 0; i < N; i++) {
mColors[2 * i] = levels.getInt(i, 0);
if (colors.getType(i) == TypedValue.TYPE_ATTRIBUTE) {
mColors[2 * i + 1] = Utils.getColorAttr(context, colors.getThemeAttributeId(i, 0));
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index fdbbf14aa958..dd55188e390f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -31,15 +31,17 @@ import android.support.v7.preference.PreferenceViewHolder;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.SparseArray;
+import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.settingslib.R;
import com.android.settingslib.TronUtils;
+import com.android.settingslib.TwoTargetPreference;
import com.android.settingslib.Utils;
import com.android.settingslib.wifi.AccessPoint.Speed;
-public class AccessPointPreference extends Preference {
+public class AccessPointPreference extends TwoTargetPreference {
private static final int[] STATE_SECURED = {
R.attr.state_encrypted
@@ -126,7 +128,6 @@ public class AccessPointPreference extends Preference {
int iconResId, boolean forSavedNetworks, StateListDrawable frictionSld,
int level, IconInjector iconInjector) {
super(context);
- setWidgetLayoutResource(R.layout.access_point_friction_widget);
mBadgeCache = cache;
mAccessPoint = accessPoint;
mForSavedNetworks = forSavedNetworks;
@@ -165,6 +166,20 @@ public class AccessPointPreference extends Preference {
ImageView frictionImageView = (ImageView) view.findViewById(R.id.friction_icon);
bindFrictionImage(frictionImageView);
+ setDividerVisibility(view, View.GONE);
+ }
+
+ protected void setDividerVisibility(final PreferenceViewHolder view,
+ @View.Visibility int visibility) {
+ final View divider = view.findViewById(R.id.two_target_divider);
+ if (divider != null) {
+ divider.setVisibility(visibility);
+ }
+ }
+
+ @Override
+ protected int getSecondTargetResId() {
+ return R.layout.access_point_friction_widget;
}
protected void updateIcon(int level, Context context) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawable/UserIconDrawableTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java
index 5fdd1149b90f..508107c1d9ce 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawable/UserIconDrawableTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java
@@ -16,22 +16,19 @@
package com.android.settingslib.drawable;
+import static com.google.common.truth.Truth.assertThat;
+
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
import com.android.settingslib.R;
-import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-import static com.google.common.truth.Truth.assertThat;
-@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+@RunWith(AndroidJUnit4.class)
public class UserIconDrawableTest {
private UserIconDrawable mDrawable;
@@ -39,7 +36,7 @@ public class UserIconDrawableTest {
@Test
public void getConstantState_shouldNotBeNull() {
final Bitmap b = BitmapFactory.decodeResource(
- RuntimeEnvironment.application.getResources(),
+ InstrumentationRegistry.getTargetContext().getResources(),
R.drawable.home);
mDrawable = new UserIconDrawable(100 /* size */).setIcon(b).bake();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java
index 17c7d13fe67e..7e374931b767 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java
@@ -16,6 +16,7 @@
package com.android.settingslib;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -31,6 +32,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsLibRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
@@ -59,6 +61,16 @@ public class CustomEditTextPreferenceTest {
verify(editText).requestFocus();
}
+ @Test
+ public void getEditText_noDialog_shouldNotCrash() {
+ ReflectionHelpers.setField(mPreference, "mFragment",
+ mock(CustomEditTextPreference.CustomPreferenceDialogFragment.class));
+
+ mPreference.getEditText();
+
+ // no crash
+ }
+
private static class TestPreference extends CustomEditTextPreference {
public TestPreference(Context context) {
super(context);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/DeviceInfoUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/DeviceInfoUtilsTest.java
new file mode 100644
index 000000000000..82604f767c47
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/DeviceInfoUtilsTest.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 com.android.settingslib;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.system.StructUtsname;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class DeviceInfoUtilsTest {
+
+ private Context mContext;
+
+ @Before
+ public void setup() {
+ mContext = RuntimeEnvironment.application;
+ }
+
+ @Test
+ public void formatKernelVersion_regularInputVersion_shouldStripOptionalValues() {
+ final String sysName = "Linux";
+ final String nodeName = "localhost";
+ final String release = "4.4.88-g134be430baab";
+ final String version = "#1 SMP PREEMPT Tue Dec 31 12:00:00 UTC 2017";
+ final String machine = "aarch64";
+ final StructUtsname uname = new StructUtsname(sysName, nodeName, release, version, machine);
+
+ final String expected = release + "\n" + "#1 Tue Dec 31 12:00:00 UTC 2017";
+
+ assertThat(DeviceInfoUtils.formatKernelVersion(mContext, uname)).isEqualTo(expected);
+ }
+
+ @Test
+ public void formatKernelVersion_nonRegularInputVersion_shouldBeUnavailable() {
+ final String sysName = "Linux";
+ final String nodeName = "localhost";
+ final String release = "4.4.88-g134be430baab";
+ final String version = "%@%!asd%#@!$" + "\n " + "fasdfasdfa13ta";
+ final String machine = "aarch64";
+ final StructUtsname uname = new StructUtsname(sysName, nodeName, release, version, machine);
+
+ final String expected = mContext.getString(R.string.status_unavailable);
+
+ assertThat(DeviceInfoUtils.formatKernelVersion(mContext, uname)).isEqualTo(expected);
+ }
+
+ @Test
+ public void formatKernelVersion_nullInputVersion_shouldBeUnavailable() {
+ final String expected = mContext.getString(R.string.status_unavailable);
+
+ assertThat(DeviceInfoUtils.formatKernelVersion(mContext, null)).isEqualTo(expected);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
index 3af976836439..1f9070c266a0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
@@ -16,8 +16,10 @@
package com.android.settingslib;
+import android.os.Build;
+
public class TestConfig {
- public static final int SDK_VERSION = 25;
+ public static final int SDK_VERSION = Build.VERSION_CODES.O;
public static final String MANIFEST_PATH =
"frameworks/base/packages/SettingsLib/tests/robotests/AndroidManifest.xml";
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java
new file mode 100644
index 000000000000..26970e1c7aff
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.settingslib.core;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settingslib.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class AbstractPreferenceControllerTest {
+
+ @Mock
+ private PreferenceScreen mScreen;
+
+ private Context mContext;
+ private Preference mPreference;
+ private TestPrefController mTestPrefController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mPreference = new Preference(mContext);
+ mPreference.setKey(TestPrefController.KEY_PREF);
+ when(mScreen.findPreference(TestPrefController.KEY_PREF)).thenReturn(mPreference);
+ mTestPrefController = new TestPrefController(mContext);
+ }
+
+ @Test
+ public void displayPref_ifAvailable() {
+ mTestPrefController.isAvailable = true;
+
+ mTestPrefController.displayPreference(mScreen);
+
+ assertThat(mPreference.isVisible()).isTrue();
+ }
+
+ @Test
+ public void setVisible_prefIsVisible_shouldSetToVisible() {
+ mTestPrefController.setVisible(mScreen, TestPrefController.KEY_PREF, true /* visible */);
+
+ assertThat(mPreference.isVisible()).isTrue();
+ }
+
+ @Test
+ public void setVisible_prefNotVisible_shouldSetToInvisible() {
+ mTestPrefController.setVisible(mScreen, TestPrefController.KEY_PREF, false /* visible */);
+
+ assertThat(mPreference.isVisible()).isFalse();
+ }
+
+ @Test
+ public void doNotDisplayPref_ifNotAvailable() {
+ mTestPrefController.isAvailable = false;
+
+ mTestPrefController.displayPreference(mScreen);
+
+ assertThat(mPreference.isVisible()).isFalse();
+ }
+
+ private class TestPrefController extends AbstractPreferenceController {
+ private static final String KEY_PREF = "test_pref";
+ public boolean isAvailable;
+
+ public TestPrefController(Context context) {
+ super(context);
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ return false;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return isAvailable;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_PREF;
+ }
+ }
+
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/PreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/PreferenceControllerTest.java
deleted file mode 100644
index 9d7cd11ec7d4..000000000000
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/PreferenceControllerTest.java
+++ /dev/null
@@ -1,178 +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.settingslib.core;
-
-import android.content.Context;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceGroup;
-import android.support.v7.preference.PreferenceManager;
-import android.support.v7.preference.PreferenceScreen;
-import com.android.settingslib.TestConfig;
-import com.android.settingslib.core.AbstractPreferenceController;
-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 org.robolectric.shadows.ShadowApplication;
-import org.robolectric.RobolectricTestRunner;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
-public class PreferenceControllerTest {
-
- @Mock
- private Context mContext;
- @Mock
- private PreferenceScreen mScreen;
- @Mock
- private Preference mPreference;
-
- private TestPrefController mTestPrefController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mTestPrefController = new TestPrefController(mContext);
- }
-
- @Test
- public void removeExistingPref_shouldBeRemoved() {
- when(mScreen.getPreferenceCount()).thenReturn(1);
- when(mScreen.getPreference(0)).thenReturn(mPreference);
- when(mPreference.getKey()).thenReturn(TestPrefController.KEY_PREF);
-
- mTestPrefController.removePreference(mScreen, TestPrefController.KEY_PREF);
-
- verify(mScreen).removePreference(mPreference);
- }
-
- @Test
- public void removeNonExistingPref_shouldNotRemoveAnything() {
- mTestPrefController.removePreference(mScreen, TestPrefController.KEY_PREF);
-
- verify(mScreen, never()).removePreference(any(Preference.class));
- }
-
- @Test
- public void displayPref_ifAvailable() {
- mTestPrefController.isAvailable = true;
-
- mTestPrefController.displayPreference(mScreen);
-
- verify(mScreen, never()).removePreference(any(Preference.class));
- }
-
- @Test
- public void doNotDisplayPref_ifNotAvailable() {
- when(mScreen.getPreferenceCount()).thenReturn(1);
- when(mScreen.getPreference(0)).thenReturn(mPreference);
- when(mPreference.getKey()).thenReturn(TestPrefController.KEY_PREF);
- mTestPrefController.isAvailable = false;
-
- mTestPrefController.displayPreference(mScreen);
-
- verify(mScreen).removePreference(any(Preference.class));
- }
-
- @Test
- public void removePreference_shouldRemoveRecursively() {
- final Context context = ShadowApplication.getInstance().getApplicationContext();
- final PreferenceManager preferenceManager = mock(PreferenceManager.class);
- // Top level
- PreferenceScreen prefRoot = spy(new PreferenceScreen(context, null));
- when(prefRoot.getPreferenceManager()).thenReturn(preferenceManager);
- Preference pref1 = mock(Preference.class);
- when(pref1.getKey()).thenReturn("key1");
- PreferenceGroup prefGroup2 = spy(new PreferenceScreen(context, null));
- when(prefGroup2.getPreferenceManager()).thenReturn(preferenceManager);
- when(prefGroup2.getKey()).thenReturn("group2");
- Preference pref3 = mock(Preference.class);
- when(pref3.getKey()).thenReturn("key3");
- PreferenceGroup prefGroup4 = spy(new PreferenceScreen(context, null));
- when(prefGroup4.getPreferenceManager()).thenReturn(preferenceManager);
- when(prefGroup4.getKey()).thenReturn("group4");
- prefRoot.addPreference(pref1);
- prefRoot.addPreference(prefGroup2);
- prefRoot.addPreference(pref3);
- prefRoot.addPreference(prefGroup4);
-
- // 2nd level
- Preference pref21 = mock(Preference.class);
- when(pref21.getKey()).thenReturn("key21");
- Preference pref22 = mock(Preference.class);
- when(pref22.getKey()).thenReturn("key22");
- prefGroup2.addPreference(pref21);
- prefGroup2.addPreference(pref22);
- PreferenceGroup prefGroup41 = spy(new PreferenceScreen(context, null));
- when(prefGroup41.getKey()).thenReturn("group41");
- when(prefGroup41.getPreferenceManager()).thenReturn(preferenceManager);
- Preference pref42 = mock(Preference.class);
- when(pref42.getKey()).thenReturn("key42");
- prefGroup4.addPreference(prefGroup41);
- prefGroup4.addPreference(pref42);
-
- // 3rd level
- Preference pref411 = mock(Preference.class);
- when(pref411.getKey()).thenReturn("key411");
- Preference pref412 = mock(Preference.class);
- when(pref412.getKey()).thenReturn("key412");
- prefGroup41.addPreference(pref411);
- prefGroup41.addPreference(pref412);
-
- mTestPrefController.removePreference(prefRoot, "key1");
- verify(prefRoot).removePreference(pref1);
-
- mTestPrefController.removePreference(prefRoot, "key411");
- verify(prefGroup41).removePreference(pref411);
-
- mTestPrefController.removePreference(prefRoot, "group41");
- verify(prefGroup4).removePreference(prefGroup41);
- }
-
- private class TestPrefController extends AbstractPreferenceController {
- private static final String KEY_PREF = "test_pref";
- public boolean isAvailable;
-
- public TestPrefController(Context context) {
- super(context);
- }
-
- @Override
- public boolean handlePreferenceTreeClick(Preference preference) {
- return false;
- }
-
- @Override
- public boolean isAvailable() {
- return isAvailable;
- }
-
- @Override
- public String getPreferenceKey() {
- return KEY_PREF;
- }
- }
-
-}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
index 1290391e3ce2..adb4832adcff 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
@@ -15,6 +15,10 @@
*/
package com.android.settingslib.core.lifecycle;
+import static android.arch.lifecycle.Lifecycle.Event.ON_START;
+
+import static com.google.common.truth.Truth.assertThat;
+
import android.content.Context;
import android.view.Menu;
import android.view.MenuInflater;
@@ -32,6 +36,7 @@ import com.android.settingslib.core.lifecycle.events.OnResume;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
@@ -39,12 +44,12 @@ import org.robolectric.android.controller.ActivityController;
import org.robolectric.android.controller.FragmentController;
import org.robolectric.annotation.Config;
-import static com.google.common.truth.Truth.assertThat;
-
@RunWith(SettingsLibRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class LifecycleTest {
+ private Lifecycle mLifecycle;
+
public static class TestDialogFragment extends ObservableDialogFragment {
final TestObserver mFragObserver;
@@ -139,6 +144,11 @@ public class LifecycleTest {
}
}
+ @Before
+ public void setUp() {
+ mLifecycle = new Lifecycle(() -> mLifecycle);
+ }
+
@Test
public void runThroughActivityLifecycles_shouldObserveEverything() {
ActivityController<TestActivity> ac = Robolectric.buildActivity(TestActivity.class);
@@ -212,9 +222,8 @@ public class LifecycleTest {
@Test
public void addObserverDuringObserve_shoudNotCrash() {
- Lifecycle lifecycle = new Lifecycle();
- lifecycle.addObserver(new OnStartObserver(lifecycle));
- lifecycle.onStart();
+ mLifecycle.addObserver(new OnStartObserver(mLifecycle));
+ mLifecycle.handleLifecycleEvent(ON_START);
}
private static class OptionItemAccepter implements LifecycleObserver, OnOptionsItemSelected {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java
index 32fa01c52f21..aac736a94832 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java
@@ -17,14 +17,9 @@
package com.android.settingslib.development;
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.Answers.RETURNS_DEEP_STUBS;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
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 static org.mockito.Mockito.when;
import android.content.Context;
@@ -67,21 +62,19 @@ public class EnableAdbPreferenceControllerTest {
shadowContext.setSystemService(Context.USER_SERVICE, mUserManager);
mContext = spy(shadowContext.getApplicationContext());
when(mContext.getPackageManager()).thenReturn(mPackageManager);
- mPreference = new SwitchPreference(mContext);
- when(mScreen.findPreference(anyString())).thenReturn(mPreference);
mController = new ConcreteEnableAdbPreferenceController(mContext);
+ mPreference = new SwitchPreference(mContext);
mPreference.setKey(mController.getPreferenceKey());
+ when(mScreen.findPreference(mPreference.getKey())).thenReturn(mPreference);
}
@Test
public void displayPreference_isNotAdmin_shouldRemovePreference() {
when(mUserManager.isAdminUser()).thenReturn(false);
- when(mScreen.getPreferenceCount()).thenReturn(1);
- when(mScreen.getPreference(0)).thenReturn(mPreference);
mController.displayPreference(mScreen);
- verify(mScreen).removePreference(any(Preference.class));
+ assertThat(mPreference.isVisible()).isFalse();
}
@Test
@@ -90,7 +83,7 @@ public class EnableAdbPreferenceControllerTest {
mController.displayPreference(mScreen);
- verify(mScreen, never()).removePreference(any(Preference.class));
+ assertThat(mPreference.isVisible()).isTrue();
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java
index 3f0eca549b40..5d5733e463ea 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java
@@ -44,7 +44,7 @@ import org.robolectric.annotation.Config;
shadows = SystemPropertiesTestImpl.class)
public class LogpersistPreferenceControllerTest {
- private Lifecycle mLifecycle = new Lifecycle();
+ private Lifecycle mLifecycle;
@Mock
private ListPreference mListPreference;
@@ -57,6 +57,7 @@ public class LogpersistPreferenceControllerTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
SystemProperties.set("ro.debuggable", "1");
+ mLifecycle = new Lifecycle(() -> mLifecycle);
mController = new AbstractLogpersistPreferenceController(RuntimeEnvironment.application,
mLifecycle) {
@Override
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java
index 4dbb957f2748..34bbf4f14d07 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java
@@ -17,13 +17,6 @@
package com.android.settingslib.deviceinfo;
import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Answers.RETURNS_DEEP_STUBS;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -38,68 +31,67 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(SettingsLibRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class SerialNumberPreferenceControllerTest {
- @Mock(answer = RETURNS_DEEP_STUBS)
- private Context mContext;
- @Mock(answer = RETURNS_DEEP_STUBS)
+ @Mock
private PreferenceScreen mScreen;
+ private Context mContext;
+ private Preference mPreference;
private AbstractSerialNumberPreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mPreference = new Preference(mContext);
+ mPreference.setKey(AbstractSerialNumberPreferenceController.KEY_SERIAL_NUMBER);
+ when(mScreen.findPreference(mPreference.getKey())).thenReturn(mPreference);
}
@Test
public void testIsAvaiable_noSerial_shouldReturnFalse() {
- mController = new ConcreteSerialNumberPreferenceController(mContext, null);
+ mController = new TestPreferenceController(mContext, null);
assertThat(mController.isAvailable()).isFalse();
}
@Test
- public void testIsAvaiable_hasSerial_shouldReturnTrue() {
- mController = new ConcreteSerialNumberPreferenceController(mContext, "123");
+ public void testIsAvailable_hasSerial_shouldReturnTrue() {
+ mController = new TestPreferenceController(mContext, "123");
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void testDisplay_noSerial_shouldHidePreference() {
- final Preference preference = mock(Preference.class);
- when(mScreen.getPreferenceCount()).thenReturn(1);
- when(mScreen.getPreference(0)).thenReturn(preference);
- mController = new ConcreteSerialNumberPreferenceController(mContext, null);
- when(preference.getKey()).thenReturn(mController.getPreferenceKey());
+ mController = new TestPreferenceController(mContext, null);
mController.displayPreference(mScreen);
- verify(mScreen).removePreference(any(Preference.class));
+ assertThat(mPreference.isVisible()).isFalse();
}
@Test
public void testDisplay_hasSerial_shouldSetSummary() {
final String serial = "123";
- final Preference preference = mock(Preference.class);
- when(mScreen.findPreference(anyString())).thenReturn(preference);
- mController = new ConcreteSerialNumberPreferenceController(mContext, serial);
+ mController = new TestPreferenceController(mContext, serial);
mController.displayPreference(mScreen);
- verify(mScreen, never()).removePreference(any(Preference.class));
- verify(preference).setSummary(serial);
+ assertThat(mPreference.isVisible()).isTrue();
+ assertThat(mPreference.getSummary()).isEqualTo(serial);
}
- private static class ConcreteSerialNumberPreferenceController
+ private static class TestPreferenceController
extends AbstractSerialNumberPreferenceController {
- ConcreteSerialNumberPreferenceController(Context context, String serialNumber) {
+ TestPreferenceController(Context context, String serialNumber) {
super(context, serialNumber);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
index 3522b8abfe62..e0222329f231 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
@@ -18,6 +18,7 @@ package com.android.settingslib.graph;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
@@ -35,11 +36,13 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsLibRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
shadows = SettingsLibShadowResources.class)
public class BatteryMeterDrawableBaseTest {
+ private static final int CRITICAL_LEVEL = 5;
private static final int PADDING = 5;
private static final int HEIGHT = 80;
private static final int WIDTH = 40;
@@ -53,7 +56,8 @@ public class BatteryMeterDrawableBaseTest {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
- mBatteryMeterDrawableBase = new BatteryMeterDrawableBase(mContext, 0 /* frameColor */);
+ mBatteryMeterDrawableBase = spy(new BatteryMeterDrawableBase(mContext, 0 /* frameColor */));
+ ReflectionHelpers.setField(mBatteryMeterDrawableBase, "mCriticalLevel", CRITICAL_LEVEL);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java
index 97fda996c80d..75b6c5fcefc1 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java
@@ -16,6 +16,14 @@
package com.android.settingslib.widget;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+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.support.v14.preference.PreferenceFragment;
import android.support.v7.preference.PreferenceManager;
import android.support.v7.preference.PreferenceScreen;
@@ -32,13 +40,6 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
@RunWith(SettingsLibRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class FooterPreferenceMixinTest {
@@ -54,7 +55,7 @@ public class FooterPreferenceMixinTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mLifecycle = new Lifecycle();
+ mLifecycle = new Lifecycle(() -> mLifecycle);
when(mFragment.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
when(mFragment.getPreferenceManager().getContext())
.thenReturn(ShadowApplication.getInstance().getApplicationContext());
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 1557d911e6bf..742814924137 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1836,20 +1836,10 @@ class DatabaseHelper extends SQLiteOpenHelper {
}
if (upgradeVersion < 116) {
- if (mUserHandle == UserHandle.USER_SYSTEM) {
- db.beginTransaction();
- SQLiteStatement stmt = null;
- try {
- stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
- + " VALUES(?,?);");
- loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED,
- ImsConfig.FeatureValueConstants.ON);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- if (stmt != null) stmt.close();
- }
- }
+ /*
+ * To control the default value by carrier config manager, initializing
+ * ENHANCED_4G_MODE_ENABLED has been removed.
+ */
upgradeVersion = 116;
}
@@ -2633,9 +2623,6 @@ class DatabaseHelper extends SQLiteOpenHelper {
loadSetting(stmt, Settings.Global.DEVICE_NAME, getDefaultDeviceName());
- loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED,
- ImsConfig.FeatureValueConstants.ON);
-
/*
* IMPORTANT: Do not add any more upgrade steps here as the global,
* secure, and system settings are no longer stored in a database
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 67fb4d9ffeaa..41b205bc5761 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -37,9 +37,11 @@ class SettingsProtoDumpUtil {
// Global settings
SettingsState globalSettings = settingsRegistry.getSettingsLocked(
SettingsProvider.SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
- long globalSettingsToken = proto.start(SettingsServiceDumpProto.GLOBAL_SETTINGS);
- dumpProtoGlobalSettingsLocked(globalSettings, proto);
- proto.end(globalSettingsToken);
+ if (globalSettings != null) {
+ long globalSettingsToken = proto.start(SettingsServiceDumpProto.GLOBAL_SETTINGS);
+ dumpProtoGlobalSettingsLocked(globalSettings, proto);
+ proto.end(globalSettingsToken);
+ }
// Per-user settings
SparseBooleanArray users = settingsRegistry.getKnownUsersLocked();
@@ -67,19 +69,26 @@ class SettingsProtoDumpUtil {
SettingsState secureSettings = settingsRegistry.getSettingsLocked(
SettingsProvider.SETTINGS_TYPE_SECURE, user.getIdentifier());
- long secureSettingsToken = proto.start(UserSettingsProto.SECURE_SETTINGS);
- dumpProtoSecureSettingsLocked(secureSettings, proto);
- proto.end(secureSettingsToken);
+ if (secureSettings != null) {
+ long secureSettingsToken = proto.start(UserSettingsProto.SECURE_SETTINGS);
+ dumpProtoSecureSettingsLocked(secureSettings, proto);
+ proto.end(secureSettingsToken);
+ }
SettingsState systemSettings = settingsRegistry.getSettingsLocked(
SettingsProvider.SETTINGS_TYPE_SYSTEM, user.getIdentifier());
- long systemSettingsToken = proto.start(UserSettingsProto.SYSTEM_SETTINGS);
- dumpProtoSystemSettingsLocked(systemSettings, proto);
- proto.end(systemSettingsToken);
+ if (systemSettings != null) {
+ long systemSettingsToken = proto.start(UserSettingsProto.SYSTEM_SETTINGS);
+ dumpProtoSystemSettingsLocked(systemSettings, proto);
+ proto.end(systemSettingsToken);
+ }
}
private static void dumpProtoGlobalSettingsLocked(
@NonNull SettingsState s, @NonNull ProtoOutputStream p) {
+ s.dumpHistoricalOperations(p, GlobalSettingsProto.HISTORICAL_OPERATIONS);
+
+ // This uses the same order as in Settings.Global.
dumpSetting(s, p,
Settings.Global.ADD_USERS_WHEN_LOCKED,
GlobalSettingsProto.ADD_USERS_WHEN_LOCKED);
@@ -114,6 +123,9 @@ class SettingsProtoDumpUtil {
Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
GlobalSettingsProto.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
dumpSetting(s, p,
+ Settings.Global.BLUETOOTH_CLASS_OF_DEVICE,
+ GlobalSettingsProto.BLUETOOTH_CLASS_OF_DEVICE);
+ dumpSetting(s, p,
Settings.Global.BLUETOOTH_DISABLED_PROFILES,
GlobalSettingsProto.BLUETOOTH_DISABLED_PROFILES);
dumpSetting(s, p,
@@ -194,6 +206,7 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Global.CDMA_SUBSCRIPTION_MODE,
GlobalSettingsProto.CDMA_SUBSCRIPTION_MODE);
+ // Settings.Global.DEFAULT_RESTRICT_BACKGROUND_DATA intentionally excluded.
dumpSetting(s, p,
Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
GlobalSettingsProto.DATA_ACTIVITY_TIMEOUT_MOBILE);
@@ -209,6 +222,10 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
GlobalSettingsProto.FORCE_ALLOW_ON_EXTERNAL);
+ // Settings.Global.DEFAULT_SM_DP_PLUS intentionally excluded.
+ dumpSetting(s, p,
+ Settings.Global.EUICC_PROVISIONED,
+ GlobalSettingsProto.EUICC_PROVISIONED);
dumpSetting(s, p,
Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
GlobalSettingsProto.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES);
@@ -236,6 +253,7 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE,
GlobalSettingsProto.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE);
+ // Settings.Global.INSTALL_NON_MARKET_APPS intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Global.HDMI_CONTROL_ENABLED,
GlobalSettingsProto.HDMI_CONTROL_ENABLED);
@@ -249,6 +267,21 @@ class SettingsProtoDumpUtil {
Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
GlobalSettingsProto.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED);
dumpSetting(s, p,
+ Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
+ GlobalSettingsProto.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS);
+ dumpSetting(s, p,
+ Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS,
+ GlobalSettingsProto.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS);
+ dumpSetting(s, p,
+ Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
+ GlobalSettingsProto.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
+ dumpSetting(s, p,
+ Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS,
+ GlobalSettingsProto.WIFI_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS);
+ dumpSetting(s, p,
+ Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
+ GlobalSettingsProto.WIFI_SCAN_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
+ dumpSetting(s, p,
Settings.Global.MHL_INPUT_SWITCHING_ENABLED,
GlobalSettingsProto.MHL_INPUT_SWITCHING_ENABLED);
dumpSetting(s, p,
@@ -279,6 +312,9 @@ class SettingsProtoDumpUtil {
Settings.Global.NETSTATS_SAMPLE_ENABLED,
GlobalSettingsProto.NETSTATS_SAMPLE_ENABLED);
dumpSetting(s, p,
+ Settings.Global.NETSTATS_AUGMENT_ENABLED,
+ GlobalSettingsProto.NETSTATS_AUGMENT_ENABLED);
+ dumpSetting(s, p,
Settings.Global.NETSTATS_DEV_BUCKET_DURATION,
GlobalSettingsProto.NETSTATS_DEV_BUCKET_DURATION);
dumpSetting(s, p,
@@ -420,6 +456,9 @@ class SettingsProtoDumpUtil {
Settings.Global.TETHER_DUN_APN,
GlobalSettingsProto.TETHER_DUN_APN);
dumpSetting(s, p,
+ Settings.Global.TETHER_OFFLOAD_DISABLED,
+ GlobalSettingsProto.TETHER_OFFLOAD_DISABLED);
+ dumpSetting(s, p,
Settings.Global.CARRIER_APP_WHITELIST,
GlobalSettingsProto.CARRIER_APP_WHITELIST);
dumpSetting(s, p,
@@ -450,6 +489,15 @@ class SettingsProtoDumpUtil {
Settings.Global.NETWORK_AVOID_BAD_WIFI,
GlobalSettingsProto.NETWORK_AVOID_BAD_WIFI);
dumpSetting(s, p,
+ Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE,
+ GlobalSettingsProto.NETWORK_METERED_MULTIPATH_PREFERENCE);
+ dumpSetting(s, p,
+ Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME,
+ GlobalSettingsProto.NETWORK_WATCHLIST_LAST_REPORT_TIME);
+ dumpSetting(s, p,
+ Settings.Global.WIFI_BADGING_THRESHOLDS,
+ GlobalSettingsProto.WIFI_BADGING_THRESHOLDS);
+ dumpSetting(s, p,
Settings.Global.WIFI_DISPLAY_ON,
GlobalSettingsProto.WIFI_DISPLAY_ON);
dumpSetting(s, p,
@@ -489,12 +537,30 @@ class SettingsProtoDumpUtil {
Settings.Global.WIFI_WAKEUP_ENABLED,
GlobalSettingsProto.WIFI_WAKEUP_ENABLED);
dumpSetting(s, p,
+ Settings.Global.WIFI_WAKEUP_AVAILABLE,
+ GlobalSettingsProto.WIFI_WAKEUP_AVAILABLE);
+ dumpSetting(s, p,
+ Settings.Global.NETWORK_SCORING_UI_ENABLED,
+ GlobalSettingsProto.NETWORK_SCORING_UI_ENABLED);
+ dumpSetting(s, p,
+ Settings.Global.SPEED_LABEL_CACHE_EVICTION_AGE_MILLIS,
+ GlobalSettingsProto.SPEED_LABEL_CACHE_EVICTION_AGE_MILLIS);
+ dumpSetting(s, p,
Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
GlobalSettingsProto.NETWORK_RECOMMENDATIONS_ENABLED);
dumpSetting(s, p,
Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE,
GlobalSettingsProto.NETWORK_RECOMMENDATIONS_PACKAGE);
dumpSetting(s, p,
+ Settings.Global.USE_OPEN_WIFI_PACKAGE,
+ GlobalSettingsProto.USE_OPEN_WIFI_PACKAGE);
+ dumpSetting(s, p,
+ Settings.Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS,
+ GlobalSettingsProto.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS);
+ dumpSetting(s, p,
+ Settings.Global.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS,
+ GlobalSettingsProto.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS);
+ dumpSetting(s, p,
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE,
GlobalSettingsProto.BLE_SCAN_ALWAYS_AVAILABLE);
dumpSetting(s, p,
@@ -612,6 +678,12 @@ class SettingsProtoDumpUtil {
Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
GlobalSettingsProto.SYS_STORAGE_FULL_THRESHOLD_BYTES);
dumpSetting(s, p,
+ Settings.Global.SYS_STORAGE_CACHE_PERCENTAGE,
+ GlobalSettingsProto.SYS_STORAGE_CACHE_PERCENTAGE);
+ dumpSetting(s, p,
+ Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES,
+ GlobalSettingsProto.SYS_STORAGE_CACHE_MAX_BYTES);
+ dumpSetting(s, p,
Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS,
GlobalSettingsProto.SYNC_MAX_RETRY_DELAY_IN_SECONDS);
dumpSetting(s, p,
@@ -627,6 +699,9 @@ class SettingsProtoDumpUtil {
Settings.Global.CAPTIVE_PORTAL_MODE,
GlobalSettingsProto.CAPTIVE_PORTAL_MODE);
dumpSetting(s, p,
+ Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED,
+ GlobalSettingsProto.CAPTIVE_PORTAL_DETECTION_ENABLED);
+ dumpSetting(s, p,
Settings.Global.CAPTIVE_PORTAL_SERVER,
GlobalSettingsProto.CAPTIVE_PORTAL_SERVER);
dumpSetting(s, p,
@@ -639,6 +714,9 @@ class SettingsProtoDumpUtil {
Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL,
GlobalSettingsProto.CAPTIVE_PORTAL_FALLBACK_URL);
dumpSetting(s, p,
+ Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
+ GlobalSettingsProto.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS);
+ dumpSetting(s, p,
Settings.Global.CAPTIVE_PORTAL_USE_HTTPS,
GlobalSettingsProto.CAPTIVE_PORTAL_USE_HTTPS);
dumpSetting(s, p,
@@ -684,6 +762,12 @@ class SettingsProtoDumpUtil {
Settings.Global.DEFAULT_DNS_SERVER,
GlobalSettingsProto.DEFAULT_DNS_SERVER);
dumpSetting(s, p,
+ Settings.Global.PRIVATE_DNS_MODE,
+ GlobalSettingsProto.PRIVATE_DNS_MODE);
+ dumpSetting(s, p,
+ Settings.Global.PRIVATE_DNS_SPECIFIER,
+ GlobalSettingsProto.PRIVATE_DNS_SPECIFIER);
+ dumpSetting(s, p,
Settings.Global.BLUETOOTH_HEADSET_PRIORITY_PREFIX,
GlobalSettingsProto.BLUETOOTH_HEADSET_PRIORITY_PREFIX);
dumpSetting(s, p,
@@ -717,12 +801,27 @@ class SettingsProtoDumpUtil {
Settings.Global.BLUETOOTH_PAN_PRIORITY_PREFIX,
GlobalSettingsProto.BLUETOOTH_PAN_PRIORITY_PREFIX);
dumpSetting(s, p,
+ Settings.Global.ACTIVITY_MANAGER_CONSTANTS,
+ GlobalSettingsProto.ACTIVITY_MANAGER_CONSTANTS);
+ dumpSetting(s, p,
Settings.Global.DEVICE_IDLE_CONSTANTS,
GlobalSettingsProto.DEVICE_IDLE_CONSTANTS);
dumpSetting(s, p,
+ Settings.Global.BATTERY_SAVER_CONSTANTS,
+ GlobalSettingsProto.BATTERY_SAVER_CONSTANTS);
+ dumpSetting(s, p,
+ Settings.Global.ANOMALY_DETECTION_CONSTANTS,
+ GlobalSettingsProto.ANOMALY_DETECTION_CONSTANTS);
+ dumpSetting(s, p,
+ Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS,
+ GlobalSettingsProto.ALWAYS_ON_DISPLAY_CONSTANTS);
+ dumpSetting(s, p,
Settings.Global.APP_IDLE_CONSTANTS,
GlobalSettingsProto.APP_IDLE_CONSTANTS);
dumpSetting(s, p,
+ Settings.Global.POWER_MANAGER_CONSTANTS,
+ GlobalSettingsProto.POWER_MANAGER_CONSTANTS);
+ dumpSetting(s, p,
Settings.Global.ALARM_MANAGER_CONSTANTS,
GlobalSettingsProto.ALARM_MANAGER_CONSTANTS);
dumpSetting(s, p,
@@ -732,6 +831,12 @@ class SettingsProtoDumpUtil {
Settings.Global.SHORTCUT_MANAGER_CONSTANTS,
GlobalSettingsProto.SHORTCUT_MANAGER_CONSTANTS);
dumpSetting(s, p,
+ Settings.Global.DEVICE_POLICY_CONSTANTS,
+ GlobalSettingsProto.DEVICE_POLICY_CONSTANTS);
+ dumpSetting(s, p,
+ Settings.Global.TEXT_CLASSIFIER_CONSTANTS,
+ GlobalSettingsProto.TEXT_CLASSIFIER_CONSTANTS);
+ dumpSetting(s, p,
Settings.Global.WINDOW_ANIMATION_SCALE,
GlobalSettingsProto.WINDOW_ANIMATION_SCALE);
dumpSetting(s, p,
@@ -764,6 +869,7 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Global.WAIT_FOR_DEBUGGER,
GlobalSettingsProto.WAIT_FOR_DEBUGGER);
+ // Settings.Global.SHOW_PROCESSES intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Global.LOW_POWER_MODE,
GlobalSettingsProto.LOW_POWER_MODE);
@@ -819,6 +925,18 @@ class SettingsProtoDumpUtil {
Settings.Global.INTENT_FIREWALL_UPDATE_METADATA_URL,
GlobalSettingsProto.INTENT_FIREWALL_UPDATE_METADATA_URL);
dumpSetting(s, p,
+ Settings.Global.LANG_ID_UPDATE_CONTENT_URL,
+ GlobalSettingsProto.LANG_ID_UPDATE_CONTENT_URL);
+ dumpSetting(s, p,
+ Settings.Global.LANG_ID_UPDATE_METADATA_URL,
+ GlobalSettingsProto.LANG_ID_UPDATE_METADATA_URL);
+ dumpSetting(s, p,
+ Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
+ GlobalSettingsProto.SMART_SELECTION_UPDATE_CONTENT_URL);
+ dumpSetting(s, p,
+ Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL,
+ GlobalSettingsProto.SMART_SELECTION_UPDATE_METADATA_URL);
+ dumpSetting(s, p,
Settings.Global.SELINUX_STATUS,
GlobalSettingsProto.SELINUX_STATUS);
dumpSetting(s, p,
@@ -882,11 +1000,8 @@ class SettingsProtoDumpUtil {
Settings.Global.ENABLE_EPHEMERAL_FEATURE,
GlobalSettingsProto.ENABLE_EPHEMERAL_FEATURE);
dumpSetting(s, p,
- Settings.Global.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
- GlobalSettingsProto.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD);
- dumpSetting(s, p,
- Settings.Global.UNINSTALLED_INSTANT_APP_MAX_CACHE_PERIOD,
- GlobalSettingsProto.UNINSTALLED_INSTANT_APP_MAX_CACHE_PERIOD);
+ Settings.Global.INSTANT_APP_DEXOPT_ENABLED,
+ GlobalSettingsProto.INSTANT_APP_DEXOPT_ENABLED);
dumpSetting(s, p,
Settings.Global.INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
GlobalSettingsProto.INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD);
@@ -894,6 +1009,12 @@ class SettingsProtoDumpUtil {
Settings.Global.INSTALLED_INSTANT_APP_MAX_CACHE_PERIOD,
GlobalSettingsProto.INSTALLED_INSTANT_APP_MAX_CACHE_PERIOD);
dumpSetting(s, p,
+ Settings.Global.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
+ GlobalSettingsProto.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD);
+ dumpSetting(s, p,
+ Settings.Global.UNINSTALLED_INSTANT_APP_MAX_CACHE_PERIOD,
+ GlobalSettingsProto.UNINSTALLED_INSTANT_APP_MAX_CACHE_PERIOD);
+ dumpSetting(s, p,
Settings.Global.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD,
GlobalSettingsProto.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD);
dumpSetting(s, p,
@@ -909,12 +1030,30 @@ class SettingsProtoDumpUtil {
Settings.Global.DEVICE_DEMO_MODE,
GlobalSettingsProto.DEVICE_DEMO_MODE);
dumpSetting(s, p,
+ Settings.Global.NETWORK_ACCESS_TIMEOUT_MS,
+ GlobalSettingsProto.NETWORK_ACCESS_TIMEOUT_MS);
+ dumpSetting(s, p,
Settings.Global.DATABASE_DOWNGRADE_REASON,
GlobalSettingsProto.DATABASE_DOWNGRADE_REASON);
dumpSetting(s, p,
+ Settings.Global.DATABASE_CREATION_BUILDID,
+ GlobalSettingsProto.DATABASE_CREATION_BUILDID);
+ dumpSetting(s, p,
Settings.Global.CONTACTS_DATABASE_WAL_ENABLED,
GlobalSettingsProto.CONTACTS_DATABASE_WAL_ENABLED);
dumpSetting(s, p,
+ 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,
+ Settings.Global.STORAGE_SETTINGS_CLOBBER_THRESHOLD,
+ GlobalSettingsProto.STORAGE_SETTINGS_CLOBBER_THRESHOLD);
+ dumpSetting(s, p,
Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION,
GlobalSettingsProto.MULTI_SIM_VOICE_CALL_SUBSCRIPTION);
dumpSetting(s, p,
@@ -932,6 +1071,7 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Global.NEW_CONTACT_AGGREGATOR,
GlobalSettingsProto.NEW_CONTACT_AGGREGATOR);
+ // Settings.Global.CONTACT_METADATA_SYNC intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Global.CONTACT_METADATA_SYNC_ENABLED,
GlobalSettingsProto.CONTACT_METADATA_SYNC_ENABLED);
@@ -942,8 +1082,31 @@ class SettingsProtoDumpUtil {
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
GlobalSettingsProto.MAX_NOTIFICATION_ENQUEUE_RATE);
dumpSetting(s, p,
+ Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
+ GlobalSettingsProto.SHOW_NOTIFICATION_CHANNEL_WARNINGS);
+ dumpSetting(s, p,
Settings.Global.CELL_ON,
GlobalSettingsProto.CELL_ON);
+ dumpSetting(s, p,
+ Settings.Global.SHOW_TEMPERATURE_WARNING,
+ GlobalSettingsProto.SHOW_TEMPERATURE_WARNING);
+ dumpSetting(s, p,
+ Settings.Global.WARNING_TEMPERATURE,
+ GlobalSettingsProto.WARNING_TEMPERATURE);
+ dumpSetting(s, p,
+ Settings.Global.ENABLE_DISKSTATS_LOGGING,
+ GlobalSettingsProto.ENABLE_DISKSTATS_LOGGING);
+ dumpSetting(s, p,
+ Settings.Global.ENABLE_CACHE_QUOTA_CALCULATION,
+ GlobalSettingsProto.ENABLE_CACHE_QUOTA_CALCULATION);
+ dumpSetting(s, p,
+ Settings.Global.ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE,
+ GlobalSettingsProto.ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE);
+ // The list of snooze options for notifications. This is encoded as a key=value list,
+ // separated by commas.
+ dumpSetting(s, p,
+ Settings.Global.NOTIFICATION_SNOOZE_OPTIONS,
+ GlobalSettingsProto.NOTIFICATION_SNOOZE_OPTIONS);
}
/** Dump a single {@link SettingsState.Setting} to a proto buf */
@@ -966,9 +1129,19 @@ class SettingsProtoDumpUtil {
static void dumpProtoSecureSettingsLocked(
@NonNull SettingsState s, @NonNull ProtoOutputStream p) {
+ s.dumpHistoricalOperations(p, SecureSettingsProto.HISTORICAL_OPERATIONS);
+
+ // This uses the same order as in Settings.Secure.
+
+ // Settings.Secure.DEVELOPMENT_SETTINGS_ENABLED intentionally excluded since it's deprecated.
+ // Settings.Secure.BUGREPORT_IN_POWER_MENU intentionally excluded since it's deprecated.
+ // Settings.Secure.ADB_ENABLED intentionally excluded since it's deprecated.
+ // Settings.Secure.ALLOW_MOCK_LOCATION intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Secure.ANDROID_ID,
SecureSettingsProto.ANDROID_ID);
+ // Settings.Secure.BLUETOOTH_ON intentionally excluded since it's deprecated.
+ // Settings.Secure.DATA_ROAMING intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Secure.DEFAULT_INPUT_METHOD,
SecureSettingsProto.DEFAULT_INPUT_METHOD);
@@ -987,9 +1160,16 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Secure.AUTOFILL_SERVICE,
SecureSettingsProto.AUTOFILL_SERVICE);
+ // Settings.Secure.DEVICE_PROVISIONED intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Secure.USER_SETUP_COMPLETE,
SecureSettingsProto.USER_SETUP_COMPLETE);
+ // Whether the current user has been set up via setup wizard (0 = false, 1 = true). This
+ // value differs from USER_SETUP_COMPLETE in that it can be reset back to 0 in case
+ // SetupWizard has been re-enabled on TV devices.
+ dumpSetting(s, p,
+ Settings.Secure.TV_USER_SETUP_COMPLETE,
+ SecureSettingsProto.TV_USER_SETUP_COMPLETE);
dumpSetting(s, p,
Settings.Secure.COMPLETED_CATEGORY_PREFIX,
SecureSettingsProto.COMPLETED_CATEGORY_PREFIX);
@@ -1002,6 +1182,7 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
SecureSettingsProto.SHOW_IME_WITH_HARD_KEYBOARD);
+ // Settings.Secure.HTTP_PROXY intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Secure.ALWAYS_ON_VPN_APP,
SecureSettingsProto.ALWAYS_ON_VPN_APP);
@@ -1012,17 +1193,33 @@ class SettingsProtoDumpUtil {
Settings.Secure.INSTALL_NON_MARKET_APPS,
SecureSettingsProto.INSTALL_NON_MARKET_APPS);
dumpSetting(s, p,
+ Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED,
+ SecureSettingsProto.UNKNOWN_SOURCES_DEFAULT_REVERSED);
+ // Settings.Secure.LOCATION_PROVIDERS_ALLOWED intentionally excluded since it's deprecated.
+ dumpSetting(s, p,
Settings.Secure.LOCATION_MODE,
SecureSettingsProto.LOCATION_MODE);
dumpSetting(s, p,
Settings.Secure.LOCATION_PREVIOUS_MODE,
SecureSettingsProto.LOCATION_PREVIOUS_MODE);
+ // Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED,
SecureSettingsProto.LOCK_TO_APP_EXIT_LOCKED);
+ // Settings.Secure.LOCK_PATTERN_ENABLED intentionally excluded since it's deprecated.
+ // Settings.Secure.LOCK_PATTERN_VISIBLE intentionally excluded since it's deprecated.
+ // Settings.Secure.LOCK_PATTERN_TACTICLE_FEEDBACK_ENABLED intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
SecureSettingsProto.LOCK_SCREEN_LOCK_AFTER_TIMEOUT);
+ // Settings.Secure.LOCK_SCREEN_OWNER_INFO intentionally excluded since it's deprecated.
+ // Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS intentionally excluded since it's deprecated.
+ // Settings.Secure.LOCK_SCREEN_FALLBACK_APPWIDGET_ID intentionally excluded since it's deprecated.
+ // Settings.Secure.LOCK_SCREEN_STICKY_APPWIDGET intentionally excluded since it's deprecated.
+ // Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED intentionally excluded since it's deprecated.
+ dumpSetting(s, p,
+ Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ SecureSettingsProto.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);
dumpSetting(s, p,
Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
SecureSettingsProto.LOCK_SCREEN_ALLOW_REMOTE_INPUT);
@@ -1032,6 +1229,8 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Secure.TRUST_AGENTS_INITIALIZED,
SecureSettingsProto.TRUST_AGENTS_INITIALIZED);
+ // Settings.Secure.LOGGING_ID intentionally excluded since it's deprecated.
+ // Settings.Secure.NETWORK_PREFERENCE intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Secure.PARENTAL_CONTROL_ENABLED,
SecureSettingsProto.PARENTAL_CONTROL_ENABLED);
@@ -1044,10 +1243,27 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Secure.SETTINGS_CLASSNAME,
SecureSettingsProto.SETTINGS_CLASSNAME);
+ // Settings.Secure.USB_MASS_STORAGE_ENABLED intentionally excluded since it's deprecated.
+ // Settings.Secure.USE_GOOGLE_MAIL intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Secure.ACCESSIBILITY_ENABLED,
SecureSettingsProto.ACCESSIBILITY_ENABLED);
dumpSetting(s, p,
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED,
+ SecureSettingsProto.ACCESSIBILITY_SHORTCUT_ENABLED);
+ dumpSetting(s, p,
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
+ SecureSettingsProto.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN);
+ dumpSetting(s, p,
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+ SecureSettingsProto.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN);
+ dumpSetting(s, p,
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+ SecureSettingsProto.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
+ dumpSetting(s, p,
+ Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
+ SecureSettingsProto.ACCESSIBILITY_BUTTON_TARGET_COMPONENT);
+ dumpSetting(s, p,
Settings.Secure.TOUCH_EXPLORATION_ENABLED,
SecureSettingsProto.TOUCH_EXPLORATION_ENABLED);
dumpSetting(s, p,
@@ -1066,9 +1282,15 @@ class SettingsProtoDumpUtil {
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
SecureSettingsProto.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
dumpSetting(s, p,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
+ SecureSettingsProto.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED);
+ dumpSetting(s, p,
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
SecureSettingsProto.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE);
dumpSetting(s, p,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE,
+ SecureSettingsProto.ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE);
+ dumpSetting(s, p,
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
SecureSettingsProto.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
dumpSetting(s, p,
@@ -1134,6 +1356,7 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Secure.DISPLAY_DENSITY_FORCED,
SecureSettingsProto.DISPLAY_DENSITY_FORCED);
+ // Settings.Secure.TTS_USE_DEFAULTS intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Secure.TTS_DEFAULT_RATE,
SecureSettingsProto.TTS_DEFAULT_RATE);
@@ -1143,15 +1366,37 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Secure.TTS_DEFAULT_SYNTH,
SecureSettingsProto.TTS_DEFAULT_SYNTH);
+ // Settings.Secure.TTS_DEFAULT_LANG intentionally excluded since it's deprecated.
+ // Settings.Secure.TTS_DEFAULT_COUNTRY intentionally excluded since it's deprecated.
+ // Settings.Secure.TTS_DEFAULT_VARIANT intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Secure.TTS_DEFAULT_LOCALE,
SecureSettingsProto.TTS_DEFAULT_LOCALE);
dumpSetting(s, p,
Settings.Secure.TTS_ENABLED_PLUGINS,
SecureSettingsProto.TTS_ENABLED_PLUGINS);
+ // Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_NUM_OPEN_NETWORKS_KEPT intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_ON intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_WATCHDOG_AP_COUNT intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_WATCHDOG_MAX_AP_CHECKS intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_WATCHDOG_ON intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_WATCHDOG_WATCH_LIST intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_WATCHDOG_PING_COUNT intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_WATCHDOG_PING_DELAY_MS intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT intentionally excluded since it's deprecated.
+ // Settings.Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS,
SecureSettingsProto.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS);
+ // Settings.Secure.BACKGROUND_DATA intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Secure.ALLOWED_GEOLOCATION_ORIGINS,
SecureSettingsProto.ALLOWED_GEOLOCATION_ORIGINS);
@@ -1179,6 +1424,7 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Secure.LAST_SETUP_SHOWN,
SecureSettingsProto.LAST_SETUP_SHOWN);
+ // Settings.Secure.WIFI_IDLE_MS intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.Secure.SEARCH_GLOBAL_SEARCH_ACTIVITY,
SecureSettingsProto.SEARCH_GLOBAL_SEARCH_ACTIVITY);
@@ -1285,6 +1531,9 @@ class SettingsProtoDumpUtil {
Settings.Secure.DOZE_PULSE_ON_PICK_UP,
SecureSettingsProto.DOZE_PULSE_ON_PICK_UP);
dumpSetting(s, p,
+ Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
+ SecureSettingsProto.DOZE_PULSE_ON_LONG_PRESS);
+ dumpSetting(s, p,
Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP,
SecureSettingsProto.DOZE_PULSE_ON_DOUBLE_TAP);
dumpSetting(s, p,
@@ -1351,6 +1600,9 @@ class SettingsProtoDumpUtil {
Settings.Secure.PAYMENT_SERVICE_SEARCH_URI,
SecureSettingsProto.PAYMENT_SERVICE_SEARCH_URI);
dumpSetting(s, p,
+ Settings.Secure.AUTOFILL_SERVICE_SEARCH_URI,
+ SecureSettingsProto.AUTOFILL_SERVICE_SEARCH_URI);
+ dumpSetting(s, p,
Settings.Secure.SKIP_FIRST_USE_HINTS,
SecureSettingsProto.SKIP_FIRST_USE_HINTS);
dumpSetting(s, p,
@@ -1387,18 +1639,42 @@ class SettingsProtoDumpUtil {
Settings.Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
SecureSettingsProto.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED);
dumpSetting(s, p,
+ Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED,
+ SecureSettingsProto.CAMERA_LIFT_TRIGGER_ENABLED);
+ dumpSetting(s, p,
+ Settings.Secure.ASSIST_GESTURE_ENABLED,
+ SecureSettingsProto.ASSIST_GESTURE_ENABLED);
+ dumpSetting(s, p,
+ Settings.Secure.ASSIST_GESTURE_SENSITIVITY,
+ SecureSettingsProto.ASSIST_GESTURE_SENSITIVITY);
+ dumpSetting(s, p,
+ Settings.Secure.ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
+ SecureSettingsProto.ASSIST_GESTURE_SILENCE_ALERTS_ENABLED);
+ dumpSetting(s, p,
+ Settings.Secure.ASSIST_GESTURE_WAKE_ENABLED,
+ SecureSettingsProto.ASSIST_GESTURE_WAKE_ENABLED);
+ dumpSetting(s, p,
+ Settings.Secure.ASSIST_GESTURE_SETUP_COMPLETE,
+ SecureSettingsProto.ASSIST_GESTURE_SETUP_COMPLETE);
+ dumpSetting(s, p,
Settings.Secure.NIGHT_DISPLAY_ACTIVATED,
SecureSettingsProto.NIGHT_DISPLAY_ACTIVATED);
dumpSetting(s, p,
Settings.Secure.NIGHT_DISPLAY_AUTO_MODE,
SecureSettingsProto.NIGHT_DISPLAY_AUTO_MODE);
dumpSetting(s, p,
+ Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE,
+ SecureSettingsProto.NIGHT_DISPLAY_COLOR_TEMPERATURE);
+ dumpSetting(s, p,
Settings.Secure.NIGHT_DISPLAY_CUSTOM_START_TIME,
SecureSettingsProto.NIGHT_DISPLAY_CUSTOM_START_TIME);
dumpSetting(s, p,
Settings.Secure.NIGHT_DISPLAY_CUSTOM_END_TIME,
SecureSettingsProto.NIGHT_DISPLAY_CUSTOM_END_TIME);
dumpSetting(s, p,
+ Settings.Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+ SecureSettingsProto.NIGHT_DISPLAY_LAST_ACTIVATED_TIME);
+ dumpSetting(s, p,
Settings.Secure.ENABLED_VR_LISTENERS,
SecureSettingsProto.ENABLED_VR_LISTENERS);
dumpSetting(s, p,
@@ -1423,6 +1699,9 @@ class SettingsProtoDumpUtil {
Settings.Secure.AUTOMATIC_STORAGE_MANAGER_LAST_RUN,
SecureSettingsProto.AUTOMATIC_STORAGE_MANAGER_LAST_RUN);
dumpSetting(s, p,
+ Settings.Secure.AUTOMATIC_STORAGE_MANAGER_TURNED_OFF_BY_POLICY,
+ SecureSettingsProto.AUTOMATIC_STORAGE_MANAGER_TURNED_OFF_BY_POLICY);
+ dumpSetting(s, p,
Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED,
SecureSettingsProto.SYSTEM_NAVIGATION_KEYS_ENABLED);
dumpSetting(s, p,
@@ -1438,33 +1717,76 @@ class SettingsProtoDumpUtil {
Settings.Secure.DEVICE_PAIRED,
SecureSettingsProto.DEVICE_PAIRED);
dumpSetting(s, p,
+ Settings.Secure.PACKAGE_VERIFIER_STATE,
+ SecureSettingsProto.PACKAGE_VERIFIER_STATE);
+ dumpSetting(s, p,
+ Settings.Secure.CMAS_ADDITIONAL_BROADCAST_PKG,
+ SecureSettingsProto.CMAS_ADDITIONAL_BROADCAST_PKG);
+ dumpSetting(s, p,
Settings.Secure.NOTIFICATION_BADGING,
SecureSettingsProto.NOTIFICATION_BADGING);
dumpSetting(s, p,
+ Settings.Secure.QS_AUTO_ADDED_TILES,
+ SecureSettingsProto.QS_AUTO_ADDED_TILES);
+ dumpSetting(s, p,
+ Settings.Secure.LOCKDOWN_IN_POWER_MENU,
+ SecureSettingsProto.LOCKDOWN_IN_POWER_MENU);
+ dumpSetting(s, p,
Settings.Secure.BACKUP_MANAGER_CONSTANTS,
SecureSettingsProto.BACKUP_MANAGER_CONSTANTS);
}
private static void dumpProtoSystemSettingsLocked(
@NonNull SettingsState s, @NonNull ProtoOutputStream p) {
+ s.dumpHistoricalOperations(p, SystemSettingsProto.HISTORICAL_OPERATIONS);
+
+ // This uses the same order as in Settings.System.
+
+ // Settings.System.STAY_ON_WHILE_PLUGGED_IN intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.System.END_BUTTON_BEHAVIOR,
SystemSettingsProto.END_BUTTON_BEHAVIOR);
dumpSetting(s, p,
Settings.System.ADVANCED_SETTINGS,
SystemSettingsProto.ADVANCED_SETTINGS);
+ // Settings.System.AIRPLANE_MODE_ON intentionally excluded since it's deprecated.
+ // Settings.System.RADIO_BLUETOOTH intentionally excluded since it's deprecated.
+ // Settings.System.RADIO_WIFI intentionally excluded since it's deprecated.
+ // Settings.System.RADIO_WIMAX intentionally excluded since it's deprecated.
+ // Settings.System.RADIO_CELL intentionally excluded since it's deprecated.
+ // Settings.System.RADIO_NFC intentionally excluded since it's deprecated.
+ // Settings.System.AIRPLANE_MODE_RADIOS intentionally excluded since it's deprecated.
+ // Settings.System.AIRPLANE_MODE_TOGGLABLE_RADIOS intentionally excluded since it's deprecated.
+ // Settings.System.WIFI_SLEEP_POLICY intentionally excluded since it's deprecated.
+ // Settings.System.MODE_RINGER intentionally excluded since it's deprecated.
+ // Settings.System.WIFI_USE_STATIC_IP intentionally excluded since it's deprecated.
+ // Settings.System.WIFI_STATIC_IP intentionally excluded since it's deprecated.
+ // Settings.System.WIFI_STATIC_GATEWAY intentionally excluded since it's deprecated.
+ // Settings.System.WIFI_STATIC_NETMASK intentionally excluded since it's deprecated.
+ // Settings.System.WIFI_STATIC_DNS1 intentionally excluded since it's deprecated.
+ // Settings.System.WIFI_STATIC_DNS2 intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.System.BLUETOOTH_DISCOVERABILITY,
SystemSettingsProto.BLUETOOTH_DISCOVERABILITY);
dumpSetting(s, p,
Settings.System.BLUETOOTH_DISCOVERABILITY_TIMEOUT,
SystemSettingsProto.BLUETOOTH_DISCOVERABILITY_TIMEOUT);
+ // Settings.System.LOCK_PATTERN_ENABLED intentionally excluded since it's deprecated.
+ // Settings.System.LOCK_PATTERN_VISIBLE intentionally excluded since it's deprecated.
+ // Settings.System.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED intentionally excluded since it's deprecated.
+ // Settings.System.NEXT_ALARM_FORMATTED intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.System.FONT_SCALE,
SystemSettingsProto.FONT_SCALE);
dumpSetting(s, p,
Settings.System.SYSTEM_LOCALES,
SystemSettingsProto.SYSTEM_LOCALES);
+ // Settings.System.DEBUG_APP intentionally excluded since it's deprecated.
+ // Settings.System.WAIT_FOR_DEBUGGER intentionally excluded since it's deprecated.
+ // Settings.System.DIM_SCREEN intentionally excluded since it's deprecated.
+ dumpSetting(s, p,
+ Settings.System.DISPLAY_COLOR_MODE,
+ SystemSettingsProto.DISPLAY_COLOR_MODE);
dumpSetting(s, p,
Settings.System.SCREEN_OFF_TIMEOUT,
SystemSettingsProto.SCREEN_OFF_TIMEOUT);
@@ -1480,6 +1802,8 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
SystemSettingsProto.SCREEN_AUTO_BRIGHTNESS_ADJ);
+ // Settings.System.SHOW_PROCESSES intentionally excluded since it's deprecated.
+ // Settings.System.ALWAYS_FINISH_ACTIVITIES intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.System.MODE_RINGER_STREAMS_AFFECTED,
SystemSettingsProto.MODE_RINGER_STREAMS_AFFECTED);
@@ -1514,11 +1838,15 @@ class SettingsProtoDumpUtil {
Settings.System.VOLUME_BLUETOOTH_SCO,
SystemSettingsProto.VOLUME_BLUETOOTH_SCO);
dumpSetting(s, p,
+ Settings.System.VOLUME_ACCESSIBILITY,
+ SystemSettingsProto.VOLUME_ACCESSIBILITY);
+ dumpSetting(s, p,
Settings.System.VOLUME_MASTER,
SystemSettingsProto.VOLUME_MASTER);
dumpSetting(s, p,
Settings.System.MASTER_MONO,
SystemSettingsProto.MASTER_MONO);
+ // Settings.System.NOTIFICATIONS_USE_RING_VOLUME intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.System.VIBRATE_IN_SILENT,
SystemSettingsProto.VIBRATE_IN_SILENT);
@@ -1561,6 +1889,9 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.System.SHOW_GTALK_SERVICE_STATUS,
SystemSettingsProto.SHOW_GTALK_SERVICE_STATUS);
+ // Settings.System.WALLPAPER_ACTIVITY intentionally excluded since it's deprecated.
+ // Settings.System.AUTO_TIME intentionally excluded since it's deprecated.
+ // Settings.System.AUTO_TIME_ZONE intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.System.TIME_12_24,
SystemSettingsProto.TIME_12_24);
@@ -1570,6 +1901,9 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.System.SETUP_WIZARD_HAS_RUN,
SystemSettingsProto.SETUP_WIZARD_HAS_RUN);
+ // Settings.System.WINDOW_ANIMATION_SCALE intentionally excluded since it's deprecated.
+ // Settings.System.TRANSITION_ANIMATION_SCALE intentionally excluded since it's deprecated.
+ // Settings.System.ANIMATOR_ANIMATION_SCALE intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.System.ACCELEROMETER_ROTATION,
SystemSettingsProto.ACCELEROMETER_ROTATION);
@@ -1600,6 +1934,7 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.System.HAPTIC_FEEDBACK_ENABLED,
SystemSettingsProto.HAPTIC_FEEDBACK_ENABLED);
+ // Settings.System.SHOW_WEB_SUGGESTIONS intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.System.NOTIFICATION_LIGHT_PULSE,
SystemSettingsProto.NOTIFICATION_LIGHT_PULSE);
@@ -1612,12 +1947,21 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.System.WINDOW_ORIENTATION_LISTENER_LOG,
SystemSettingsProto.WINDOW_ORIENTATION_LISTENER_LOG);
+ // Settings.System.POWER_SOUNDS_ENABLED intentionally excluded since it's deprecated.
+ // Settings.System.DOCK_SOUNDS_ENABLED intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.System.LOCKSCREEN_SOUNDS_ENABLED,
SystemSettingsProto.LOCKSCREEN_SOUNDS_ENABLED);
dumpSetting(s, p,
Settings.System.LOCKSCREEN_DISABLED,
SystemSettingsProto.LOCKSCREEN_DISABLED);
+ // Settings.System.LOW_BATTERY_SOUND intentionally excluded since it's deprecated.
+ // Settings.System.DESK_DOCK_SOUND intentionally excluded since it's deprecated.
+ // Settings.System.DESK_UNDOCK_SOUND intentionally excluded since it's deprecated.
+ // Settings.System.CAR_DOCK_SOUND intentionally excluded since it's deprecated.
+ // Settings.System.CAR_UNDOCK_SOUND intentionally excluded since it's deprecated.
+ // Settings.System.LOCK_SOUND intentionally excluded since it's deprecated.
+ // Settings.System.UNLOCK_SOUND intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.System.SIP_RECEIVE_CALLS,
SystemSettingsProto.SIP_RECEIVE_CALLS);
@@ -1630,6 +1974,7 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.System.SIP_ADDRESS_ONLY,
SystemSettingsProto.SIP_ADDRESS_ONLY);
+ // Settings.System.SIP_ASK_ME_EACH_TIME intentionally excluded since it's deprecated.
dumpSetting(s, p,
Settings.System.POINTER_SPEED,
SystemSettingsProto.POINTER_SPEED);
@@ -1640,7 +1985,12 @@ class SettingsProtoDumpUtil {
Settings.System.EGG_MODE,
SystemSettingsProto.EGG_MODE);
dumpSetting(s, p,
+ Settings.System.SHOW_BATTERY_PERCENT,
+ SystemSettingsProto.SHOW_BATTERY_PERCENT);
+ dumpSetting(s, p,
Settings.System.WHEN_TO_MAKE_WIFI_CALLS,
SystemSettingsProto.WHEN_TO_MAKE_WIFI_CALLS);
+ // The rest of the settings were moved to Settings.Secure, and are thus excluded here since
+ // they're deprecated from Settings.System.
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 36f9b840b4ac..258c96cf40be 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -18,6 +18,7 @@ package com.android.providers.settings;
import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.backup.BackupManager;
@@ -657,7 +658,6 @@ public class SettingsProvider extends ContentProvider {
synchronized (mLock) {
SettingsProtoDumpUtil.dumpProtoLocked(mSettingsRegistry, proto);
-
}
proto.flush();
@@ -2284,6 +2284,7 @@ public class SettingsProvider extends ContentProvider {
return users;
}
+ @Nullable
public SettingsState getSettingsLocked(int type, int userId) {
final int key = makeKey(type, userId);
return peekSettingsStateLocked(key);
@@ -2578,6 +2579,7 @@ public class SettingsProvider extends ContentProvider {
ssaidSettings.deleteSettingLocked(Integer.toString(uid));
}
+ @Nullable
private SettingsState peekSettingsStateLocked(int key) {
SettingsState settingsState = mSettingsStates.get(key);
if (settingsState != null) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 4151ada9ce80..f901bcaee69e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -434,8 +434,9 @@ final class SettingsState {
* Dump historical operations as a proto buf.
*
* @param proto The proto buf stream to dump to
+ * @param fieldId The repeated field ID to use to save an operation to.
*/
- void dumpProtoHistoricalOperations(@NonNull ProtoOutputStream proto) {
+ void dumpHistoricalOperations(@NonNull ProtoOutputStream proto, long fieldId) {
synchronized (mLock) {
if (mHistoricalOperations == null) {
return;
@@ -448,7 +449,8 @@ final class SettingsState {
index = operationCount + index;
}
HistoricalOperation operation = mHistoricalOperations.get(index);
- long settingsOperationToken = proto.start(GlobalSettingsProto.HISTORICAL_OP);
+
+ final long token = proto.start(fieldId);
proto.write(SettingsOperationProto.TIMESTAMP, operation.mTimestamp);
proto.write(SettingsOperationProto.OPERATION, operation.mOperation);
if (operation.mSetting != null) {
@@ -457,7 +459,7 @@ final class SettingsState {
// add is what the current data is).
proto.write(SettingsOperationProto.SETTING, operation.mSetting.getName());
}
- proto.end(settingsOperationToken);
+ proto.end(token);
}
}
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 7b8d0db9739e..29ecac0080ee 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -120,6 +120,7 @@
<uses-permission android:name="android.permission.TRUST_LISTENER" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT" />
+ <uses-permission android:name="android.permission.BIND_SLICE" />
<!-- Needed for WallpaperManager.clear in ImageWallpaper.updateWallpaperLocked -->
<uses-permission android:name="android.permission.SET_WALLPAPER"/>
@@ -222,7 +223,7 @@
-->
<service android:name="SystemUIService"
android:exported="true"
- />
+ />
<!-- Recents depends on every user having their own SystemUI process, so on user switch,
ensure that the process is created by starting this service.
@@ -568,6 +569,11 @@
android:resource="@xml/fileprovider" />
</provider>
+ <provider android:name=".keyguard.KeyguardSliceProvider"
+ android:authorities="com.android.systemui.keyguard"
+ android:exported="true">
+ </provider>
+
<receiver
android:name=".statusbar.KeyboardShortcutsReceiver">
<intent-filter>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml
index 39cba742d9b5..3018a022e763 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml
@@ -33,8 +33,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Keyguard.TextView"
+ android:singleLine="true"
android:ellipsize="marquee"
android:visibility="gone"
+ android:gravity="center"
androidprv:allCaps="@bool/kg_use_all_caps" />
<com.android.keyguard.EmergencyButton
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
index 97c896591eb2..947f27deb84e 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
@@ -32,6 +32,7 @@
android:id="@+id/keyguard_sim"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:tint="@color/background_protected"
android:src="@drawable/ic_lockscreen_sim"/>
<include layout="@layout/keyguard_message_area"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
index d4c5d7474aed..6f270b405c11 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
@@ -33,6 +33,7 @@
android:id="@+id/keyguard_sim"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:tint="@color/background_protected"
android:src="@drawable/ic_lockscreen_sim"/>
<include layout="@layout/keyguard_message_area"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
index 56fb73faf868..020cfeeaa194 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
@@ -18,34 +18,37 @@
-->
<!-- This is a view that shows general status information in Keyguard. -->
-<LinearLayout
+<com.android.keyguard.KeyguardSliceView
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="center">
- <com.android.systemui.statusbar.policy.DateView
- android:id="@+id/date_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="?attr/wallpaperTextColor"
- style="@style/widget_label"
- android:letterSpacing="0.05"
- android:gravity="center"
- />
- <TextView android:id="@+id/alarm_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:drawablePadding="6dp"
- android:drawableStart="@drawable/ic_access_alarms_big"
- android:drawableTint="?attr/wallpaperTextColorSecondary"
- android:drawableTintMode="src_in"
- android:textColor="?attr/wallpaperTextColorSecondary"
- android:letterSpacing="0.05"
- style="@style/widget_label"
- android:layout_marginStart="6dp"
- android:gravity="center"
- android:visibility="gone"
- />
-</LinearLayout>
+ android:layout_marginTop="@dimen/date_owner_info_margin"
+ android:layout_gravity="center_horizontal"
+ android:paddingTop="4dp"
+ android:clipToPadding="false"
+ android:orientation="vertical"
+ android:layout_centerHorizontal="true">
+ <TextView android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:fadingEdge="horizontal"
+ android:gravity="center"
+ android:textSize="22sp"
+ android:textColor="?attr/wallpaperTextColor"
+ />
+ <TextView android:id="@+id/text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:gravity="center"
+ android:visibility="gone"
+ android:textSize="16sp"
+ android:textColor="?attr/wallpaperTextColor"
+ android:layout_marginTop="4dp"
+ android:ellipsize="end"
+ />
+</com.android.keyguard.KeyguardSliceView> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml
index b33c523c23ec..359271d5abdc 100644
--- a/packages/SystemUI/res-keyguard/values-be/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-be/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Увядзіце пароль для разблакіравання"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Каб разблакіраваць, увядзіце PIN-код"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Няправільны PIN-код."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Несапраўдная картка."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Зараджаны"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Ідзе зарадка"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Зараджаецца хутка"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index d0d905b0518f..e5119402674f 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -29,6 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Type password to unlock"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Type PIN to unlock"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Incorrect PIN code."</string>
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Invalid card."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Charged"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Charging"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Charging rapidly"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
index d0d905b0518f..e5119402674f 100644
--- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
@@ -29,6 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Type password to unlock"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Type PIN to unlock"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Incorrect PIN code."</string>
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Invalid card."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Charged"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Charging"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Charging rapidly"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index d0d905b0518f..e5119402674f 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -29,6 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Type password to unlock"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Type PIN to unlock"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Incorrect PIN code."</string>
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Invalid card."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Charged"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Charging"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Charging rapidly"</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index d0d905b0518f..e5119402674f 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -29,6 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Type password to unlock"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Type PIN to unlock"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Incorrect PIN code."</string>
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Invalid card."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Charged"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Charging"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Charging rapidly"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index b8689ee24906..dc2a4411b268 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Poista lukitus antamalla salasana."</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Poista lukitus antamalla PIN-koodi."</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Väärä PIN-koodi"</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Virheellinen kortti"</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Ladattu"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Ladataan"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Nopea lataus käynnissä"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index e70dca379ad3..8e614e04d560 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Entrez le mot de passe pour déverrouiller le clavier."</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Entrez le NIP pour déverrouiller le clavier."</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"NIP erroné."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Cette carte n\'est pas valide."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Chargé"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Pile en cours de charge"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Charge rapide"</string>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index 4fe50ed05bdf..7be5f41fa409 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Escribe o contrasinal para desbloquear"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Escribe o PIN para desbloquear"</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">"A tarxeta non é 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">"Cargando rapidamente"</string>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index 72d9b752b2c0..48aa75b9f29a 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"અનલૉક કરવા માટે પાસવર્ડ લખો"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"અનલૉક કરવા માટે પિન લખો"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"ખોટો પિન કોડ."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"અમાન્ય કાર્ડ."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"ચાર્જ થઈ ગયું"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"ચાર્જ થઈ રહ્યું છે"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"ઝડપથી ચાર્જ થઈ રહ્યું છે"</string>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index 5b944687958a..093c5cbc791a 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"ಅನ್‌ಲಾಕ್‌ ಮಾಡಲು ಪಾಸ್‌ವರ್ಡ್‌ ಟೈಪ್‌ ಮಾಡಿ"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"ಅನ್‌ಲಾಕ್‌ ಮಾಡಲು ಪಿನ್‌ ಟೈಪ್‌ ಮಾಡಿ"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"ತಪ್ಪಾದ ಪಿನ್‌ ಕೋಡ್."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"ಅಮಾನ್ಯ ಕಾರ್ಡ್."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"ವೇಗವಾಗಿ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index b00584fb2b91..0b2123189559 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"അൺലോക്കുചെയ്യുന്നതിന് പാസ്‌വേഡ് ടൈപ്പുചെയ്യുക"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"അൺലോക്കുചെയ്യുന്നതിന് പിൻ ടൈപ്പുചെയ്യുക"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"പിൻ കോഡ് തെറ്റാണ്."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"അസാധുവായ കാർഡ്."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"ചാർജായി"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"ചാർജ്ജുചെയ്യുന്നു"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"വേഗത്തിൽ ചാർജുചെയ്യുന്നു"</string>
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index 8ab95f974908..cfda6cc1cd8d 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -25,12 +25,11 @@
<string name="keyguard_password_enter_puk_code" msgid="670683628782925409">"सिम PUK आणि नवीन पिन कोड टाइप करा"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="3747778500166059332">"सिम PUK कोड"</string>
<string name="keyguard_password_enter_pin_prompt" msgid="8188243197504453830">"नवीन सिम पिन कोड"</string>
- <string name="keyguard_password_entry_touch_hint" msgid="5790410752696806482"><font size="17">"संकेतशब्द टाइप करण्यासाठी स्पर्श करा"</font></string>
- <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"अनलॉक करण्यासाठी संकेतशब्द टाइप करा"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="5790410752696806482"><font size="17">"पासवर्ड टाइप करण्यासाठी स्पर्श करा"</font></string>
+ <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>
@@ -54,10 +53,10 @@
<string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"पुढील अलार्म <xliff:g id="ALARM">%1$s</xliff:g> साठी सेट केला"</string>
<string name="keyboardview_keycode_delete" msgid="6883116827512721630">"हटवा"</string>
<string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIM बंद करा"</string>
- <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"प्रविष्ट करा"</string>
+ <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"एंटर करा"</string>
<string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"पॅटर्न विसरलात"</string>
<string name="kg_wrong_pattern" msgid="7620081431514773802">"चुकीचा पॅटर्न"</string>
- <string name="kg_wrong_password" msgid="4580683060277329277">"चुकीचा संकेतशब्द"</string>
+ <string name="kg_wrong_password" msgid="4580683060277329277">"चुकीचा पासवर्ड"</string>
<string name="kg_wrong_pin" msgid="4785660766909463466">"चुकीचा पिन"</string>
<plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="4368805541257003755">
<item quantity="one"><xliff:g id="NUMBER">%d</xliff:g> सेकंदात पुन्हा प्रयत्न करा.</item>
@@ -67,20 +66,20 @@
<string name="kg_sim_pin_instructions" msgid="6389000973113699187">"सिम पिन एंटर करा"</string>
<string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" साठी सिम पिन एंटर करा"</string>
<string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"मोबाइल सेवांशिवाय डिव्हाइस वापरण्यासाठी eSIM बंद करा."</string>
- <string name="kg_pin_instructions" msgid="4069609316644030034">"पिन प्रविष्ट करा"</string>
- <string name="kg_password_instructions" msgid="136952397352976538">"संकेतशब्द प्रविष्ट करा"</string>
- <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"सिम आता अक्षम केले आहे. सुरू ठेवण्यासाठी PUK कोड प्रविष्ट करा. तपशीलांसाठी वाहकाशी संपर्क साधा."</string>
- <string name="kg_puk_enter_puk_hint_multi" msgid="1373131883510840794">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" सिम आता अक्षम केले आहे. सुरू ठेवण्यासाठी PUK कोड प्रविष्ट करा. तपशीलांसाठी वाहकाशी संपर्क साधा."</string>
- <string name="kg_puk_enter_pin_hint" msgid="3137789674920391087">"इच्छित पिन कोड प्रविष्ट करा"</string>
+ <string name="kg_pin_instructions" msgid="4069609316644030034">"पिन एंटर करा"</string>
+ <string name="kg_password_instructions" msgid="136952397352976538">"पासवर्ड एंटर करा"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"सिम आता अक्षम केले आहे. सुरू ठेवण्यासाठी PUK कोड एंटर करा. तपशीलांसाठी वाहकाशी संपर्क साधा."</string>
+ <string name="kg_puk_enter_puk_hint_multi" msgid="1373131883510840794">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" सिम आता अक्षम केले आहे. सुरू ठेवण्यासाठी PUK कोड एंटर करा. तपशीलांसाठी वाहकाशी संपर्क साधा."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="3137789674920391087">"इच्छित पिन कोड एंटर करा"</string>
<string name="kg_enter_confirm_pin_hint" msgid="3089485999116759671">"इच्छित पिन कोड ची पुष्टी करा"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="4471738151810900114">"सिम कार्ड अनलॉक करत आहे…"</string>
<string name="kg_invalid_sim_pin_hint" msgid="3057533256729513335">"4 ते 8 अंकांचा पिन टाईप करा."</string>
<string name="kg_invalid_sim_puk_hint" msgid="6003602401368264144">"PUK कोड 8 अंकी किंवा त्यापेक्षा अधिकचा असावा."</string>
- <string name="kg_invalid_puk" msgid="5399287873762592502">"योग्य PUK कोड पुन्हा प्रविष्ट करा. पुनःपुन्हा प्रयत्न करणे सिम कायमचे अक्षम करेल."</string>
+ <string name="kg_invalid_puk" msgid="5399287873762592502">"योग्य PUK कोड पुन्हा एंटर करा. पुनःपुन्हा प्रयत्न करणे सिम कायमचे अक्षम करेल."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="5672736555427444330">"पिन कोड जुळत नाहीत"</string>
<string name="kg_login_too_many_attempts" msgid="6604574268387867255">"खूप जास्त पॅटर्न प्रयत्न"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8637788033282252027">"आपण आपला PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने टाइप केला आहे. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7724148763268377734">"आपण आपला संकेतशब्द <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने टाइप केला आहे. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7724148763268377734">"आपण आपला पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने टाइप केला आहे. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4820967667848302092">"तुम्ही आपला अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने काढला. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1629351522209932316">"आपण टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, हे टॅबलेट रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="3921998703529189931">"आपण फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, हा फोन रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
@@ -117,10 +116,10 @@
<string name="kg_prompt_reason_restart_password" msgid="6984641181515902406">"डिव्हाइस रीस्टार्ट झाल्यावर पासवर्ड आवश्यक आहे"</string>
<string name="kg_prompt_reason_timeout_pattern" msgid="5304487696073914063">"अतिरिक्त सुरक्षिततेसाठी पॅटर्न आवश्‍यक आहे"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="8851462864335757813">"अतिरिक्त सुरक्षिततेसाठी पिन आवश्‍यक आहे"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="6563904839641583441">"अतिरिक्त सुरक्षिततेसाठी संकेतशब्द आवश्‍यक आहे"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="6563904839641583441">"अतिरिक्त सुरक्षिततेसाठी पासवर्ड आवश्‍यक आहे"</string>
<string name="kg_prompt_reason_switch_profiles_pattern" msgid="3398054847288438444">"तुम्ही प्रोफाईल स्विच करता तेव्‍हा पॅटर्न आवश्‍यक आहे"</string>
<string name="kg_prompt_reason_switch_profiles_pin" msgid="7426368139226961699">"आपण प्रोफाईल स्विच करता तेव्‍हा पिन आवश्‍यक आहे"</string>
- <string name="kg_prompt_reason_switch_profiles_password" msgid="8383831046318421845">"आपण प्रोफाईल स्विच करता तेव्‍हा संकेतशब्द आवश्‍यक आहे"</string>
+ <string name="kg_prompt_reason_switch_profiles_password" msgid="8383831046318421845">"आपण प्रोफाईल स्विच करता तेव्‍हा पासवर्ड आवश्‍यक आहे"</string>
<string name="kg_prompt_reason_device_admin" msgid="3452168247888906179">"प्रशासकाद्वारे लॉक केलेले डिव्हाइस"</string>
<string name="kg_prompt_reason_user_request" msgid="8236951765212462286">"डिव्हाइस मॅन्युअली लॉक केले होते"</string>
<plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="71299470072448533">
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index bedcf1792a62..0bab97dd1959 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਪਾਸਵਰਡ ਟਾਈਪ ਕਰੋ"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਪਿੰਨ ਟਾਈਪ ਕਰੋ"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"ਗਲਤ ਪਿੰਨ ਕੋਡ।"</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"ਅਵੈਧ ਕਾਰਡ।"</string>
<string name="keyguard_charged" msgid="2222329688813033109">"ਚਾਰਜ ਹੋ ਗਿਆ"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"ਤੇਜ਼ੀ ਨਾਲ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index 60c6f49689ca..362ffcf70852 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Digite a senha para desbloquear"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Insira o PIN para desbloquear"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Código PIN incorreto."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Cartão inválido."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Carregada"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Carregando"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Carregando rapidamente"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index 60c6f49689ca..362ffcf70852 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Digite a senha para desbloquear"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Insira o PIN para desbloquear"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Código PIN incorreto."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Cartão inválido."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Carregada"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Carregando"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Carregando rapidamente"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index 743bbc11a93d..d0dc17e567a6 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Introduceți parola pentru a debloca"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Introduceți codul PIN pentru a debloca"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Cod PIN incorect."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Card nevalid"</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Încărcată"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Se încarcă"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Se încarcă rapid"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index 7ee090217523..ff75819b04cd 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"Andika nenosiri ili ufungue"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"Andika PIN ili ufungue"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"Nambari ya PIN si sahihi."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"Kadi si Sahihi."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"Betri imejaa"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"Inachaji"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"Inachaji kwa kasi"</string>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index bbcc57ec4451..73f709462af4 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"అన్‌లాక్ చేయడానికి పాస్‌వర్డ్‌ను టైప్ చేయండి"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"అన్‌లాక్ చేయడానికి పిన్ టైప్ చేయండి"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"పిన్ కోడ్ తప్పు."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"చెల్లని కార్డ్."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"ఛార్జ్ చేయబడింది"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"ఛార్జ్ అవుతోంది"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"వేగంగా ఛార్జ్ అవుతోంది"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index 4f09c98f0399..3bb59f01aa61 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"غیر مقفل کرنے کیلئے پاس ورڈ ٹائپ کریں"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"‏غیر مقفل کرنے کیلئے PIN ٹائپ کریں"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"‏غلط PIN کوڈ۔"</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"غلط کارڈ۔"</string>
<string name="keyguard_charged" msgid="2222329688813033109">"چارج ہوگئی"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"چارج ہو رہا ہے"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"تیزی سے چارج ہو رہا ہے"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index 30737ccb5380..d523c20cc5ac 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -29,8 +29,7 @@
<string name="keyguard_password_enter_password_code" msgid="595980919238127672">"输入密码即可解锁"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"输入 PIN 码即可解锁"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"PIN 码有误。"</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"SIM 卡无效。"</string>
<string name="keyguard_charged" msgid="2222329688813033109">"已充满电"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"正在充电"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"正在快速充电"</string>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 4487abc318dc..fac254a0083a 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -13,65 +13,36 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<RelativeLayout
+<com.android.systemui.HardwareUiLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/volume_dialog"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/volume_dialog_margin_bottom"
- android:background="@drawable/volume_dialog_background"
- android:paddingTop="@dimen/volume_dialog_padding_top"
+ android:layout_height="match_parent"
android:theme="@style/qs_theme"
- android:translationZ="4dp" >
-
- <LinearLayout
- android:id="@+id/volume_dialog_content"
- android:layout_width="match_parent"
+ android:clipChildren="false" >
+ <RelativeLayout
+ android:id="@+id/volume_dialog"
+ android:layout_width="@dimen/volume_dialog_panel_width"
android:layout_height="wrap_content"
- android:orientation="vertical" >
+ 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" >
<LinearLayout
- android:id="@+id/volume_dialog_rows"
+ android:id="@+id/volume_dialog_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingEnd="@dimen/volume_button_size"
android:orientation="vertical" >
- <!-- volume rows added and removed here! :-) -->
- </LinearLayout>
-
- <include layout="@layout/volume_zen_footer" />
-
- <!-- Only shown from Tuner setting -->
- <include layout="@layout/tuner_zen_mode_panel" />
- </LinearLayout>
- <LinearLayout
- android:id="@+id/volume_dialog_content"
- 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_collapse_animation"
- android:background="@drawable/ripple_drawable"
- tools:ignore="RtlHardcoded"
- />
+ <LinearLayout
+ android:id="@+id/volume_dialog_rows"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <!-- volume rows added and removed here! :-) -->
+ </LinearLayout>
+ </LinearLayout>
- </LinearLayout>
-</RelativeLayout>
+ </RelativeLayout>
+</com.android.systemui.HardwareUiLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index 7328d0597633..bf76e78c94a2 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -19,8 +19,8 @@
android:layout_height="@dimen/volume_row_height"
android:clipChildren="false"
android:clipToPadding="false"
- android:orientation="vertical"
- android:paddingBottom="@dimen/volume_row_padding_bottom" >
+ android:theme="@style/qs_theme"
+ android:orientation="vertical" >
<TextView
android:id="@+id/volume_row_header"
@@ -28,7 +28,8 @@
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
- android:textAppearance="@style/TextAppearance.Volume.Header"
+ android:textColor="?android:attr/colorControlNormal"
+ android:textAppearance="?android:attr/textAppearanceSmall"
android:paddingStart="@dimen/volume_row_header_padding_start" />
<LinearLayout
@@ -53,4 +54,9 @@
android:paddingStart="@dimen/volume_row_slider_padding_start"/>
</LinearLayout>
+ <Space
+ android:id="@+id/spacer"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/volume_row_padding_bottom"/>
+
</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_zen_footer.xml b/packages/SystemUI/res/layout/volume_zen_footer.xml
deleted file mode 100644
index df79c5ff5ba4..000000000000
--- a/packages/SystemUI/res/layout/volume_zen_footer.xml
+++ /dev/null
@@ -1,127 +0,0 @@
-<!--
- 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.
--->
-<com.android.systemui.volume.ZenFooter xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/volume_zen_footer"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingBottom="8dp" > <!-- extends LinearLayout -->
-
- <View
- android:id="@+id/zen_embedded_divider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_marginTop="8dp"
- android:background="@color/qs_tile_divider" />
-
- <RelativeLayout
- android:id="@+id/zen_introduction"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="16dp"
- android:layout_marginEnd="16dp"
- android:paddingBottom="8dp"
- android:background="@drawable/zen_introduction_message_background"
- android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent.Light">
-
- <ImageView
- android:id="@+id/zen_introduction_confirm"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_marginEnd="8dp"
- android:layout_alignParentEnd="true"
- android:background="@drawable/btn_borderless_rect"
- android:clickable="true"
- android:contentDescription="@string/accessibility_desc_close"
- android:scaleType="center"
- android:src="@drawable/ic_close_white_rounded" />
-
- <TextView
- android:id="@+id/zen_introduction_message"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dp"
- android:layout_marginStart="24dp"
- android:textDirection="locale"
- android:lineSpacingMultiplier="1.20029"
- android:layout_toStartOf="@id/zen_introduction_confirm"
- android:text="@string/zen_alarms_introduction"
- android:textAppearance="@style/TextAppearance.QS.Introduction" />
-
- <View
- android:layout_width="0dp"
- android:layout_height="16dp"
- android:layout_below="@id/zen_introduction_message"
- android:layout_alignParentEnd="true" />
-
- </RelativeLayout>
-
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:orientation="horizontal" >
-
- <ImageView
- android:id="@+id/volume_zen_icon"
- android:layout_width="@dimen/volume_button_size"
- android:layout_height="@dimen/volume_button_size"
- android:layout_marginEnd="7dp"
- android:scaleType="center" />
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:orientation="vertical" >
-
- <TextView
- android:id="@+id/volume_zen_summary_line_1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textDirection="locale"
- android:textAppearance="@style/TextAppearance.Volume.ZenSummary" />
-
- <TextView
- android:id="@+id/volume_zen_summary_line_2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="1dp"
- android:textDirection="locale"
- android:textAppearance="@style/TextAppearance.Volume.ZenDetail" />
-
- </LinearLayout>
-
- </LinearLayout>
-
- <TextView
- android:id="@+id/volume_zen_end_now"
- style="@style/QSBorderlessButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end"
- android:layout_marginEnd="8dp"
- android:clickable="true"
- android:focusable="true"
- android:paddingStart="15dp"
- android:paddingEnd="15dp"
- android:text="@string/volume_zen_end_now"
- android:textColor="?android:attr/colorAccent"
- android:textAppearance="@style/TextAppearance.QS.DetailButton" />
-
-</com.android.systemui.volume.ZenFooter>
diff --git a/packages/SystemUI/res/values-be/config.xml b/packages/SystemUI/res/values-be/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-be/config.xml
+++ b/packages/SystemUI/res/values-be/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-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 6de7852a69e0..e2ee4ea5ac50 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -53,15 +53,21 @@
<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> атрымлiваць доступ да прылады 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>
+ <!-- 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_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>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-bn/config.xml b/packages/SystemUI/res/values-bn/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-bn/config.xml
+++ b/packages/SystemUI/res/values-bn/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-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index ab1b0a17e40a..58bddb0ad296 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -51,15 +51,21 @@
<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>
+ <!-- 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_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>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-ca/config.xml b/packages/SystemUI/res/values-ca/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-ca/config.xml
+++ b/packages/SystemUI/res/values-ca/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-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 28b0ffe6b789..6db3e3843ac7 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -51,15 +51,21 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Xarxa compartida per Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configura els mètodes d\'entrada"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teclat físic"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Vols permetre que l\'aplicació <xliff:g id="APPLICATION">%1$s</xliff:g> accedeixi al dispositiu USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vols permetre que l\'aplicació <xliff:g id="APPLICATION">%1$s</xliff:g> accedeixi a l\'accessori USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vols que s\'obri <xliff:g id="ACTIVITY">%1$s</xliff:g> quan aquest dispositiu USB estigui connectat?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Vols que s\'obri <xliff:g id="ACTIVITY">%1$s</xliff:g> quan aquest accessori USB estigui connectat?"</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_accessory_uri_prompt" msgid="513450621413733343">"Les aplicacions instal·lades no funcionen amb l\'accessori USB. Més informació: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Accessori USB"</string>
<string name="label_view" msgid="6304565553218192990">"Mostra"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Utilitza de manera predet. per al dispositiu USB"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Utilitza de manera predet. per a l\'accessori USB"</string>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<string name="usb_debugging_title" msgid="4513918393387141949">"Vols permetre la depuració USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"L\'empremta digital de la clau de l\'RSA de l\'equip és:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Dona sempre permís des d\'aquest equip"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/config.xml b/packages/SystemUI/res/values-en-rAU/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-en-rAU/config.xml
+++ b/packages/SystemUI/res/values-en-rAU/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-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index fe17a2d8bc0c..76b21b5cee0e 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tethered"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Set up input methods"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Physical keyboard"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Allow the app <xliff:g id="APPLICATION">%1$s</xliff:g> to access the USB device?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Allow the app <xliff:g id="APPLICATION">%1$s</xliff:g> to access the USB accessory?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Open <xliff:g id="ACTIVITY">%1$s</xliff:g> when this USB device is connected?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Open <xliff:g id="ACTIVITY">%1$s</xliff:g> when this USB accessory is connected?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Open <xliff:g id="APPLICATION">%1$s</xliff:g> to handle <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Open <xliff:g id="APPLICATION">%1$s</xliff:g> to handle <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"No installed apps work with this USB accessory. Learn more about this accessory at <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">"View"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Use by default for this USB device"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Use by default for this USB accessory"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Always open <xliff:g id="APPLICATION">%1$s</xliff:g> when <xliff:g id="USB_DEVICE">%2$s</xliff:g> is connected"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Always open <xliff:g id="APPLICATION">%1$s</xliff:g> when <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> is connected"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Allow USB debugging?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"The computer\'s RSA key fingerprint is:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Always allow from this computer"</string>
@@ -180,7 +180,6 @@
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"All recent applications dismissed."</string>
<string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Open <xliff:g id="APP">%s</xliff:g> application info."</string>
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starting <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">"Notification dismissed."</string>
<string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Notification shade."</string>
<string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Quick settings."</string>
@@ -343,8 +342,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">"Charged"</string>
<string name="expanded_header_battery_charging" msgid="205623198487189724">"Charging"</string>
<string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> until full"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/config.xml b/packages/SystemUI/res/values-en-rCA/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-en-rCA/config.xml
+++ b/packages/SystemUI/res/values-en-rCA/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-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 1ff0ee402a27..1bc1197a06e0 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tethered"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Set up input methods"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Physical keyboard"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Allow the app <xliff:g id="APPLICATION">%1$s</xliff:g> to access the USB device?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Allow the app <xliff:g id="APPLICATION">%1$s</xliff:g> to access the USB accessory?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Open <xliff:g id="ACTIVITY">%1$s</xliff:g> when this USB device is connected?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Open <xliff:g id="ACTIVITY">%1$s</xliff:g> when this USB accessory is connected?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Open <xliff:g id="APPLICATION">%1$s</xliff:g> to handle <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Open <xliff:g id="APPLICATION">%1$s</xliff:g> to handle <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"No installed apps work with this USB accessory. Learn more about this accessory at <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">"View"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Use by default for this USB device"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Use by default for this USB accessory"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Always open <xliff:g id="APPLICATION">%1$s</xliff:g> when <xliff:g id="USB_DEVICE">%2$s</xliff:g> is connected"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Always open <xliff:g id="APPLICATION">%1$s</xliff:g> when <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> is connected"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Allow USB debugging?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"The computer\'s RSA key fingerprint is:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Always allow from this computer"</string>
@@ -180,7 +180,6 @@
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"All recent applications dismissed."</string>
<string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Open <xliff:g id="APP">%s</xliff:g> application info."</string>
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starting <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">"Notification dismissed."</string>
<string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Notification shade."</string>
<string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Quick settings."</string>
@@ -343,8 +342,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">"Charged"</string>
<string name="expanded_header_battery_charging" msgid="205623198487189724">"Charging"</string>
<string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> until full"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/config.xml b/packages/SystemUI/res/values-en-rGB/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-en-rGB/config.xml
+++ b/packages/SystemUI/res/values-en-rGB/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-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index fe17a2d8bc0c..76b21b5cee0e 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tethered"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Set up input methods"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Physical keyboard"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Allow the app <xliff:g id="APPLICATION">%1$s</xliff:g> to access the USB device?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Allow the app <xliff:g id="APPLICATION">%1$s</xliff:g> to access the USB accessory?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Open <xliff:g id="ACTIVITY">%1$s</xliff:g> when this USB device is connected?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Open <xliff:g id="ACTIVITY">%1$s</xliff:g> when this USB accessory is connected?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Open <xliff:g id="APPLICATION">%1$s</xliff:g> to handle <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Open <xliff:g id="APPLICATION">%1$s</xliff:g> to handle <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"No installed apps work with this USB accessory. Learn more about this accessory at <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">"View"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Use by default for this USB device"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Use by default for this USB accessory"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Always open <xliff:g id="APPLICATION">%1$s</xliff:g> when <xliff:g id="USB_DEVICE">%2$s</xliff:g> is connected"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Always open <xliff:g id="APPLICATION">%1$s</xliff:g> when <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> is connected"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Allow USB debugging?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"The computer\'s RSA key fingerprint is:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Always allow from this computer"</string>
@@ -180,7 +180,6 @@
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"All recent applications dismissed."</string>
<string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Open <xliff:g id="APP">%s</xliff:g> application info."</string>
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starting <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">"Notification dismissed."</string>
<string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Notification shade."</string>
<string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Quick settings."</string>
@@ -343,8 +342,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">"Charged"</string>
<string name="expanded_header_battery_charging" msgid="205623198487189724">"Charging"</string>
<string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> until full"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/config.xml b/packages/SystemUI/res/values-en-rIN/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-en-rIN/config.xml
+++ b/packages/SystemUI/res/values-en-rIN/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-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index fe17a2d8bc0c..76b21b5cee0e 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tethered"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Set up input methods"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Physical keyboard"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Allow the app <xliff:g id="APPLICATION">%1$s</xliff:g> to access the USB device?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Allow the app <xliff:g id="APPLICATION">%1$s</xliff:g> to access the USB accessory?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Open <xliff:g id="ACTIVITY">%1$s</xliff:g> when this USB device is connected?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Open <xliff:g id="ACTIVITY">%1$s</xliff:g> when this USB accessory is connected?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Allow <xliff:g id="APPLICATION">%1$s</xliff:g> to access <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Open <xliff:g id="APPLICATION">%1$s</xliff:g> to handle <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Open <xliff:g id="APPLICATION">%1$s</xliff:g> to handle <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"No installed apps work with this USB accessory. Learn more about this accessory at <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">"View"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Use by default for this USB device"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Use by default for this USB accessory"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Always open <xliff:g id="APPLICATION">%1$s</xliff:g> when <xliff:g id="USB_DEVICE">%2$s</xliff:g> is connected"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Always open <xliff:g id="APPLICATION">%1$s</xliff:g> when <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> is connected"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Allow USB debugging?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"The computer\'s RSA key fingerprint is:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Always allow from this computer"</string>
@@ -180,7 +180,6 @@
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"All recent applications dismissed."</string>
<string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"Open <xliff:g id="APP">%s</xliff:g> application info."</string>
<string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Starting <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">"Notification dismissed."</string>
<string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Notification shade."</string>
<string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Quick settings."</string>
@@ -343,8 +342,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">"Charged"</string>
<string name="expanded_header_battery_charging" msgid="205623198487189724">"Charging"</string>
<string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> until full"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/config.xml b/packages/SystemUI/res/values-en-rXC/config.xml
index 5309563e3986..f015d9b378d4 100644
--- a/packages/SystemUI/res/values-en-rXC/config.xml
+++ b/packages/SystemUI/res/values-en-rXC/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-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index e1326de67a03..131e1993a745 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‎‏‎‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎Bluetooth tethered‎‏‎‎‏‎"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‎‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎Set up input methods‎‏‎‎‏‎"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‎‏‏‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‏‎‏‎‎‏‎‎Physical keyboard‎‏‎‎‏‎"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‎‎‏‎‏‎‏‎‏‏‏‎‎‎‏‎‏‏‎‏‎‎‎‏‏‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎‎‎‏‏‏‏‏‎‏‎‎‏‎‎‏‎Allow the app ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to access the USB device?‎‏‎‎‏‎"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‎‏‎‏‏‎‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‎‏‎‏‎‏‏‎‎Allow the app ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to access the USB accessory?‎‏‎‎‏‎"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‎‏‏‎‎‏‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‏‎‏‎‏‏‎‎Open ‎‏‎‎‏‏‎<xliff:g id="ACTIVITY">%1$s</xliff:g>‎‏‎‎‏‏‏‎ when this USB device is connected?‎‏‎‎‏‎"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‎‎‎‏‏‏‎‎‏‏‎‏‎‏‏‏‎‎‎‎‎‎‎‎Open ‎‏‎‎‏‏‎<xliff:g id="ACTIVITY">%1$s</xliff:g>‎‏‎‎‏‏‏‎ when this USB accessory is connected?‎‏‎‎‏‎"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‏‎‏‏‎‎‎‏‎‎‎‏‏‏‎‏‎‏‎‎‏‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‎‎‎‎‎‏‎‎‏‏‏‏‏‏‏‏‎Allow ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to access ‎‏‎‎‏‏‎<xliff:g id="USB_DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‏‎‏‎‏‎‏‎‎‎‎‎‎‎‎‏‏‎‏‏‎‏‎‏‏‏‎Allow ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to access ‎‏‎‎‏‏‎<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‏‎‎‏‎‎‎‎‎‎‏‎Open ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to handle ‎‏‎‎‏‏‎<xliff:g id="USB_DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‎‎‏‎‎‎‏‎‎‏‎‏‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‎Open ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to handle ‎‏‎‎‏‏‎<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‏‎‎‏‎‎‏‎‎‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‏‎‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎No installed apps work with this USB accessory. Learn more about this accessory at ‎‏‎‎‏‏‎<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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‎‏‎‏‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‎‏‏‏‏‎‎View‎‏‎‎‏‎"</string>
- <string name="always_use_device" msgid="1450287437017315906">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‏‎‏‏‏‏‎‏‎‏‏‏‎‎‎‏‏‎‏‎‎‎‎‎‏‏‏‏‏‎‏‎‎‏‎‎‎‎‏‎‎Use by default for this USB device‎‏‎‎‏‎"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‏‏‎‎‎‏‎‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‏‏‎‎‎‎‎‎‎‎‎‎‎‏‏‏‏‎‏‏‎‏‏‎‏‏‏‎‎‎Use by default for this USB accessory‎‏‎‎‏‎"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‏‎‎‎‏‎Always open ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎ when ‎‏‎‎‏‏‎<xliff:g id="USB_DEVICE">%2$s</xliff:g>‎‏‎‎‏‏‏‎ is connected‎‏‎‎‏‎"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‏‎‏‏‏‎‎‏‏‎‎‏‏‎‏‏‏‎‎‏‎‎Always open ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎ when ‎‏‎‎‏‏‎<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>‎‏‎‎‏‏‏‎ is connected‎‏‎‎‏‎"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‏‎‏‏‏‎‎‏‏‏‎‏‏‏‎‏‏‏‏‎‎‎‏‎‏‎‎‏‎‏‏‎‎‏‏‏‏‎‏‎Allow USB debugging?‎‏‎‎‏‎"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‏‎‎‏‎‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‏‎‎‎‎‎The computer\'s RSA key fingerprint is:‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="FINGERPRINT">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‎‎‏‏‎‏‎‏‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‏‎‏‏‎‏‏‎‏‏‎‏‏‎‎‏‏‏‏‎‎Always allow from this computer‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-fi/config.xml b/packages/SystemUI/res/values-fi/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-fi/config.xml
+++ b/packages/SystemUI/res/values-fi/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-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 7b6dc5455a83..65d80a946ebe 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -51,15 +51,21 @@
<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>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Annetaanko sovellukselle <xliff:g id="APPLICATION">%1$s</xliff:g> lupa käyttää USB-laitetta?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Annetaanko sovellukselle <xliff:g id="APPLICATION">%1$s</xliff:g> lupa käyttää USB-lisälaitetta?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Avataanko <xliff:g id="ACTIVITY">%1$s</xliff:g> tämän USB-laitteen ollessa kytkettynä?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Avataanko <xliff:g id="ACTIVITY">%1$s</xliff:g> tämän USB-lisälaitteen ollessa kytkettynä?"</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_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>
- <string name="always_use_device" msgid="1450287437017315906">"Käytä oletuksena tällä USB-laitteella"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Käytä oletuksena tällä USB-lisälaitteella"</string>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
@@ -71,7 +77,7 @@
<string name="screenshot_saving_title" msgid="8242282144535555697">"Tallennetaan kuvakaappausta..."</string>
<string name="screenshot_saving_text" msgid="2419718443411738818">"Kuvakaappausta tallennetaan."</string>
<string name="screenshot_saved_title" msgid="6461865960961414961">"Kuvakaappaus tallennettu"</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Tarkastele kuvakaappausta napauttamalla."</string>
+ <string name="screenshot_saved_text" msgid="2685605830386712477">"Tarkastele kuvakaappausta napauttamalla"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Kuvakaappausta ei voitu tallentaa"</string>
<string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Kuvakaappausta tallennettaessa tapahtui virhe."</string>
<string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Kuvakaappauksen tallentaminen epäonnistui, sillä tallennustilaa ei ole riittävästi."</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/config.xml b/packages/SystemUI/res/values-fr-rCA/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-fr-rCA/config.xml
+++ b/packages/SystemUI/res/values-fr-rCA/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-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 2344c00954d3..989f6d1ee7f7 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -51,15 +51,21 @@
<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>
+ <!-- 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_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>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
@@ -71,7 +77,7 @@
<string name="screenshot_saving_title" msgid="8242282144535555697">"Enregistrement capture écran…"</string>
<string name="screenshot_saving_text" msgid="2419718443411738818">"Enregistrement de la capture d\'écran en cours…"</string>
<string name="screenshot_saved_title" msgid="6461865960961414961">"Capture d\'écran réussie"</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"Touchez pour afficher votre saisie d\'écran."</string>
+ <string name="screenshot_saved_text" msgid="2685605830386712477">"Touchez pour afficher votre capture d\'écran."</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"Impossible de réaliser une capture d\'écran"</string>
<string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Une erreur s\'est produite lors de l\'enregistrement de la saisie d\'écran."</string>
<string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Impossible d\'enregistrer la saisie d\'écran, car l\'espace de stockage est limité."</string>
diff --git a/packages/SystemUI/res/values-gl/config.xml b/packages/SystemUI/res/values-gl/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-gl/config.xml
+++ b/packages/SystemUI/res/values-gl/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-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 7f11ba26ddf9..94c525aa6a06 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -51,15 +51,21 @@
<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>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Queres permitir que a aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> acceda ao dispositivo USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Queres permitir que a aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> acceda ao accesorio USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Queres abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> cando este dispositivo USB estea conectado?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Queres abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> cando este accesorio USB estea conectado?"</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_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>
- <string name="always_use_device" msgid="1450287437017315906">"Usar de forma predeterminada para dispositivo USB"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Usar de forma predeterminada para este accesorio USB"</string>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-gu/config.xml b/packages/SystemUI/res/values-gu/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-gu/config.xml
+++ b/packages/SystemUI/res/values-gu/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-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 2dbd57bde27c..b13011aff597 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -51,15 +51,21 @@
<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>
+ <!-- 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_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>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-hi/config.xml b/packages/SystemUI/res/values-hi/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-hi/config.xml
+++ b/packages/SystemUI/res/values-hi/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-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 93dadd2d29e4..ef66a35a9a9b 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -51,15 +51,21 @@
<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>
+ <!-- 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_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>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-in/config.xml b/packages/SystemUI/res/values-in/config.xml
index 5309563e3986..9857f13948d6 100644
--- a/packages/SystemUI/res/values-in/config.xml
+++ b/packages/SystemUI/res/values-in/config.xml
@@ -22,5 +22,7 @@
<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="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 27d5f1b89868..255ba2c7a1b7 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -358,12 +358,12 @@
<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">"Notifikasi kurang darurat di bawah"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Tap lagi untuk membuka"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Gesek ke atas untuk membuka kunci"</string>
+ <string name="keyguard_unlock" msgid="8043466894212841998">"Geser ke atas untuk membuka kunci"</string>
<string name="do_disclosure_generic" msgid="5615898451805157556">"Perangkat ini dikelola oleh organisasi"</string>
<string name="do_disclosure_with_name" msgid="5640615509915445501">"Perangkat ini dikelola oleh <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <string name="phone_hint" msgid="4872890986869209950">"Gesek dari ikon untuk telepon"</string>
- <string name="voice_hint" msgid="8939888732119726665">"Gesek dari ikon untuk mengaktifkan bantuan suara"</string>
- <string name="camera_hint" msgid="7939688436797157483">"Gesek dari ikon untuk kamera"</string>
+ <string name="phone_hint" msgid="4872890986869209950">"Geser dari ikon untuk telepon"</string>
+ <string name="voice_hint" msgid="8939888732119726665">"Geser dari ikon untuk bantuan suara"</string>
+ <string name="camera_hint" msgid="7939688436797157483">"Geser dari ikon untuk kamera"</string>
<string name="interruption_level_none_with_warning" msgid="5114872171614161084">"Senyap total. Tindakan ini juga akan mensenyapkan pembaca layar."</string>
<string name="interruption_level_none" msgid="6000083681244492992">"Senyap total"</string>
<string name="interruption_level_priority" msgid="6426766465363855505">"Hanya untuk prioritas"</string>
@@ -499,7 +499,7 @@
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Ketuk untuk membisukan. Layanan aksesibilitas mungkin dibisukan."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s. Tap untuk menyetel agar bergetar."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tap untuk menonaktifkan."</string>
- <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Kontrol volume %s ditampilkan. Gesek ke atas untuk menutup."</string>
+ <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Kontrol volume %s ditampilkan. Geser ke atas untuk menutup."</string>
<string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Kontrol volume disembunyikan"</string>
<string name="system_ui_tuner" msgid="708224127392452018">"Penyetel Antarmuka Pengguna Sistem"</string>
<string name="show_battery_percentage" msgid="5444136600512968798">"Tampilkan persentase baterai yang tersemat"</string>
diff --git a/packages/SystemUI/res/values-iw/config.xml b/packages/SystemUI/res/values-iw/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-iw/config.xml
+++ b/packages/SystemUI/res/values-iw/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-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index eb850992ea20..dcef8c674251 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -53,15 +53,21 @@
<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>
+ <!-- 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_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>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-kn/config.xml b/packages/SystemUI/res/values-kn/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-kn/config.xml
+++ b/packages/SystemUI/res/values-kn/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-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index ca1a650aa982..7ba785b64dcf 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -51,15 +51,21 @@
<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>
+ <!-- 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_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>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-ml/config.xml b/packages/SystemUI/res/values-ml/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-ml/config.xml
+++ b/packages/SystemUI/res/values-ml/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-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 855ae6ad466a..5522e512db80 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -51,15 +51,21 @@
<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>
+ <!-- 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_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>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-mr/config.xml b/packages/SystemUI/res/values-mr/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-mr/config.xml
+++ b/packages/SystemUI/res/values-mr/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-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index b5975b12d712..b03d6bf5b6ce 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -51,15 +51,21 @@
<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">"अ‍ॅप <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>
+ <!-- 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_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>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
@@ -137,7 +143,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"चालू."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"बंद."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"कनेक्‍ट केले."</string>
- <string name="accessibility_desc_connecting" msgid="3812924520316280149">"कनेक्ट करीत आहे."</string>
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"कनेक्ट करत आहे."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -168,7 +174,7 @@
<string name="accessibility_overflow_action" msgid="5681882033274783311">"सर्व सूचना पहा"</string>
<string name="accessibility_remove_notification" msgid="3603099514902182350">"सूचना साफ करा."</string>
<string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS सक्षम केले."</string>
- <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS प्राप्त करीत आहे."</string>
+ <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS प्राप्त करत आहे."</string>
<string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter सक्षम केले."</string>
<string name="accessibility_ringer_vibrate" msgid="666585363364155055">"रिंगर कंपन."</string>
<string name="accessibility_ringer_silent" msgid="9061243307939135383">"रिंगर मूक."</string>
@@ -179,7 +185,7 @@
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> डिसमिस केला."</string>
<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_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%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>
@@ -310,7 +316,7 @@
<string name="quick_settings_done" msgid="3402999958839153376">"पूर्ण झाले"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"कनेक्ट केलेले"</string>
<string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"कनेक्ट केलेले आहे, बॅटरी <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="quick_settings_connecting" msgid="47623027419264404">"कनेक्ट करीत आहे..."</string>
+ <string name="quick_settings_connecting" msgid="47623027419264404">"कनेक्ट करत आहे..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"टेदरिंग"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"हॉटस्पॉट"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"सूचना"</string>
diff --git a/packages/SystemUI/res/values-ne/config.xml b/packages/SystemUI/res/values-ne/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-ne/config.xml
+++ b/packages/SystemUI/res/values-ne/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-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index b2bf111c1bfc..e994174f2cba 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -51,15 +51,21 @@
<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>
+ <!-- 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_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>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-nl/config.xml b/packages/SystemUI/res/values-nl/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-nl/config.xml
+++ b/packages/SystemUI/res/values-nl/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-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 815e5f9f7b6b..640b5d03161b 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth getetherd"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Invoermethoden instellen"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fysiek toetsenbord"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> toegang geven tot het USB-apparaat?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> toegang geven tot het USB-accessoire?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"<xliff:g id="ACTIVITY">%1$s</xliff:g> openen wanneer dit USB-apparaat wordt aangesloten?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"<xliff:g id="ACTIVITY">%1$s</xliff:g> openen wanneer dit USB-accessoire wordt aangesloten?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"<xliff:g id="APPLICATION">%1$s</xliff:g> toegang geven tot <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> toegang geven tot <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> openen om <xliff:g id="USB_DEVICE">%2$s</xliff:g> te verwerken?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="APPLICATION">%1$s</xliff:g> openen om <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> te verwerken?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Er werken geen geïnstalleerde apps met dit USB-accessoire. Meer informatie op: <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"USB-accessoire"</string>
<string name="label_view" msgid="6304565553218192990">"Weergeven"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Standaard gebruiken voor dit USB-apparaat"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Standaard gebruiken voor dit USB-accessoire"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"<xliff:g id="APPLICATION">%1$s</xliff:g> altijd openen wanneer <xliff:g id="USB_DEVICE">%2$s</xliff:g> is verbonden"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"<xliff:g id="APPLICATION">%1$s</xliff:g> altijd openen wanneer <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> is verbonden"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"USB-foutopsporing toestaan?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"De vingerafdruk voor de RSA-sleutel van de computer is:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Altijd toestaan vanaf deze computer"</string>
diff --git a/packages/SystemUI/res/values-pa/config.xml b/packages/SystemUI/res/values-pa/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-pa/config.xml
+++ b/packages/SystemUI/res/values-pa/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-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index cec5c9677b42..48be37109959 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -51,15 +51,21 @@
<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>
+ <!-- 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_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>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-pt-rBR/config.xml b/packages/SystemUI/res/values-pt-rBR/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-pt-rBR/config.xml
+++ b/packages/SystemUI/res/values-pt-rBR/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-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 4b72c2920dcf..ce457be5396e 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth vinculado"</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 o app <xliff:g id="APPLICATION">%1$s</xliff:g> acesse o dispositivo USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Permitir que o app <xliff:g id="APPLICATION">%1$s</xliff:g> acesse o 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 conectado?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> quando este acessório USB estiver conectado?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Permitir que o app <xliff:g id="APPLICATION">%1$s</xliff:g> acesse <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Permitir que o app <xliff:g id="APPLICATION">%1$s</xliff:g> acesse <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Abrir o app <xliff:g id="APPLICATION">%1$s</xliff:g> para lidar com o <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Abrir o app <xliff:g id="APPLICATION">%1$s</xliff:g> para lidar com o <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Nenhum apl. instalado funciona com o USB. Saiba mais sobre o 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">"Visualizar"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Usar por padrão para este dispositivo USB"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Usar por padrão para este acessório USB"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Sempre abrir o app <xliff:g id="APPLICATION">%1$s</xliff:g> quando <xliff:g id="USB_DEVICE">%2$s</xliff:g> for conectado"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Sempre abrir o app <xliff:g id="APPLICATION">%1$s</xliff:g> quando <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> for conectado"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Permitir a depuração USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"A impressão digital da chave RSA deste computador é:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Sempre permitir a partir deste computador"</string>
diff --git a/packages/SystemUI/res/values-pt/config.xml b/packages/SystemUI/res/values-pt/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-pt/config.xml
+++ b/packages/SystemUI/res/values-pt/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/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 4b72c2920dcf..ce457be5396e 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -51,15 +51,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth vinculado"</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 o app <xliff:g id="APPLICATION">%1$s</xliff:g> acesse o dispositivo USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Permitir que o app <xliff:g id="APPLICATION">%1$s</xliff:g> acesse o 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 conectado?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> quando este acessório USB estiver conectado?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Permitir que o app <xliff:g id="APPLICATION">%1$s</xliff:g> acesse <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Permitir que o app <xliff:g id="APPLICATION">%1$s</xliff:g> acesse <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Abrir o app <xliff:g id="APPLICATION">%1$s</xliff:g> para lidar com o <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Abrir o app <xliff:g id="APPLICATION">%1$s</xliff:g> para lidar com o <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Nenhum apl. instalado funciona com o USB. Saiba mais sobre o 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">"Visualizar"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Usar por padrão para este dispositivo USB"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Usar por padrão para este acessório USB"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Sempre abrir o app <xliff:g id="APPLICATION">%1$s</xliff:g> quando <xliff:g id="USB_DEVICE">%2$s</xliff:g> for conectado"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Sempre abrir o app <xliff:g id="APPLICATION">%1$s</xliff:g> quando <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> for conectado"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Permitir a depuração USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"A impressão digital da chave RSA deste computador é:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Sempre permitir a partir deste computador"</string>
diff --git a/packages/SystemUI/res/values-ro/config.xml b/packages/SystemUI/res/values-ro/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-ro/config.xml
+++ b/packages/SystemUI/res/values-ro/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-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 48005783ad43..c7822e0d1a26 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -52,15 +52,15 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Conectat prin tethering prin Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Setați metode introducere text"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Tastatură fizică"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Permiteți aplicației <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze dispozitivul USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Permiteți aplicației <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze accesoriul USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Deschideți <xliff:g id="ACTIVITY">%1$s</xliff:g> la conectarea acestui dispozitiv USB?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Deschideți <xliff:g id="ACTIVITY">%1$s</xliff:g> la conectarea acestui accesoriu USB?"</string>
+ <string name="usb_device_permission_prompt" msgid="1825685909587559679">"Permiteți <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Permiteți <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
+ <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Deschideți <xliff:g id="APPLICATION">%1$s</xliff:g> ca să gestioneze <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Deschideți <xliff:g id="APPLICATION">%1$s</xliff:g> ca să gestioneze <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
<string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Aplic. instal. nu funcț. cu acest acces. USB. Aflați despre acest accesoriu la <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Accesoriu USB"</string>
<string name="label_view" msgid="6304565553218192990">"Afișați"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Utilizați în mod prestabilit pt. acest dispoz. USB"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Utiliz. în mod prestabilit pt. acest accesoriu USB"</string>
+ <string name="always_use_device" msgid="4015357883336738417">"Deschideți întotdeauna <xliff:g id="APPLICATION">%1$s</xliff:g> când este conectat <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
+ <string name="always_use_accessory" msgid="3257892669444535154">"Deschideți întotdeauna <xliff:g id="APPLICATION">%1$s</xliff:g> când este conectat <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
<string name="usb_debugging_title" msgid="4513918393387141949">"Permiteți remedierea erorilor prin USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Amprenta digitală din cheia RSA a computerului este:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Permiteți întotdeauna de pe acest computer"</string>
diff --git a/packages/SystemUI/res/values-sw/config.xml b/packages/SystemUI/res/values-sw/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-sw/config.xml
+++ b/packages/SystemUI/res/values-sw/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-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 524faea9cf28..d1bbe50585aa 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -51,15 +51,21 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth imefungwa"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Weka mbinu za ingizo"</string>
<string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Kibodi halisi"</string>
- <string name="usb_device_permission_prompt" msgid="834698001271562057">"Ruhusu programu <xliff:g id="APPLICATION">%1$s</xliff:g> kufikia kifaa cha USB?"</string>
- <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Ruhusu programu <xliff:g id="APPLICATION">%1$s</xliff:g> kufikia kifaa cha ziada cha USB?"</string>
- <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Je, ungetaka kufungua <xliff:g id="ACTIVITY">%1$s</xliff:g>wakati kifaa cha USB kimeunganishwa?"</string>
- <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Je, ungetaka kufungua <xliff:g id="ACTIVITY">%1$s</xliff:g>wakati kifaa cha USB kimeunganishwa?"</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_accessory_uri_prompt" msgid="513450621413733343">"Hakuna programu zilizosakinishwa zinazofanya kazi na kifaa hiki cha USB. Pata maelezo zaidi kuhusu kifaa hiki kwenye <xliff:g id="URL">%1$s</xliff:g>"</string>
<string name="title_usb_accessory" msgid="4966265263465181372">"Kifaa cha Usb"</string>
<string name="label_view" msgid="6304565553218192990">"Ona"</string>
- <string name="always_use_device" msgid="1450287437017315906">"Kwa kifaa hiki cha USB tumia chaguo-msingi"</string>
- <string name="always_use_accessory" msgid="1210954576979621596">"Tumia kama chaguo-msingi ya kifuasi hiki cha USB"</string>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<string name="usb_debugging_title" msgid="4513918393387141949">"Ruhusu utatuaji wa USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"Alama ya kidole ya kitufe cha RSA ya kompyuta ni:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Ruhusu kutoka kwenye kompyuta hii kila wakati"</string>
diff --git a/packages/SystemUI/res/values-ta/config.xml b/packages/SystemUI/res/values-ta/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-ta/config.xml
+++ b/packages/SystemUI/res/values-ta/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-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index ada5d4bbb8d3..02d66136d65f 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -51,15 +51,21 @@
<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>
+ <!-- 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_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>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-te/config.xml b/packages/SystemUI/res/values-te/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-te/config.xml
+++ b/packages/SystemUI/res/values-te/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-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index f23e169aaba3..0652de95a267 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -51,15 +51,21 @@
<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>
+ <!-- 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_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>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-ur/config.xml b/packages/SystemUI/res/values-ur/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-ur/config.xml
+++ b/packages/SystemUI/res/values-ur/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-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 7f171829865e..68db1bfd21ca 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -51,15 +51,21 @@
<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>
+ <!-- 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_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>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-zh-rCN/config.xml b/packages/SystemUI/res/values-zh-rCN/config.xml
index 5309563e3986..477f2198e4a6 100644
--- a/packages/SystemUI/res/values-zh-rCN/config.xml
+++ b/packages/SystemUI/res/values-zh-rCN/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-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index e179c5df5b19..74afc22fd118 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -51,15 +51,21 @@
<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>
+ <!-- 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_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>
+ <!-- no translation found for always_use_device (4015357883336738417) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (3257892669444535154) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f54115b0c9e2..cf7923805f0f 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -45,6 +45,9 @@
interface. This name is in the ComponentName flattened format (package/class) -->
<string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.StatusBar</string>
+ <!-- Component name of launcher service for overview to connect to -->
+ <string name="config_overviewServiceComponent" translateable="false">com.android.launcher3/com.android.quickstep.TouchInteractionService</string>
+
<!-- Whether or not we show the number in the bar. -->
<bool name="config_statusBarShowNumber">false</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9901f6ff8fda..f0bad2ac3a23 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -95,6 +95,10 @@
<!-- Height of a heads up notification in the status bar -->
<dimen name="notification_max_heads_up_height_increased">188dp</dimen>
+ <!-- Height of a messaging notifications with actions at least. Not that this is an upper bound
+ and the notification won't use this much, but is measured with wrap_content -->
+ <dimen name="notification_messaging_actions_min_height">196dp</dimen>
+
<!-- a threshold in dp per second that is considered fast scrolling -->
<dimen name="scroll_fast_threshold">1500dp</dimen>
@@ -236,7 +240,7 @@
<!-- The width of the panel that holds the quick settings. -->
<dimen name="qs_panel_width">@dimen/notification_panel_width</dimen>
- <dimen name="volume_dialog_panel_width">@dimen/standard_notification_panel_width</dimen>
+ <dimen name="volume_dialog_panel_width">315dp</dimen>
<!-- Gravity for the notification panel -->
<integer name="notification_panel_layout_gravity">0x31</integer><!-- center_horizontal|top -->
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index e5f802944ff3..cfd95b41825a 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -66,9 +66,6 @@
<!-- For notification icons for which targetSdk < L, this caches whether the icon is grayscale -->
<item type="id" name="icon_is_grayscale" />
- <item type="id" name="clip_children_tag" />
- <item type="id" name="clip_children_set_tag" />
- <item type="id" name="clip_to_padding_tag" />
<item type="id" name="image_icon_tag" />
<item type="id" name="contains_transformed_view" />
<item type="id" name="is_clicked_heads_up_tag" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 1536b64dc41f..b132160d4504 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -124,16 +124,16 @@
<string name="status_bar_use_physical_keyboard">Physical keyboard</string>
<!-- Prompt for the USB device permission dialog [CHAR LIMIT=80] -->
- <string name="usb_device_permission_prompt">Allow the app <xliff:g id="application">%1$s</xliff:g> to access the USB device?</string>
+ <string name="usb_device_permission_prompt">Allow <xliff:g id="application">%1$s</xliff:g> to access <xliff:g id="usb_device">%2$s</xliff:g>?</string>
<!-- Prompt for the USB accessory permission dialog [CHAR LIMIT=80] -->
- <string name="usb_accessory_permission_prompt">Allow the app <xliff:g id="application">%1$s</xliff:g> to access the USB accessory?</string>
+ <string name="usb_accessory_permission_prompt">Allow <xliff:g id="application">%1$s</xliff:g> to access <xliff:g id="usb_accessory">%2$s</xliff:g>?</string>
<!-- Prompt for the USB device confirm dialog [CHAR LIMIT=80] -->
- <string name="usb_device_confirm_prompt">Open <xliff:g id="activity">%1$s</xliff:g> when this USB device is connected?</string>
+ <string name="usb_device_confirm_prompt">Open <xliff:g id="application">%1$s</xliff:g> to handle <xliff:g id="usb_device">%2$s</xliff:g>?</string>
<!-- Prompt for the USB accessory confirm dialog [CHAR LIMIT=80] -->
- <string name="usb_accessory_confirm_prompt">Open <xliff:g id="activity">%1$s</xliff:g> when this USB accessory is connected?</string>
+ <string name="usb_accessory_confirm_prompt">Open <xliff:g id="application">%1$s</xliff:g> to handle <xliff:g id="usb_accessory">%2$s</xliff:g>?</string>
<!-- Prompt for the USB accessory URI dialog [CHAR LIMIT=80] -->
<string name="usb_accessory_uri_prompt">No installed apps work with this USB accessory. Learn more about this accessory at <xliff:g id="url">%1$s</xliff:g></string>
@@ -145,10 +145,10 @@
<string name="label_view">View</string>
<!-- Checkbox label for USB device dialogs. [CHAR LIMIT=50] -->
- <string name="always_use_device">Use by default for this USB device</string>
+ <string name="always_use_device">Always open <xliff:g id="application">%1$s</xliff:g> when <xliff:g id="usb_device">%2$s</xliff:g> is connected</string>
- <!-- Checkbox label for USB accessory dialogs. [CHAR LIMIT=50] -->
- <string name="always_use_accessory">Use by default for this USB accessory</string>
+ <!-- Checkbox label for USB accessory dialogs. [CHAR LIMIT=50]-->
+ <string name="always_use_accessory">Always open <xliff:g id="application">%1$s</xliff:g> when <xliff:g id="usb_accessory">%2$s</xliff:g> is connected</string>
<!-- Title of confirmation dialog for USB debugging -->
<string name="usb_debugging_title">Allow USB debugging?</string>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 32f502b1957e..46ea4949512b 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -105,13 +105,6 @@
android:title="@string/volume_and_do_not_disturb">
<!-- Action for this is
- MetricsConstants.ACTION_TUNER_DO_NOT_DISTURB_VOLUME_PANEL -->
- <com.android.systemui.tuner.TunerSwitch
- android:key="sysui_show_full_zen"
- android:title="@string/tuner_full_zen_title"
- sysui:metricsAction="314" />
-
- <!-- Action for this is
MetricsConstants.ACTION_TUNER_DO_NOT_DISTURB_VOLUME_SHORTCUT -->
<com.android.systemui.tuner.TunerSwitch
android:key="sysui_volume_down_silent,sysui_volume_up_silent"
diff --git a/packages/SystemUI/shared/Android.mk b/packages/SystemUI/shared/Android.mk
index 88a89bc8eba2..5f75f7d71584 100644
--- a/packages/SystemUI/shared/Android.mk
+++ b/packages/SystemUI/shared/Android.mk
@@ -21,7 +21,7 @@ LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := SystemUISharedLib
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_JAR_EXCLUDE_FILES := none
@@ -30,7 +30,7 @@ include $(BUILD_STATIC_JAVA_LIBRARY)
include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := SharedDummyLib
+LOCAL_PACKAGE_NAME := SystemUISharedLib
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_JAVA_LIBRARIES := SystemUISharedLib
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
new file mode 100644
index 000000000000..173a90a5baa7
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shared.recents;
+
+import android.view.MotionEvent;
+import com.android.systemui.shared.recents.ISystemUiProxy;
+
+oneway interface IOverviewProxy {
+ void onBind(in ISystemUiProxy sysUiProxy);
+ void onMotionEvent(in MotionEvent event);
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
new file mode 100644
index 000000000000..cc4bc58fbf9d
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.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 com.android.systemui.shared.recents;
+
+import android.graphics.Rect;
+import com.android.systemui.shared.system.GraphicBufferCompat;
+
+/**
+ * Temporary callbacks into SystemUI.
+ */
+interface ISystemUiProxy {
+
+ /**
+ * Proxies SurfaceControl.screenshotToBuffer().
+ */
+ GraphicBufferCompat screenshot(in Rect sourceCrop, int width, int height, int minLayer,
+ int maxLayer, boolean useIdentityTransform, int rotation);
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
index f92509d8ab5b..4834bb18f53c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
@@ -45,6 +45,11 @@ import java.util.List;
*/
public class RecentsTaskLoadPlan {
+ /** The set of conditions to preload tasks. */
+ public static class PreloadOptions {
+ public boolean loadTitles = true;
+ }
+
/** The set of conditions to load tasks. */
public static class Options {
public int runningTaskId = -1;
@@ -80,7 +85,8 @@ public class RecentsTaskLoadPlan {
* Note: Do not lock, since this can be calling back to the loader, which separately also drives
* this call (callers should synchronize on the loader before making this call).
*/
- public void preloadPlan(RecentsTaskLoader loader, int runningTaskId, int currentUserId) {
+ public void preloadPlan(PreloadOptions opts, RecentsTaskLoader loader, int runningTaskId,
+ int currentUserId) {
Resources res = mContext.getResources();
ArrayList<Task> allTasks = new ArrayList<>();
if (mRawTasks == null) {
@@ -110,9 +116,12 @@ public class RecentsTaskLoadPlan {
}
// Load the title, icon, and color
- String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription);
- String titleDescription = loader.getAndUpdateContentDescription(taskKey,
- t.taskDescription);
+ String title = opts.loadTitles
+ ? loader.getAndUpdateActivityTitle(taskKey, t.taskDescription)
+ : "";
+ String titleDescription = opts.loadTitles
+ ? loader.getAndUpdateContentDescription(taskKey, t.taskDescription)
+ : "";
Drawable icon = isStackTask
? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
: null;
@@ -153,7 +162,7 @@ public class RecentsTaskLoadPlan {
Resources res = mContext.getResources();
// Iterate through each of the tasks and load them according to the load conditions.
- ArrayList<Task> tasks = mStack.getStackTasks();
+ ArrayList<Task> tasks = mStack.getTasks();
int taskCount = tasks.size();
for (int i = 0; i < taskCount; i++) {
Task task = tasks.get(i);
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
index 9a991cfa0699..0f68026c7464 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
@@ -32,6 +32,7 @@ import android.util.LruCache;
import com.android.internal.annotations.GuardedBy;
import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.Options;
+import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.PreloadOptions;
import com.android.systemui.shared.recents.model.Task.TaskKey;
import com.android.systemui.shared.recents.model.TaskKeyLruCache.EvictionCallback;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -155,7 +156,7 @@ public class RecentsTaskLoader {
int currentUserId) {
try {
Trace.beginSection("preloadPlan");
- plan.preloadPlan(this, runningTaskId, currentUserId);
+ plan.preloadPlan(new PreloadOptions(), this, runningTaskId, currentUserId);
} finally {
Trace.endSection();
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java
index 693379d3ee13..a36939769477 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java
@@ -19,7 +19,6 @@ package com.android.systemui.shared.recents.model;
import android.content.ComponentName;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.SparseArray;
import com.android.systemui.shared.recents.model.Task.TaskKey;
import com.android.systemui.shared.recents.utilities.AnimationProps;
@@ -92,7 +91,7 @@ public class TaskStack {
boolean dismissRecentsIfAllRemoved) {
if (mStackTaskList.contains(t)) {
mStackTaskList.remove(t);
- Task newFrontMostTask = getStackFrontMostTask();
+ Task newFrontMostTask = getFrontMostTask();
if (mCb != null) {
// Notify that a task has been removed
mCb.onStackTaskRemoved(this, t, newFrontMostTask, animation,
@@ -183,7 +182,7 @@ public class TaskStack {
// Only callback for the removed tasks after the stack has updated
int removedTaskCount = removedTasks.size();
- Task newFrontMostTask = getStackFrontMostTask();
+ Task newFrontMostTask = getFrontMostTask();
for (int i = 0; i < removedTaskCount; i++) {
mCb.onStackTaskRemoved(this, removedTasks.get(i), newFrontMostTask,
AnimationProps.IMMEDIATE, false /* fromDockGesture */,
@@ -205,7 +204,7 @@ public class TaskStack {
/**
* Gets the front-most task in the stack.
*/
- public Task getStackFrontMostTask() {
+ public Task getFrontMostTask() {
ArrayList<Task> stackTasks = mStackTaskList.getTasks();
if (stackTasks.isEmpty()) {
return null;
@@ -228,7 +227,7 @@ public class TaskStack {
/**
* Returns the set of "active" (non-historical) tasks in the stack that have been used recently.
*/
- public ArrayList<Task> getStackTasks() {
+ public ArrayList<Task> getTasks() {
return mStackTaskList.getTasks();
}
@@ -242,16 +241,9 @@ public class TaskStack {
}
/**
- * Returns the number of stacktasks.
- */
- public int getTaskCount() {
- return mStackTaskList.size();
- }
-
- /**
* Returns the number of stack tasks.
*/
- public int getStackTaskCount() {
+ public int getTaskCount() {
return mStackTaskList.size();
}
@@ -298,7 +290,7 @@ public class TaskStack {
if (nextLaunchTarget != null) {
return nextLaunchTarget;
}
- return getStackTasks().get(getTaskCount() - 1);
+ return getTasks().get(getTaskCount() - 1);
}
private Task getNextLaunchTargetRaw() {
@@ -306,15 +298,15 @@ public class TaskStack {
if (taskCount == 0) {
return null;
}
- int launchTaskIndex = indexOfStackTask(getLaunchTarget());
+ int launchTaskIndex = indexOfTask(getLaunchTarget());
if (launchTaskIndex != -1 && launchTaskIndex > 0) {
- return getStackTasks().get(launchTaskIndex - 1);
+ return getTasks().get(launchTaskIndex - 1);
}
return null;
}
/** Returns the index of this task in this current task stack */
- public int indexOfStackTask(Task t) {
+ public int indexOfTask(Task t) {
return mStackTaskList.indexOf(t);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AppTrace.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AppTrace.java
new file mode 100644
index 000000000000..0241c593b850
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AppTrace.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.shared.recents.utilities;
+
+import static android.os.Trace.TRACE_TAG_APP;
+
+/**
+ * Helper class for internal trace functions.
+ */
+public class AppTrace {
+
+ /**
+ * Begins a new async trace section with the given {@param key} and {@param cookie}.
+ */
+ public static void start(String key, int cookie) {
+ android.os.Trace.asyncTraceBegin(TRACE_TAG_APP, key, cookie);
+ }
+
+ /**
+ * Begins a new async trace section with the given {@param key}.
+ */
+ public static void start(String key) {
+ android.os.Trace.asyncTraceBegin(TRACE_TAG_APP, key, 0);
+ }
+
+ /**
+ * Ends an existing async trace section with the given {@param key}.
+ */
+ public static void end(String key) {
+ android.os.Trace.asyncTraceEnd(TRACE_TAG_APP, key, 0);
+ }
+
+ /**
+ * Ends an existing async trace section with the given {@param key} and {@param cookie}.
+ */
+ public static void end(String key, int cookie) {
+ android.os.Trace.asyncTraceEnd(TRACE_TAG_APP, key, cookie);
+ }
+
+ /**
+ * Begins a new trace section with the given {@param key}. Can be nested.
+ */
+ public static void beginSection(String key) {
+ android.os.Trace.beginSection(key);
+ }
+
+ /**
+ * Ends an existing trace section started in the last {@link #beginSection(String)}.
+ */
+ public static void endSection() {
+ android.os.Trace.endSection();
+ }
+
+ /**
+ * Traces a counter value.
+ */
+ public static void count(String name, int count) {
+ android.os.Trace.traceCounter(TRACE_TAG_APP, name, count);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AnimateableViewBounds.java
index b598ec6fc31f..45728c403ac4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AnimateableViewBounds.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.recents.views;
+package com.android.systemui.shared.recents.view;
import android.graphics.Outline;
import android.graphics.Rect;
@@ -24,22 +24,19 @@ import android.view.ViewOutlineProvider;
import com.android.systemui.shared.recents.utilities.Utilities;
-/* An outline provider that has a clip and outline that can be animated. */
+/**
+ * An outline provider that has a clip and outline that can be animated.
+ */
public class AnimateableViewBounds extends ViewOutlineProvider {
private static final float MIN_ALPHA = 0.1f;
private static final float MAX_ALPHA = 0.8f;
protected View mSourceView;
- @ViewDebug.ExportedProperty(category="recents")
protected Rect mClipRect = new Rect();
- @ViewDebug.ExportedProperty(category="recents")
protected Rect mClipBounds = new Rect();
- @ViewDebug.ExportedProperty(category="recents")
protected Rect mLastClipBounds = new Rect();
- @ViewDebug.ExportedProperty(category="recents")
protected int mCornerRadius;
- @ViewDebug.ExportedProperty(category="recents")
protected float mAlpha = 1f;
public AnimateableViewBounds(View source, int cornerRadius) {
@@ -73,7 +70,7 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
/**
* Sets the view outline alpha.
*/
- void setAlpha(float alpha) {
+ public void setAlpha(float alpha) {
if (Float.compare(alpha, mAlpha) != 0) {
mAlpha = alpha;
// TODO, If both clip and alpha change in the same frame, only invalidate once
@@ -88,28 +85,43 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
return mAlpha;
}
- /** Sets the top clip. */
+ /**
+ * Sets the top clip.
+ */
public void setClipTop(int top) {
mClipRect.top = top;
updateClipBounds();
}
- /** Returns the top clip. */
+ /**
+ * @return the top clip.
+ */
public int getClipTop() {
return mClipRect.top;
}
- /** Sets the bottom clip. */
+ /**
+ * Sets the bottom clip.
+ */
public void setClipBottom(int bottom) {
mClipRect.bottom = bottom;
updateClipBounds();
}
- /** Returns the bottom clip. */
+ /**
+ * @return the bottom clip.
+ */
public int getClipBottom() {
return mClipRect.bottom;
}
+ /**
+ * @return the clip bounds.
+ */
+ public Rect getClipBounds() {
+ return mClipBounds;
+ }
+
protected void updateClipBounds() {
mClipBounds.set(Math.max(0, mClipRect.left), Math.max(0, mClipRect.top),
mSourceView.getWidth() - Math.max(0, mClipRect.right),
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecCompat.java
new file mode 100644
index 000000000000..ebdc884285d2
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecCompat.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 com.android.systemui.shared.recents.view;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.view.AppTransitionAnimationSpec;
+
+/**
+ * Wraps the internal app transition animation spec.
+ */
+public class AppTransitionAnimationSpecCompat {
+
+ private int mTaskId;
+ private Bitmap mBuffer;
+ private Rect mRect;
+
+ public AppTransitionAnimationSpecCompat(int taskId, Bitmap buffer, Rect rect) {
+ mTaskId = taskId;
+ mBuffer = buffer;
+ mRect = rect;
+ }
+
+ public AppTransitionAnimationSpec toAppTransitionAnimationSpec() {
+ return new AppTransitionAnimationSpec(mTaskId,
+ mBuffer != null ? mBuffer.createGraphicBufferHandle() : null, mRect);
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecsFuture.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecsFuture.java
index a46fab35f66b..85d362a7a767 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecsFuture.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecsFuture.java
@@ -22,6 +22,7 @@ import android.view.AppTransitionAnimationSpec;
import android.view.IAppTransitionAnimationSpecsFuture;
import java.util.List;
+import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
/**
@@ -31,11 +32,13 @@ import java.util.concurrent.FutureTask;
public abstract class AppTransitionAnimationSpecsFuture {
private final Handler mHandler;
- private FutureTask<List<AppTransitionAnimationSpec>> mComposeTask = new FutureTask<>(() -> {
- synchronized (AppTransitionAnimationSpecsFuture.this) {
- return composeSpecs();
- }
- });
+ private FutureTask<List<AppTransitionAnimationSpecCompat>> mComposeTask = new FutureTask<>(
+ new Callable<List<AppTransitionAnimationSpecCompat>>() {
+ @Override
+ public List<AppTransitionAnimationSpecCompat> call() throws Exception {
+ return composeSpecs();
+ }
+ });
private final IAppTransitionAnimationSpecsFuture mFuture =
new IAppTransitionAnimationSpecsFuture.Stub() {
@@ -45,13 +48,15 @@ public abstract class AppTransitionAnimationSpecsFuture {
if (!mComposeTask.isDone()) {
mHandler.post(mComposeTask);
}
- List<AppTransitionAnimationSpec> specs = mComposeTask.get();
+ List<AppTransitionAnimationSpecCompat> specs = mComposeTask.get();
if (specs == null) {
return null;
}
AppTransitionAnimationSpec[] arr = new AppTransitionAnimationSpec[specs.size()];
- specs.toArray(arr);
+ for (int i = 0; i < specs.size(); i++) {
+ arr[i] = specs.get(i).toAppTransitionAnimationSpec();
+ }
return arr;
} catch (Exception e) {
return null;
@@ -80,5 +85,5 @@ public abstract class AppTransitionAnimationSpecsFuture {
mComposeTask.run();
}
- public abstract List<AppTransitionAnimationSpec> composeSpecs();
+ public abstract List<AppTransitionAnimationSpecCompat> composeSpecs();
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java
index 3095d151726d..ab890439a381 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java
@@ -42,7 +42,7 @@ public class RecentsTransition {
*/
public static ActivityOptions createAspectScaleAnimation(Context context, Handler handler,
boolean scaleUp, AppTransitionAnimationSpecsFuture animationSpecsFuture,
- OnAnimationStartedListener animationStartCallback) {
+ final Runnable animationStartCallback) {
final OnAnimationStartedListener animStartedListener = new OnAnimationStartedListener() {
private boolean mHandled;
@@ -56,7 +56,7 @@ public class RecentsTransition {
mHandled = true;
if (animationStartCallback != null) {
- animationStartCallback.onAnimationStarted();
+ animationStartCallback.run();
}
}
};
@@ -70,15 +70,15 @@ public class RecentsTransition {
/**
* Wraps a animation-start callback in a binder that can be called from window manager.
*/
- public static IRemoteCallback wrapStartedListener(Handler handler,
- OnAnimationStartedListener listener) {
- if (listener == null) {
+ public static IRemoteCallback wrapStartedListener(final Handler handler,
+ final Runnable animationStartCallback) {
+ if (animationStartCallback == null) {
return null;
}
return new IRemoteCallback.Stub() {
@Override
public void sendResult(Bundle data) throws RemoteException {
- handler.post(listener::onAnimationStarted);
+ handler.post(animationStartCallback);
}
};
}
@@ -87,18 +87,20 @@ public class RecentsTransition {
* @return a {@link GraphicBuffer} with the {@param view} drawn into it. Result can be null if
* we were unable to allocate a hardware bitmap.
*/
- public static GraphicBuffer drawViewIntoGraphicBuffer(int width, int height, View view,
- float scale, int eraseColor) {
- final Bitmap hwBitmap = createHardwareBitmap(width, height, (c) -> {
- c.scale(scale, scale);
- if (eraseColor != 0) {
- c.drawColor(eraseColor);
- }
- if (view != null) {
- view.draw(c);
+ public static Bitmap drawViewIntoHardwareBitmap(int width, int height, final View view,
+ final float scale, final int eraseColor) {
+ return createHardwareBitmap(width, height, new Consumer<Canvas>() {
+ @Override
+ public void accept(Canvas c) {
+ c.scale(scale, scale);
+ if (eraseColor != 0) {
+ c.drawColor(eraseColor);
+ }
+ if (view != null) {
+ view.draw(c);
+ }
}
});
- return hwBitmap != null ? hwBitmap.createGraphicBufferHandle() : null;
}
/**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index db1583ab132a..f6fab86cefaa 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -29,6 +29,7 @@ import android.app.ActivityManager;
import android.app.ActivityManager.RecentTaskInfo;
import android.app.ActivityOptions;
import android.app.AppGlobals;
+import android.app.IAssistDataReceiver;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -39,7 +40,9 @@ import android.content.res.Resources.NotFoundException;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.IconDrawableFactory;
@@ -62,12 +65,14 @@ public class ActivityManagerWrapper {
private final PackageManager mPackageManager;
private final IconDrawableFactory mDrawableFactory;
private final BackgroundExecutor mBackgroundExecutor;
+ private final TaskStackChangeListeners mTaskStackChangeListeners;
private ActivityManagerWrapper() {
final Context context = AppGlobals.getInitialApplication();
mPackageManager = context.getPackageManager();
mDrawableFactory = IconDrawableFactory.newInstance(context);
mBackgroundExecutor = BackgroundExecutor.get();
+ mTaskStackChangeListeners = new TaskStackChangeListeners(Looper.getMainLooper());
}
public static ActivityManagerWrapper getInstance() {
@@ -232,13 +237,54 @@ public class ActivityManagerWrapper {
}
/**
+ * Starts the recents activity. The caller should manage the thread on which this is called.
+ */
+ public void startRecentsActivity(AssistDataReceiverCompat assistDataReceiver, Bundle options,
+ ActivityOptions opts, int userId, Consumer<Boolean> resultCallback,
+ Handler resultCallbackHandler) {
+ Bundle activityOptions = opts != null ? opts.toBundle() : null;
+ try {
+ IAssistDataReceiver receiver = null;
+ if (assistDataReceiver != null) {
+ receiver = new IAssistDataReceiver.Stub() {
+ public void onHandleAssistData(Bundle resultData) {
+ assistDataReceiver.onHandleAssistData(resultData);
+ }
+ public void onHandleAssistScreenshot(Bitmap screenshot) {
+ assistDataReceiver.onHandleAssistScreenshot(screenshot);
+ }
+ };
+ }
+ ActivityManager.getService().startRecentsActivity(receiver, options, activityOptions,
+ userId);
+ if (resultCallback != null) {
+ resultCallbackHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ resultCallback.accept(true);
+ }
+ });
+ }
+ } catch (Exception e) {
+ if (resultCallback != null) {
+ resultCallbackHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ resultCallback.accept(false);
+ }
+ });
+ }
+ }
+ }
+
+ /**
* Starts a task from Recents.
*
- * @see {@link #startActivityFromRecents(TaskKey, ActivityOptions, int, int, Consumer, Handler)}
+ * @see {@link #startActivityFromRecentsAsync(TaskKey, ActivityOptions, int, int, Consumer, Handler)}
*/
- public void startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options,
+ public void startActivityFromRecentsAsync(Task.TaskKey taskKey, ActivityOptions options,
Consumer<Boolean> resultCallback, Handler resultCallbackHandler) {
- startActivityFromRecents(taskKey, options, WINDOWING_MODE_UNDEFINED,
+ startActivityFromRecentsAsync(taskKey, options, WINDOWING_MODE_UNDEFINED,
ACTIVITY_TYPE_UNDEFINED, resultCallback, resultCallbackHandler);
}
@@ -248,7 +294,7 @@ public class ActivityManagerWrapper {
* @param resultCallback The result success callback
* @param resultCallbackHandler The handler to receive the result callback
*/
- public void startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options,
+ public void startActivityFromRecentsAsync(Task.TaskKey taskKey, ActivityOptions options,
int windowingMode, int activityType, Consumer<Boolean> resultCallback,
Handler resultCallbackHandler) {
if (taskKey.windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
@@ -270,30 +316,66 @@ public class ActivityManagerWrapper {
// Execute this from another thread such that we can do other things (like caching the
// bitmap for the thumbnail) while AM is busy starting our activity.
- mBackgroundExecutor.submit(() -> {
- try {
- ActivityManager.getService().startActivityFromRecents(taskKey.id,
- finalOptions == null ? null : finalOptions.toBundle());
- if (resultCallback != null) {
- resultCallbackHandler.post(() -> resultCallback.accept(true));
- }
- } catch (Exception e) {
- if (resultCallback != null) {
- resultCallbackHandler.post(() -> resultCallback.accept(false));
+ mBackgroundExecutor.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ ActivityManager.getService().startActivityFromRecents(taskKey.id,
+ finalOptions == null ? null : finalOptions.toBundle());
+ if (resultCallback != null) {
+ resultCallbackHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ resultCallback.accept(true);
+ }
+ });
+ }
+ } catch (Exception e) {
+ if (resultCallback != null) {
+ resultCallbackHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ resultCallback.accept(false);
+ }
+ });
+ }
}
}
});
}
/**
+ * Registers a task stack listener with the system.
+ * This should be called on the main thread.
+ */
+ public void registerTaskStackListener(TaskStackChangeListener listener) {
+ synchronized (mTaskStackChangeListeners) {
+ mTaskStackChangeListeners.addListener(ActivityManager.getService(), listener);
+ }
+ }
+
+ /**
+ * Unregisters a task stack listener with the system.
+ * This should be called on the main thread.
+ */
+ public void unregisterTaskStackListener(TaskStackChangeListener listener) {
+ synchronized (mTaskStackChangeListeners) {
+ mTaskStackChangeListeners.removeListener(listener);
+ }
+ }
+
+ /**
* Requests that the system close any open system windows (including other SystemUI).
*/
public void closeSystemWindows(String reason) {
- mBackgroundExecutor.submit(() -> {
- try {
- ActivityManager.getService().closeSystemDialogs(reason);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to close system windows", e);
+ mBackgroundExecutor.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ ActivityManager.getService().closeSystemDialogs(reason);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to close system windows", e);
+ }
}
});
}
@@ -302,11 +384,14 @@ public class ActivityManagerWrapper {
* Removes a task by id.
*/
public void removeTask(int taskId) {
- mBackgroundExecutor.submit(() -> {
- try {
- ActivityManager.getService().removeTask(taskId);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to remove task=" + taskId, e);
+ mBackgroundExecutor.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ ActivityManager.getService().removeTask(taskId);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to remove task=" + taskId, e);
+ }
}
});
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiverCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiverCompat.java
new file mode 100644
index 000000000000..cd943f62ea9b
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiverCompat.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shared.system;
+
+import android.graphics.Bitmap;
+import android.os.Bundle;
+
+/**
+ * Abstract class for assist data receivers.
+ */
+public abstract class AssistDataReceiverCompat {
+ public abstract void onHandleAssistData(Bundle resultData);
+ public abstract void onHandleAssistScreenshot(Bitmap screenshot);
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/BackgroundExecutor.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/BackgroundExecutor.java
index 26e1813792bd..0bd89a78cfda 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/BackgroundExecutor.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/BackgroundExecutor.java
@@ -16,6 +16,7 @@
package com.android.systemui.shared.system;
+import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@@ -37,9 +38,24 @@ public class BackgroundExecutor {
}
/**
+ * Runs the given {@param callable} on one of the background executor threads.
+ */
+ public <T> Future<T> submit(Callable<T> callable) {
+ return mExecutorService.submit(callable);
+ }
+
+ /**
* Runs the given {@param runnable} on one of the background executor threads.
*/
public Future<?> submit(Runnable runnable) {
return mExecutorService.submit(runnable);
}
+
+ /**
+ * Runs the given {@param runnable} on one of the background executor threads. Return
+ * {@param result} when the future is resolved.
+ */
+ public <T> Future<T> submit(Runnable runnable, T result) {
+ return mExecutorService.submit(runnable, result);
+ }
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ChoreographerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ChoreographerCompat.java
new file mode 100644
index 000000000000..5ebb22d30892
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ChoreographerCompat.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shared.system;
+
+import static android.view.Choreographer.CALLBACK_INPUT;
+
+import android.graphics.Bitmap;
+import android.graphics.GraphicBuffer;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.Choreographer;
+
+/**
+ * Wraps the internal choreographer.
+ */
+public class ChoreographerCompat {
+
+ /**
+ * Posts an input callback to the choreographer.
+ */
+ public static void postInputFrame(Runnable runnable) {
+ Choreographer.getInstance().postCallback(CALLBACK_INPUT, runnable, null);
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.aidl
new file mode 100644
index 000000000000..f9450adcdf30
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shared.system;
+
+parcelable GraphicBufferCompat; \ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.java
new file mode 100644
index 000000000000..66b8fed1a48f
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/GraphicBufferCompat.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.shared.system;
+
+import android.graphics.Bitmap;
+import android.graphics.GraphicBuffer;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Wraps the internal graphic buffer.
+ */
+public class GraphicBufferCompat implements Parcelable {
+
+ private GraphicBuffer mBuffer;
+
+ public GraphicBufferCompat(GraphicBuffer buffer) {
+ mBuffer = buffer;
+ }
+
+ public GraphicBufferCompat(Parcel in) {
+ mBuffer = GraphicBuffer.CREATOR.createFromParcel(in);
+ }
+
+ public Bitmap toBitmap() {
+ return mBuffer != null
+ ? Bitmap.createHardwareBitmap(mBuffer)
+ : null;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ mBuffer.writeToParcel(dest, flags);
+ }
+
+ public static final Parcelable.Creator<GraphicBufferCompat> CREATOR
+ = new Parcelable.Creator<GraphicBufferCompat>() {
+ public GraphicBufferCompat createFromParcel(Parcel in) {
+ return new GraphicBufferCompat(in);
+ }
+
+ public GraphicBufferCompat[] newArray(int size) {
+ return new GraphicBufferCompat[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
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 36310f11c22d..17cb0d80f6ab 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
@@ -20,6 +20,8 @@ import android.app.ActivityManager.TaskSnapshot;
import android.os.UserHandle;
import android.util.Log;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
/**
* An interface to track task stack changes. Classes should implement this instead of
* {@link android.app.ITaskStackListener} to reduce IPC calls from system services.
@@ -31,7 +33,7 @@ public abstract class TaskStackChangeListener {
// Main thread callbacks
public void onTaskStackChanged() { }
- public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { }
+ public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { }
public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { }
public void onActivityUnpinned() { }
public void onPinnedActivityRestartAttempt(boolean clearedTask) { }
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 95fc96f5f228..81c37a95a4f3 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
@@ -26,6 +26,8 @@ import android.os.RemoteException;
import android.os.Trace;
import android.util.Log;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
import java.util.ArrayList;
import java.util.List;
@@ -43,6 +45,7 @@ public class TaskStackChangeListeners extends TaskStackListener {
private final List<TaskStackChangeListener> mTmpListeners = new ArrayList<>();
private final Handler mHandler;
+ private boolean mRegistered;
public TaskStackChangeListeners(Looper looper) {
mHandler = new H(looper);
@@ -50,16 +53,21 @@ public class TaskStackChangeListeners extends TaskStackListener {
public void addListener(IActivityManager am, TaskStackChangeListener listener) {
mTaskStackListeners.add(listener);
- if (mTaskStackListeners.size() == 1) {
+ if (!mRegistered) {
// Register mTaskStackListener to IActivityManager only once if needed.
try {
am.registerTaskStackListener(this);
+ mRegistered = true;
} catch (Exception e) {
Log.w(TAG, "Failed to call registerTaskStackListener", e);
}
}
}
+ public void removeListener(TaskStackChangeListener listener) {
+ mTaskStackListeners.remove(listener);
+ }
+
@Override
public void onTaskStackChanged() throws RemoteException {
// Call the task changed callback for the non-ui thread listeners first
@@ -170,7 +178,7 @@ public class TaskStackChangeListeners extends TaskStackListener {
Trace.beginSection("onTaskSnapshotChanged");
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1,
- (TaskSnapshot) msg.obj);
+ new ThumbnailData((TaskSnapshot) msg.obj));
}
Trace.endSection();
break;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
new file mode 100644
index 000000000000..1477558a0e97
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.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 com.android.systemui.shared.system;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.graphics.Rect;
+import android.view.WindowManagerGlobal;
+
+public class WindowManagerWrapper {
+
+ private static final String TAG = "WindowManagerWrapper";
+
+ private static final WindowManagerWrapper sInstance = new WindowManagerWrapper();
+
+ public static WindowManagerWrapper getInstance() {
+ return sInstance;
+ }
+
+ /**
+ * @return the stable insets for the primary display.
+ */
+ public void getStableInsets(Rect outStableInsets) {
+ try {
+ WindowManagerGlobal.getWindowManagerService().getStableInsets(DEFAULT_DISPLAY,
+ outStableInsets);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
new file mode 100644
index 000000000000..c18f9b61c044
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+import android.app.PendingIntent;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.graphics.ColorUtils;
+import com.android.systemui.R;
+import com.android.systemui.keyguard.KeyguardSliceProvider;
+
+/**
+ * View visible under the clock on the lock screen and AoD.
+ */
+public class KeyguardSliceView extends LinearLayout {
+
+ private final Uri mKeyguardSliceUri;
+ private TextView mTitle;
+ private TextView mText;
+ private Slice mSlice;
+ private PendingIntent mSliceAction;
+ private int mTextColor;
+ private float mDarkAmount = 0;
+
+ private final ContentObserver mObserver;
+
+ public KeyguardSliceView(Context context) {
+ this(context, null, 0);
+ }
+
+ public KeyguardSliceView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public KeyguardSliceView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ mObserver = new KeyguardSliceObserver(new Handler());
+ mKeyguardSliceUri = Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI);;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mTitle = findViewById(R.id.title);
+ mText = findViewById(R.id.text);
+ mTextColor = mTitle.getCurrentTextColor();
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ // Set initial content
+ showSlice(Slice.bindSlice(getContext().getContentResolver(), mKeyguardSliceUri));
+
+ // Make sure we always have the most current slice
+ getContext().getContentResolver().registerContentObserver(mKeyguardSliceUri,
+ false /* notifyDescendants */, mObserver);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ getContext().getContentResolver().unregisterContentObserver(mObserver);
+ }
+
+ private void showSlice(Slice slice) {
+ // Items will be wrapped into an action when they have tap targets.
+ SliceItem actionSlice = SliceQuery.find(slice, SliceItem.TYPE_ACTION);
+ if (actionSlice != null) {
+ mSlice = actionSlice.getSlice();
+ mSliceAction = actionSlice.getAction();
+ } else {
+ mSlice = slice;
+ mSliceAction = null;
+ }
+
+ if (mSlice == null) {
+ setVisibility(GONE);
+ return;
+ }
+
+ SliceItem title = SliceQuery.find(mSlice, SliceItem.TYPE_TEXT, Slice.HINT_TITLE, null);
+ if (title == null) {
+ mTitle.setVisibility(GONE);
+ } else {
+ mTitle.setVisibility(VISIBLE);
+ mTitle.setText(title.getText());
+ }
+
+ SliceItem text = SliceQuery.find(mSlice, SliceItem.TYPE_TEXT, null, Slice.HINT_TITLE);
+ if (text == null) {
+ mText.setVisibility(GONE);
+ } else {
+ mText.setVisibility(VISIBLE);
+ mText.setText(text.getText());
+ }
+
+ final int visibility = title == null && text == null ? GONE : VISIBLE;
+ if (visibility != getVisibility()) {
+ setVisibility(visibility);
+ }
+ }
+
+ public void setDark(float darkAmount) {
+ mDarkAmount = darkAmount;
+ updateTextColors();
+ }
+
+ public void setTextColor(int textColor) {
+ mTextColor = textColor;
+ }
+
+ private void updateTextColors() {
+ final int blendedColor = ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount);
+ mTitle.setTextColor(blendedColor);
+ mText.setTextColor(blendedColor);
+ }
+
+ private class KeyguardSliceObserver extends ContentObserver {
+ KeyguardSliceObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ this.onChange(selfChange, null);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ showSlice(Slice.bindSlice(getContext().getContentResolver(), mKeyguardSliceUri));
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index bc2a59df42a6..78cf2b9bf1ed 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -19,11 +19,9 @@ package com.android.keyguard;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
-import android.graphics.PorterDuff;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
@@ -42,8 +40,8 @@ import android.widget.TextView;
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.LockPatternUtils;
+import com.android.settingslib.Utils;
import com.android.systemui.ChargingView;
-import com.android.systemui.statusbar.policy.DateView;
import java.util.Locale;
@@ -55,13 +53,11 @@ public class KeyguardStatusView extends GridLayout {
private final LockPatternUtils mLockPatternUtils;
private final AlarmManager mAlarmManager;
- private TextView mAlarmStatusView;
- private DateView mDateView;
private TextClock mClockView;
private TextView mOwnerInfo;
private ViewGroup mClockContainer;
private ChargingView mBatteryDoze;
- private View mKeyguardStatusArea;
+ private KeyguardSliceView mKeyguardSlice;
private Runnable mPendingMarqueeStart;
private Handler mHandler;
@@ -69,8 +65,6 @@ public class KeyguardStatusView extends GridLayout {
private boolean mPulsing;
private float mDarkAmount = 0;
private int mTextColor;
- private int mDateTextColor;
- private int mAlarmTextColor;
private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
@@ -141,7 +135,6 @@ public class KeyguardStatusView extends GridLayout {
private void setEnableMarqueeImpl(boolean enabled) {
if (DEBUG) Log.v(TAG, (enabled ? "Enable" : "Disable") + " transport text marquee");
- if (mAlarmStatusView != null) mAlarmStatusView.setSelected(enabled);
if (mOwnerInfo != null) mOwnerInfo.setSelected(enabled);
}
@@ -149,8 +142,6 @@ public class KeyguardStatusView extends GridLayout {
protected void onFinishInflate() {
super.onFinishInflate();
mClockContainer = findViewById(R.id.keyguard_clock_container);
- mAlarmStatusView = findViewById(R.id.alarm_status);
- mDateView = findViewById(R.id.date_view);
mClockView = findViewById(R.id.clock_view);
mClockView.setShowCurrentUserTime(true);
if (KeyguardClockAccessibilityDelegate.isNeeded(mContext)) {
@@ -158,11 +149,9 @@ public class KeyguardStatusView extends GridLayout {
}
mOwnerInfo = findViewById(R.id.owner_info);
mBatteryDoze = findViewById(R.id.battery_doze);
- mKeyguardStatusArea = findViewById(R.id.keyguard_status_area);
- mVisibleInDoze = new View[]{mBatteryDoze, mClockView, mKeyguardStatusArea};
+ mKeyguardSlice = findViewById(R.id.keyguard_status_area);
+ mVisibleInDoze = new View[]{mBatteryDoze, mClockView, mKeyguardSlice};
mTextColor = mClockView.getCurrentTextColor();
- mDateTextColor = mDateView.getCurrentTextColor();
- mAlarmTextColor = mAlarmStatusView.getCurrentTextColor();
boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
setEnableMarquee(shouldMarquee);
@@ -184,8 +173,6 @@ public class KeyguardStatusView extends GridLayout {
layoutParams.bottomMargin = getResources().getDimensionPixelSize(
R.dimen.bottom_text_spacing_digital);
mClockView.setLayoutParams(layoutParams);
- mDateView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
- getResources().getDimensionPixelSize(R.dimen.widget_label_font_size));
if (mOwnerInfo != null) {
mOwnerInfo.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(R.dimen.widget_label_font_size));
@@ -193,8 +180,6 @@ public class KeyguardStatusView extends GridLayout {
}
public void refreshTime() {
- mDateView.setDatePattern(Patterns.dateViewSkel);
-
mClockView.setFormat12Hour(Patterns.clockView12);
mClockView.setFormat24Hour(Patterns.clockView24);
}
@@ -205,23 +190,11 @@ public class KeyguardStatusView extends GridLayout {
Patterns.update(mContext, nextAlarm != null);
refreshTime();
- refreshAlarmStatus(nextAlarm);
- }
-
- void refreshAlarmStatus(AlarmManager.AlarmClockInfo nextAlarm) {
- if (nextAlarm != null) {
- String alarm = formatNextAlarm(mContext, nextAlarm);
- mAlarmStatusView.setText(alarm);
- mAlarmStatusView.setContentDescription(
- getResources().getString(R.string.keyguard_accessibility_next_alarm, alarm));
- mAlarmStatusView.setVisibility(View.VISIBLE);
- } else {
- mAlarmStatusView.setVisibility(View.GONE);
- }
}
public int getClockBottom() {
- return mKeyguardStatusArea.getBottom();
+ return mKeyguardSlice.getVisibility() == VISIBLE ? mKeyguardSlice.getBottom()
+ : mClockView.getBottom();
}
public float getClockTextSize() {
@@ -341,11 +314,8 @@ public class KeyguardStatusView extends GridLayout {
updateDozeVisibleViews();
mBatteryDoze.setDark(dark);
+ mKeyguardSlice.setDark(darkAmount);
mClockView.setTextColor(ColorUtils.blendARGB(mTextColor, Color.WHITE, darkAmount));
- mDateView.setTextColor(ColorUtils.blendARGB(mDateTextColor, Color.WHITE, darkAmount));
- int blendedAlarmColor = ColorUtils.blendARGB(mAlarmTextColor, Color.WHITE, darkAmount);
- mAlarmStatusView.setTextColor(blendedAlarmColor);
- mAlarmStatusView.setCompoundDrawableTintList(ColorStateList.valueOf(blendedAlarmColor));
}
public void setPulsing(boolean pulsing) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 623fe53f5d7f..41b007af46ae 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -78,6 +78,7 @@ import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.google.android.collect.Lists;
@@ -1187,7 +1188,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
mFpm.addLockoutResetCallback(mLockoutResetCallback);
}
- SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
mUserManager = context.getSystemService(UserManager.class);
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index d8a47c5e07de..e7e70afa20ce 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -26,7 +26,7 @@ import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.NightDisplayController;
+import com.android.internal.app.ColorDisplayController;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.Preconditions;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -205,8 +205,8 @@ public class Dependency extends SystemUI {
mProviders.put(BatteryController.class, () ->
new BatteryControllerImpl(mContext));
- mProviders.put(NightDisplayController.class, () ->
- new NightDisplayController(mContext));
+ mProviders.put(ColorDisplayController.class, () ->
+ new ColorDisplayController(mContext));
mProviders.put(ManagedProfileController.class, () ->
new ManagedProfileControllerImpl(mContext));
@@ -308,6 +308,8 @@ public class Dependency extends SystemUI {
mProviders.put(IWindowManager.class, () -> WindowManagerGlobal.getWindowManagerService());
+ mProviders.put(OverviewProxyService.class, () -> new OverviewProxyService(mContext));
+
// Put all dependencies above here so the factory can override them if it wants.
SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
}
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
new file mode 100644
index 000000000000..22922e7bbac4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.PatternMatcher;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.SurfaceControl;
+
+import com.android.systemui.OverviewProxyService.OverviewProxyListener;
+import com.android.systemui.shared.recents.IOverviewProxy;
+import com.android.systemui.shared.recents.ISystemUiProxy;
+import com.android.systemui.shared.system.GraphicBufferCompat;
+import com.android.systemui.statusbar.policy.CallbackController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class to send information from overview to launcher with a binder.
+ */
+public class OverviewProxyService implements CallbackController<OverviewProxyListener>, Dumpable {
+
+ private static final String TAG = "OverviewProxyService";
+ private static final long BACKOFF_MILLIS = 5000;
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
+ private final ComponentName mLauncherComponentName;
+ private final DeviceProvisionedController mDeviceProvisionedController
+ = Dependency.get(DeviceProvisionedController.class);
+ private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
+
+ private IOverviewProxy mOverviewProxy;
+ private int mConnectionBackoffAttempts;
+
+ private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
+ public GraphicBufferCompat screenshot(Rect sourceCrop, int width, int height, int minLayer,
+ int maxLayer, boolean useIdentityTransform, int rotation) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ return new GraphicBufferCompat(SurfaceControl.screenshotToBuffer(sourceCrop, width,
+ height, minLayer, maxLayer, useIdentityTransform, rotation));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ };
+
+ private final BroadcastReceiver mLauncherAddedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Reconnect immediately, instead of waiting for resume to arrive.
+ startConnectionToCurrentUser();
+ }
+ };
+
+ private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (service != null) {
+ mConnectionBackoffAttempts = 0;
+ mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
+ // Listen for launcher's death
+ try {
+ service.linkToDeath(mOverviewServiceDeathRcpt, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Lost connection to launcher service", e);
+ }
+ try {
+ mOverviewProxy.onBind(mSysUiProxy);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to call onBind()", e);
+ }
+ notifyConnectionChanged();
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ // Do nothing
+ }
+ };
+
+ private final DeviceProvisionedListener mDeviceProvisionedCallback =
+ new DeviceProvisionedListener() {
+ @Override
+ public void onUserSetupChanged() {
+ if (mDeviceProvisionedController.isCurrentUserSetup()) {
+ internalConnectToCurrentUser();
+ }
+ }
+
+ @Override
+ public void onUserSwitched() {
+ mConnectionBackoffAttempts = 0;
+ internalConnectToCurrentUser();
+ }
+ };
+
+ // This is the death handler for the binder from the launcher service
+ private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
+ = this::startConnectionToCurrentUser;
+
+ public OverviewProxyService(Context context) {
+ mContext = context;
+ mHandler = new Handler();
+ mConnectionBackoffAttempts = 0;
+ mLauncherComponentName = ComponentName
+ .unflattenFromString(context.getString(R.string.config_overviewServiceComponent));
+ mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
+
+ // Listen for the package update changes.
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addDataScheme("package");
+ filter.addDataSchemeSpecificPart(mLauncherComponentName.getPackageName(),
+ PatternMatcher.PATTERN_LITERAL);
+ mContext.registerReceiver(mLauncherAddedReceiver, filter);
+ }
+
+ public void startConnectionToCurrentUser() {
+ if (mHandler.getLooper() != Looper.myLooper()) {
+ mHandler.post(mConnectionRunnable);
+ } else {
+ internalConnectToCurrentUser();
+ }
+ }
+
+ private void internalConnectToCurrentUser() {
+ disconnectFromLauncherService();
+
+ // If user has not setup yet or already connected, do not try to connect
+ if (!mDeviceProvisionedController.isCurrentUserSetup()) {
+ return;
+ }
+ mHandler.removeCallbacks(mConnectionRunnable);
+ Intent launcherServiceIntent = new Intent();
+ launcherServiceIntent.setComponent(mLauncherComponentName);
+ boolean bound = mContext.bindServiceAsUser(launcherServiceIntent,
+ mOverviewServiceConnection, Context.BIND_AUTO_CREATE,
+ UserHandle.getUserHandleForUid(mDeviceProvisionedController.getCurrentUser()));
+ if (!bound) {
+ // Retry after exponential backoff timeout
+ final long timeoutMs = (long) Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts);
+ mHandler.postDelayed(mConnectionRunnable, timeoutMs);
+ mConnectionBackoffAttempts++;
+ }
+ }
+
+ @Override
+ public void addCallback(OverviewProxyListener listener) {
+ mConnectionCallbacks.add(listener);
+ listener.onConnectionChanged(mOverviewProxy != null);
+ }
+
+ @Override
+ public void removeCallback(OverviewProxyListener listener) {
+ mConnectionCallbacks.remove(listener);
+ }
+
+ public IOverviewProxy getProxy() {
+ return mOverviewProxy;
+ }
+
+ private void disconnectFromLauncherService() {
+ if (mOverviewProxy != null) {
+ mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
+ mContext.unbindService(mOverviewServiceConnection);
+ mOverviewProxy = null;
+ notifyConnectionChanged();
+ }
+ }
+
+ private void notifyConnectionChanged() {
+ for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+ mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null);
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(TAG + " state:");
+ pw.print(" mConnectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts);
+ pw.print(" isCurrentUserSetup="); pw.println(mDeviceProvisionedController
+ .isCurrentUserSetup());
+ pw.print(" isConnected="); pw.println(mOverviewProxy != null);
+ }
+
+ public interface OverviewProxyListener {
+ void onConnectionChanged(boolean isConnected);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenStatePreventingAdapter.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenStatePreventingAdapter.java
index 5d0a9d70e99d..03b0082b96e7 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenStatePreventingAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenStatePreventingAdapter.java
@@ -33,8 +33,10 @@ public class DozeScreenStatePreventingAdapter extends DozeMachine.Service.Delega
@Override
public void setDozeScreenState(int state) {
- if (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND) {
+ if (state == Display.STATE_DOZE) {
state = Display.STATE_ON;
+ } else if (state == Display.STATE_DOZE_SUSPEND) {
+ state = Display.STATE_ON_SUSPEND;
}
super.setDozeScreenState(state);
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 98b110619a1c..6650cc634700 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -92,6 +92,7 @@ public class DozeService extends DreamService
@Override
protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) {
+ super.dumpOnHandler(fd, pw, args);
if (mDozeMachine != null) {
mDozeMachine.dump(pw);
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index d82f9cd44e4a..00e8b1a44e47 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -80,7 +80,7 @@ import com.android.systemui.Interpolators;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.statusbar.phone.ScrimController;
-import com.android.systemui.volume.VolumeDialogMotion.LogAccelerateInterpolator;
+import com.android.systemui.volume.SystemUIInterpolators.LogAccelerateInterpolator;
import java.util.ArrayList;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
new file mode 100644
index 000000000000..03018f7d8778
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.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.systemui.keyguard;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.icu.text.DateFormat;
+import android.icu.text.DisplayContext;
+import android.net.Uri;
+import android.os.Handler;
+import android.app.slice.Slice;
+import android.app.slice.SliceProvider;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * Simple Slice provider that shows the current date.
+ */
+public class KeyguardSliceProvider extends SliceProvider {
+
+ public static final String KEYGUARD_SLICE_URI = "content://com.android.systemui.keyguard/main";
+
+ private final Date mCurrentTime = new Date();
+ protected final Uri mSliceUri;
+ private final Handler mHandler;
+ private String mDatePattern;
+ private DateFormat mDateFormat;
+ private String mLastText;
+ private boolean mRegistered;
+ private boolean mRegisteredEveryMinute;
+
+ /**
+ * Receiver responsible for time ticking and updating the date format.
+ */
+ @VisibleForTesting
+ final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_TIME_TICK.equals(action)
+ || Intent.ACTION_DATE_CHANGED.equals(action)
+ || Intent.ACTION_TIME_CHANGED.equals(action)
+ || Intent.ACTION_TIMEZONE_CHANGED.equals(action)
+ || Intent.ACTION_LOCALE_CHANGED.equals(action)) {
+ if (Intent.ACTION_LOCALE_CHANGED.equals(action)
+ || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
+ // need to get a fresh date format
+ mHandler.post(KeyguardSliceProvider.this::cleanDateFormat);
+ }
+ mHandler.post(KeyguardSliceProvider.this::updateClock);
+ }
+ }
+ };
+
+ public KeyguardSliceProvider() {
+ this(new Handler());
+ }
+
+ @VisibleForTesting
+ KeyguardSliceProvider(Handler handler) {
+ mHandler = handler;
+ mSliceUri = Uri.parse(KEYGUARD_SLICE_URI);
+ }
+
+ @Override
+ public Slice onBindSlice(Uri sliceUri) {
+ return new Slice.Builder(sliceUri).addText(mLastText, Slice.HINT_TITLE).build();
+ }
+
+ @Override
+ public boolean onCreate() {
+
+ mDatePattern = getContext().getString(R.string.system_ui_date_pattern);
+
+ registerClockUpdate(false /* everyMinute */);
+ updateClock();
+ return true;
+ }
+
+ protected void registerClockUpdate(boolean everyMinute) {
+ if (mRegistered) {
+ if (mRegisteredEveryMinute == everyMinute) {
+ return;
+ } else {
+ unregisterClockUpdate();
+ }
+ }
+
+ IntentFilter filter = new IntentFilter();
+ if (everyMinute) {
+ filter.addAction(Intent.ACTION_TIME_TICK);
+ }
+ filter.addAction(Intent.ACTION_DATE_CHANGED);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ filter.addAction(Intent.ACTION_LOCALE_CHANGED);
+ getContext().registerReceiver(mIntentReceiver, filter, null /* permission*/,
+ null /* scheduler */);
+ mRegistered = true;
+ mRegisteredEveryMinute = everyMinute;
+ }
+
+ protected void unregisterClockUpdate() {
+ if (!mRegistered) {
+ return;
+ }
+ getContext().unregisterReceiver(mIntentReceiver);
+ mRegistered = false;
+ }
+
+ @VisibleForTesting
+ boolean isRegistered() {
+ return mRegistered;
+ }
+
+ protected void updateClock() {
+ final String text = getFormattedDate();
+ if (!text.equals(mLastText)) {
+ mLastText = text;
+ getContext().getContentResolver().notifyChange(mSliceUri, null /* observer */);
+ }
+ }
+
+ protected String getFormattedDate() {
+ if (mDateFormat == null) {
+ final Locale l = Locale.getDefault();
+ DateFormat format = DateFormat.getInstanceForSkeleton(mDatePattern, l);
+ format.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE);
+ mDateFormat = format;
+ }
+ mCurrentTime.setTime(System.currentTimeMillis());
+ return mDateFormat.format(mCurrentTime);
+ }
+
+ @VisibleForTesting
+ void cleanDateFormat() {
+ mDateFormat = null;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 28adca97b8bf..a35ba9fadab4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -28,6 +28,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlarmManager;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.app.trust.TrustManager;
@@ -1691,6 +1692,8 @@ public class KeyguardViewMediator extends SystemUI {
mUiOffloadThread.submit(() -> {
// If the stream is muted, don't play the sound
if (mAudioManager.isStreamMute(mUiSoundsStreamType)) return;
+ // If DND blocks the sound, don't play the sound
+ if (areSystemSoundsZenModeBlocked(mContext)) return;
int id = mLockSounds.play(soundId,
mLockSoundVolume, mLockSoundVolume, 1/*priortiy*/, 0/*loop*/, 1.0f/*rate*/);
@@ -1702,6 +1705,25 @@ public class KeyguardViewMediator extends SystemUI {
}
}
+ private boolean areSystemSoundsZenModeBlocked(Context context) {
+ int zenMode = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.ZEN_MODE, 0);
+
+ switch (zenMode) {
+ case Settings.Global.ZEN_MODE_NO_INTERRUPTIONS:
+ case Settings.Global.ZEN_MODE_ALARMS:
+ return true;
+ case Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+ final NotificationManager noMan = (NotificationManager) context
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+ return (noMan.getNotificationPolicy().priorityCategories
+ & NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER) == 0;
+ case Settings.Global.ZEN_MODE_OFF:
+ default:
+ return false;
+ }
+ }
+
private void playTrustedSound() {
playSound(mTrustedSoundId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
index 4119ec076dc3..b9e9e0a7f529 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -31,6 +31,7 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
public class WorkLockActivityController {
private static final String TAG = WorkLockActivityController.class.getSimpleName();
@@ -39,15 +40,15 @@ public class WorkLockActivityController {
private final IActivityManager mIam;
public WorkLockActivityController(Context context) {
- this(context, SystemServicesProxy.getInstance(context), ActivityManager.getService());
+ this(context, ActivityManagerWrapper.getInstance(), ActivityManager.getService());
}
@VisibleForTesting
- WorkLockActivityController(Context context, SystemServicesProxy ssp, IActivityManager am) {
+ WorkLockActivityController(Context context, ActivityManagerWrapper am, IActivityManager iAm) {
mContext = context;
- mIam = am;
+ mIam = iAm;
- ssp.registerTaskStackListener(mLockListener);
+ am.registerTaskStackListener(mLockListener);
}
private void startWorkChallengeInTask(int taskId, int userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 7ef0f1539dd6..2963506865ef 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -174,7 +174,7 @@ public class PipManager implements BasePipManager {
} catch (RemoteException e) {
Log.e(TAG, "Failed to register pinned stack listener", e);
}
- SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
mInputConsumerController = new InputConsumerController(mWindowManager);
mMediaController = new PipMediaController(context, mActivityManager);
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 5a91defc42df..eef43d292249 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -47,6 +47,7 @@ import com.android.systemui.R;
import com.android.systemui.pip.BasePipManager;
import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -234,7 +235,7 @@ public class PipManager implements BasePipManager {
mActivityManager = ActivityManager.getService();
mWindowManager = WindowManagerGlobal.getWindowManagerService();
- SystemServicesProxy.getInstance(context).registerTaskStackListener(mTaskStackListener);
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
mContext.registerReceiver(mBroadcastReceiver, intentFilter);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 532ead1f0475..5ffd7859a487 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -338,7 +338,9 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
- mMultiUserSwitch.setVisibility(mExpanded && mMultiUserSwitch.hasMultipleUsers() && !isDemo
+
+ mMultiUserSwitch.setVisibility(mExpanded
+ && UserManager.get(mContext).isUserSwitcherEnabled()
? View.VISIBLE : View.INVISIBLE);
mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index 4c2036141daf..763ffc677bc2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -22,8 +22,7 @@ import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.widget.Switch;
-import com.android.internal.app.NightDisplayController;
-import com.android.internal.logging.MetricsLogger;
+import com.android.internal.app.ColorDisplayController;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSHost;
@@ -31,19 +30,19 @@ import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.qs.tileimpl.QSTileImpl;
public class NightDisplayTile extends QSTileImpl<BooleanState>
- implements NightDisplayController.Callback {
+ implements ColorDisplayController.Callback {
- private NightDisplayController mController;
+ private ColorDisplayController mController;
private boolean mIsListening;
public NightDisplayTile(QSHost host) {
super(host);
- mController = new NightDisplayController(mContext, ActivityManager.getCurrentUser());
+ mController = new ColorDisplayController(mContext, ActivityManager.getCurrentUser());
}
@Override
public boolean isAvailable() {
- return NightDisplayController.isAvailable(mContext);
+ return ColorDisplayController.isAvailable(mContext);
}
@Override
@@ -65,7 +64,7 @@ public class NightDisplayTile extends QSTileImpl<BooleanState>
}
// Make a new controller for the new user.
- mController = new NightDisplayController(mContext, newUserId);
+ mController = new ColorDisplayController(mContext, newUserId);
if (mIsListening) {
mController.setListener(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index c666d572e10a..9aecc686d8aa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -17,7 +17,6 @@
package com.android.systemui.recents;
import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_HOME_KEY;
-import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
import android.app.Activity;
import android.app.ActivityOptions;
@@ -96,7 +95,6 @@ import com.android.systemui.shared.recents.model.TaskStack;
import com.android.systemui.recents.views.RecentsView;
import com.android.systemui.recents.views.SystemBarScrimViews;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.statusbar.phone.StatusBar;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -471,7 +469,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
if (launchState.launchedFromApp) {
Task launchTarget = stack.getLaunchTarget();
int launchTaskIndexInStack = launchTarget != null
- ? stack.indexOfStackTask(launchTarget)
+ ? stack.indexOfTask(launchTarget)
: 0;
MetricsLogger.count(this, "overview_source_app", 1);
// If from an app, track the stack index of the app in the stack (for affiliated tasks)
@@ -517,7 +515,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
// Notify of the config change
Configuration newDeviceConfiguration = Utilities.getAppConfiguration(this);
- int numStackTasks = mRecentsView.getStack().getStackTaskCount();
+ int numStackTasks = mRecentsView.getStack().getTaskCount();
EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */,
mLastConfig.orientation != newDeviceConfiguration.orientation,
mLastConfig.densityDpi != newDeviceConfiguration.densityDpi, numStackTasks > 0));
@@ -826,7 +824,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
loader.loadTasks(loadPlan, loadOpts);
TaskStack stack = loadPlan.getTaskStack();
- int numStackTasks = stack.getStackTaskCount();
+ int numStackTasks = stack.getTaskCount();
boolean showDeferredAnimation = numStackTasks > 0;
if (sendConfigChangedEvent) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index d2326ce2673d..14fda952b7ac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -50,24 +50,4 @@ public class RecentsActivityLaunchState {
launchedViaDragGesture = false;
launchedViaDockGesture = false;
}
-
- /**
- * Returns the task to focus given the current launch state.
- */
- public int getInitialFocusTaskIndex(int numTasks, boolean useGridLayout) {
- RecentsDebugFlags debugFlags = Recents.getDebugFlags();
- RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
- if (launchedFromApp) {
- if (useGridLayout) {
- // If coming from another app to the grid layout, focus the front most task
- return numTasks - 1;
- }
-
- // If coming from another app, focus the next task
- return Math.max(0, numTasks - 2);
- } else {
- // If coming from home, focus the front most task
- return numTasks - 1;
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 0b816b5ff820..3b1b2f9079d5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -25,11 +25,11 @@ import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASO
import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityOptions;
-import android.app.ActivityOptions.OnAnimationStartedListener;
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;
@@ -40,7 +40,6 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.MutableBoolean;
import android.util.Pair;
-import android.view.AppTransitionAnimationSpec;
import android.view.LayoutInflater;
import android.view.ViewConfiguration;
import android.view.WindowManager;
@@ -85,6 +84,7 @@ import com.android.systemui.recents.views.TaskStackView;
import com.android.systemui.recents.views.TaskViewHeader;
import com.android.systemui.recents.views.TaskViewTransform;
import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
+import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -159,7 +159,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
mBackgroundLayoutAlgorithm.update(plan.getTaskStack(), EMPTY_SET, launchState);
VisibilityReport visibilityReport =
mBackgroundLayoutAlgorithm.computeStackVisibilityReport(
- stack.getStackTasks());
+ stack.getTasks());
launchOpts.runningTaskId = runningTaskInfo != null ? runningTaskInfo.id : -1;
launchOpts.numVisibleTasks = visibilityReport.numVisibleTasks;
@@ -200,14 +200,13 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
}
@Override
- public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) {
+ public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) {
// Check this is for the right user
if (!checkCurrentUserId(mContext, false /* debug */)) {
return;
}
- EventBus.getDefault().send(new TaskSnapshotChangedEvent(taskId,
- new ThumbnailData(snapshot)));
+ EventBus.getDefault().send(new TaskSnapshotChangedEvent(taskId, snapshot));
}
}
@@ -221,13 +220,12 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
// recents. In this case, we defer the toggle state until then and apply it immediately after.
private static boolean mToggleFollowingTransitionStart = true;
- private ActivityOptions.OnAnimationStartedListener mResetToggleFlagListener =
- new OnAnimationStartedListener() {
- @Override
- public void onAnimationStarted() {
- setWaitingForTransitionStart(false);
- }
- };
+ private Runnable mResetToggleFlagListener = new Runnable() {
+ @Override
+ public void run() {
+ setWaitingForTransitionStart(false);
+ }
+ };
protected Context mContext;
protected Handler mHandler;
@@ -270,8 +268,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
// Register the task stack listener
mTaskStackListener = new TaskStackListenerImpl();
- SystemServicesProxy ssp = Recents.getSystemServices();
- ssp.registerTaskStackListener(mTaskStackListener);
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
// Initialize the static configuration resources
mDummyStackView = new TaskStackView(mContext);
@@ -535,7 +532,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
boolean isRunningTaskInHomeStack =
runningTask.configuration.windowConfiguration.getActivityType()
== ACTIVITY_TYPE_HOME;
- ArrayList<Task> tasks = focusedStack.getStackTasks();
+ ArrayList<Task> tasks = focusedStack.getTasks();
Task toTask = null;
ActivityOptions launchOpts = null;
int taskCount = tasks.size();
@@ -565,7 +562,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
}
// Launch the task
- ActivityManagerWrapper.getInstance().startActivityFromRecents(toTask.key, launchOpts,
+ ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(toTask.key, launchOpts,
null /* resultCallback */, null /* resultCallbackHandler */);
}
@@ -591,7 +588,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) return;
// Find the task in the recents list
- ArrayList<Task> tasks = focusedStack.getStackTasks();
+ ArrayList<Task> tasks = focusedStack.getTasks();
Task toTask = null;
ActivityOptions launchOpts = null;
int taskCount = tasks.size();
@@ -635,7 +632,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1);
// Launch the task
- ActivityManagerWrapper.getInstance().startActivityFromRecents(toTask.key, launchOpts,
+ ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(toTask.key, launchOpts,
null /* resultListener */, null /* resultCallbackHandler */);
}
@@ -736,7 +733,10 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
// However, the window bounds include the insets, so we need to subtract them here to make
// them identical.
if (ssp.hasDockedTask()) {
- windowRect.bottom -= systemInsets.bottom;
+ if (systemInsets.bottom < windowRect.height()) {
+ // Only apply inset if it isn't going to cause the rect height to go negative.
+ windowRect.bottom -= systemInsets.bottom;
+ }
systemInsets.bottom = 0;
}
calculateWindowStableInsets(systemInsets, windowRect, displayRect);
@@ -876,12 +876,12 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
RectF toTaskRect = toTransform.rect;
AppTransitionAnimationSpecsFuture future = new AppTransitionAnimationSpecsFuture(mHandler) {
@Override
- public List<AppTransitionAnimationSpec> composeSpecs() {
+ public List<AppTransitionAnimationSpecCompat> composeSpecs() {
Rect rect = new Rect();
toTaskRect.round(rect);
- GraphicBuffer thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform);
- return Lists.newArrayList(new AppTransitionAnimationSpec(toTask.key.id, thumbnail,
- rect));
+ Bitmap thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform);
+ return Lists.newArrayList(new AppTransitionAnimationSpecCompat(toTask.key.id,
+ thumbnail, rect));
}
};
@@ -904,7 +904,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
runningTaskOut.copyFrom(launchTask);
} else {
// If no task is specified or we can not find the task just use the front most one
- launchTask = stack.getStackFrontMostTask();
+ launchTask = stack.getFrontMostTask();
runningTaskOut.copyFrom(launchTask);
}
@@ -919,7 +919,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
/**
* Draws the header of a task used for the window animation into a bitmap.
*/
- private GraphicBuffer drawThumbnailTransitionBitmap(Task toTask,
+ private Bitmap drawThumbnailTransitionBitmap(Task toTask,
TaskViewTransform toTransform) {
SystemServicesProxy ssp = Recents.getSystemServices();
int width = (int) toTransform.rect.width();
@@ -929,7 +929,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
boolean disabledInSafeMode = !toTask.isSystemApp && ssp.isInSafeMode();
mHeaderBar.onTaskViewSizeChanged(width, height);
if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
- return RecentsTransition.drawViewIntoGraphicBuffer(width, mTaskBarHeight,
+ return RecentsTransition.drawViewIntoHardwareBitmap(width, mTaskBarHeight,
null, 1f, 0xFFff0000);
} else {
// Workaround for b/27815919, reset the callback so that we do not trigger an
@@ -942,7 +942,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
disabledInSafeMode);
mHeaderBar.onTaskDataLoaded();
mHeaderBar.setDimAlpha(toTransform.dimAlpha);
- return RecentsTransition.drawViewIntoGraphicBuffer(width, mTaskBarHeight,
+ return RecentsTransition.drawViewIntoHardwareBitmap(width, mTaskBarHeight,
mHeaderBar, 1f, 0);
}
}
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 a436e177cb51..d89bab758bd0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -114,7 +114,6 @@ public class SystemServicesProxy {
UserManager mUm;
Display mDisplay;
String mRecentsPackage;
- private TaskStackChangeListeners mTaskStackChangeListeners;
private int mCurrentUserId;
boolean mIsSafeMode;
@@ -156,7 +155,6 @@ public class SystemServicesProxy {
mRecentsPackage = context.getPackageName();
mIsSafeMode = mPm.isSafeMode();
mCurrentUserId = mAm.getCurrentUser();
- mTaskStackChangeListeners = new TaskStackChangeListeners(Looper.getMainLooper());
// Get the dummy thumbnail width/heights
Resources res = context.getResources();
@@ -208,6 +206,8 @@ public class SystemServicesProxy {
*
* @param isHomeStackVisible if provided, will return whether the home stack is visible
* regardless of the recents visibility
+ *
+ * TODO(winsonc): Refactor this check to just use the recents activity lifecycle
*/
public boolean isRecentsActivityVisible(MutableBoolean isHomeStackVisible) {
if (mIam == null) return false;
@@ -222,13 +222,13 @@ public class SystemServicesProxy {
final WindowConfiguration winConfig = stackInfo.configuration.windowConfiguration;
final int activityType = winConfig.getActivityType();
final int windowingMode = winConfig.getWindowingMode();
- if (activityType == ACTIVITY_TYPE_HOME) {
+ if (homeStackInfo == null && activityType == ACTIVITY_TYPE_HOME) {
homeStackInfo = stackInfo;
- } else if (activityType == ACTIVITY_TYPE_STANDARD
+ } else if (fullscreenStackInfo == null && activityType == ACTIVITY_TYPE_STANDARD
&& (windowingMode == WINDOWING_MODE_FULLSCREEN
|| windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)) {
fullscreenStackInfo = stackInfo;
- } else if (activityType == ACTIVITY_TYPE_RECENTS) {
+ } else if (recentsStackInfo == null && activityType == ACTIVITY_TYPE_RECENTS) {
recentsStackInfo = stackInfo;
}
}
@@ -492,18 +492,6 @@ public class SystemServicesProxy {
}
}
- /**
- * Registers a task stack listener with the system.
- * This should be called on the main thread.
- */
- public void registerTaskStackListener(SysUiTaskStackChangeListener listener) {
- if (mIam == null) return;
-
- synchronized (mTaskStackChangeListeners) {
- mTaskStackChangeListeners.addListener(mIam, listener);
- }
- }
-
public void endProlongedAnimations() {
if (mWm == null) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionComposer.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionComposer.java
index 99390ecfe08c..1c47430106e8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionComposer.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionComposer.java
@@ -23,14 +23,15 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECOND
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.content.Context;
+import android.graphics.Bitmap;
import android.graphics.GraphicBuffer;
import android.graphics.Rect;
import android.util.Log;
-import android.view.AppTransitionAnimationSpec;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
import com.android.systemui.shared.recents.view.RecentsTransition;
import java.util.ArrayList;
@@ -54,9 +55,9 @@ public class RecentsTransitionComposer {
/**
* Composes a single animation spec for the given {@link TaskView}
*/
- private static AppTransitionAnimationSpec composeAnimationSpec(TaskStackView stackView,
+ private static AppTransitionAnimationSpecCompat composeAnimationSpec(TaskStackView stackView,
TaskView taskView, TaskViewTransform transform, boolean addHeaderBitmap) {
- GraphicBuffer b = null;
+ Bitmap b = null;
if (addHeaderBitmap) {
b = composeHeaderBitmap(taskView, transform);
if (b == null) {
@@ -71,28 +72,28 @@ public class RecentsTransitionComposer {
// force the task thumbnail to full stackView height immediately causing the transition
// jarring.
if (!Recents.getConfiguration().isLowRamDevice && taskView.getTask() !=
- stackView.getStack().getStackFrontMostTask()) {
+ stackView.getStack().getFrontMostTask()) {
taskRect.bottom = taskRect.top + stackView.getMeasuredHeight();
}
- return new AppTransitionAnimationSpec(taskView.getTask().key.id, b, taskRect);
+ return new AppTransitionAnimationSpecCompat(taskView.getTask().key.id, b, taskRect);
}
/**
* Composes the transition spec when docking a task, which includes a full task bitmap.
*/
- public List<AppTransitionAnimationSpec> composeDockAnimationSpec(TaskView taskView,
+ public List<AppTransitionAnimationSpecCompat> composeDockAnimationSpec(TaskView taskView,
Rect bounds) {
mTmpTransform.fillIn(taskView);
Task task = taskView.getTask();
- GraphicBuffer buffer = RecentsTransitionComposer.composeTaskBitmap(taskView, mTmpTransform);
- return Collections.singletonList(new AppTransitionAnimationSpec(task.key.id, buffer,
+ Bitmap buffer = RecentsTransitionComposer.composeTaskBitmap(taskView, mTmpTransform);
+ return Collections.singletonList(new AppTransitionAnimationSpecCompat(task.key.id, buffer,
bounds));
}
/**
* Composes the animation specs for all the tasks in the target stack.
*/
- public List<AppTransitionAnimationSpec> composeAnimationSpecs(final Task task,
+ public List<AppTransitionAnimationSpecCompat> composeAnimationSpecs(final Task task,
final TaskStackView stackView, int windowingMode, int activityType, Rect windowRect) {
// Calculate the offscreen task rect (for tasks that are not backed by views)
TaskView taskView = stackView.getChildViewForTask(task);
@@ -110,13 +111,13 @@ public class RecentsTransitionComposer {
|| windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
|| activityType == ACTIVITY_TYPE_ASSISTANT
|| windowingMode == WINDOWING_MODE_UNDEFINED) {
- List<AppTransitionAnimationSpec> specs = new ArrayList<>();
+ List<AppTransitionAnimationSpecCompat> specs = new ArrayList<>();
if (taskView == null) {
specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect));
} else {
mTmpTransform.fillIn(taskView);
stackLayout.transformToScreenCoordinates(mTmpTransform, windowRect);
- AppTransitionAnimationSpec spec = composeAnimationSpec(stackView, taskView,
+ AppTransitionAnimationSpecCompat spec = composeAnimationSpec(stackView, taskView,
mTmpTransform, true /* addHeaderBitmap */);
if (spec != null) {
specs.add(spec);
@@ -130,12 +131,12 @@ public class RecentsTransitionComposer {
/**
* Composes a single animation spec for the given {@link Task}
*/
- private static AppTransitionAnimationSpec composeOffscreenAnimationSpec(Task task,
+ private static AppTransitionAnimationSpecCompat composeOffscreenAnimationSpec(Task task,
Rect taskRect) {
- return new AppTransitionAnimationSpec(task.key.id, null, taskRect);
+ return new AppTransitionAnimationSpecCompat(task.key.id, null, taskRect);
}
- public static GraphicBuffer composeTaskBitmap(TaskView taskView, TaskViewTransform transform) {
+ public static Bitmap composeTaskBitmap(TaskView taskView, TaskViewTransform transform) {
float scale = transform.scale;
int fromWidth = (int) (transform.rect.width() * scale);
int fromHeight = (int) (transform.rect.height() * scale);
@@ -143,19 +144,19 @@ public class RecentsTransitionComposer {
Log.e(TAG, "Could not compose thumbnail for task: " + taskView.getTask() +
" at transform: " + transform);
- return RecentsTransition.drawViewIntoGraphicBuffer(1, 1, null, 1f, 0x00ffffff);
+ return RecentsTransition.drawViewIntoHardwareBitmap(1, 1, null, 1f, 0x00ffffff);
} else {
if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
- return RecentsTransition.drawViewIntoGraphicBuffer(fromWidth, fromHeight, null, 1f,
+ return RecentsTransition.drawViewIntoHardwareBitmap(fromWidth, fromHeight, null, 1f,
0xFFff0000);
} else {
- return RecentsTransition.drawViewIntoGraphicBuffer(fromWidth, fromHeight, taskView,
+ return RecentsTransition.drawViewIntoHardwareBitmap(fromWidth, fromHeight, taskView,
scale, 0);
}
}
}
- private static GraphicBuffer composeHeaderBitmap(TaskView taskView,
+ private static Bitmap composeHeaderBitmap(TaskView taskView,
TaskViewTransform transform) {
float scale = transform.scale;
int headerWidth = (int) (transform.rect.width());
@@ -165,10 +166,10 @@ public class RecentsTransitionComposer {
}
if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
- return RecentsTransition.drawViewIntoGraphicBuffer(headerWidth, headerHeight, null, 1f,
+ return RecentsTransition.drawViewIntoHardwareBitmap(headerWidth, headerHeight, null, 1f,
0xFFff0000);
} else {
- return RecentsTransition.drawViewIntoGraphicBuffer(headerWidth, headerHeight,
+ return RecentsTransition.drawViewIntoHardwareBitmap(headerWidth, headerHeight,
taskView.mHeaderView, scale, 0);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index b82f15eff4b8..1440fc168cc6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -16,7 +16,6 @@
package com.android.systemui.recents.views;
-import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_HOME_KEY;
import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
import android.animation.ValueAnimator;
@@ -90,6 +89,7 @@ import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.TaskStack;
+import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -296,7 +296,7 @@ public class RecentsView extends FrameLayout {
* @return True if it changed.
*/
private boolean updateBusyness() {
- final int taskCount = mTaskStackView.getStack().getStackTaskCount();
+ final int taskCount = mTaskStackView.getStack().getTaskCount();
final float busyness = Math.min(taskCount, BUSY_RECENTS_TASK_COUNT)
/ (float) BUSY_RECENTS_TASK_COUNT;
if (mBusynessFactor == busyness) {
@@ -611,27 +611,23 @@ public class RecentsView extends FrameLayout {
// Dock the task and launch it
SystemServicesProxy ssp = Recents.getSystemServices();
if (ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode)) {
- final OnAnimationStartedListener startedListener =
- new OnAnimationStartedListener() {
- @Override
- public void onAnimationStarted() {
- EventBus.getDefault().send(new DockedFirstAnimationFrameEvent());
- // Remove the task and don't bother relaying out, as all the tasks will be
- // relaid out when the stack changes on the multiwindow change event
- getStack().removeTask(event.task, null, true /* fromDockGesture */);
- }
+ final Runnable animStartedListener = () -> {
+ EventBus.getDefault().send(new DockedFirstAnimationFrameEvent());
+ // Remove the task and don't bother relaying out, as all the tasks will be
+ // relaid out when the stack changes on the multiwindow change event
+ getStack().removeTask(event.task, null, true /* fromDockGesture */);
};
final Rect taskRect = getTaskRect(event.taskView);
AppTransitionAnimationSpecsFuture future = new AppTransitionAnimationSpecsFuture(
getHandler()) {
@Override
- public List<AppTransitionAnimationSpec> composeSpecs() {
+ public List<AppTransitionAnimationSpecCompat> composeSpecs() {
return mTransitionHelper.composeDockAnimationSpec(event.taskView, taskRect);
}
};
ssp.overridePendingAppTransitionMultiThumbFuture(future.getFuture(),
- RecentsTransition.wrapStartedListener(getHandler(), startedListener),
+ RecentsTransition.wrapStartedListener(getHandler(), animStartedListener),
true /* scaleUp */);
MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP,
@@ -928,7 +924,7 @@ public class RecentsView extends FrameLayout {
final TaskStackView stackView, final TaskView taskView,
final boolean screenPinningRequested, final int windowingMode, final int activityType) {
- final ActivityOptions.OnAnimationStartedListener animStartedListener;
+ final Runnable animStartedListener;
final AppTransitionAnimationSpecsFuture transitionFuture;
if (taskView != null) {
@@ -937,16 +933,16 @@ public class RecentsView extends FrameLayout {
final Rect windowRect = Recents.getSystemServices().getWindowRect();
transitionFuture = new AppTransitionAnimationSpecsFuture(stackView.getHandler()) {
@Override
- public List<AppTransitionAnimationSpec> composeSpecs() {
+ public List<AppTransitionAnimationSpecCompat> composeSpecs() {
return mTransitionHelper.composeAnimationSpecs(task, stackView, windowingMode,
activityType, windowRect);
}
};
- animStartedListener = new OnAnimationStartedListener() {
+ animStartedListener = new Runnable() {
private boolean mHandled;
@Override
- public void onAnimationStarted() {
+ public void run() {
if (mHandled) {
return;
}
@@ -975,11 +971,11 @@ public class RecentsView extends FrameLayout {
} else {
// This is only the case if the task is not on screen (scrolled offscreen for example)
transitionFuture = null;
- animStartedListener = new OnAnimationStartedListener() {
+ animStartedListener = new Runnable() {
private boolean mHandled;
@Override
- public void onAnimationStarted() {
+ public void run() {
if (mHandled) {
return;
}
@@ -1027,12 +1023,12 @@ public class RecentsView extends FrameLayout {
private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView,
ActivityOptions opts, AppTransitionAnimationSpecsFuture transitionFuture,
int windowingMode, int activityType) {
- ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key, opts, windowingMode,
- activityType, succeeded -> {
+ ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(task.key, opts,
+ windowingMode, activityType, succeeded -> {
if (succeeded) {
// Keep track of the index of the task launch
int taskIndexFromFront = 0;
- int taskIndex = stack.indexOfStackTask(task);
+ int taskIndex = stack.indexOfTask(task);
if (taskIndex > -1) {
taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 0cfdbdecdf2a..5c69ae3915b3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -40,7 +40,6 @@ import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragStartInitializeDropTargetsEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.TaskStack;
import java.util.ArrayList;
@@ -106,7 +105,7 @@ public class RecentsViewTouchHandler {
/** Handles touch events once we have intercepted them */
public boolean onTouchEvent(MotionEvent ev) {
handleTouchEvent(ev);
- if (ev.getAction() == MotionEvent.ACTION_UP && mRv.getStack().getStackTaskCount() == 0) {
+ if (ev.getAction() == MotionEvent.ACTION_UP && mRv.getStack().getTaskCount() == 0) {
EventBus.getDefault().send(new HideRecentsEvent(false, true));
}
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 7827c590ed81..170e39dfc360 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -154,7 +154,7 @@ public class SystemBarScrimViews {
public final void onBusEvent(MultiWindowStateChangedEvent event) {
mHasDockedTasks = event.inMultiWindow;
- animateScrimToCurrentNavBarState(event.stack.getStackTaskCount() > 0);
+ animateScrimToCurrentNavBarState(event.stack.getTaskCount() > 0);
}
public final void onBusEvent(final DragEndEvent event) {
@@ -166,7 +166,7 @@ public class SystemBarScrimViews {
public final void onBusEvent(final DragEndCancelledEvent event) {
// Restore the scrims to the normal state
- animateScrimToCurrentNavBarState(event.stack.getStackTaskCount() > 0);
+ animateScrimToCurrentNavBarState(event.stack.getTaskCount() > 0);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index 26db26fa3c36..67d09787e9f3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -449,7 +449,7 @@ public class TaskStackAnimationHelper {
// Get the current set of task transforms
int taskViewCount = mStackView.getTaskViews().size();
- ArrayList<Task> stackTasks = stack.getStackTasks();
+ ArrayList<Task> stackTasks = stack.getTasks();
mStackView.getCurrentTaskTransforms(stackTasks, mTmpCurrentTaskTransforms);
// Pick up the newly visible views after the scroll
@@ -541,7 +541,7 @@ public class TaskStackAnimationHelper {
TaskStackViewScroller stackScroller = mStackView.getScroller();
// Get the current set of task transforms
- ArrayList<Task> stackTasks = newStack.getStackTasks();
+ ArrayList<Task> stackTasks = newStack.getTasks();
mStackView.getCurrentTaskTransforms(stackTasks, mTmpCurrentTaskTransforms);
// Update the stack
@@ -563,7 +563,7 @@ public class TaskStackAnimationHelper {
false /* ignoreTaskOverrides */, mTmpFinalTaskTransforms);
// Hide the front most task view until the scroll is complete
- Task frontMostTask = newStack.getStackFrontMostTask();
+ Task frontMostTask = newStack.getFrontMostTask();
final TaskView frontMostTaskView = mStackView.getChildViewForTask(frontMostTask);
final TaskViewTransform frontMostTransform = mTmpFinalTaskTransforms.get(
stackTasks.indexOf(frontMostTask));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index acb058cee716..600da0410fc4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -438,7 +438,7 @@ public class TaskStackLayoutAlgorithm {
mTaskIndexMap.clear();
// Return early if we have no tasks
- ArrayList<Task> tasks = stack.getStackTasks();
+ ArrayList<Task> tasks = stack.getTasks();
if (tasks.isEmpty()) {
mFrontMostTaskP = 0;
mMinScrollP = mMaxScrollP = mInitialScrollP = 0;
@@ -468,7 +468,7 @@ public class TaskStackLayoutAlgorithm {
// Calculate the min/max/initial scroll
Task launchTask = stack.getLaunchTarget();
int launchTaskIndex = launchTask != null
- ? stack.indexOfStackTask(launchTask)
+ ? stack.indexOfTask(launchTask)
: mNumStackTasks - 1;
if (getInitialFocusState() == STATE_FOCUSED) {
int maxBottomOffset = mStackBottomOffset + mTaskRect.height();
@@ -557,7 +557,7 @@ public class TaskStackLayoutAlgorithm {
}
mUnfocusedRange.offset(0f);
- List<Task> tasks = stack.getStackTasks();
+ List<Task> tasks = stack.getTasks();
int taskCount = tasks.size();
for (int i = taskCount - 1; i >= 0; i--) {
int indexFromFront = taskCount - i - 1;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 428113a2a065..1197501268a6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -535,7 +535,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
*/
void bindVisibleTaskViews(float targetStackScroll, boolean ignoreTaskOverrides) {
// Get all the task transforms
- ArrayList<Task> tasks = mStack.getStackTasks();
+ ArrayList<Task> tasks = mStack.getTasks();
int[] visibleTaskRange = computeVisibleTaskTransforms(mCurrentTaskTransforms, tasks,
mStackScroller.getStackScroll(), targetStackScroll, mIgnoreTasks,
ignoreTaskOverrides);
@@ -557,7 +557,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// It is possible for the set of lingering TaskViews to differ from the stack if the
// stack was updated before the relayout. If the task view is no longer in the stack,
// then just return it back to the view pool.
- int taskIndex = mStack.indexOfStackTask(task);
+ int taskIndex = mStack.indexOfTask(task);
TaskViewTransform transform = null;
if (taskIndex != -1) {
transform = mCurrentTaskTransforms.get(taskIndex);
@@ -601,7 +601,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
} else {
// Reattach it in the right z order
- final int taskIndex = mStack.indexOfStackTask(task);
+ final int taskIndex = mStack.indexOfTask(task);
final int insertIndex = findTaskViewInsertIndex(task, taskIndex);
if (insertIndex != getTaskViews().indexOf(tv)){
detachViewFromParent(tv);
@@ -663,7 +663,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
continue;
}
- int taskIndex = mStack.indexOfStackTask(task);
+ int taskIndex = mStack.indexOfTask(task);
TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex);
if (animationOverrides != null && animationOverrides.containsKey(task)) {
animation = animationOverrides.get(task);
@@ -866,7 +866,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
int newFocusedTaskIndex = mStack.getTaskCount() > 0 ?
Utilities.clamp(focusTaskIndex, 0, mStack.getTaskCount() - 1) : -1;
final Task newFocusedTask = (newFocusedTaskIndex != -1) ?
- mStack.getStackTasks().get(newFocusedTaskIndex) : null;
+ mStack.getTasks().get(newFocusedTaskIndex) : null;
// Reset the last focused task state if changed
if (mFocusedTask != null) {
@@ -953,10 +953,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated,
boolean cancelWindowAnimations, int timerIndicatorDuration) {
Task focusedTask = getFocusedTask();
- int newIndex = mStack.indexOfStackTask(focusedTask);
+ int newIndex = mStack.indexOfTask(focusedTask);
if (focusedTask != null) {
if (stackTasksOnly) {
- List<Task> tasks = mStack.getStackTasks();
+ List<Task> tasks = mStack.getTasks();
// Try the next task if it is a stack task
int tmpNewIndex = newIndex + (forward ? -1 : 1);
if (0 <= tmpNewIndex && tmpNewIndex < tasks.size()) {
@@ -971,7 +971,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
} else {
// We don't have a focused task
float stackScroll = mStackScroller.getStackScroll();
- ArrayList<Task> tasks = mStack.getStackTasks();
+ ArrayList<Task> tasks = mStack.getTasks();
int taskCount = tasks.size();
if (useGridLayout()) {
// For the grid layout, we directly set focus to the most recently used task
@@ -1060,8 +1060,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
if (taskViewCount > 0) {
TaskView backMostTask = taskViews.get(0);
TaskView frontMostTask = taskViews.get(taskViewCount - 1);
- event.setFromIndex(mStack.indexOfStackTask(backMostTask.getTask()));
- event.setToIndex(mStack.indexOfStackTask(frontMostTask.getTask()));
+ event.setFromIndex(mStack.indexOfTask(backMostTask.getTask()));
+ event.setToIndex(mStack.indexOfTask(frontMostTask.getTask()));
event.setContentDescription(frontMostTask.getTask().title);
}
event.setItemCount(mStack.getTaskCount());
@@ -1080,7 +1080,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// Find the accessibility focused task
Task focusedTask = getAccessibilityFocusedTask();
info.setScrollable(true);
- int focusedTaskIndex = mStack.indexOfStackTask(focusedTask);
+ int focusedTaskIndex = mStack.indexOfTask(focusedTask);
if (focusedTaskIndex > 0 || !mStackActionButtonVisible) {
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
}
@@ -1101,7 +1101,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
return true;
}
Task focusedTask = getAccessibilityFocusedTask();
- int taskIndex = mStack.indexOfStackTask(focusedTask);
+ int taskIndex = mStack.indexOfTask(focusedTask);
if (0 <= taskIndex && taskIndex < mStack.getTaskCount()) {
switch (action) {
case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
@@ -1157,7 +1157,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
* updateLayoutForStack() is called first.
*/
public TaskStackLayoutAlgorithm.VisibilityReport computeStackVisibilityReport() {
- return mLayoutAlgorithm.computeStackVisibilityReport(mStack.getStackTasks());
+ return mLayoutAlgorithm.computeStackVisibilityReport(mStack.getTasks());
}
/**
@@ -1328,10 +1328,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// We set the initial focused task view iff the following conditions are satisfied:
// 1. Recents is showing task views in stack layout.
// 2. Recents is launched with ALT + TAB.
- boolean setFocusOnFirstLayout = !useGridLayout() ||
- Recents.getConfiguration().getLaunchState().launchedWithAltTab;
+ boolean setFocusOnFirstLayout = !useGridLayout() || launchState.launchedWithAltTab;
if (setFocusOnFirstLayout) {
- int focusedTaskIndex = launchState.getInitialFocusTaskIndex(mStack.getTaskCount(),
+ int focusedTaskIndex = getInitialFocusTaskIndex(launchState, mStack.getTaskCount(),
useGridLayout());
if (focusedTaskIndex != -1) {
setFocusedTask(focusedTaskIndex, false /* scrollToTask */,
@@ -1502,7 +1501,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
@Override
public void onPickUpViewFromPool(TaskView tv, Task task, boolean isNewView) {
// Find the index where this task should be placed in the stack
- int taskIndex = mStack.indexOfStackTask(task);
+ int taskIndex = mStack.indexOfTask(task);
int insertIndex = findTaskViewInsertIndex(task, taskIndex);
// Add/attach the view to the hierarchy
@@ -1545,7 +1544,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
// Restore the action button visibility if it is the front most task view
- if (mScreenPinningEnabled && tv.getTask() == mStack.getStackFrontMostTask()) {
+ if (mScreenPinningEnabled && tv.getTask() == mStack.getFrontMostTask()) {
tv.showActionButton(false /* fadeIn */, 0 /* fadeInDuration */);
}
}
@@ -1669,7 +1668,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
event.packageName, event.userId);
// For other tasks, just remove them directly if they no longer exist
- ArrayList<Task> tasks = mStack.getStackTasks();
+ ArrayList<Task> tasks = mStack.getTasks();
for (int i = tasks.size() - 1; i >= 0; i--) {
final Task t = tasks.get(i);
if (removedComponents.contains(t.key.getComponent())) {
@@ -1692,7 +1691,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
public final void onBusEvent(LaunchMostRecentTaskRequestEvent event) {
if (mStack.getTaskCount() > 0) {
- Task mostRecentTask = mStack.getStackFrontMostTask();
+ Task mostRecentTask = mStack.getFrontMostTask();
launchTask(mostRecentTask);
}
}
@@ -1786,7 +1785,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
public final void onBusEvent(final DismissAllTaskViewsEvent event) {
// Keep track of the tasks which will have their data removed
- ArrayList<Task> tasks = new ArrayList<>(mStack.getStackTasks());
+ ArrayList<Task> tasks = new ArrayList<>(mStack.getTasks());
mAnimationHelper.startDeleteAllTasksAnimation(
getTaskViews(), useGridLayout(), event.getAnimationTrigger());
event.addPostAnimationCallback(new Runnable() {
@@ -1854,7 +1853,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
public final void onBusEvent(NavigateTaskViewEvent event) {
if (useGridLayout()) {
final int taskCount = mStack.getTaskCount();
- final int currentIndex = mStack.indexOfStackTask(getFocusedTask());
+ final int currentIndex = mStack.indexOfTask(getFocusedTask());
final int nextIndex = mLayoutAlgorithm.mTaskGridLayoutAlgorithm.navigateFocus(taskCount,
currentIndex, event.direction);
setFocusedTask(nextIndex, false, true);
@@ -2000,7 +1999,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
if (mFocusedTask != null) {
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
- setFocusedTask(mStack.indexOfStackTask(mFocusedTask),
+ setFocusedTask(mStack.indexOfTask(mFocusedTask),
false /* scrollToTask */, launchState.launchedWithAltTab);
TaskView focusedTaskView = getChildViewForTask(mFocusedTask);
if (mTouchExplorationEnabled && focusedTaskView != null) {
@@ -2131,7 +2130,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
Task tvTask = taskViews.get(i).getTask();
if (tvTask == task) {
foundTaskView = true;
- } else if (taskIndex < mStack.indexOfStackTask(tvTask)) {
+ } else if (taskIndex < mStack.indexOfTask(tvTask)) {
if (foundTaskView) {
return i - 1;
} else {
@@ -2201,6 +2200,25 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
/**
+ * Returns the task to focus given the current launch state.
+ */
+ private int getInitialFocusTaskIndex(RecentsActivityLaunchState launchState, int numTasks,
+ boolean useGridLayout) {
+ if (launchState.launchedFromApp) {
+ if (useGridLayout) {
+ // If coming from another app to the grid layout, focus the front most task
+ return numTasks - 1;
+ }
+
+ // If coming from another app, focus the next task
+ return Math.max(0, numTasks - 2);
+ } else {
+ // If coming from home, focus the front most task
+ return numTasks - 1;
+ }
+ }
+
+ /**
* Updates {@param transforms} to be the same size as {@param tasks}.
*/
private void matchTaskListSize(List<Task> tasks, List<TaskViewTransform> transforms) {
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 b9ca2483f3be..bfaa8cdb8e27 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -446,7 +446,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
TaskView tv = (TaskView) v;
Task task = tv.getTask();
return !mSwipeHelperAnimations.containsKey(v) &&
- (mSv.getStack().indexOfStackTask(task) != -1);
+ (mSv.getStack().indexOfTask(task) != -1);
}
/**
@@ -476,7 +476,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
mSv.addIgnoreTask(tv.getTask());
// Determine if we are animating the other tasks while dismissing this task
- mCurrentTasks = new ArrayList<Task>(mSv.getStack().getStackTasks());
+ mCurrentTasks = new ArrayList<Task>(mSv.getStack().getTasks());
MutableBoolean isFrontMostTask = new MutableBoolean(false);
Task anchorTask = mSv.findAnchorTask(mCurrentTasks, isFrontMostTask);
TaskStackLayoutAlgorithm layoutAlgorithm = mSv.getStackAlgorithm();
@@ -673,7 +673,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
/** Returns the view at the specified coordinates */
private TaskView findViewAtPoint(int x, int y) {
- List<Task> tasks = mSv.getStack().getStackTasks();
+ List<Task> tasks = mSv.getStack().getTasks();
int taskCount = tasks.size();
for (int i = taskCount - 1; i >= 0; i--) {
TaskView tv = mSv.getChildViewForTask(tasks.get(i));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index b44084743896..f0278a69e116 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -55,6 +55,7 @@ import com.android.systemui.shared.recents.utilities.AnimationProps;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.recents.view.AnimateableViewBounds;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -683,7 +684,7 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
}
SystemServicesProxy ssp = Recents.getSystemServices();
boolean inBounds = false;
- Rect clipBounds = new Rect(mViewBounds.mClipBounds);
+ Rect clipBounds = new Rect(mViewBounds.getClipBounds());
if (!clipBounds.isEmpty()) {
// If we are clipping the view to the bounds, manually do the hit test.
clipBounds.scale(getScaleX());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java
index a029478c2045..3bdad314d7f3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/AnimateableGridViewBounds.java
@@ -17,7 +17,7 @@
package com.android.systemui.recents.views.grid;
import android.view.View;
-import com.android.systemui.recents.views.AnimateableViewBounds;
+import com.android.systemui.shared.recents.view.AnimateableViewBounds;
/* An outline provider for grid-based task views. */
class AnimateableGridViewBounds extends AnimateableViewBounds {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
index 8b4700c54b00..0d5115444b01 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskView.java
@@ -19,7 +19,7 @@ package com.android.systemui.recents.views.grid;
import android.content.Context;
import android.util.AttributeSet;
import com.android.systemui.R;
-import com.android.systemui.recents.views.AnimateableViewBounds;
+import com.android.systemui.shared.recents.view.AnimateableViewBounds;
import com.android.systemui.recents.views.TaskView;
public class GridTaskView extends TaskView {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
index 95f1d5837e8e..fe6bafb27c7c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
@@ -125,7 +125,7 @@ public class TaskViewFocusFrame extends View implements OnGlobalFocusChangeListe
// We're returning from touch mode, set the focus to the previously focused task.
final TaskStack stack = mSv.getStack();
final int taskCount = stack.getTaskCount();
- final int k = stack.indexOfStackTask(mSv.getFocusedTask());
+ final int k = stack.indexOfTask(mSv.getFocusedTask());
final int taskIndexToFocus = k == -1 ? (taskCount - 1) : (k % taskCount);
mSv.setFocusedTask(taskIndexToFocus, false, true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
index b2bbe307d8bf..826fa6cefccc 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -33,6 +33,7 @@ import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
import com.android.systemui.recents.events.component.ShowUserToastEvent;
import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.stackdivider.events.StartedDragingEvent;
import com.android.systemui.stackdivider.events.StoppedDragingEvent;
@@ -75,7 +76,7 @@ public class ForcedResizableInfoActivityController {
public ForcedResizableInfoActivityController(Context context) {
mContext = context;
EventBus.getDefault().register(this);
- SystemServicesProxy.getInstance(context).registerTaskStackListener(
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(
new SysUiTaskStackChangeListener() {
@Override
public void onActivityForcedResizable(String packageName, int taskId,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 6c5f4b237033..8ff950ed1c24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -69,6 +69,7 @@ import com.android.systemui.statusbar.notification.AboveShelfObserver;
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.NotificationInflater;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -453,6 +454,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
} else {
headsUpheight = mMaxHeadsUpHeight;
}
+ NotificationViewWrapper headsUpWrapper = layout.getVisibleWrapper(
+ NotificationContentView.VISIBLE_TYPE_HEADSUP);
+ if (headsUpWrapper != null) {
+ headsUpheight = Math.max(headsUpheight, headsUpWrapper.getMinLayoutHeight());
+ }
layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
mNotificationAmbientHeight);
}
@@ -1256,16 +1262,21 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
private void initDimens() {
- mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
- mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
- mNotificationMinHeightLarge = getFontScaledHeight(
+ mNotificationMinHeightLegacy = NotificationUtils.getFontScaledHeight(mContext,
+ R.dimen.notification_min_height_legacy);
+ mNotificationMinHeight = NotificationUtils.getFontScaledHeight(mContext,
+ R.dimen.notification_min_height);
+ mNotificationMinHeightLarge = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_min_height_increased);
- mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
- mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height);
- mMaxHeadsUpHeightLegacy = getFontScaledHeight(
+ mNotificationMaxHeight = NotificationUtils.getFontScaledHeight(mContext,
+ R.dimen.notification_max_height);
+ mNotificationAmbientHeight = NotificationUtils.getFontScaledHeight(mContext,
+ R.dimen.notification_ambient_height);
+ mMaxHeadsUpHeightLegacy = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_max_heads_up_height_legacy);
- mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
- mMaxHeadsUpHeightIncreased = getFontScaledHeight(
+ mMaxHeadsUpHeight = NotificationUtils.getFontScaledHeight(mContext,
+ R.dimen.notification_max_heads_up_height);
+ mMaxHeadsUpHeightIncreased = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_max_heads_up_height_increased);
Resources res = getResources();
@@ -1280,17 +1291,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
/**
- * @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
- */
- private int getFontScaledHeight(int dimenId) {
- int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
- float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
- getResources().getDisplayMetrics().density);
- return (int) (dimensionPixelSize * factor);
- }
-
- /**
* Resets this view so it can be re-used for an updated notification.
*/
public void reset() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 54d622b341f1..c4024a57ceed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -18,46 +18,21 @@ package com.android.systemui.statusbar;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.app.INotificationManager;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Handler;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import android.view.ViewAnimationUtils;
-import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.SeekBar;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settingslib.Utils;
+
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
import com.android.systemui.statusbar.stack.StackStateAnimator;
-import java.util.Set;
-
/**
* The guts of a notification revealed when performing a long press.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
new file mode 100644
index 000000000000..b585bdff292e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.INotificationManager;
+import android.app.NotificationChannel;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
+import android.util.Log;
+import android.view.HapticFeedbackConstants;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.systemui.Dependency;
+import com.android.systemui.Dumpable;
+import com.android.systemui.Interpolators;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Handles various NotificationGuts related tasks, such as binding guts to a row, opening and
+ * closing guts, and keeping track of the currently exposed notification guts.
+ */
+public class NotificationGutsManager implements Dumpable {
+ private static final String TAG = "NotificationGutsManager";
+
+ // Must match constant in Settings. Used to highlight preferences when linking to Settings.
+ private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
+
+ 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;
+ // which notification is currently being longpress-examined by the user
+ private NotificationGuts mNotificationGutsExposed;
+ private NotificationMenuRowPlugin.MenuItem mGutsMenuItem;
+ private final NotificationInfo.CheckSaveListener mCheckSaveListener;
+ private String mKeyToRemoveOnGutsClosed;
+
+ public NotificationGutsManager(
+ NotificationPresenter presenter,
+ NotificationStackScrollLayout stackScroller,
+ NotificationInfo.CheckSaveListener checkSaveListener,
+ Context context) {
+ mPresenter = presenter;
+ mStackScroller = stackScroller;
+ mCheckSaveListener = checkSaveListener;
+ mContext = context;
+ Resources res = context.getResources();
+
+ mNonBlockablePkgs = new HashSet<>();
+ Collections.addAll(mNonBlockablePkgs, res.getStringArray(
+ com.android.internal.R.array.config_nonBlockableNotificationPackages));
+
+ mAccessibilityManager = (AccessibilityManager)
+ mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ }
+
+ public String getKeyToRemoveOnGutsClosed() {
+ return mKeyToRemoveOnGutsClosed;
+ }
+
+ public void setKeyToRemoveOnGutsClosed(String keyToRemoveOnGutsClosed) {
+ mKeyToRemoveOnGutsClosed = keyToRemoveOnGutsClosed;
+ }
+
+ private void saveAndCloseNotificationMenu(
+ ExpandableNotificationRow row, NotificationGuts guts, View done) {
+ guts.resetFalsingCheck();
+ int[] rowLocation = new int[2];
+ int[] doneLocation = new int[2];
+ row.getLocationOnScreen(rowLocation);
+ done.getLocationOnScreen(doneLocation);
+
+ final int centerX = done.getWidth() / 2;
+ final int centerY = done.getHeight() / 2;
+ final int x = doneLocation[0] - rowLocation[0] + centerX;
+ final int y = doneLocation[1] - rowLocation[1] + centerY;
+ closeAndSaveGuts(false /* removeLeavebehind */, false /* force */,
+ true /* removeControls */, x, y, true /* resetMenu */);
+ }
+
+ /**
+ * Sends an intent to open the notification settings for a particular package and optional
+ * channel.
+ */
+ private void startAppNotificationSettingsActivity(String packageName, final int appUid,
+ final NotificationChannel channel) {
+ final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
+ intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
+ intent.putExtra(Settings.EXTRA_APP_UID, appUid);
+ if (channel != null) {
+ intent.putExtra(EXTRA_FRAGMENT_ARG_KEY, channel.getId());
+ }
+ mPresenter.startNotificationGutsIntent(intent, appUid);
+ }
+
+ public void bindGuts(final ExpandableNotificationRow row) {
+ bindGuts(row, mGutsMenuItem);
+ }
+
+ private void bindGuts(final ExpandableNotificationRow row,
+ NotificationMenuRowPlugin.MenuItem item) {
+ row.inflateGuts();
+ row.setGutsView(item);
+ final StatusBarNotification sbn = row.getStatusBarNotification();
+ row.setTag(sbn.getPackageName());
+ final NotificationGuts guts = row.getGuts();
+ guts.setClosedListener((NotificationGuts g) -> {
+ if (!g.willBeRemoved() && !row.isRemoved()) {
+ mStackScroller.onHeightChanged(
+ row, !mPresenter.isPresenterFullyCollapsed() /* needsAnimation */);
+ }
+ if (mNotificationGutsExposed == g) {
+ mNotificationGutsExposed = null;
+ mGutsMenuItem = null;
+ }
+ String key = sbn.getKey();
+ if (key.equals(mKeyToRemoveOnGutsClosed)) {
+ mKeyToRemoveOnGutsClosed = null;
+ mPresenter.removeNotification(key, mPresenter.getLatestRankingMap());
+ }
+ });
+
+ View gutsView = item.getGutsView();
+ if (gutsView instanceof NotificationSnooze) {
+ NotificationSnooze snoozeGuts = (NotificationSnooze) gutsView;
+ snoozeGuts.setSnoozeListener(mStackScroller.getSwipeActionHelper());
+ snoozeGuts.setStatusBarNotification(sbn);
+ snoozeGuts.setSnoozeOptions(row.getEntry().snoozeCriteria);
+ guts.setHeightChangedListener((NotificationGuts g) -> {
+ mStackScroller.onHeightChanged(row, row.isShown() /* needsAnimation */);
+ });
+ }
+
+ if (gutsView instanceof NotificationInfo) {
+ final UserHandle userHandle = sbn.getUser();
+ PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext,
+ userHandle.getIdentifier());
+ final INotificationManager iNotificationManager = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ final String pkg = sbn.getPackageName();
+ NotificationInfo info = (NotificationInfo) gutsView;
+ // Settings link is only valid for notifications that specify a user, unless this is the
+ // system user.
+ NotificationInfo.OnSettingsClickListener onSettingsClick = null;
+ if (!userHandle.equals(UserHandle.ALL)
+ || mPresenter.getCurrentUserId() == UserHandle.USER_SYSTEM) {
+ onSettingsClick = (View v, NotificationChannel channel, int appUid) -> {
+ mMetricsLogger.action(MetricsProto.MetricsEvent.ACTION_NOTE_INFO);
+ guts.resetFalsingCheck();
+ startAppNotificationSettingsActivity(pkg, appUid, channel);
+ };
+ }
+ final NotificationInfo.OnAppSettingsClickListener onAppSettingsClick = (View v,
+ Intent intent) -> {
+ mMetricsLogger.action(MetricsProto.MetricsEvent.ACTION_APP_NOTE_SETTINGS);
+ guts.resetFalsingCheck();
+ mPresenter.startNotificationGutsIntent(intent, sbn.getUid());
+ };
+ final View.OnClickListener onDoneClick = (View v) -> {
+ saveAndCloseNotificationMenu(row, guts, v);
+ };
+
+ ArraySet<NotificationChannel> channels = new ArraySet<>();
+ channels.add(row.getEntry().channel);
+ if (row.isSummaryWithChildren()) {
+ // If this is a summary, then add in the children notification channels for the
+ // same user and pkg.
+ final List<ExpandableNotificationRow> childrenRows = row.getNotificationChildren();
+ final int numChildren = childrenRows.size();
+ for (int i = 0; i < numChildren; i++) {
+ final ExpandableNotificationRow childRow = childrenRows.get(i);
+ final NotificationChannel childChannel = childRow.getEntry().channel;
+ final StatusBarNotification childSbn = childRow.getStatusBarNotification();
+ if (childSbn.getUser().equals(userHandle) &&
+ childSbn.getPackageName().equals(pkg)) {
+ channels.add(childChannel);
+ }
+ }
+ }
+ try {
+ info.bindNotification(pmUser, iNotificationManager, pkg, new ArrayList(channels),
+ row.getEntry().channel.getImportance(), sbn, onSettingsClick,
+ onAppSettingsClick, onDoneClick, mCheckSaveListener,
+ mNonBlockablePkgs);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ }
+ }
+
+ /**
+ * Closes guts or notification menus that might be visible and saves any changes.
+ *
+ * @param removeLeavebehinds true if leavebehinds (e.g. snooze) should be closed.
+ * @param force true if guts should be closed regardless of state (used for snooze only).
+ * @param removeControls true if controls (e.g. info) should be closed.
+ * @param x if closed based on touch location, this is the x touch location.
+ * @param y if closed based on touch location, this is the y touch location.
+ * @param resetMenu if any notification menus that might be revealed should be closed.
+ */
+ public void closeAndSaveGuts(boolean removeLeavebehinds, boolean force, boolean removeControls,
+ int x, int y, boolean resetMenu) {
+ if (mNotificationGutsExposed != null) {
+ mNotificationGutsExposed.closeControls(removeLeavebehinds, removeControls, x, y, force);
+ }
+ if (resetMenu) {
+ mStackScroller.resetExposedMenuView(false /* animate */, true /* force */);
+ }
+ }
+
+ /**
+ * Returns the exposed NotificationGuts or null if none are exposed.
+ */
+ public NotificationGuts getExposedGuts() {
+ return mNotificationGutsExposed;
+ }
+
+ public void setExposedGuts(NotificationGuts guts) {
+ mNotificationGutsExposed = guts;
+ }
+
+ /**
+ * Opens guts on the given ExpandableNotificationRow |v|.
+ *
+ * @param v ExpandableNotificationRow to open guts on
+ * @param x x coordinate of origin of circular reveal
+ * @param y y coordinate of origin of circular reveal
+ * @param item MenuItem the guts should display
+ * @return true if guts was opened
+ */
+ public boolean openGuts(View v, int x, int y,
+ NotificationMenuRowPlugin.MenuItem item) {
+ if (!(v instanceof ExpandableNotificationRow)) {
+ return false;
+ }
+
+ if (v.getWindowToken() == null) {
+ Log.e(TAG, "Trying to show notification guts, but not attached to window");
+ return false;
+ }
+
+ final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+ if (row.isDark()) {
+ return false;
+ }
+ v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ if (row.areGutsExposed()) {
+ closeAndSaveGuts(false /* removeLeavebehind */, false /* force */,
+ true /* removeControls */, -1 /* x */, -1 /* y */,
+ true /* resetMenu */);
+ return false;
+ }
+ bindGuts(row, item);
+ NotificationGuts guts = row.getGuts();
+
+ // Assume we are a status_bar_notification_row
+ if (guts == null) {
+ // This view has no guts. Examples are the more card or the dismiss all view
+ return false;
+ }
+
+ mMetricsLogger.action(MetricsProto.MetricsEvent.ACTION_NOTE_CONTROLS);
+
+ // ensure that it's laid but not visible until actually laid out
+ guts.setVisibility(View.INVISIBLE);
+ // Post to ensure the the guts are properly laid out.
+ guts.post(new Runnable() {
+ @Override
+ public void run() {
+ if (row.getWindowToken() == null) {
+ Log.e(TAG, "Trying to show notification guts, but not attached to "
+ + "window");
+ return;
+ }
+ closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
+ true /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ guts.setVisibility(View.VISIBLE);
+ final double horz = Math.max(guts.getWidth() - x, x);
+ final double vert = Math.max(guts.getHeight() - y, y);
+ final float r = (float) Math.hypot(horz, vert);
+ final Animator a
+ = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
+ a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+ a.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ // Move the notification view back over the menu
+ row.resetTranslation();
+ }
+ });
+ a.start();
+ final boolean needsFalsingProtection =
+ (mPresenter.isPresenterLocked() &&
+ !mAccessibilityManager.isTouchExplorationEnabled());
+ guts.setExposed(true /* exposed */, needsFalsingProtection);
+ row.closeRemoteInput();
+ mStackScroller.onHeightChanged(row, true /* needsAnimation */);
+ mNotificationGutsExposed = guts;
+ mGutsMenuItem = item;
+ }
+ });
+ return true;
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.print("mKeyToRemoveOnGutsClosed: ");
+ pw.println(mKeyToRemoveOnGutsClosed);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 3b23a0c0db89..8d1bb5fe940d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -84,7 +84,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
public interface CheckSaveListener {
// Invoked when importance has changed and the NotificationInfo wants to try to save it.
// Listener should run saveImportance unless the change should be canceled.
- void checkSave(Runnable saveImportance);
+ void checkSave(Runnable saveImportance, StatusBarNotification sbn);
}
public interface OnSettingsClickListener {
@@ -409,7 +409,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
public boolean handleCloseControls(boolean save, boolean force) {
if (save && hasImportanceChanged()) {
if (mCheckSaveListener != null) {
- mCheckSaveListener.checkSave(() -> { saveImportance(); });
+ mCheckSaveListener.checkSave(this::saveImportance, mSbn);
} else {
saveImportance();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
new file mode 100644
index 000000000000..e65bab29b519
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -0,0 +1,245 @@
+package com.android.systemui.statusbar;
+
+import android.app.Notification;
+import android.content.Context;
+import android.media.MediaMetadata;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
+import android.media.session.PlaybackState;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.systemui.Dumpable;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Handles tasks and state related to media notifications. For example, there is a 'current' media
+ * notification, which this class keeps track of.
+ */
+public class NotificationMediaManager implements Dumpable {
+ private static final String TAG = "NotificationMediaManager";
+ public static final boolean DEBUG_MEDIA = false;
+
+ private final NotificationPresenter mPresenter;
+ private final Context mContext;
+ private final MediaSessionManager mMediaSessionManager;
+ private MediaController mMediaController;
+ private String mMediaNotificationKey;
+ private MediaMetadata mMediaMetadata;
+
+ private final MediaController.Callback mMediaListener = new MediaController.Callback() {
+ @Override
+ public void onPlaybackStateChanged(PlaybackState state) {
+ super.onPlaybackStateChanged(state);
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: onPlaybackStateChanged: " + state);
+ }
+ if (state != null) {
+ if (!isPlaybackActive(state.getState())) {
+ clearCurrentMediaNotification();
+ mPresenter.updateMediaMetaData(true, true);
+ }
+ }
+ }
+
+ @Override
+ public void onMetadataChanged(MediaMetadata metadata) {
+ super.onMetadataChanged(metadata);
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
+ }
+ mMediaMetadata = metadata;
+ mPresenter.updateMediaMetaData(true, true);
+ }
+ };
+
+ public NotificationMediaManager(NotificationPresenter presenter, Context context) {
+ mPresenter = presenter;
+ mContext = context;
+ mMediaSessionManager
+ = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
+ // TODO: use MediaSessionManager.SessionListener to hook us up to future updates
+ // in session state
+ }
+
+ public void onNotificationRemoved(String key) {
+ if (key.equals(mMediaNotificationKey)) {
+ clearCurrentMediaNotification();
+ mPresenter.updateMediaMetaData(true, true);
+ }
+ }
+
+ public String getMediaNotificationKey() {
+ return mMediaNotificationKey;
+ }
+
+ public MediaMetadata getMediaMetadata() {
+ return mMediaMetadata;
+ }
+
+ public void findAndUpdateMediaNotifications() {
+ boolean metaDataChanged = false;
+
+ synchronized (mPresenter.getNotificationData()) {
+ ArrayList<NotificationData.Entry> activeNotifications = mPresenter
+ .getNotificationData().getActiveNotifications();
+ final int N = activeNotifications.size();
+
+ // Promote the media notification with a controller in 'playing' state, if any.
+ NotificationData.Entry mediaNotification = null;
+ MediaController controller = null;
+ for (int i = 0; i < N; i++) {
+ final NotificationData.Entry entry = activeNotifications.get(i);
+
+ if (isMediaNotification(entry)) {
+ final MediaSession.Token token =
+ entry.notification.getNotification().extras.getParcelable(
+ Notification.EXTRA_MEDIA_SESSION);
+ if (token != null) {
+ MediaController aController = new MediaController(mContext, token);
+ if (PlaybackState.STATE_PLAYING ==
+ getMediaControllerPlaybackState(aController)) {
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: found mediastyle controller matching "
+ + entry.notification.getKey());
+ }
+ mediaNotification = entry;
+ controller = aController;
+ break;
+ }
+ }
+ }
+ }
+ if (mediaNotification == null) {
+ // Still nothing? OK, let's just look for live media sessions and see if they match
+ // one of our notifications. This will catch apps that aren't (yet!) using media
+ // notifications.
+
+ if (mMediaSessionManager != null) {
+ // TODO: Should this really be for all users?
+ final List<MediaController> sessions
+ = mMediaSessionManager.getActiveSessionsForUser(
+ null,
+ UserHandle.USER_ALL);
+
+ for (MediaController aController : sessions) {
+ if (PlaybackState.STATE_PLAYING ==
+ getMediaControllerPlaybackState(aController)) {
+ // now to see if we have one like this
+ final String pkg = aController.getPackageName();
+
+ for (int i = 0; i < N; i++) {
+ final NotificationData.Entry entry = activeNotifications.get(i);
+ if (entry.notification.getPackageName().equals(pkg)) {
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: found controller matching "
+ + entry.notification.getKey());
+ }
+ controller = aController;
+ mediaNotification = entry;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (controller != null && !sameSessions(mMediaController, controller)) {
+ // We have a new media session
+ clearCurrentMediaNotification();
+ mMediaController = controller;
+ mMediaController.registerCallback(mMediaListener);
+ mMediaMetadata = mMediaController.getMetadata();
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: "
+ + mMediaMetadata);
+ }
+
+ if (mediaNotification != null) {
+ mMediaNotificationKey = mediaNotification.notification.getKey();
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key="
+ + mMediaNotificationKey + " controller=" + mMediaController);
+ }
+ }
+ metaDataChanged = true;
+ }
+ }
+
+ if (metaDataChanged) {
+ mPresenter.updateNotifications();
+ }
+ mPresenter.updateMediaMetaData(metaDataChanged, true);
+ }
+
+ public void clearCurrentMediaNotification() {
+ mMediaNotificationKey = null;
+ mMediaMetadata = null;
+ if (mMediaController != null) {
+ if (DEBUG_MEDIA) {
+ Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: "
+ + mMediaController.getPackageName());
+ }
+ mMediaController.unregisterCallback(mMediaListener);
+ }
+ mMediaController = null;
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.print(" mMediaSessionManager=");
+ pw.println(mMediaSessionManager);
+ pw.print(" mMediaNotificationKey=");
+ pw.println(mMediaNotificationKey);
+ pw.print(" mMediaController=");
+ pw.print(mMediaController);
+ if (mMediaController != null) {
+ pw.print(" state=" + mMediaController.getPlaybackState());
+ }
+ pw.println();
+ pw.print(" mMediaMetadata=");
+ pw.print(mMediaMetadata);
+ if (mMediaMetadata != null) {
+ pw.print(" title=" + mMediaMetadata.getText(MediaMetadata.METADATA_KEY_TITLE));
+ }
+ pw.println();
+ }
+
+ private boolean isPlaybackActive(int state) {
+ return state != PlaybackState.STATE_STOPPED && state != PlaybackState.STATE_ERROR
+ && state != PlaybackState.STATE_NONE;
+ }
+
+ private boolean sameSessions(MediaController a, MediaController b) {
+ if (a == b) {
+ return true;
+ }
+ if (a == null) {
+ return false;
+ }
+ return a.controlsSameSession(b);
+ }
+
+ private int getMediaControllerPlaybackState(MediaController controller) {
+ if (controller != null) {
+ final PlaybackState playbackState = controller.getPlaybackState();
+ if (playbackState != null) {
+ return playbackState.getState();
+ }
+ }
+ return PlaybackState.STATE_NONE;
+ }
+
+ private boolean isMediaNotification(NotificationData.Entry entry) {
+ // TODO: confirm that there's a valid media key
+ return entry.getExpandedContentView() != null &&
+ entry.getExpandedContentView()
+ .findViewById(com.android.internal.R.id.media_actions) != null;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
new file mode 100644
index 000000000000..1aca60c90ed8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.statusbar;
+
+import android.content.Intent;
+import android.service.notification.NotificationListenerService;
+
+/**
+ * An abstraction of something that presents notifications, e.g. StatusBar. Contains methods
+ * for both querying the state of the system (some modularised piece of functionality may
+ * want to act differently based on e.g. whether the presenter is visible to the user or not) and
+ * 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 {
+
+ /**
+ * Returns true if the presenter is not visible. For example, it may not be necessary to do
+ * animations if this returns true.
+ */
+ boolean isPresenterFullyCollapsed();
+
+ /**
+ * Returns true if the presenter is locked. For example, if the keyguard is active.
+ */
+ 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.
+ */
+ void startNotificationGutsIntent(Intent intent, int appUid);
+
+ /**
+ * Returns NotificationData.
+ */
+ NotificationData getNotificationData();
+
+ // TODO: Create NotificationEntryManager and move this method to there.
+ /**
+ * Signals that some notifications have changed, and NotificationPresenter should update itself.
+ */
+ void updateNotifications();
+
+ /**
+ * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
+ */
+ 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();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
index 535300573c6e..09b11c295701 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
@@ -35,7 +35,8 @@ import java.util.Stack;
/**
* A view that can be transformed to and from.
*/
-public class ViewTransformationHelper implements TransformableView {
+public class ViewTransformationHelper implements TransformableView,
+ TransformState.TransformInfo {
private static final int TAG_CONTAINS_TRANSFORMED_VIEW = R.id.contains_transformed_view;
@@ -59,7 +60,7 @@ public class ViewTransformationHelper implements TransformableView {
public TransformState getCurrentState(int fadingView) {
View view = mTransformedViews.get(fadingView);
if (view != null && view.getVisibility() != View.GONE) {
- return TransformState.createFrom(view);
+ return TransformState.createFrom(view, this);
}
return null;
}
@@ -88,6 +89,7 @@ public class ViewTransformationHelper implements TransformableView {
endRunnable.run();
}
setVisible(false);
+ mViewTransformationAnimation = null;
} else {
abortTransformations();
}
@@ -245,7 +247,7 @@ public class ViewTransformationHelper implements TransformableView {
}
public void resetTransformedView(View view) {
- TransformState state = TransformState.createFrom(view);
+ TransformState state = TransformState.createFrom(view, this);
state.setVisible(true /* visible */, true /* force */);
state.recycle();
}
@@ -257,6 +259,11 @@ public class ViewTransformationHelper implements TransformableView {
return new ArraySet<>(mTransformedViews.values());
}
+ @Override
+ public boolean isAnimating() {
+ return mViewTransformationAnimation != null && mViewTransformationAnimation.isRunning();
+ }
+
public static abstract class CustomTransformation {
/**
* Transform a state to the given view
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 41cae6b0be57..5941af2483c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -85,7 +85,7 @@ public class CarStatusBar extends StatusBar implements
public void start() {
super.start();
mTaskStackListener = new TaskStackListenerImpl();
- SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
registerPackageChangeReceivers();
mStackScroller.setScrollingEnabled(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
index 92f26d65f25e..8227b7797706 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
@@ -39,8 +39,8 @@ public class ImageTransformState extends TransformState {
private Icon mIcon;
@Override
- public void initFrom(View view) {
- super.initFrom(view);
+ public void initFrom(View view, TransformInfo transformInfo) {
+ super.initFrom(view, transformInfo);
if (view instanceof ImageView) {
mIcon = (Icon) view.getTag(ICON_TAG);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
new file mode 100644
index 000000000000..fc420eb72c4d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import android.content.res.Resources;
+import android.util.Pools;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.widget.MessagingGroup;
+import com.android.internal.widget.MessagingLayout;
+import com.android.internal.widget.MessagingLinearLayout;
+import com.android.internal.widget.MessagingMessage;
+import com.android.internal.widget.MessagingPropertyAnimator;
+import com.android.internal.widget.ViewClippingUtil;
+import com.android.systemui.Interpolators;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * A transform state of the action list
+*/
+public class MessagingLayoutTransformState extends TransformState {
+
+ private static Pools.SimplePool<MessagingLayoutTransformState> sInstancePool
+ = new Pools.SimplePool<>(40);
+ private MessagingLinearLayout mMessageContainer;
+ private MessagingLayout mMessagingLayout;
+ private HashMap<MessagingGroup, MessagingGroup> mGroupMap = new HashMap<>();
+ private float mRelativeTranslationOffset;
+
+ public static MessagingLayoutTransformState obtain() {
+ MessagingLayoutTransformState instance = sInstancePool.acquire();
+ if (instance != null) {
+ return instance;
+ }
+ return new MessagingLayoutTransformState();
+ }
+
+ @Override
+ public void initFrom(View view, TransformInfo transformInfo) {
+ super.initFrom(view, transformInfo);
+ if (mTransformedView instanceof MessagingLinearLayout) {
+ mMessageContainer = (MessagingLinearLayout) mTransformedView;
+ mMessagingLayout = mMessageContainer.getMessagingLayout();
+ Resources resources = view.getContext().getResources();
+ mRelativeTranslationOffset = resources.getDisplayMetrics().density * 8;
+ }
+ }
+
+ @Override
+ public boolean transformViewTo(TransformState otherState, float transformationAmount) {
+ if (otherState instanceof MessagingLayoutTransformState) {
+ // It's a party! Let's transform between these two layouts!
+ transformViewInternal((MessagingLayoutTransformState) otherState, transformationAmount,
+ true /* to */);
+ return true;
+ } else {
+ return super.transformViewTo(otherState, transformationAmount);
+ }
+ }
+
+ @Override
+ public void transformViewFrom(TransformState otherState, float transformationAmount) {
+ if (otherState instanceof MessagingLayoutTransformState) {
+ // It's a party! Let's transform between these two layouts!
+ transformViewInternal((MessagingLayoutTransformState) otherState, transformationAmount,
+ false /* to */);
+ } else {
+ super.transformViewFrom(otherState, transformationAmount);
+ }
+ }
+
+ private void transformViewInternal(MessagingLayoutTransformState mlt,
+ float transformationAmount, boolean to) {
+ ArrayList<MessagingGroup> ownGroups = filterHiddenGroups(
+ mMessagingLayout.getMessagingGroups());
+ ArrayList<MessagingGroup> otherGroups = filterHiddenGroups(
+ mlt.mMessagingLayout.getMessagingGroups());
+ HashMap<MessagingGroup, MessagingGroup> pairs = findPairs(ownGroups, otherGroups);
+ MessagingGroup lastPairedGroup = null;
+ float currentTranslation = 0;
+ float transformationDistanceRemaining = 0;
+ for (int i = ownGroups.size() - 1; i >= 0; i--) {
+ MessagingGroup ownGroup = ownGroups.get(i);
+ MessagingGroup matchingGroup = pairs.get(ownGroup);
+ if (!isGone(ownGroup)) {
+ if (matchingGroup != null) {
+ transformGroups(ownGroup, matchingGroup, transformationAmount, to);
+ if (lastPairedGroup == null) {
+ lastPairedGroup = ownGroup;
+ if (to){
+ float totalTranslation = ownGroup.getTop() - matchingGroup.getTop();
+ transformationDistanceRemaining
+ = matchingGroup.getAvatar().getTranslationY();
+ currentTranslation = transformationDistanceRemaining - totalTranslation;
+ } else {
+ float totalTranslation = matchingGroup.getTop() - ownGroup.getTop();
+ currentTranslation = ownGroup.getAvatar().getTranslationY();
+ transformationDistanceRemaining = currentTranslation - totalTranslation;
+ }
+ }
+ } else {
+ float groupTransformationAmount = transformationAmount;
+ if (lastPairedGroup != null) {
+ adaptGroupAppear(ownGroup, transformationAmount, currentTranslation,
+ to);
+ int distance = lastPairedGroup.getTop() - ownGroup.getTop();
+ float transformationDistance = mTransformInfo.isAnimating()
+ ? distance
+ : ownGroup.getHeight() * 0.75f;
+ float translationProgress = transformationDistanceRemaining
+ - (distance - transformationDistance);
+ groupTransformationAmount =
+ translationProgress / transformationDistance;
+ groupTransformationAmount = Math.max(0.0f, Math.min(1.0f,
+ groupTransformationAmount));
+ if (to) {
+ groupTransformationAmount = 1.0f - groupTransformationAmount;
+ }
+ }
+ if (to) {
+ disappear(ownGroup, groupTransformationAmount);
+ } else {
+ appear(ownGroup, groupTransformationAmount);
+ }
+ }
+ }
+ }
+ }
+
+ private void appear(MessagingGroup ownGroup, float transformationAmount) {
+ MessagingLinearLayout ownMessages = ownGroup.getMessageContainer();
+ for (int j = 0; j < ownMessages.getChildCount(); j++) {
+ View child = ownMessages.getChildAt(j);
+ if (isGone(child)) {
+ continue;
+ }
+ appear(child, transformationAmount);
+ setClippingDeactivated(child, true);
+ }
+ appear(ownGroup.getAvatar(), transformationAmount);
+ appear(ownGroup.getSender(), transformationAmount);
+ setClippingDeactivated(ownGroup.getSender(), true);
+ setClippingDeactivated(ownGroup.getAvatar(), true);
+ }
+
+ private void adaptGroupAppear(MessagingGroup ownGroup, float transformationAmount,
+ float overallTranslation, boolean to) {
+ float relativeOffset;
+ if (to) {
+ relativeOffset = transformationAmount * mRelativeTranslationOffset;
+ } else {
+ relativeOffset = (1.0f - transformationAmount) * mRelativeTranslationOffset;
+ }
+ if (ownGroup.getSender().getVisibility() != View.GONE) {
+ relativeOffset *= 0.5f;
+ }
+ ownGroup.getMessageContainer().setTranslationY(relativeOffset);
+ ownGroup.setTranslationY(overallTranslation * 0.85f);
+ }
+
+ private void disappear(MessagingGroup ownGroup, float transformationAmount) {
+ MessagingLinearLayout ownMessages = ownGroup.getMessageContainer();
+ for (int j = 0; j < ownMessages.getChildCount(); j++) {
+ View child = ownMessages.getChildAt(j);
+ if (isGone(child)) {
+ continue;
+ }
+ disappear(child, transformationAmount);
+ setClippingDeactivated(child, true);
+ }
+ disappear(ownGroup.getAvatar(), transformationAmount);
+ disappear(ownGroup.getSender(), transformationAmount);
+ setClippingDeactivated(ownGroup.getSender(), true);
+ setClippingDeactivated(ownGroup.getAvatar(), true);
+ }
+
+ private void appear(View child, float transformationAmount) {
+ if (child.getVisibility() == View.GONE) {
+ return;
+ }
+ TransformState ownState = TransformState.createFrom(child, mTransformInfo);
+ ownState.appear(transformationAmount, null);
+ ownState.recycle();
+ }
+
+ private void disappear(View child, float transformationAmount) {
+ if (child.getVisibility() == View.GONE) {
+ return;
+ }
+ TransformState ownState = TransformState.createFrom(child, mTransformInfo);
+ ownState.disappear(transformationAmount, null);
+ ownState.recycle();
+ }
+
+ private ArrayList<MessagingGroup> filterHiddenGroups(
+ ArrayList<MessagingGroup> groups) {
+ ArrayList<MessagingGroup> result = new ArrayList<>(groups);
+ for (int i = 0; i < result.size(); i++) {
+ MessagingGroup messagingGroup = result.get(i);
+ if (isGone(messagingGroup)) {
+ result.remove(i);
+ i--;
+ }
+ }
+ return result;
+ }
+
+ private void transformGroups(MessagingGroup ownGroup, MessagingGroup otherGroup,
+ float transformationAmount, boolean to) {
+ transformView(transformationAmount, to, ownGroup.getSender(), otherGroup.getSender(),
+ true /* sameAsAny */);
+ transformView(transformationAmount, to, ownGroup.getAvatar(), otherGroup.getAvatar(),
+ true /* sameAsAny */);
+ MessagingLinearLayout ownMessages = ownGroup.getMessageContainer();
+ MessagingLinearLayout otherMessages = otherGroup.getMessageContainer();
+ float previousTranslation = 0;
+ for (int i = 0; i < ownMessages.getChildCount(); i++) {
+ View child = ownMessages.getChildAt(ownMessages.getChildCount() - 1 - i);
+ if (isGone(child)) {
+ continue;
+ }
+ int otherIndex = otherMessages.getChildCount() - 1 - i;
+ View otherChild = null;
+ if (otherIndex >= 0) {
+ otherChild = otherMessages.getChildAt(otherIndex);
+ if (isGone(otherChild)) {
+ otherChild = null;
+ }
+ }
+ if (otherChild == null) {
+ float distanceToTop = child.getTop() + child.getHeight() + previousTranslation;
+ transformationAmount = distanceToTop / child.getHeight();
+ transformationAmount = Math.max(0.0f, Math.min(1.0f, transformationAmount));
+ if (to) {
+ transformationAmount = 1.0f - transformationAmount;
+ }
+ }
+ transformView(transformationAmount, to, child, otherChild, false /* sameAsAny */);
+ if (otherChild == null) {
+ child.setTranslationY(previousTranslation);
+ setClippingDeactivated(child, true);
+ } else if (to) {
+ float totalTranslation = child.getTop() + ownGroup.getTop()
+ - otherChild.getTop() - otherChild.getTop();
+ previousTranslation = otherChild.getTranslationY() - totalTranslation;
+ } else {
+ previousTranslation = child.getTranslationY();
+ }
+ }
+ }
+
+ private void transformView(float transformationAmount, boolean to, View ownView,
+ View otherView, boolean sameAsAny) {
+ TransformState ownState = TransformState.createFrom(ownView, mTransformInfo);
+ if (!mTransformInfo.isAnimating()) {
+ ownState.setDefaultInterpolator(Interpolators.LINEAR);
+ }
+ ownState.setIsSameAsAnyView(sameAsAny);
+ if (to) {
+ if (otherView != null) {
+ TransformState otherState = TransformState.createFrom(otherView, mTransformInfo);
+ ownState.transformViewTo(otherState, transformationAmount);
+ otherState.recycle();
+ } else {
+ ownState.disappear(transformationAmount, null);
+ }
+ } else {
+ if (otherView != null) {
+ TransformState otherState = TransformState.createFrom(otherView, mTransformInfo);
+ ownState.transformViewFrom(otherState, transformationAmount);
+ otherState.recycle();
+ } else {
+ ownState.appear(transformationAmount, null);
+ }
+ }
+ ownState.recycle();
+ }
+
+ private HashMap<MessagingGroup, MessagingGroup> findPairs(ArrayList<MessagingGroup> ownGroups,
+ ArrayList<MessagingGroup> otherGroups) {
+ mGroupMap.clear();
+ int lastMatch = Integer.MAX_VALUE;
+ for (int i = ownGroups.size() - 1; i >= 0; i--) {
+ MessagingGroup ownGroup = ownGroups.get(i);
+ MessagingGroup bestMatch = null;
+ int bestCompatibility = 0;
+ for (int j = Math.min(otherGroups.size(), lastMatch) - 1; j >= 0; j--) {
+ MessagingGroup otherGroup = otherGroups.get(j);
+ int compatibility = ownGroup.calculateGroupCompatibility(otherGroup);
+ if (compatibility > bestCompatibility) {
+ bestCompatibility = compatibility;
+ bestMatch = otherGroup;
+ lastMatch = j;
+ }
+ }
+ if (bestMatch != null) {
+ mGroupMap.put(ownGroup, bestMatch);
+ }
+ }
+ return mGroupMap;
+ }
+
+ private boolean isGone(View view) {
+ if (view.getVisibility() == View.GONE) {
+ return true;
+ }
+ final ViewGroup.LayoutParams lp = view.getLayoutParams();
+ if (lp instanceof MessagingLinearLayout.LayoutParams
+ && ((MessagingLinearLayout.LayoutParams) lp).hide) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void setVisible(boolean visible, boolean force) {
+ resetTransformedView();
+ ArrayList<MessagingGroup> ownGroups = mMessagingLayout.getMessagingGroups();
+ for (int i = 0; i < ownGroups.size(); i++) {
+ MessagingGroup ownGroup = ownGroups.get(i);
+ if (!isGone(ownGroup)) {
+ MessagingLinearLayout ownMessages = ownGroup.getMessageContainer();
+ for (int j = 0; j < ownMessages.getChildCount(); j++) {
+ MessagingMessage child = (MessagingMessage) ownMessages.getChildAt(j);
+ setVisible(child, visible, force);
+ }
+ setVisible(ownGroup.getAvatar(), visible, force);
+ setVisible(ownGroup.getSender(), visible, force);
+ }
+ }
+ }
+
+ private void setVisible(View child, boolean visible, boolean force) {
+ if (isGone(child) || MessagingPropertyAnimator.isAnimatingAlpha(child)) {
+ return;
+ }
+ TransformState ownState = TransformState.createFrom(child, mTransformInfo);
+ ownState.setVisible(visible, force);
+ ownState.recycle();
+ }
+
+ @Override
+ protected void resetTransformedView() {
+ super.resetTransformedView();
+ ArrayList<MessagingGroup> ownGroups = mMessagingLayout.getMessagingGroups();
+ for (int i = 0; i < ownGroups.size(); i++) {
+ MessagingGroup ownGroup = ownGroups.get(i);
+ if (!isGone(ownGroup)) {
+ MessagingLinearLayout ownMessages = ownGroup.getMessageContainer();
+ for (int j = 0; j < ownMessages.getChildCount(); j++) {
+ View child = ownMessages.getChildAt(j);
+ if (isGone(child)) {
+ continue;
+ }
+ resetTransformedView(child);
+ setClippingDeactivated(child, false);
+ }
+ resetTransformedView(ownGroup.getAvatar());
+ resetTransformedView(ownGroup.getSender());
+ setClippingDeactivated(ownGroup.getAvatar(), false);
+ setClippingDeactivated(ownGroup.getSender(), false);
+ ownGroup.setTranslationY(0);
+ ownGroup.getMessageContainer().setTranslationY(0);
+ }
+ }
+ }
+
+ @Override
+ public void prepareFadeIn() {
+ super.prepareFadeIn();
+ setVisible(true /* visible */, false /* force */);
+ }
+
+ private void resetTransformedView(View child) {
+ TransformState ownState = TransformState.createFrom(child, mTransformInfo);
+ ownState.resetTransformedView();
+ ownState.recycle();
+ }
+
+ @Override
+ protected void reset() {
+ super.reset();
+ mMessageContainer = null;
+ mMessagingLayout = null;
+ }
+
+ @Override
+ public void recycle() {
+ super.recycle();
+ mGroupMap.clear();;
+ sInstancePool.release(this);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
index f6ee1cac9c3d..fb5644f76ce3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
@@ -16,7 +16,9 @@
package com.android.systemui.statusbar.notification;
+import com.android.internal.widget.MessagingLayout;
import com.android.internal.widget.MessagingLinearLayout;
+import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.TransformableView;
@@ -32,41 +34,20 @@ import java.util.ArrayList;
*/
public class NotificationMessagingTemplateViewWrapper extends NotificationTemplateViewWrapper {
- private View mContractedMessage;
- private ArrayList<View> mHistoricMessages = new ArrayList<View>();
+ private final int mMinHeightWithActions;
+ private MessagingLayout mMessagingLayout;
+ private MessagingLinearLayout mMessagingLinearLayout;
protected NotificationMessagingTemplateViewWrapper(Context ctx, View view,
ExpandableNotificationRow row) {
super(ctx, view, row);
+ mMessagingLayout = (MessagingLayout) view;
+ mMinHeightWithActions = NotificationUtils.getFontScaledHeight(ctx,
+ R.dimen.notification_messaging_actions_min_height);
}
private void resolveViews() {
- mContractedMessage = null;
-
- View container = mView.findViewById(com.android.internal.R.id.notification_messaging);
- if (container instanceof MessagingLinearLayout
- && ((MessagingLinearLayout) container).getChildCount() > 0) {
- MessagingLinearLayout messagingContainer = (MessagingLinearLayout) container;
-
- int childCount = messagingContainer.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = messagingContainer.getChildAt(i);
-
- if (child.getVisibility() == View.GONE
- && child instanceof TextView
- && !TextUtils.isEmpty(((TextView) child).getText())) {
- mHistoricMessages.add(child);
- }
-
- // Only consider the first visible child - transforming to a position other than the
- // first looks bad because we have to move across other messages that are fading in.
- if (child.getId() == messagingContainer.getContractedChildId()) {
- mContractedMessage = child;
- } else if (child.getVisibility() == View.VISIBLE) {
- break;
- }
- }
- }
+ mMessagingLinearLayout = mMessagingLayout.getMessagingLinearLayout();
}
@Override
@@ -81,16 +62,22 @@ public class NotificationMessagingTemplateViewWrapper extends NotificationTempla
protected void updateTransformedTypes() {
// This also clears the existing types
super.updateTransformedTypes();
- if (mContractedMessage != null) {
- mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TEXT,
- mContractedMessage);
+ if (mMessagingLinearLayout != null) {
+ mTransformationHelper.addTransformedView(mMessagingLinearLayout.getId(),
+ mMessagingLinearLayout);
}
}
@Override
public void setRemoteInputVisible(boolean visible) {
- for (int i = 0; i < mHistoricMessages.size(); i++) {
- mHistoricMessages.get(i).setVisibility(visible ? View.VISIBLE : View.GONE);
+ mMessagingLayout.showHistoricMessages(visible);
+ }
+
+ @Override
+ public int getMinLayoutHeight() {
+ if (mActionsContainer != null && mActionsContainer.getVisibility() != View.GONE) {
+ return mMinHeightWithActions;
}
+ return super.getMinLayoutHeight();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index bb979ebd1288..fd085d9c2391 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -41,7 +41,7 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
private ProgressBar mProgressBar;
private TextView mTitle;
private TextView mText;
- private View mActionsContainer;
+ protected View mActionsContainer;
private View mReplyAction;
private Rect mTmpRect = new Rect();
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 3115361c6927..af393c91730f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -66,4 +66,14 @@ public class NotificationUtils {
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
+ */
+ public static int getFontScaledHeight(Context context, int dimenId) {
+ int dimensionPixelSize = context.getResources().getDimensionPixelSize(dimenId);
+ float factor = Math.max(1.0f, context.getResources().getDisplayMetrics().scaledDensity /
+ context.getResources().getDisplayMetrics().density);
+ return (int) (dimensionPixelSize * factor);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 5200d6962ed5..1cd5f15b4f80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -190,4 +190,8 @@ public abstract class NotificationViewWrapper implements TransformableView {
public boolean disallowSingleClick(float x, float y) {
return false;
}
+
+ public int getMinLayoutHeight() {
+ return 0;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
index c4aabe48f61c..178c8130307f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
@@ -33,8 +33,8 @@ public class TextViewTransformState extends TransformState {
private TextView mText;
@Override
- public void initFrom(View view) {
- super.initFrom(view);
+ public void initFrom(View view, TransformInfo transformInfo) {
+ super.initFrom(view, transformInfo);
if (view instanceof TextView) {
mText = (TextView) view;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index bafedff4f78c..ad07af0a3e46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -26,6 +26,8 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.android.internal.widget.MessagingPropertyAnimator;
+import com.android.internal.widget.ViewClippingUtil;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.CrossFadeHelper;
@@ -43,23 +45,46 @@ public class TransformState {
public static final int TRANSFORM_ALL = TRANSFORM_X | TRANSFORM_Y;
private static final float UNDEFINED = -1f;
- private static final int CLIP_CLIPPING_SET = R.id.clip_children_set_tag;
- private static final int CLIP_CHILDREN_TAG = R.id.clip_children_tag;
- private static final int CLIP_TO_PADDING = R.id.clip_to_padding_tag;
private static final int TRANSFORMATION_START_X = R.id.transformation_start_x_tag;
private static final int TRANSFORMATION_START_Y = R.id.transformation_start_y_tag;
private static final int TRANSFORMATION_START_SCLALE_X = R.id.transformation_start_scale_x_tag;
private static final int TRANSFORMATION_START_SCLALE_Y = R.id.transformation_start_scale_y_tag;
private static Pools.SimplePool<TransformState> sInstancePool = new Pools.SimplePool<>(40);
+ private static ViewClippingUtil.ClippingParameters CLIPPING_PARAMETERS
+ = new ViewClippingUtil.ClippingParameters() {
+ @Override
+ public boolean shouldFinish(View view) {
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ return !row.isChildInGroup();
+ }
+ return false;
+ }
+
+ @Override
+ public void onClippingStateChanged(View view, boolean isClipping) {
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ if (isClipping) {
+ row.setClipToActualHeight(true);
+ } else if (row.isChildInGroup()) {
+ row.setClipToActualHeight(false);
+ }
+ }
+ }
+ };
protected View mTransformedView;
+ protected TransformInfo mTransformInfo;
private int[] mOwnPosition = new int[2];
private boolean mSameAsAny;
private float mTransformationEndY = UNDEFINED;
private float mTransformationEndX = UNDEFINED;
+ private Interpolator mDefaultInterpolator = Interpolators.FAST_OUT_SLOW_IN;
- public void initFrom(View view) {
+ public void initFrom(View view, TransformInfo transformInfo) {
mTransformedView = view;
+ mTransformInfo = transformInfo;
}
/**
@@ -108,13 +133,16 @@ public class TransformState {
final View transformedView = mTransformedView;
boolean transformX = (transformationFlags & TRANSFORM_X) != 0;
boolean transformY = (transformationFlags & TRANSFORM_Y) != 0;
- boolean transformScale = transformScale(otherState);
+ boolean differentHeight = otherState.getViewHeight() != getViewHeight();
+ boolean differentWidth = otherState.getViewWidth() != getViewWidth();
+ boolean transformScale = transformScale(otherState) && (differentHeight || differentWidth);
// lets animate the positions correctly
if (transformationAmount == 0.0f
|| transformX && getTransformationStartX() == UNDEFINED
|| transformY && getTransformationStartY() == UNDEFINED
- || transformScale && getTransformationStartScaleX() == UNDEFINED
- || transformScale && getTransformationStartScaleY() == UNDEFINED) {
+ || transformScale && getTransformationStartScaleX() == UNDEFINED && differentWidth
+ || transformScale && getTransformationStartScaleY() == UNDEFINED
+ && differentHeight) {
int[] otherPosition;
if (transformationAmount != 0.0f) {
otherPosition = otherState.getLaidOutLocationOnScreen();
@@ -132,14 +160,14 @@ public class TransformState {
}
// we also want to animate the scale if we're the same
View otherView = otherState.getTransformedView();
- if (transformScale && otherState.getViewWidth() != getViewWidth()) {
+ if (transformScale && differentWidth) {
setTransformationStartScaleX(otherState.getViewWidth() * otherView.getScaleX()
/ (float) getViewWidth());
transformedView.setPivotX(0);
} else {
setTransformationStartScaleX(UNDEFINED);
}
- if (transformScale && otherState.getViewHeight() != getViewHeight()) {
+ if (transformScale && differentHeight) {
setTransformationStartScaleY(otherState.getViewHeight() * otherView.getScaleY()
/ (float) getViewHeight());
transformedView.setPivotY(0);
@@ -159,7 +187,7 @@ public class TransformState {
}
setClippingDeactivated(transformedView, true);
}
- float interpolatedValue = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+ float interpolatedValue = mDefaultInterpolator.getInterpolation(
transformationAmount);
if (transformX) {
float interpolation = interpolatedValue;
@@ -297,7 +325,7 @@ public class TransformState {
}
setClippingDeactivated(transformedView, true);
}
- float interpolatedValue = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+ float interpolatedValue = mDefaultInterpolator.getInterpolation(
transformationAmount);
int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
int[] ownPosition = getLaidOutLocationOnScreen();
@@ -354,59 +382,8 @@ public class TransformState {
}
}
- public static void setClippingDeactivated(final View transformedView, boolean deactivated) {
- if (!(transformedView.getParent() instanceof ViewGroup)) {
- return;
- }
- ViewGroup view = (ViewGroup) transformedView.getParent();
- while (true) {
- ArraySet<View> clipSet = (ArraySet<View>) view.getTag(CLIP_CLIPPING_SET);
- if (clipSet == null) {
- clipSet = new ArraySet<>();
- view.setTag(CLIP_CLIPPING_SET, clipSet);
- }
- Boolean clipChildren = (Boolean) view.getTag(CLIP_CHILDREN_TAG);
- if (clipChildren == null) {
- clipChildren = view.getClipChildren();
- view.setTag(CLIP_CHILDREN_TAG, clipChildren);
- }
- Boolean clipToPadding = (Boolean) view.getTag(CLIP_TO_PADDING);
- if (clipToPadding == null) {
- clipToPadding = view.getClipToPadding();
- view.setTag(CLIP_TO_PADDING, clipToPadding);
- }
- ExpandableNotificationRow row = view instanceof ExpandableNotificationRow
- ? (ExpandableNotificationRow) view
- : null;
- if (!deactivated) {
- clipSet.remove(transformedView);
- if (clipSet.isEmpty()) {
- view.setClipChildren(clipChildren);
- view.setClipToPadding(clipToPadding);
- view.setTag(CLIP_CLIPPING_SET, null);
- if (row != null) {
- row.setClipToActualHeight(true);
- }
- }
- } else {
- clipSet.add(transformedView);
- view.setClipChildren(false);
- view.setClipToPadding(false);
- if (row != null && row.isChildInGroup()) {
- // We still want to clip to the parent's height
- row.setClipToActualHeight(false);
- }
- }
- if (row != null && !row.isChildInGroup()) {
- return;
- }
- final ViewParent parent = view.getParent();
- if (parent instanceof ViewGroup) {
- view = (ViewGroup) parent;
- } else {
- return;
- }
- }
+ protected void setClippingDeactivated(final View transformedView, boolean deactivated) {
+ ViewClippingUtil.setClippingDeactivated(transformedView, deactivated, CLIPPING_PARAMETERS);
}
public int[] getLaidOutLocationOnScreen() {
@@ -423,6 +400,9 @@ public class TransformState {
// remove scale
mOwnPosition[0] -= (1.0f - mTransformedView.getScaleX()) * mTransformedView.getPivotX();
mOwnPosition[1] -= (1.0f - mTransformedView.getScaleY()) * mTransformedView.getPivotY();
+
+ // Remove local translations
+ mOwnPosition[1] -= MessagingPropertyAnimator.getLocalTranslationY(mTransformedView);
return mOwnPosition;
}
@@ -444,20 +424,26 @@ public class TransformState {
CrossFadeHelper.fadeOut(mTransformedView, transformationAmount);
}
- public static TransformState createFrom(View view) {
+ public static TransformState createFrom(View view,
+ TransformInfo transformInfo) {
if (view instanceof TextView) {
TextViewTransformState result = TextViewTransformState.obtain();
- result.initFrom(view);
+ result.initFrom(view, transformInfo);
return result;
}
if (view.getId() == com.android.internal.R.id.actions_container) {
ActionListTransformState result = ActionListTransformState.obtain();
- result.initFrom(view);
+ result.initFrom(view, transformInfo);
+ return result;
+ }
+ if (view.getId() == com.android.internal.R.id.notification_messaging) {
+ MessagingLayoutTransformState result = MessagingLayoutTransformState.obtain();
+ result.initFrom(view, transformInfo);
return result;
}
if (view instanceof ImageView) {
ImageTransformState result = ImageTransformState.obtain();
- result.initFrom(view);
+ result.initFrom(view, transformInfo);
if (view.getId() == com.android.internal.R.id.reply_icon_action) {
((TransformState) result).setIsSameAsAnyView(true);
}
@@ -465,15 +451,15 @@ public class TransformState {
}
if (view instanceof ProgressBar) {
ProgressTransformState result = ProgressTransformState.obtain();
- result.initFrom(view);
+ result.initFrom(view, transformInfo);
return result;
}
TransformState result = obtain();
- result.initFrom(view);
+ result.initFrom(view, transformInfo);
return result;
}
- private void setIsSameAsAnyView(boolean sameAsAny) {
+ public void setIsSameAsAnyView(boolean sameAsAny) {
mSameAsAny = sameAsAny;
}
@@ -533,6 +519,7 @@ public class TransformState {
mSameAsAny = false;
mTransformationEndX = UNDEFINED;
mTransformationEndY = UNDEFINED;
+ mDefaultInterpolator = Interpolators.FAST_OUT_SLOW_IN;
}
public void setVisible(boolean visible, boolean force) {
@@ -578,4 +565,12 @@ public class TransformState {
public View getTransformedView() {
return mTransformedView;
}
+
+ public void setDefaultInterpolator(Interpolator interpolator) {
+ mDefaultInterpolator = interpolator;
+ }
+
+ public interface TransformInfo {
+ boolean isAnimating();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 1bd90fa9ca08..149ec0b3a56a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -20,7 +20,7 @@ import android.os.Looper;
import android.provider.Settings.Secure;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.NightDisplayController;
+import com.android.internal.app.ColorDisplayController;
import com.android.systemui.Dependency;
import com.android.systemui.Prefs;
import com.android.systemui.Prefs.Key;
@@ -78,8 +78,8 @@ public class AutoTileManager {
}
if (!mAutoTracker.isAdded(NIGHT)
- && NightDisplayController.isAvailable(mContext)) {
- Dependency.get(NightDisplayController.class).setListener(mNightDisplayCallback);
+ && ColorDisplayController.isAvailable(mContext)) {
+ Dependency.get(ColorDisplayController.class).setListener(mColorDisplayCallback);
}
}
@@ -89,7 +89,7 @@ public class AutoTileManager {
Dependency.get(HotspotController.class).removeCallback(mHotspotCallback);
Dependency.get(DataSaverController.class).removeCallback(mDataSaverListener);
Dependency.get(ManagedProfileController.class).removeCallback(mProfileCallback);
- Dependency.get(NightDisplayController.class).setListener(null);
+ Dependency.get(ColorDisplayController.class).setListener(null);
}
private final ManagedProfileController.Callback mProfileCallback =
@@ -139,8 +139,8 @@ public class AutoTileManager {
};
@VisibleForTesting
- final NightDisplayController.Callback mNightDisplayCallback =
- new NightDisplayController.Callback() {
+ final ColorDisplayController.Callback mColorDisplayCallback =
+ new ColorDisplayController.Callback() {
@Override
public void onActivated(boolean activated) {
if (activated) {
@@ -150,8 +150,8 @@ public class AutoTileManager {
@Override
public void onAutoModeChanged(int autoMode) {
- if (autoMode == NightDisplayController.AUTO_MODE_CUSTOM
- || autoMode == NightDisplayController.AUTO_MODE_TWILIGHT) {
+ if (autoMode == ColorDisplayController.AUTO_MODE_CUSTOM
+ || autoMode == ColorDisplayController.AUTO_MODE_TWILIGHT) {
addNightTile();
}
}
@@ -160,7 +160,7 @@ public class AutoTileManager {
if (mAutoTracker.isAdded(NIGHT)) return;
mHost.addTile(NIGHT);
mAutoTracker.setTileAdded(NIGHT);
- mHandler.post(() -> Dependency.get(NightDisplayController.class)
+ mHandler.post(() -> Dependency.get(ColorDisplayController.class)
.setListener(null));
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index d226fedef706..1c361caa4a1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -175,9 +175,8 @@ public class LightBarController implements BatteryController.BatteryStateChangeC
private boolean isLight(int vis, int barMode, int flag) {
boolean isTransparentBar = (barMode == MODE_TRANSPARENT
|| barMode == MODE_LIGHTS_OUT_TRANSPARENT);
- boolean allowLight = isTransparentBar && !mBatteryController.isPowerSave();
boolean light = (vis & flag) != 0;
- return allowLight && light;
+ return isTransparentBar && light;
}
private boolean animateChange() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 8e0a506ac52d..bed6d82147fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -19,7 +19,10 @@ package com.android.systemui.statusbar.phone;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Matrix;
import android.graphics.Rect;
+import android.os.RemoteException;
+import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@@ -29,9 +32,11 @@ import android.view.ViewConfiguration;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.systemui.Dependency;
+import com.android.systemui.OverviewProxyService;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
+import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.tuner.TunerService;
@@ -45,6 +50,7 @@ import static android.view.WindowManager.DOCKED_TOP;
public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureListener
implements TunerService.Tunable, GestureHelper {
+ private static final String TAG = "NavBarGestureHelper";
private static final String KEY_DOCK_WINDOW_GESTURE = "overview_nav_bar_gesture";
/**
* When dragging from the navigation bar, we drag in recents.
@@ -71,10 +77,13 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL
private final GestureDetector mTaskSwitcherDetector;
private final int mScrollTouchSlop;
private final int mMinFlingVelocity;
+ private final Matrix mTransformGlobalMatrix = new Matrix();
+ private final Matrix mTransformLocalMatrix = new Matrix();
private int mTouchDownX;
private int mTouchDownY;
private boolean mDownOnRecents;
private VelocityTracker mVelocityTracker;
+ private OverviewProxyService mOverviewEventSender = Dependency.get(OverviewProxyService.class);
private boolean mDockWindowEnabled;
private boolean mDockWindowTouchSlopExceeded;
@@ -106,15 +115,34 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL
mIsRTL = isRTL;
}
+ private boolean proxyMotionEvents(MotionEvent event) {
+ final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
+ if (overviewProxy != null) {
+ mNavigationBarView.requestUnbufferedDispatch(event);
+ event.transform(mTransformGlobalMatrix);
+ try {
+ overviewProxy.onMotionEvent(event);
+ return true;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
+ } finally {
+ event.transform(mTransformLocalMatrix);
+ }
+ }
+ return false;
+ }
+
public boolean onInterceptTouchEvent(MotionEvent event) {
- // If we move more than a fixed amount, then start capturing for the
- // task switcher detector
- mTaskSwitcherDetector.onTouchEvent(event);
int action = event.getAction();
+ boolean result = false;
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
mTouchDownX = (int) event.getX();
mTouchDownY = (int) event.getY();
+ mTransformGlobalMatrix.set(Matrix.IDENTITY_MATRIX);
+ mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX);
+ mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix);
+ mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
break;
}
case MotionEvent.ACTION_MOVE: {
@@ -122,11 +150,10 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL
int y = (int) event.getY();
int xDiff = Math.abs(x - mTouchDownX);
int yDiff = Math.abs(y - mTouchDownY);
- boolean exceededTouchSlop = !mIsVertical
- ? xDiff > mScrollTouchSlop && xDiff > yDiff
- : yDiff > mScrollTouchSlop && yDiff > xDiff;
+ boolean exceededTouchSlop = xDiff > mScrollTouchSlop && xDiff > yDiff
+ || yDiff > mScrollTouchSlop && yDiff > xDiff;
if (exceededTouchSlop) {
- return true;
+ result = true;
}
break;
}
@@ -134,7 +161,12 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL
case MotionEvent.ACTION_UP:
break;
}
- return mDockWindowEnabled && interceptDockWindowEvent(event);
+ if (!proxyMotionEvents(event)) {
+ // If we move more than a fixed amount, then start capturing for the
+ // task switcher detector, disabled when proxying motion events to launcher service
+ mTaskSwitcherDetector.onTouchEvent(event);
+ }
+ return result || (mDockWindowEnabled && interceptDockWindowEvent(event));
}
private boolean interceptDockWindowEvent(MotionEvent event) {
@@ -274,7 +306,7 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL
}
public boolean onTouchEvent(MotionEvent event) {
- boolean result = mTaskSwitcherDetector.onTouchEvent(event);
+ boolean result = proxyMotionEvents(event) || mTaskSwitcherDetector.onTouchEvent(event);
if (mDockWindowEnabled) {
result |= handleDockWindowEvent(event);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 094129c5793b..4e7f205f167e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -47,6 +47,8 @@ import android.widget.FrameLayout;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.DockedStackExistsListener;
+import com.android.systemui.OverviewProxyService;
+import com.android.systemui.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.plugins.PluginListener;
@@ -196,6 +198,9 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
}
}
+ private final OverviewProxyListener mOverviewProxyListener =
+ isConnected -> setSlippery(!isConnected);
+
public NavigationBarView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -531,6 +536,24 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
}
}
+ private void setSlippery(boolean slippery) {
+ boolean changed = false;
+ final ViewGroup navbarView = ((ViewGroup) getParent());
+ final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) navbarView
+ .getLayoutParams();
+ if (slippery && (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) == 0) {
+ lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY;
+ changed = true;
+ } else if (!slippery && (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) != 0) {
+ lp.flags &= ~WindowManager.LayoutParams.FLAG_SLIPPERY;
+ changed = true;
+ }
+ if (changed) {
+ WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
+ wm.updateViewLayout(navbarView, lp);
+ }
+ }
+
public void setMenuVisibility(final boolean show) {
setMenuVisibility(show, false);
}
@@ -756,6 +779,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
onPluginDisconnected(null); // Create default gesture helper
Dependency.get(PluginManager.class).addPluginListener(this,
NavGesture.class, false /* Only one */);
+ Dependency.get(OverviewProxyService.class).addCallback(mOverviewProxyListener);
}
@Override
@@ -765,6 +789,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
if (mGestureHelper != null) {
mGestureHelper.destroy();
}
+ Dependency.get(OverviewProxyService.class).removeCallback(mOverviewProxyListener);
}
@Override
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 af03440629db..86a8f4115eee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -596,7 +596,7 @@ public class NotificationPanelView extends PanelView implements
mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
}
closeQs();
- mStatusBar.closeAndSaveGuts(true /* leavebehind */, true /* force */,
+ mStatusBar.getGutsManager().closeAndSaveGuts(true /* leavebehind */, true /* force */,
true /* controls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, false /* animate */,
true /* cancelAnimators */);
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 ba4ff585fed7..09fe579b83c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -67,6 +67,7 @@ import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.policy.BluetoothController;
@@ -249,7 +250,7 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
mLocationController.addCallback(this);
SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallbacks(this);
- SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskListener);
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskListener);
// Clear out all old notifications on startup (only present in the case where sysui dies)
NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
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 fa34d4a62d1b..6775615923d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -20,11 +20,12 @@ 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;
-
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
+
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.NotificationMediaManager.DEBUG_MEDIA;
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;
@@ -40,10 +41,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
-import android.app.INotificationManager;
import android.app.KeyguardManager;
import android.app.Notification;
-import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.RemoteInput;
@@ -80,10 +79,7 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.media.AudioAttributes;
import android.media.MediaMetadata;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
import android.media.session.MediaSessionManager;
-import android.media.session.PlaybackState;
import android.metrics.LogMaker;
import android.net.Uri;
import android.os.AsyncTask;
@@ -115,14 +111,12 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.Display;
-import android.view.HapticFeedbackConstants;
import android.view.IWindowManager;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.ThreadedRenderer;
import android.view.View;
-import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
@@ -146,6 +140,8 @@ import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.NotificationMessagingUtil;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.MessagingGroup;
+import com.android.internal.widget.MessagingMessage;
import com.android.keyguard.KeyguardHostView.OnDismissAction;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -158,6 +154,7 @@ import com.android.systemui.Dependency;
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;
@@ -178,7 +175,6 @@ import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QS;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanel;
@@ -204,10 +200,11 @@ import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
-import com.android.systemui.statusbar.NotificationGuts;
+import com.android.systemui.statusbar.NotificationGutsManager;
import com.android.systemui.statusbar.NotificationInfo;
+import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationShelf;
-import com.android.systemui.statusbar.NotificationSnooze;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.SignalClusterView;
@@ -240,7 +237,6 @@ import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout
.OnChildLocationsChangedListener;
-import com.android.systemui.statusbar.stack.StackStateAnimator;
import com.android.systemui.util.NotificationChannels;
import com.android.systemui.util.leak.LeakDetector;
import com.android.systemui.volume.VolumeComponent;
@@ -252,10 +248,8 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.Stack;
public class StatusBar extends SystemUI implements DemoMode,
@@ -264,7 +258,7 @@ public class StatusBar extends SystemUI implements DemoMode,
ActivatableNotificationView.OnActivatedListener,
ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
ExpandableNotificationRow.OnExpandClickListener, InflationCallback,
- ColorExtractor.OnColorsChangedListener, ConfigurationListener {
+ ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter {
public static final boolean MULTIUSER_DEBUG = false;
public static final boolean ENABLE_REMOTE_INPUT =
@@ -272,7 +266,7 @@ public class StatusBar extends SystemUI implements DemoMode,
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", false);
+ 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;
@@ -284,9 +278,6 @@ public class StatusBar extends SystemUI implements DemoMode,
protected static final boolean ENABLE_HEADS_UP = true;
protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
- // Must match constant in Settings. Used to highlight preferences when linking to Settings.
- private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
-
private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
// Should match the values in PhoneWindowManager
@@ -305,7 +296,6 @@ public class StatusBar extends SystemUI implements DemoMode,
public static final boolean SPEW = false;
public static final boolean DUMPTRUCK = true; // extra dumpsys info
public static final boolean DEBUG_GESTURES = false;
- public static final boolean DEBUG_MEDIA = false;
public static final boolean DEBUG_MEDIA_FAKE_ARTWORK = false;
public static final boolean DEBUG_CAMERA_LIFT = false;
@@ -455,6 +445,8 @@ public class StatusBar extends SystemUI implements DemoMode,
private final int[] mAbsPos = new int[2];
private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
+ private NotificationGutsManager mGutsManager;
+
// for disabling the status bar
private int mDisabled1 = 0;
private int mDisabled2 = 0;
@@ -550,31 +542,7 @@ public class StatusBar extends SystemUI implements DemoMode,
protected final PorterDuffXfermode mSrcOverXferMode =
new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
- private MediaSessionManager mMediaSessionManager;
- private MediaController mMediaController;
- private String mMediaNotificationKey;
- private MediaMetadata mMediaMetadata;
- private final MediaController.Callback mMediaListener = new MediaController.Callback() {
- @Override
- public void onPlaybackStateChanged(PlaybackState state) {
- super.onPlaybackStateChanged(state);
- if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onPlaybackStateChanged: " + state);
- if (state != null) {
- if (!isPlaybackActive(state.getState())) {
- clearCurrentMediaNotification();
- updateMediaMetaData(true, true);
- }
- }
- }
-
- @Override
- public void onMetadataChanged(MediaMetadata metadata) {
- super.onMetadataChanged(metadata);
- if (DEBUG_MEDIA) Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
- mMediaMetadata = metadata;
- updateMediaMetaData(true, true);
- }
- };
+ private NotificationMediaManager mMediaManager;
/** Keys of notifications currently visible to the user. */
private final ArraySet<NotificationVisibility> mCurrentlyVisibleNotifications =
@@ -697,7 +665,6 @@ public class StatusBar extends SystemUI implements DemoMode,
private final HashMap<String, Entry> mPendingNotifications = new HashMap<>();
private boolean mClearAllEnabled;
@Nullable private View mAmbientIndicationContainer;
- private String mKeyToRemoveOnGutsClosed;
private SysuiColorExtractor mColorExtractor;
private ForegroundServiceController mForegroundServiceController;
private ScreenLifecycle mScreenLifecycle;
@@ -814,6 +781,8 @@ public class StatusBar extends SystemUI implements DemoMode,
mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
mLockPatternUtils = new LockPatternUtils(mContext);
+ mMediaManager = new NotificationMediaManager(this, mContext);
+
// Connect in to the status bar manager service
mCommandQueue = getComponent(CommandQueue.class);
mCommandQueue.addCallbacks(this);
@@ -875,6 +844,7 @@ public class StatusBar extends SystemUI implements DemoMode,
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();
@@ -899,16 +869,8 @@ public class StatusBar extends SystemUI implements DemoMode,
Slog.e(TAG, "Failed to register VR mode state listener: " + e);
}
- mNonBlockablePkgs = new HashSet<>();
- Collections.addAll(mNonBlockablePkgs, res.getStringArray(
- com.android.internal.R.array.config_nonBlockableNotificationPackages));
// end old BaseStatusBar.start().
- mMediaSessionManager
- = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
- // TODO: use MediaSessionManager.SessionListener to hook us up to future updates
- // in session state
-
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
mSettingsObserver.onChange(false); // set up
@@ -956,6 +918,8 @@ public class StatusBar extends SystemUI implements DemoMode,
// 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);
mNotificationPanel.setStatusBar(this);
mNotificationPanel.setGroupManager(mGroupManager);
mAboveShelfObserver = new AboveShelfObserver(mStackScroller);
@@ -1230,6 +1194,8 @@ public class StatusBar extends SystemUI implements DemoMode,
}
public void onDensityOrFontScaleChanged() {
+ MessagingMessage.dropCache();
+ MessagingGroup.dropCache();
// start old BaseStatusBar.onDensityOrFontScaleChanged().
if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
updateNotificationsOnDensityOrFontScaleChanged();
@@ -1296,12 +1262,12 @@ public class StatusBar extends SystemUI implements DemoMode,
ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
for (int i = 0; i < activeNotifications.size(); i++) {
Entry entry = activeNotifications.get(i);
- boolean exposedGuts = mNotificationGutsExposed != null
- && entry.row.getGuts() == mNotificationGutsExposed;
+ boolean exposedGuts = mGutsManager.getExposedGuts() != null
+ && entry.row.getGuts() == mGutsManager.getExposedGuts();
entry.row.onDensityOrFontScaleChanged();
if (exposedGuts) {
- mNotificationGutsExposed = entry.row.getGuts();
- bindGuts(entry.row, mGutsMenuItem);
+ mGutsManager.setExposedGuts(entry.row.getGuts());
+ mGutsManager.bindGuts(entry.row);
}
}
}
@@ -1666,6 +1632,7 @@ public class StatusBar extends SystemUI implements DemoMode,
updateNotifications();
}
+ @Override
public void removeNotification(String key, RankingMap ranking) {
boolean deferRemoval = false;
abortExistingInflation(key);
@@ -1679,12 +1646,11 @@ public class StatusBar extends SystemUI implements DemoMode,
|| !mVisualStabilityManager.isReorderingAllowed();
deferRemoval = !mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime);
}
- if (key.equals(mMediaNotificationKey)) {
- clearCurrentMediaNotification();
- updateMediaMetaData(true, true);
- }
- if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)) {
- Entry entry = mNotificationData.get(key);
+ mMediaManager.onNotificationRemoved(key);
+
+ Entry entry = mNotificationData.get(key);
+ if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)
+ && entry.row != null && !entry.row.isDismissed()) {
StatusBarNotification sbn = entry.notification;
Notification.Builder b = Notification.Builder
@@ -1720,6 +1686,7 @@ public class StatusBar extends SystemUI implements DemoMode,
deferRemoval = false;
}
if (updated) {
+ Log.w(TAG, "Keeping notification around after sending remote input "+ entry.key);
mKeysKeptForRemoteInput.add(entry.key);
return;
}
@@ -1729,7 +1696,6 @@ public class StatusBar extends SystemUI implements DemoMode,
mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
return;
}
- Entry entry = mNotificationData.get(key);
if (entry != null && mRemoteInputController.isRemoteInputActive(entry)
&& (entry.row != null && !entry.row.isDismissed())) {
@@ -1737,12 +1703,12 @@ public class StatusBar extends SystemUI implements DemoMode,
mRemoteInputEntriesToRemoveOnCollapse.add(entry);
return;
}
- if (entry != null && mNotificationGutsExposed != null
- && mNotificationGutsExposed == entry.row.getGuts() && entry.row.getGuts() != null
- && !entry.row.getGuts().isLeavebehind()) {
+ if (entry != null && mGutsManager.getExposedGuts() != null
+ && mGutsManager.getExposedGuts() == entry.row.getGuts()
+ && entry.row.getGuts() != null && !entry.row.getGuts().isLeavebehind()) {
Log.w(TAG, "Keeping notification because it's showing guts. " + key);
mLatestRankingMap = ranking;
- mKeyToRemoveOnGutsClosed = key;
+ mGutsManager.setKeyToRemoveOnGutsClosed(key);
return;
}
@@ -2135,7 +2101,8 @@ public class StatusBar extends SystemUI implements DemoMode,
return entry.row.getParent() instanceof NotificationStackScrollLayout;
}
- protected void updateNotifications() {
+ @Override
+ public void updateNotifications() {
mNotificationData.filterAndSort();
updateNotificationShade();
@@ -2177,136 +2144,9 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
- findAndUpdateMediaNotifications();
- }
-
- public void findAndUpdateMediaNotifications() {
- boolean metaDataChanged = false;
-
- synchronized (mNotificationData) {
- ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
- final int N = activeNotifications.size();
-
- // Promote the media notification with a controller in 'playing' state, if any.
- Entry mediaNotification = null;
- MediaController controller = null;
- for (int i = 0; i < N; i++) {
- final Entry entry = activeNotifications.get(i);
-
- if (isMediaNotification(entry)) {
- final MediaSession.Token token =
- entry.notification.getNotification().extras.getParcelable(
- Notification.EXTRA_MEDIA_SESSION);
- if (token != null) {
- MediaController aController = new MediaController(mContext, token);
- if (PlaybackState.STATE_PLAYING ==
- getMediaControllerPlaybackState(aController)) {
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: found mediastyle controller matching "
- + entry.notification.getKey());
- }
- mediaNotification = entry;
- controller = aController;
- break;
- }
- }
- }
- }
- if (mediaNotification == null) {
- // Still nothing? OK, let's just look for live media sessions and see if they match
- // one of our notifications. This will catch apps that aren't (yet!) using media
- // notifications.
-
- if (mMediaSessionManager != null) {
- final List<MediaController> sessions
- = mMediaSessionManager.getActiveSessionsForUser(
- null,
- UserHandle.USER_ALL);
-
- for (MediaController aController : sessions) {
- if (PlaybackState.STATE_PLAYING ==
- getMediaControllerPlaybackState(aController)) {
- // now to see if we have one like this
- final String pkg = aController.getPackageName();
-
- for (int i = 0; i < N; i++) {
- final Entry entry = activeNotifications.get(i);
- if (entry.notification.getPackageName().equals(pkg)) {
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: found controller matching "
- + entry.notification.getKey());
- }
- controller = aController;
- mediaNotification = entry;
- break;
- }
- }
- }
- }
- }
- }
-
- if (controller != null && !sameSessions(mMediaController, controller)) {
- // We have a new media session
- clearCurrentMediaNotification();
- mMediaController = controller;
- mMediaController.registerCallback(mMediaListener);
- mMediaMetadata = mMediaController.getMetadata();
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: "
- + mMediaMetadata);
- }
-
- if (mediaNotification != null) {
- mMediaNotificationKey = mediaNotification.notification.getKey();
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key="
- + mMediaNotificationKey + " controller=" + mMediaController);
- }
- }
- metaDataChanged = true;
- }
- }
-
- if (metaDataChanged) {
- updateNotifications();
- }
- updateMediaMetaData(metaDataChanged, true);
- }
-
- private int getMediaControllerPlaybackState(MediaController controller) {
- if (controller != null) {
- final PlaybackState playbackState = controller.getPlaybackState();
- if (playbackState != null) {
- return playbackState.getState();
- }
- }
- return PlaybackState.STATE_NONE;
+ mMediaManager.findAndUpdateMediaNotifications();
}
- private boolean isPlaybackActive(int state) {
- return state != PlaybackState.STATE_STOPPED && state != PlaybackState.STATE_ERROR
- && state != PlaybackState.STATE_NONE;
- }
-
- private void clearCurrentMediaNotification() {
- mMediaNotificationKey = null;
- mMediaMetadata = null;
- if (mMediaController != null) {
- if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: "
- + mMediaController.getPackageName());
- }
- mMediaController.unregisterCallback(mMediaListener);
- }
- mMediaController = null;
- }
-
- private boolean sameSessions(MediaController a, MediaController b) {
- if (a == b) return true;
- if (a == null) return false;
- return a.controlsSameSession(b);
- }
/**
* Hide the album artwork that is fading out and release its bitmap.
@@ -2323,9 +2163,11 @@ public class StatusBar extends SystemUI implements DemoMode,
}
};
+ // TODO: Move this to NotificationMediaManager.
/**
* Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
*/
+ @Override
public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
Trace.beginSection("StatusBar#updateMediaMetaData");
if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) {
@@ -2344,19 +2186,22 @@ public class StatusBar extends SystemUI implements DemoMode,
return;
}
+ MediaMetadata mediaMetadata = mMediaManager.getMediaMetadata();
+
if (DEBUG_MEDIA) {
- Log.v(TAG, "DEBUG_MEDIA: updating album art for notification " + mMediaNotificationKey
- + " metadata=" + mMediaMetadata
+ Log.v(TAG, "DEBUG_MEDIA: updating album art for notification "
+ + mMediaManager.getMediaNotificationKey()
+ + " metadata=" + mediaMetadata
+ " metaDataChanged=" + metaDataChanged
+ " state=" + mState);
}
Drawable artworkDrawable = null;
- if (mMediaMetadata != null) {
+ if (mediaMetadata != null) {
Bitmap artworkBitmap = null;
- artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
+ artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
if (artworkBitmap == null) {
- artworkBitmap = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+ artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
// might still be null
}
if (artworkBitmap != null) {
@@ -2629,7 +2474,7 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override // NotificationData.Environment
public String getCurrentMediaNotificationKey() {
- return mMediaNotificationKey;
+ return mMediaManager.getMediaNotificationKey();
}
public boolean isScrimSrcModeEnabled() {
@@ -3094,8 +2939,8 @@ public class StatusBar extends SystemUI implements DemoMode,
mStatusBarWindowManager.setForceStatusBarVisible(false);
// Close any guts that might be visible
- closeAndSaveGuts(true /* removeLeavebehind */, true /* force */, true /* removeControls */,
- -1 /* x */, -1 /* y */, true /* resetMenu */);
+ mGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
+ true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
runPostCollapseRunnables();
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
@@ -3276,12 +3121,8 @@ public class StatusBar extends SystemUI implements DemoMode,
}
void checkBarMode(int mode, int windowState, BarTransitions transitions) {
- final boolean powerSave = mBatteryController.isPowerSave();
final boolean anim = !mNoAnimationOnNextBarModeChange && mDeviceInteractive
- && windowState != WINDOW_STATE_HIDDEN && !powerSave;
- if (powerSave && getBarState() == StatusBarState.SHADE) {
- mode = MODE_WARNING;
- }
+ && windowState != WINDOW_STATE_HIDDEN;
transitions.transitionTo(mode, anim);
}
@@ -3446,28 +3287,18 @@ public class StatusBar extends SystemUI implements DemoMode,
pw.println(Settings.Global.zenModeToString(mZenMode));
pw.print(" mUseHeadsUp=");
pw.println(mUseHeadsUp);
- pw.print(" mKeyToRemoveOnGutsClosed=");
- pw.println(mKeyToRemoveOnGutsClosed);
+ pw.print(" mGutsManager: ");
+ if (mGutsManager != null) {
+ mGutsManager.dump(fd, pw, args);
+ }
if (mStatusBarView != null) {
dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
}
- pw.print(" mMediaSessionManager=");
- pw.println(mMediaSessionManager);
- pw.print(" mMediaNotificationKey=");
- pw.println(mMediaNotificationKey);
- pw.print(" mMediaController=");
- pw.print(mMediaController);
- if (mMediaController != null) {
- pw.print(" state=" + mMediaController.getPlaybackState());
- }
- pw.println();
- pw.print(" mMediaMetadata=");
- pw.print(mMediaMetadata);
- if (mMediaMetadata != null) {
- pw.print(" title=" + mMediaMetadata.getText(MediaMetadata.METADATA_KEY_TITLE));
+ pw.println(" mMediaManager: ");
+ if (mMediaManager != null) {
+ mMediaManager.dump(fd, pw, args);
}
- pw.println();
pw.println(" Panels: ");
if (mNotificationPanel != null) {
@@ -3789,7 +3620,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mReinflateNotificationsOnUserSwitched = false;
}
updateNotificationShade();
- clearCurrentMediaNotification();
+ mMediaManager.clearCurrentMediaNotification();
setLockscreenUser(newUserId);
}
@@ -3869,10 +3700,10 @@ public class StatusBar extends SystemUI implements DemoMode,
if (visibleToUser) {
boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
boolean clearNotificationEffects =
- !isPanelFullyCollapsed() &&
+ !isPresenterFullyCollapsed() &&
(mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
int notificationLoad = mNotificationData.getActiveNotifications().size();
- if (pinnedHeadsUp && isPanelFullyCollapsed()) {
+ if (pinnedHeadsUp && isPresenterFullyCollapsed()) {
notificationLoad = 1;
}
mBarService.onPanelRevealed(clearNotificationEffects, notificationLoad);
@@ -4149,7 +3980,8 @@ public class StatusBar extends SystemUI implements DemoMode,
return mState;
}
- public boolean isPanelFullyCollapsed() {
+ @Override
+ public boolean isPresenterFullyCollapsed() {
return mNotificationPanel.isFullyCollapsed();
}
@@ -4732,7 +4564,7 @@ public class StatusBar extends SystemUI implements DemoMode,
public void onClosingFinished() {
runPostCollapseRunnables();
- if (!isPanelFullyCollapsed()) {
+ if (!isPresenterFullyCollapsed()) {
// if we set it not to be focusable when collapsing, we have to undo it when we aborted
// the closing
mStatusBarWindowManager.setStatusBarFocusable(true);
@@ -5597,10 +5429,6 @@ public class StatusBar extends SystemUI implements DemoMode,
protected int mZenMode;
- // which notification is currently being longpress-examined by the user
- private NotificationGuts mNotificationGutsExposed;
- private MenuItem mGutsMenuItem;
-
protected NotificationShelf mNotificationShelf;
protected DismissView mDismissView;
protected EmptyShadeView mEmptyShadeView;
@@ -5611,8 +5439,6 @@ public class StatusBar extends SystemUI implements DemoMode,
protected boolean mVrMode;
- private Set<String> mNonBlockablePkgs;
-
public boolean isDeviceInteractive() {
return mDeviceInteractive;
}
@@ -5884,6 +5710,9 @@ public class StatusBar extends SystemUI implements DemoMode,
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 {
@@ -6141,26 +5970,8 @@ public class StatusBar extends SystemUI implements DemoMode,
return mGroupManager;
}
- public boolean isMediaNotification(NotificationData.Entry entry) {
- // TODO: confirm that there's a valid media key
- return entry.getExpandedContentView() != null &&
- entry.getExpandedContentView()
- .findViewById(com.android.internal.R.id.media_actions) != null;
- }
-
- // The button in the guts that links to the system notification settings for that app
- private void startAppNotificationSettingsActivity(String packageName, final int appUid,
- final NotificationChannel channel) {
- final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
- intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
- intent.putExtra(Settings.EXTRA_APP_UID, appUid);
- if (channel != null) {
- intent.putExtra(EXTRA_FRAGMENT_ARG_KEY, channel.getId());
- }
- startNotificationGutsIntent(intent, appUid);
- }
-
- private void startNotificationGutsIntent(final Intent intent, final int appUid) {
+ @Override
+ public void startNotificationGutsIntent(final Intent intent, final int appUid) {
dismissKeyguardThenExecute(() -> {
AsyncTask.execute(() -> {
TaskStackBuilder.create(mContext)
@@ -6183,231 +5994,8 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
- private void bindGuts(final ExpandableNotificationRow row, MenuItem item) {
- row.inflateGuts();
- row.setGutsView(item);
- final StatusBarNotification sbn = row.getStatusBarNotification();
- row.setTag(sbn.getPackageName());
- final NotificationGuts guts = row.getGuts();
- guts.setClosedListener((NotificationGuts g) -> {
- if (!g.willBeRemoved() && !row.isRemoved()) {
- mStackScroller.onHeightChanged(row, !isPanelFullyCollapsed() /* needsAnimation */);
- }
- if (mNotificationGutsExposed == g) {
- mNotificationGutsExposed = null;
- mGutsMenuItem = null;
- }
- String key = sbn.getKey();
- if (key.equals(mKeyToRemoveOnGutsClosed)) {
- mKeyToRemoveOnGutsClosed = null;
- removeNotification(key, mLatestRankingMap);
- }
- });
-
- View gutsView = item.getGutsView();
- if (gutsView instanceof NotificationSnooze) {
- NotificationSnooze snoozeGuts = (NotificationSnooze) gutsView;
- snoozeGuts.setSnoozeListener(mStackScroller.getSwipeActionHelper());
- snoozeGuts.setStatusBarNotification(sbn);
- snoozeGuts.setSnoozeOptions(row.getEntry().snoozeCriteria);
- guts.setHeightChangedListener((NotificationGuts g) -> {
- mStackScroller.onHeightChanged(row, row.isShown() /* needsAnimation */);
- });
- }
-
- if (gutsView instanceof NotificationInfo) {
- final UserHandle userHandle = sbn.getUser();
- PackageManager pmUser = getPackageManagerForUser(mContext,
- userHandle.getIdentifier());
- final INotificationManager iNotificationManager = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
- final String pkg = sbn.getPackageName();
- NotificationInfo info = (NotificationInfo) gutsView;
- // Settings link is only valid for notifications that specify a user, unless this is the
- // system user.
- NotificationInfo.OnSettingsClickListener onSettingsClick = null;
- if (!userHandle.equals(UserHandle.ALL) || mCurrentUserId == UserHandle.USER_SYSTEM) {
- onSettingsClick = (View v, NotificationChannel channel, int appUid) -> {
- mMetricsLogger.action(MetricsEvent.ACTION_NOTE_INFO);
- guts.resetFalsingCheck();
- startAppNotificationSettingsActivity(pkg, appUid, channel);
- };
- }
- final NotificationInfo.OnAppSettingsClickListener onAppSettingsClick = (View v,
- Intent intent) -> {
- mMetricsLogger.action(MetricsEvent.ACTION_APP_NOTE_SETTINGS);
- guts.resetFalsingCheck();
- startNotificationGutsIntent(intent, sbn.getUid());
- };
- final View.OnClickListener onDoneClick = (View v) -> {
- saveAndCloseNotificationMenu(row, guts, v);
- };
- final NotificationInfo.CheckSaveListener checkSaveListener =
- (Runnable saveImportance) -> {
- // If the user has security enabled, show challenge if the setting is changed.
- if (isLockscreenPublicMode(userHandle.getIdentifier())
- && (mState == StatusBarState.KEYGUARD
- || mState == StatusBarState.SHADE_LOCKED)) {
- onLockedNotificationImportanceChange(() -> {
- saveImportance.run();
- return true;
- });
- } else {
- saveImportance.run();
- }
- };
-
- ArraySet<NotificationChannel> channels = new ArraySet<>();
- channels.add(row.getEntry().channel);
- if (row.isSummaryWithChildren()) {
- // If this is a summary, then add in the children notification channels for the
- // same user and pkg.
- final List<ExpandableNotificationRow> childrenRows = row.getNotificationChildren();
- final int numChildren = childrenRows.size();
- for (int i = 0; i < numChildren; i++) {
- final ExpandableNotificationRow childRow = childrenRows.get(i);
- final NotificationChannel childChannel = childRow.getEntry().channel;
- final StatusBarNotification childSbn = childRow.getStatusBarNotification();
- if (childSbn.getUser().equals(userHandle) &&
- childSbn.getPackageName().equals(pkg)) {
- channels.add(childChannel);
- }
- }
- }
- try {
- info.bindNotification(pmUser, iNotificationManager, pkg, new ArrayList(channels),
- row.getEntry().channel.getImportance(), sbn, onSettingsClick,
- onAppSettingsClick, onDoneClick, checkSaveListener,
- mNonBlockablePkgs);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- }
- }
-
- private void saveAndCloseNotificationMenu(
- ExpandableNotificationRow row, NotificationGuts guts, View done) {
- guts.resetFalsingCheck();
- int[] rowLocation = new int[2];
- int[] doneLocation = new int[2];
- row.getLocationOnScreen(rowLocation);
- done.getLocationOnScreen(doneLocation);
-
- final int centerX = done.getWidth() / 2;
- final int centerY = done.getHeight() / 2;
- final int x = doneLocation[0] - rowLocation[0] + centerX;
- final int y = doneLocation[1] - rowLocation[1] + centerY;
- closeAndSaveGuts(false /* removeLeavebehind */, false /* force */,
- true /* removeControls */, x, y, true /* resetMenu */);
- }
-
protected ExpandableNotificationRow.LongPressListener getNotificationLongClicker() {
- return new ExpandableNotificationRow.LongPressListener() {
- @Override
- public boolean onLongPress(View v, final int x, final int y,
- MenuItem item) {
- if (!(v instanceof ExpandableNotificationRow)) {
- return false;
- }
-
- if (v.getWindowToken() == null) {
- Log.e(TAG, "Trying to show notification guts, but not attached to window");
- return false;
- }
-
- final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
- if (row.isDark()) {
- return false;
- }
- v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- if (row.areGutsExposed()) {
- closeAndSaveGuts(false /* removeLeavebehind */, false /* force */,
- true /* removeControls */, -1 /* x */, -1 /* y */,
- true /* resetMenu */);
- return true;
- }
- bindGuts(row, item);
- NotificationGuts guts = row.getGuts();
-
- // Assume we are a status_bar_notification_row
- if (guts == null) {
- // This view has no guts. Examples are the more card or the dismiss all view
- return false;
- }
-
- mMetricsLogger.action(MetricsEvent.ACTION_NOTE_CONTROLS);
-
- // ensure that it's laid but not visible until actually laid out
- guts.setVisibility(View.INVISIBLE);
- // Post to ensure the the guts are properly laid out.
- guts.post(new Runnable() {
- @Override
- public void run() {
- if (row.getWindowToken() == null) {
- Log.e(TAG, "Trying to show notification guts, but not attached to "
- + "window");
- return;
- }
- closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
- true /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- guts.setVisibility(View.VISIBLE);
- final double horz = Math.max(guts.getWidth() - x, x);
- final double vert = Math.max(guts.getHeight() - y, y);
- final float r = (float) Math.hypot(horz, vert);
- final Animator a
- = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
- a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
- a.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- // Move the notification view back over the menu
- row.resetTranslation();
- }
- });
- a.start();
- final boolean needsFalsingProtection =
- (mState == StatusBarState.KEYGUARD &&
- !mAccessibilityManager.isTouchExplorationEnabled());
- guts.setExposed(true /* exposed */, needsFalsingProtection);
- row.closeRemoteInput();
- mStackScroller.onHeightChanged(row, true /* needsAnimation */);
- mNotificationGutsExposed = guts;
- mGutsMenuItem = item;
- }
- });
- return true;
- }
- };
- }
-
- /**
- * Returns the exposed NotificationGuts or null if none are exposed.
- */
- public NotificationGuts getExposedGuts() {
- return mNotificationGutsExposed;
- }
-
- /**
- * Closes guts or notification menus that might be visible and saves any changes.
- *
- * @param removeLeavebehinds true if leavebehinds (e.g. snooze) should be closed.
- * @param force true if guts should be closed regardless of state (used for snooze only).
- * @param removeControls true if controls (e.g. info) should be closed.
- * @param x if closed based on touch location, this is the x touch location.
- * @param y if closed based on touch location, this is the y touch location.
- * @param resetMenu if any notification menus that might be revealed should be closed.
- */
- public void closeAndSaveGuts(boolean removeLeavebehinds, boolean force, boolean removeControls,
- int x, int y, boolean resetMenu) {
- if (mNotificationGutsExposed != null) {
- mNotificationGutsExposed.closeControls(removeLeavebehinds, removeControls, x, y, force);
- }
- if (resetMenu) {
- mStackScroller.resetExposedMenuView(false /* animate */, true /* force */);
- }
+ return (v, x, y, item) -> mGutsManager.openGuts(v, x, y, item);
}
@Override
@@ -6796,7 +6384,7 @@ public class StatusBar extends SystemUI implements DemoMode,
if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
// Release the HUN notification to the shade.
- if (isPanelFullyCollapsed()) {
+ if (isPresenterFullyCollapsed()) {
HeadsUpManager.setIsClickedNotification(row, true);
}
//
@@ -6928,7 +6516,7 @@ public class StatusBar extends SystemUI implements DemoMode,
if (mVisible != visible) {
mVisible = visible;
if (!visible) {
- closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
+ mGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
}
}
@@ -7112,7 +6700,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
}
- private void updateLockscreenNotificationSetting() {
+ protected void updateLockscreenNotificationSetting() {
final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
1,
@@ -7150,8 +6738,8 @@ public class StatusBar extends SystemUI implements DemoMode,
}
mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
mRemoteInputEntriesToRemoveOnCollapse.remove(entry);
- if (key.equals(mKeyToRemoveOnGutsClosed)) {
- mKeyToRemoveOnGutsClosed = null;
+ if (key.equals(mGutsManager.getKeyToRemoveOnGutsClosed())) {
+ mGutsManager.setKeyToRemoveOnGutsClosed(null);
Log.w(TAG, "Notification that was kept for guts was updated. " + key);
}
@@ -7250,6 +6838,15 @@ public class StatusBar extends SystemUI implements DemoMode,
return false;
}
+ if (mIsOccluded && !isDozing()) {
+ boolean devicePublic = isLockscreenPublicMode(mCurrentUserId);
+ boolean userPublic = devicePublic || isLockscreenPublicMode(sbn.getUserId());
+ boolean needsRedaction = needsRedaction(entry);
+ if (userPublic && needsRedaction) {
+ return false;
+ }
+ }
+
if (sbn.getNotification().fullScreenIntent != null) {
if (mAccessibilityManager.isTouchExplorationEnabled()) {
if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
@@ -7349,4 +6946,43 @@ public class StatusBar extends SystemUI implements DemoMode,
mNavigationBar.getBarTransitions().setAutoDim(true);
}
};
+
+ public NotificationGutsManager getGutsManager() {
+ return mGutsManager;
+ }
+
+ @Override
+ public boolean isPresenterLocked() {
+ return mState == StatusBarState.KEYGUARD;
+ }
+
+ @Override
+ public int getCurrentUserId() {
+ return mCurrentUserId;
+ }
+
+ @Override
+ public NotificationData getNotificationData() {
+ return mNotificationData;
+ }
+
+ @Override
+ public RankingMap getLatestRankingMap() {
+ return mLatestRankingMap;
+ }
+
+ 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)) {
+ onLockedNotificationImportanceChange(() -> {
+ saveImportance.run();
+ return true;
+ });
+ } else {
+ saveImportance.run();
+ }
+ };
}
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 1e14626d9c99..efe049ab2a7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -1343,7 +1343,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
// Check if we need to clear any snooze leavebehinds
- NotificationGuts guts = mStatusBar.getExposedGuts();
+ NotificationGuts guts = mStatusBar.getGutsManager().getExposedGuts();
if (guts != null && !isTouchInView(ev, guts)
&& guts.getGutsContent() instanceof NotificationSnooze) {
NotificationSnooze ns = (NotificationSnooze) guts.getGutsContent();
@@ -2508,12 +2508,13 @@ public class NotificationStackScrollLayout extends ViewGroup
}
// Check if we need to clear any snooze leavebehinds
boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP;
- NotificationGuts guts = mStatusBar.getExposedGuts();
+ NotificationGuts guts = mStatusBar.getGutsManager().getExposedGuts();
if (!isTouchInView(ev, guts) && isUp && !swipeWantsIt && !expandWantsIt
&& !scrollWantsIt) {
mCheckForLeavebehind = false;
- mStatusBar.closeAndSaveGuts(true /* removeLeavebehind */, false /* force */,
- false /* removeControls */, -1 /* x */, -1 /* y */, false /* resetMenu */);
+ mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */,
+ false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
}
if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
mCheckForLeavebehind = true;
@@ -3065,7 +3066,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
if (!childWasSwipedOut) {
Rect clipBounds = child.getClipBounds();
- childWasSwipedOut = clipBounds.height() == 0;
+ childWasSwipedOut = clipBounds != null && clipBounds.height() == 0;
}
int animationType = childWasSwipedOut
? AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT
@@ -3355,8 +3356,9 @@ public class NotificationStackScrollLayout extends ViewGroup
public void checkSnoozeLeavebehind() {
if (mCheckForLeavebehind) {
- mStatusBar.closeAndSaveGuts(true /* removeLeavebehind */, false /* force */,
- false /* removeControls */, -1 /* x */, -1 /* y */, false /* resetMenu */);
+ mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */,
+ false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
mCheckForLeavebehind = false;
}
}
@@ -4438,8 +4440,9 @@ public class NotificationStackScrollLayout extends ViewGroup
// of the panel early.
handleChildDismissed(view);
}
- mStatusBar.closeAndSaveGuts(true /* removeLeavebehind */, false /* force */,
- false /* removeControls */, -1 /* x */, -1 /* y */, false /* resetMenu */);
+ mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */,
+ false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
handleMenuCoveredOrDismissed();
}
@@ -4524,7 +4527,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
public void closeControlsIfOutsideTouch(MotionEvent ev) {
- NotificationGuts guts = mStatusBar.getExposedGuts();
+ NotificationGuts guts = mStatusBar.getGutsManager().getExposedGuts();
View view = null;
if (guts != null && !guts.getGutsContent().isLeavebehind()) {
// Only close visible guts if they're not a leavebehind.
@@ -4536,8 +4539,9 @@ public class NotificationStackScrollLayout extends ViewGroup
}
if (view != null && !isTouchInView(ev, view)) {
// Touch was outside visible guts / menu notification, close what's visible
- mStatusBar.closeAndSaveGuts(false /* removeLeavebehind */, false /* force */,
- true /* removeControls */, -1 /* x */, -1 /* y */, false /* resetMenu */);
+ mStatusBar.getGutsManager().closeAndSaveGuts(false /* removeLeavebehind */,
+ false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
resetExposedMenuView(true /* animate */, true /* force */);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
index f91e45d05e79..27bf534c290e 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/PluginFragment.java
@@ -169,16 +169,23 @@ public class PluginFragment extends PreferenceFragment {
protected boolean persistBoolean(boolean value) {
final int desiredState = value ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+ boolean shouldSendBroadcast = false;
for (int i = 0; i < mInfo.services.length; i++) {
ComponentName componentName = new ComponentName(mInfo.packageName,
mInfo.services[i].name);
- mPm.setComponentEnabledSetting(componentName, desiredState,
- PackageManager.DONT_KILL_APP);
+
+ if (mPm.getComponentEnabledSetting(componentName) != desiredState) {
+ mPm.setComponentEnabledSetting(componentName, desiredState,
+ PackageManager.DONT_KILL_APP);
+ shouldSendBroadcast = true;
+ }
+ }
+ if (shouldSendBroadcast) {
+ final String pkg = mInfo.packageName;
+ final Intent intent = new Intent(PluginManager.PLUGIN_CHANGED,
+ pkg != null ? Uri.fromParts("package", pkg, null) : null);
+ getContext().sendBroadcast(intent);
}
- final String pkg = mInfo.packageName;
- final Intent intent = new Intent(PluginManager.PLUGIN_CHANGED,
- pkg != null ? Uri.fromParts("package", pkg, null) : null);
- getContext().sendBroadcast(intent);
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
index 3eccccdd75bf..e117969c5993 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
@@ -71,10 +71,12 @@ public class UsbConfirmActivity extends AlertActivity
ap.mIcon = mResolveInfo.loadIcon(packageManager);
ap.mTitle = appName;
if (mDevice == null) {
- ap.mMessage = getString(R.string.usb_accessory_confirm_prompt, appName);
+ ap.mMessage = getString(R.string.usb_accessory_confirm_prompt, appName,
+ mAccessory.getDescription());
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
} else {
- ap.mMessage = getString(R.string.usb_device_confirm_prompt, appName);
+ ap.mMessage = getString(R.string.usb_device_confirm_prompt, appName,
+ mDevice.getProductName());
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
}
ap.mPositiveButtonText = getString(android.R.string.ok);
@@ -88,9 +90,11 @@ public class UsbConfirmActivity extends AlertActivity
ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
mAlwaysUse = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
if (mDevice == null) {
- mAlwaysUse.setText(R.string.always_use_accessory);
+ mAlwaysUse.setText(getString(R.string.always_use_accessory, appName,
+ mAccessory.getDescription()));
} else {
- mAlwaysUse.setText(R.string.always_use_device);
+ mAlwaysUse.setText(getString(R.string.always_use_device, appName,
+ mDevice.getProductName()));
}
mAlwaysUse.setOnCheckedChangeListener(this);
mClearDefaultHint = (TextView)ap.mView.findViewById(
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
index 1e69fc5ce1fc..4606aee346cc 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
@@ -16,13 +16,17 @@
package com.android.systemui.usb;
+import android.annotation.NonNull;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.res.XmlResourceParser;
import android.hardware.usb.IUsbManager;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
@@ -41,8 +45,13 @@ import android.widget.TextView;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
+import com.android.internal.util.XmlUtils;
+import android.hardware.usb.AccessoryFilter;
+import android.hardware.usb.DeviceFilter;
import com.android.systemui.R;
+import org.xmlpull.v1.XmlPullParser;
+
public class UsbPermissionActivity extends AlertActivity
implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
@@ -84,10 +93,12 @@ public class UsbPermissionActivity extends AlertActivity
ap.mIcon = aInfo.loadIcon(packageManager);
ap.mTitle = appName;
if (mDevice == null) {
- ap.mMessage = getString(R.string.usb_accessory_permission_prompt, appName);
+ ap.mMessage = getString(R.string.usb_accessory_permission_prompt, appName,
+ mAccessory.getDescription());
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
} else {
- ap.mMessage = getString(R.string.usb_device_permission_prompt, appName);
+ ap.mMessage = getString(R.string.usb_device_permission_prompt, appName,
+ mDevice.getProductName());
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
}
ap.mPositiveButtonText = getString(android.R.string.ok);
@@ -95,25 +106,123 @@ public class UsbPermissionActivity extends AlertActivity
ap.mPositiveButtonListener = this;
ap.mNegativeButtonListener = this;
- // add "always use" checkbox
- LayoutInflater inflater = (LayoutInflater)getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
- mAlwaysUse = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
- if (mDevice == null) {
- mAlwaysUse.setText(R.string.always_use_accessory);
- } else {
- mAlwaysUse.setText(R.string.always_use_device);
+ try {
+ PackageInfo packageInfo = packageManager.getPackageInfo(mPackageName,
+ PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
+
+ if ((mDevice != null && canBeDefault(mDevice, packageInfo))
+ || (mAccessory != null && canBeDefault(mAccessory, packageInfo))) {
+ // add "open when" checkbox
+ LayoutInflater inflater = (LayoutInflater) getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
+ mAlwaysUse = (CheckBox) ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
+ if (mDevice == null) {
+ mAlwaysUse.setText(getString(R.string.always_use_accessory, appName,
+ mAccessory.getDescription()));
+ } else {
+ mAlwaysUse.setText(getString(R.string.always_use_device, appName,
+ mDevice.getProductName()));
+ }
+ mAlwaysUse.setOnCheckedChangeListener(this);
+
+ mClearDefaultHint = (TextView)ap.mView.findViewById(
+ com.android.internal.R.id.clearDefaultHint);
+ mClearDefaultHint.setVisibility(View.GONE);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // ignore
}
- mAlwaysUse.setOnCheckedChangeListener(this);
- mClearDefaultHint = (TextView)ap.mView.findViewById(
- com.android.internal.R.id.clearDefaultHint);
- mClearDefaultHint.setVisibility(View.GONE);
setupAlert();
}
+ /**
+ * Can the app be the default for the USB device. I.e. can the app be launched by default if
+ * the device is plugged in.
+ *
+ * @param device The device the app would be default for
+ * @param packageInfo The package info of the app
+ *
+ * @return {@code true} iff the app can be default
+ */
+ private boolean canBeDefault(@NonNull UsbDevice device, @NonNull PackageInfo packageInfo) {
+ ActivityInfo[] activities = packageInfo.activities;
+ if (activities != null) {
+ int numActivities = activities.length;
+ for (int i = 0; i < numActivities; i++) {
+ ActivityInfo activityInfo = activities[i];
+
+ try (XmlResourceParser parser = activityInfo.loadXmlMetaData(getPackageManager(),
+ UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
+ if (parser == null) {
+ continue;
+ }
+
+ XmlUtils.nextElement(parser);
+ while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+ if ("usb-device".equals(parser.getName())) {
+ DeviceFilter filter = DeviceFilter.read(parser);
+ if (filter.matches(device)) {
+ return true;
+ }
+ }
+
+ XmlUtils.nextElement(parser);
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Unable to load component info " + activityInfo.toString(), e);
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Can the app be the default for the USB accessory. I.e. can the app be launched by default if
+ * the accessory is plugged in.
+ *
+ * @param accessory The accessory the app would be default for
+ * @param packageInfo The package info of the app
+ *
+ * @return {@code true} iff the app can be default
+ */
+ private boolean canBeDefault(@NonNull UsbAccessory accessory,
+ @NonNull PackageInfo packageInfo) {
+ ActivityInfo[] activities = packageInfo.activities;
+ if (activities != null) {
+ int numActivities = activities.length;
+ for (int i = 0; i < numActivities; i++) {
+ ActivityInfo activityInfo = activities[i];
+
+ try (XmlResourceParser parser = activityInfo.loadXmlMetaData(getPackageManager(),
+ UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) {
+ if (parser == null) {
+ continue;
+ }
+
+ XmlUtils.nextElement(parser);
+ while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+ if ("usb-accessory".equals(parser.getName())) {
+ AccessoryFilter filter = AccessoryFilter.read(parser);
+ if (filter.matches(accessory)) {
+ return true;
+ }
+ }
+
+ XmlUtils.nextElement(parser);
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Unable to load component info " + activityInfo.toString(), e);
+ }
+ }
+ }
+
+ return false;
+ }
+
@Override
public void onDestroy() {
IBinder b = ServiceManager.getService(USB_SERVICE);
@@ -126,7 +235,7 @@ public class UsbPermissionActivity extends AlertActivity
intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
if (mPermissionGranted) {
service.grantDevicePermission(mDevice, mUid);
- if (mAlwaysUse.isChecked()) {
+ if (mAlwaysUse != null && mAlwaysUse.isChecked()) {
final int userId = UserHandle.getUserId(mUid);
service.setDevicePackage(mDevice, mPackageName, userId);
}
@@ -136,7 +245,7 @@ public class UsbPermissionActivity extends AlertActivity
intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
if (mPermissionGranted) {
service.grantAccessoryPermission(mAccessory, mUid);
- if (mAlwaysUse.isChecked()) {
+ if (mAlwaysUse != null && mAlwaysUse.isChecked()) {
final int userId = UserHandle.getUserId(mUid);
service.setAccessoryPackage(mAccessory, mPackageName, userId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SystemUIInterpolators.java b/packages/SystemUI/src/com/android/systemui/volume/SystemUIInterpolators.java
new file mode 100644
index 000000000000..5ad8840a9dd1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/SystemUIInterpolators.java
@@ -0,0 +1,78 @@
+/*
+ * 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 android.animation.TimeInterpolator;
+
+public class SystemUIInterpolators {
+ public static final class LogDecelerateInterpolator implements TimeInterpolator {
+ private final float mBase;
+ private final float mDrift;
+ private final float mTimeScale;
+ private final float mOutputScale;
+
+ public LogDecelerateInterpolator() {
+ this(400f, 1.4f, 0);
+ }
+
+ private LogDecelerateInterpolator(float base, float timeScale, float drift) {
+ mBase = base;
+ mDrift = drift;
+ mTimeScale = 1f / timeScale;
+
+ mOutputScale = 1f / computeLog(1f);
+ }
+
+ 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;
+ }
+ }
+
+ public static final class LogAccelerateInterpolator implements TimeInterpolator {
+ private final int mBase;
+ private final int mDrift;
+ private final float mLogScale;
+
+ public LogAccelerateInterpolator() {
+ this(100, 0);
+ }
+
+ private LogAccelerateInterpolator(int base, int drift) {
+ mBase = base;
+ mDrift = drift;
+ mLogScale = 1f / computeLog(1, mBase, mDrift);
+ }
+
+ private static float computeLog(float t, int base, int drift) {
+ return (float) -Math.pow(base, -t) + 1 + (drift * t);
+ }
+
+ @Override
+ public float getInterpolation(float t) {
+ return 1 - computeLog(1 - t, mBase, mDrift) * mLogScale;
+ }
+ }
+
+ public interface Callback {
+ void onAnimatingChanged(boolean animating);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index f6d36e855964..4dff9bd5c782 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -62,7 +62,6 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE
| ActivityInfo.CONFIG_ASSETS_PATHS);
- private final Extension mExtension;
private VolumeDialog mDialog;
private VolumePolicy mVolumePolicy = new VolumePolicy(
DEFAULT_VOLUME_DOWN_TO_ENTER_SILENT, // volumeDownToEnterSilent
@@ -79,7 +78,7 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
// Allow plugins to reference the VolumeDialogController.
Dependency.get(PluginDependencyProvider.class)
.allowPluginDependency(VolumeDialogController.class);
- mExtension = Dependency.get(ExtensionController.class).newExtension(VolumeDialog.class)
+ Dependency.get(ExtensionController.class).newExtension(VolumeDialog.class)
.withPlugin(VolumeDialog.class)
.withDefault(this::createDefault)
.withCallback(dialog -> {
@@ -96,7 +95,6 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
private VolumeDialog createDefault() {
VolumeDialogImpl impl = new VolumeDialogImpl(mContext);
- impl.setStreamImportant(AudioManager.STREAM_ALARM, true);
impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
impl.setAutomute(true);
impl.setSilentMode(false);
@@ -152,7 +150,7 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (mConfigChanges.applyNewConfig(mContext.getResources())) {
- mExtension.reload();
+ mController.mCallbacks.onConfigurationChanged();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 761e979d3244..4b8f581ac11a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -19,6 +19,8 @@ package com.android.systemui.volume;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
+import static com.android.systemui.volume.Events.DISMISS_REASON_TOUCH_OUTSIDE;
+
import android.accessibilityservice.AccessibilityServiceInfo;
import android.animation.ObjectAnimator;
import android.annotation.NonNull;
@@ -26,16 +28,13 @@ import android.annotation.SuppressLint;
import android.app.Dialog;
import android.app.KeyguardManager;
import android.content.Context;
-import android.content.pm.PackageManager;
+import android.content.DialogInterface;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
-import android.graphics.PixelFormat;
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;
@@ -44,15 +43,10 @@ import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.provider.Settings.Global;
-import android.transition.AutoTransition;
-import android.transition.Transition;
-import android.transition.TransitionManager;
-import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.view.ContextThemeWrapper;
-import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.AccessibilityDelegate;
@@ -60,7 +54,6 @@ import android.view.View.OnAttachStateChangeListener;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
-import android.view.ViewGroup.MarginLayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
@@ -74,16 +67,13 @@ import android.widget.TextView;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
+import com.android.systemui.HardwareUiLayout;
import com.android.systemui.Interpolators;
-import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.plugins.VolumeDialog;
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.plugins.VolumeDialogController.State;
import com.android.systemui.plugins.VolumeDialogController.StreamState;
-import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerZenModePanel;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -96,11 +86,9 @@ import java.util.List;
*
* Methods ending in "H" must be called on the (ui) handler.
*/
-public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
+public class VolumeDialogImpl implements VolumeDialog {
private static final String TAG = Util.logTag(VolumeDialogImpl.class);
- public static final String SHOW_FULL_ZEN = "sysui_show_full_zen";
-
private static final long USER_ATTEMPT_GRACE_PERIOD = 1000;
private static final int UPDATE_ANIMATION_DURATION = 80;
@@ -109,29 +97,22 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
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 final List<VolumeRow> mRows = new ArrayList<>();
private ConfigurableTexts mConfigurableTexts;
private final SparseBooleanArray mDynamic = new SparseBooleanArray();
private final KeyguardManager mKeyguard;
- private final AudioManager mAudioManager;
private final AccessibilityManager mAccessibilityMgr;
- private int mExpandButtonAnimationDuration;
- private ZenFooter mZenFooter;
private final Object mSafetyWarningLock = new Object();
private final Accessibility mAccessibility = new Accessibility();
private final ColorStateList mActiveSliderTint;
private final ColorStateList mInactiveSliderTint;
- private VolumeDialogMotion mMotion;
- private int mWindowType;
- private final ZenModeController mZenModeController;
private boolean mShowing;
- private boolean mExpanded;
private boolean mShowA11yStream;
private int mActiveStream;
@@ -139,24 +120,13 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE;
private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE;
private State mState;
- private boolean mExpandButtonAnimationRunning;
private SafetyWarningDialog mSafetyWarning;
- private Callback mCallback;
- private boolean mPendingStateChanged;
- private boolean mPendingRecheckAll;
- private long mCollapseTime;
private boolean mHovering = false;
- private int mDensity;
-
- private boolean mShowFullZen;
- private TunerZenModePanel mZenPanel;
public VolumeDialogImpl(Context context) {
mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
- mZenModeController = Dependency.get(ZenModeController.class);
mController = Dependency.get(VolumeDialogController.class);
mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
- mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
mAccessibilityMgr =
(AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext));
@@ -164,29 +134,18 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
}
public void init(int windowType, Callback callback) {
- mCallback = callback;
- mWindowType = windowType;
-
initDialog();
mAccessibility.init();
mController.addCallback(mControllerCallbackH, mHandler);
mController.getState();
- Dependency.get(TunerService.class).addTunable(this, SHOW_FULL_ZEN);
-
- final Configuration currentConfig = mContext.getResources().getConfiguration();
- mDensity = currentConfig.densityDpi;
}
@Override
public void destroy() {
mAccessibility.destroy();
mController.removeCallback(mControllerCallbackH);
- if (mZenFooter != null) {
- mZenFooter.cleanup();
- }
- Dependency.get(TunerService.class).removeTunable(this);
mHandler.removeCallbacksAndMessages(null);
}
@@ -199,25 +158,16 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
mWindow = mDialog.getWindow();
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
- mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
- 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);
- mDialog.setCanceledOnTouchOutside(true);
- final Resources res = mContext.getResources();
- final WindowManager.LayoutParams lp = mWindow.getAttributes();
- lp.type = mWindowType;
- lp.format = PixelFormat.TRANSLUCENT;
- lp.setTitle(VolumeDialogImpl.class.getSimpleName());
- lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
- lp.y = res.getDimensionPixelSize(R.dimen.volume_offset_top);
- lp.gravity = Gravity.TOP;
- lp.windowAnimations = -1;
- mWindow.setAttributes(lp);
- mWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
+ 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.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);
@@ -231,33 +181,11 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
return true;
}
});
+ mHardwareLayout = HardwareUiLayout.get(mDialogView);
+ mHardwareLayout.setOutsideTouchListener(view -> dismiss(DISMISS_REASON_TOUCH_OUTSIDE));
mDialogContentView = mDialog.findViewById(R.id.volume_dialog_content);
mDialogRowsView = mDialogContentView.findViewById(R.id.volume_dialog_rows);
- mExpanded = false;
- mExpandButton = (ImageButton) mDialogView.findViewById(R.id.volume_expand_button);
- mExpandButton.setOnClickListener(mClickExpand);
-
- mExpandButton.setVisibility(
- AudioSystem.isSingleVolume(mContext) ? View.GONE : View.VISIBLE);
- updateWindowWidthH();
- updateExpandButtonH();
-
- mMotion = new VolumeDialogMotion(mDialog, mDialogView, mDialogContentView, mExpandButton,
- new VolumeDialogMotion.Callback() {
- @Override
- public void onAnimatingChanged(boolean animating) {
- if (animating) return;
- if (mPendingStateChanged) {
- mHandler.sendEmptyMessage(H.STATE_CHANGED);
- mPendingStateChanged = false;
- }
- if (mPendingRecheckAll) {
- mHandler.sendEmptyMessage(H.RECHECK_ALL);
- mPendingRecheckAll = false;
- }
- }
- });
if (mRows.isEmpty()) {
addRow(AudioManager.STREAM_MUSIC,
@@ -279,40 +207,12 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
} else {
addExistingRows();
}
- mExpandButtonAnimationDuration = res.getInteger(R.integer.volume_expand_animation_duration);
- mZenFooter = (ZenFooter) mDialog.findViewById(R.id.volume_zen_footer);
- mZenFooter.init(mZenModeController);
- mZenPanel = (TunerZenModePanel) mDialog.findViewById(R.id.tuner_zen_mode_panel);
- mZenPanel.init(mZenModeController);
- mZenPanel.setCallback(mZenPanelCallback);
- }
-
- @Override
- public void onTuningChanged(String key, String newValue) {
- if (SHOW_FULL_ZEN.equals(key)) {
- mShowFullZen = newValue != null && Integer.parseInt(newValue) != 0;
- }
}
private ColorStateList loadColorStateList(int colorResId) {
return ColorStateList.valueOf(mContext.getColor(colorResId));
}
- private void updateWindowWidthH() {
- final ViewGroup.MarginLayoutParams lp =
- (ViewGroup.MarginLayoutParams) mDialogView.getLayoutParams();
- final DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
- if (D.BUG) Log.d(TAG, "updateWindowWidth dm.w=" + dm.widthPixels);
- int w = dm.widthPixels;
- final int max = mContext.getResources()
- .getDimensionPixelSize(R.dimen.volume_dialog_panel_width);
- if (w > max) {
- w = max;
- }
- lp.width = w - lp.getMarginEnd() - lp.getMarginStart();
- mDialogView.setLayoutParams(lp);
- }
-
public void setStreamImportant(int stream, boolean important) {
mHandler.obtainMessage(H.SET_STREAM_IMPORTANT, stream, important ? 1 : 0).sendToTarget();
}
@@ -356,14 +256,10 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
final VolumeRow row = mRows.get(i);
initRow(row, row.stream, row.iconRes, row.iconMuteRes, row.important);
mDialogRowsView.addView(row.view);
+ updateVolumeRowH(row);
}
}
-
- private boolean isAttached() {
- return mDialogContentView != null && mDialogContentView.isAttachedToWindow();
- }
-
private VolumeRow getActiveRow() {
for (VolumeRow row : mRows) {
if (row.stream == mActiveStream) {
@@ -383,14 +279,10 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
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(" mExpandButtonAnimationRunning: ");
- writer.println(mExpandButtonAnimationRunning);
writer.print(" mActiveStream: "); writer.println(mActiveStream);
writer.print(" mDynamic: "); writer.println(mDynamic);
writer.print(" mAutomute: "); writer.println(mAutomute);
writer.print(" mSilentMode: "); writer.println(mSilentMode);
- writer.print(" mCollapseTime: "); writer.println(mCollapseTime);
writer.print(" mAccessibility.mFeedbackEnabled: ");
writer.println(mAccessibility.mFeedbackEnabled);
}
@@ -413,9 +305,9 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
row.view = mDialog.getLayoutInflater().inflate(R.layout.volume_dialog_row, null);
row.view.setId(row.stream);
row.view.setTag(row);
- row.header = (TextView) row.view.findViewById(R.id.volume_row_header);
+ row.header = row.view.findViewById(R.id.volume_row_header);
row.header.setId(20 * row.stream);
- row.slider = (SeekBar) row.view.findViewById(R.id.volume_row_slider);
+ row.slider = row.view.findViewById(R.id.volume_row_slider);
row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row));
row.anim = null;
@@ -496,11 +388,27 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
rescheduleTimeoutH();
if (mShowing) return;
mShowing = true;
- mMotion.startShow();
+ 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();
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();
@@ -514,28 +422,24 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
if (mAccessibility.mFeedbackEnabled) return 20000;
if (mHovering) return 16000;
if (mSafetyWarning != null) return 5000;
- if (mExpanded || mExpandButtonAnimationRunning) return 5000;
if (mActiveStream == AudioManager.STREAM_MUSIC) return 1500;
- if (mZenFooter.shouldShowIntroduction()) {
- return 6000;
- }
return 3000;
}
protected void dismissH(int reason) {
- if (mMotion.isAnimating()) {
- return;
- }
mHandler.removeMessages(H.DISMISS);
mHandler.removeMessages(H.SHOW);
if (!mShowing) return;
mShowing = false;
- mMotion.startDismiss(new Runnable() {
- @Override
- public void run() {
- updateExpandedH(false /* expanding */, true /* dismissing */);
- }
- });
+ mHardwareLayout.setTranslationX(0);
+ mHardwareLayout.setAlpha(1);
+ mHardwareLayout.animate()
+ .alpha(0)
+ .translationX(getAnimTranslation())
+ .setDuration(300)
+ .withEndAction(() -> mDialog.dismiss())
+ .setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator())
+ .start();
if (mAccessibilityMgr.isEnabled()) {
AccessibilityEvent event =
AccessibilityEvent.obtain(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
@@ -555,83 +459,6 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
}
}
- private void updateDialogBottomMarginH() {
- final long diff = System.currentTimeMillis() - mCollapseTime;
- final boolean collapsing = mCollapseTime != 0 && diff < getConservativeCollapseDuration();
- final ViewGroup.MarginLayoutParams mlp = (MarginLayoutParams) mDialogView.getLayoutParams();
- final int bottomMargin = collapsing ? mDialogContentView.getHeight() :
- mContext.getResources().getDimensionPixelSize(R.dimen.volume_dialog_margin_bottom);
- if (bottomMargin != mlp.bottomMargin) {
- if (D.BUG) Log.d(TAG, "bottomMargin " + mlp.bottomMargin + " -> " + bottomMargin);
- mlp.bottomMargin = bottomMargin;
- mDialogView.setLayoutParams(mlp);
- }
- }
-
- private long getConservativeCollapseDuration() {
- return mExpandButtonAnimationDuration * 3;
- }
-
- private void prepareForCollapse() {
- mHandler.removeMessages(H.UPDATE_BOTTOM_MARGIN);
- mCollapseTime = System.currentTimeMillis();
- updateDialogBottomMarginH();
- mHandler.sendEmptyMessageDelayed(H.UPDATE_BOTTOM_MARGIN, getConservativeCollapseDuration());
- }
-
- private void updateExpandedH(final boolean expanded, final boolean dismissing) {
- if (mExpanded == expanded) return;
- mExpanded = expanded;
- mExpandButtonAnimationRunning = isAttached();
- if (D.BUG) Log.d(TAG, "updateExpandedH " + expanded);
- updateExpandButtonH();
- updateFooterH();
- 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 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();
- }
- }, mExpandButtonAnimationDuration);
- }
- }
- }
-
private boolean shouldBeVisibleH(VolumeRow row, VolumeRow activeRow) {
boolean isActive = row == activeRow;
if (row.stream == AudioSystem.STREAM_ACCESSIBILITY) {
@@ -639,15 +466,13 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
}
// if the active row is accessibility, then continue to display previous
- // active row since accessibility is dispalyed under it
+ // active row since accessibility is displayed under it
if (activeRow.stream == AudioSystem.STREAM_ACCESSIBILITY &&
row.stream == mPrevActiveStream) {
return true;
}
- return mExpanded && row.view.getVisibility() == View.VISIBLE
- || (mExpanded && (row.important || isActive))
- || !mExpanded && isActive;
+ return row.important || isActive;
}
private void updateRowsH(final VolumeRow activeRow) {
@@ -680,13 +505,7 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
}
private void onStateChangedH(State state) {
- final boolean animating = mMotion.isAnimating();
- if (D.BUG) Log.d(TAG, "onStateChangedH animating=" + animating);
mState = state;
- if (animating) {
- mPendingStateChanged = true;
- return;
- }
mDynamic.clear();
// add any new dynamic rows
for (int i = 0; i < state.states.size(); i++) {
@@ -709,38 +528,6 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
for (VolumeRow row : mRows) {
updateVolumeRowH(row);
}
- updateFooterH();
- }
-
- private void updateFooterH() {
- if (D.BUG) Log.d(TAG, "updateFooterH");
- final boolean wasVisible = mZenFooter.getVisibility() == View.VISIBLE;
- final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF
- && (mAudioManager.isStreamAffectedByRingerMode(mActiveStream) || mExpanded)
- && !mZenPanel.isEditing();
-
- TransitionManager.endTransitions(mDialogView);
- TransitionManager.beginDelayedTransition(mDialogView, getTransition());
- if (wasVisible != visible && !visible) {
- prepareForCollapse();
- }
- Util.setVisOrGone(mZenFooter, visible);
- mZenFooter.update();
-
- final boolean fullWasVisible = mZenPanel.getVisibility() == View.VISIBLE;
- final boolean fullVisible = mShowFullZen && !visible;
- if (fullWasVisible != fullVisible) {
- Util.setVisOrGone(mZenPanel, fullVisible);
- if (fullVisible) {
- mZenPanel.setZenState(mState.zenMode);
- mZenPanel.setDoneListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mHandler.sendEmptyMessage(H.UPDATE_FOOTER);
- }
- });
- }
- }
}
private void updateVolumeRowH(VolumeRow row) {
@@ -787,19 +574,13 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
row.icon.setAlpha(iconEnabled ? 1 : 0.5f);
final int iconRes =
isRingVibrate ? R.drawable.ic_volume_ringer_vibrate
- : isRingSilent || zenMuted ? row.cachedIconRes
+ : isRingSilent || zenMuted ? row.iconMuteRes
: ss.routedToBluetooth ?
(ss.muted ? R.drawable.ic_volume_media_bt_mute
: R.drawable.ic_volume_media_bt)
: mAutomute && ss.level == 0 ? row.iconMuteRes
: (ss.muted ? row.iconMuteRes : row.iconRes);
- if (iconRes != row.cachedIconRes) {
- if (row.cachedIconRes != 0 && isRingVibrate) {
- mController.vibrate();
- }
- row.cachedIconRes = iconRes;
- row.icon.setImageResource(iconRes);
- }
+ row.icon.setImageResource(iconRes);
row.iconState =
iconRes == R.drawable.ic_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE
: (iconRes == R.drawable.ic_volume_media_bt_mute || iconRes == row.iconMuteRes)
@@ -860,7 +641,7 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
}
private void updateVolumeRowSliderTintH(VolumeRow row, boolean isActive) {
- if (isActive && mExpanded) {
+ if (isActive) {
row.slider.requestFocus();
}
final ColorStateList tint = isActive && row.slider.isEnabled() ? mActiveSliderTint
@@ -980,43 +761,6 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
}
}
- private AutoTransition getTransition() {
- AutoTransition transition = new AutoTransition();
- transition.setDuration(mExpandButtonAnimationDuration);
- transition.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
- transition.addListener(new Transition.TransitionListener() {
- @Override
- public void onTransitionStart(Transition transition) {
- }
-
- @Override
- public void onTransitionEnd(Transition transition) {
- mWindow.setLayout(
- mWindow.getAttributes().width, ViewGroup.LayoutParams.WRAP_CONTENT);
- }
-
- @Override
- public void onTransitionCancel(Transition transition) {
- }
-
- @Override
- public void onTransitionPause(Transition transition) {
- mWindow.setLayout(
- mWindow.getAttributes().width, ViewGroup.LayoutParams.WRAP_CONTENT);
- }
-
- @Override
- public void onTransitionResume(Transition transition) {
- }
- });
- return transition;
- }
-
- private boolean hasTouchFeature() {
- final PackageManager pm = mContext.getPackageManager();
- return pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
- }
-
private final VolumeDialogController.Callbacks mControllerCallbackH
= new VolumeDialogController.Callbacks() {
@Override
@@ -1046,17 +790,9 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
@Override
public void onConfigurationChanged() {
- Configuration newConfig = mContext.getResources().getConfiguration();
- final int density = newConfig.densityDpi;
- if (density != mDensity) {
- mDialog.dismiss();
- mZenFooter.cleanup();
- initDialog();
- mDensity = density;
- }
- updateWindowWidthH();
+ mDialog.dismiss();
+ initDialog();
mConfigurableTexts.update();
- mZenFooter.onConfigurationChanged();
}
@Override
@@ -1092,33 +828,6 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
}
};
- private final ZenModePanel.Callback mZenPanelCallback = new ZenModePanel.Callback() {
- @Override
- public void onPrioritySettings() {
- mCallback.onZenPrioritySettingsClicked();
- }
-
- @Override
- public void onInteraction() {
- mHandler.sendEmptyMessage(H.RESCHEDULE_TIMEOUT);
- }
-
- @Override
- public void onExpanded(boolean expanded) {
- // noop.
- }
- };
-
- private final OnClickListener mClickExpand = new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mExpandButtonAnimationRunning) return;
- final boolean newExpand = !mExpanded;
- Events.writeEvent(mContext, Events.EVENT_EXPAND, newExpand);
- updateExpandedH(newExpand, false /* dismissing */);
- }
- };
-
private final class H extends Handler {
private static final int SHOW = 1;
private static final int DISMISS = 2;
@@ -1127,8 +836,6 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
private static final int SET_STREAM_IMPORTANT = 5;
private static final int RESCHEDULE_TIMEOUT = 6;
private static final int STATE_CHANGED = 7;
- private static final int UPDATE_BOTTOM_MARGIN = 8;
- private static final int UPDATE_FOOTER = 9;
public H() {
super(Looper.getMainLooper());
@@ -1144,15 +851,13 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
case SET_STREAM_IMPORTANT: setStreamImportantH(msg.arg1, msg.arg2 != 0); break;
case RESCHEDULE_TIMEOUT: rescheduleTimeoutH(); break;
case STATE_CHANGED: onStateChangedH(mState); break;
- case UPDATE_BOTTOM_MARGIN: updateDialogBottomMarginH(); break;
- case UPDATE_FOOTER: updateFooterH(); break;
}
}
}
- private final class CustomDialog extends Dialog {
+ private final class CustomDialog extends Dialog implements DialogInterface {
public CustomDialog(Context context) {
- super(context);
+ super(context, com.android.systemui.R.style.qs_theme);
}
@Override
@@ -1162,26 +867,15 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
}
@Override
- protected void onStop() {
- super.onStop();
- final boolean animating = mMotion.isAnimating();
- if (D.BUG) Log.d(TAG, "onStop animating=" + animating);
- if (animating) {
- mPendingRecheckAll = true;
- return;
- }
- mHandler.sendEmptyMessage(H.RECHECK_ALL);
+ protected void onStart() {
+ super.setCanceledOnTouchOutside(true);
+ super.onStart();
}
@Override
- public boolean onTouchEvent(MotionEvent event) {
- if (isShowing()) {
- if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
- dismissH(Events.DISMISS_REASON_TOUCH_OUTSIDE);
- return true;
- }
- }
- return false;
+ protected void onStop() {
+ super.onStop();
+ mHandler.sendEmptyMessage(H.RECHECK_ALL);
}
@Override
@@ -1324,7 +1018,6 @@ public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
private int iconRes;
private int iconMuteRes;
private boolean important;
- private int cachedIconRes;
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/VolumeDialogMotion.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java
deleted file mode 100644
index 01d31e2a9852..000000000000
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * 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 android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnDismissListener;
-import android.content.DialogInterface.OnShowListener;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.PathInterpolator;
-
-public class VolumeDialogMotion {
- private static final String TAG = Util.logTag(VolumeDialogMotion.class);
-
- private static final float ANIMATION_SCALE = 1.0f;
- private static final int PRE_DISMISS_DELAY = 50;
-
- private final Dialog mDialog;
- private final View mDialogView;
- private final ViewGroup mContents; // volume rows + zen footer
- private final View mChevron;
- private final Handler mHandler = new Handler();
- private final Callback mCallback;
-
- private boolean mAnimating; // show or dismiss animation is running
- private boolean mShowing; // show animation is running
- private boolean mDismissing; // dismiss animation is running
- private ValueAnimator mChevronPositionAnimator;
- private ValueAnimator mContentsPositionAnimator;
-
- public VolumeDialogMotion(Dialog dialog, View dialogView, ViewGroup contents, View chevron,
- Callback callback) {
- mDialog = dialog;
- mDialogView = dialogView;
- mContents = contents;
- mChevron = chevron;
- mCallback = callback;
- mDialog.setOnDismissListener(new OnDismissListener() {
- @Override
- public void onDismiss(DialogInterface dialog) {
- if (D.BUG) Log.d(TAG, "mDialog.onDismiss");
- }
- });
- mDialog.setOnShowListener(new OnShowListener() {
- @Override
- public void onShow(DialogInterface dialog) {
- if (D.BUG) Log.d(TAG, "mDialog.onShow");
- final int h = mDialogView.getHeight();
- mDialogView.setTranslationY(-h);
- startShowAnimation();
- }
- });
- }
-
- public boolean isAnimating() {
- return mAnimating;
- }
-
- private void setShowing(boolean showing) {
- if (showing == mShowing) return;
- mShowing = showing;
- if (D.BUG) Log.d(TAG, "mShowing = " + mShowing);
- updateAnimating();
- }
-
- private void setDismissing(boolean dismissing) {
- if (dismissing == mDismissing) return;
- mDismissing = dismissing;
- if (D.BUG) Log.d(TAG, "mDismissing = " + mDismissing);
- updateAnimating();
- }
-
- private void updateAnimating() {
- final boolean animating = mShowing || mDismissing;
- if (animating == mAnimating) return;
- mAnimating = animating;
- if (D.BUG) Log.d(TAG, "mAnimating = " + mAnimating);
- if (mCallback != null) {
- mCallback.onAnimatingChanged(mAnimating);
- }
- }
-
- public void startShow() {
- if (D.BUG) Log.d(TAG, "startShow");
- if (mShowing) return;
- setShowing(true);
- if (mDismissing) {
- mDialogView.animate().cancel();
- setDismissing(false);
- startShowAnimation();
- return;
- }
- if (D.BUG) Log.d(TAG, "mDialog.show()");
- mDialog.show();
- }
-
- private int chevronDistance() {
- return mChevron.getHeight() / 6;
- }
-
- private int chevronPosY() {
- final Object tag = mChevron == null ? null : mChevron.getTag();
- return tag == null ? 0 : (Integer) tag;
- }
-
- private void startShowAnimation() {
- if (D.BUG) Log.d(TAG, "startShowAnimation");
- mDialogView.animate()
- .translationY(0)
- .setDuration(scaledDuration(300))
- .setInterpolator(new LogDecelerateInterpolator())
- .setListener(null)
- .setUpdateListener(animation -> {
- if (mChevronPositionAnimator != null) {
- final float v = (Float) mChevronPositionAnimator.getAnimatedValue();
- if (mChevronPositionAnimator == null) return;
- // reposition chevron
- final int posY = chevronPosY();
- mChevron.setTranslationY(posY + v + -mDialogView.getTranslationY());
- }
- })
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- if (mChevronPositionAnimator == null) return;
- // reposition chevron
- final int posY = chevronPosY();
- mChevron.setTranslationY(posY + -mDialogView.getTranslationY());
- }
- })
- .start();
-
- mContentsPositionAnimator = ValueAnimator.ofFloat(-chevronDistance(), 0)
- .setDuration(scaledDuration(400));
- mContentsPositionAnimator.addListener(new AnimatorListenerAdapter() {
- private boolean mCancelled;
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mCancelled) return;
- if (D.BUG) Log.d(TAG, "show.onAnimationEnd");
- setShowing(false);
- }
- @Override
- public void onAnimationCancel(Animator animation) {
- if (D.BUG) Log.d(TAG, "show.onAnimationCancel");
- mCancelled = true;
- }
- });
- mContentsPositionAnimator.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float v = (Float) animation.getAnimatedValue();
- mContents.setTranslationY(v + -mDialogView.getTranslationY());
- }
- });
- mContentsPositionAnimator.setInterpolator(new LogDecelerateInterpolator());
- mContentsPositionAnimator.start();
-
- mContents.setAlpha(0);
- mContents.animate()
- .alpha(1)
- .setDuration(scaledDuration(150))
- .setInterpolator(new PathInterpolator(0f, 0f, .2f, 1f))
- .start();
-
- mChevronPositionAnimator = ValueAnimator.ofFloat(-chevronDistance(), 0)
- .setDuration(scaledDuration(250));
- mChevronPositionAnimator.setInterpolator(new PathInterpolator(.4f, 0f, .2f, 1f));
- mChevronPositionAnimator.start();
-
- mChevron.setAlpha(0);
- mChevron.animate()
- .alpha(1)
- .setStartDelay(scaledDuration(50))
- .setDuration(scaledDuration(150))
- .setInterpolator(new PathInterpolator(.4f, 0f, 1f, 1f))
- .start();
- }
-
- public void startDismiss(final Runnable onComplete) {
- if (D.BUG) Log.d(TAG, "startDismiss");
- if (mDismissing) return;
- setDismissing(true);
- if (mShowing) {
- mDialogView.animate().cancel();
- if (mContentsPositionAnimator != null) {
- mContentsPositionAnimator.cancel();
- }
- mContents.animate().cancel();
- if (mChevronPositionAnimator != null) {
- mChevronPositionAnimator.cancel();
- }
- mChevron.animate().cancel();
- setShowing(false);
- }
- mDialogView.animate()
- .translationY(-mDialogView.getHeight())
- .setDuration(scaledDuration(250))
- .setInterpolator(new LogAccelerateInterpolator())
- .setUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mContents.setTranslationY(-mDialogView.getTranslationY());
- final int posY = chevronPosY();
- mChevron.setTranslationY(posY + -mDialogView.getTranslationY());
- }
- })
- .setListener(new AnimatorListenerAdapter() {
- private boolean mCancelled;
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mCancelled) return;
- if (D.BUG) Log.d(TAG, "dismiss.onAnimationEnd");
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- if (D.BUG) Log.d(TAG, "mDialog.dismiss()");
- mDialog.dismiss();
- onComplete.run();
- setDismissing(false);
- }
- }, PRE_DISMISS_DELAY);
-
- }
- @Override
- public void onAnimationCancel(Animator animation) {
- if (D.BUG) Log.d(TAG, "dismiss.onAnimationCancel");
- mCancelled = true;
- }
- }).start();
- }
-
- private static int scaledDuration(int base) {
- return (int) (base * ANIMATION_SCALE);
- }
-
- public static final class LogDecelerateInterpolator implements TimeInterpolator {
- private final float mBase;
- private final float mDrift;
- private final float mTimeScale;
- private final float mOutputScale;
-
- public LogDecelerateInterpolator() {
- this(400f, 1.4f, 0);
- }
-
- private LogDecelerateInterpolator(float base, float timeScale, float drift) {
- mBase = base;
- mDrift = drift;
- mTimeScale = 1f / timeScale;
-
- mOutputScale = 1f / computeLog(1f);
- }
-
- 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;
- }
- }
-
- public static final class LogAccelerateInterpolator implements TimeInterpolator {
- private final int mBase;
- private final int mDrift;
- private final float mLogScale;
-
- public LogAccelerateInterpolator() {
- this(100, 0);
- }
-
- private LogAccelerateInterpolator(int base, int drift) {
- mBase = base;
- mDrift = drift;
- mLogScale = 1f / computeLog(1, mBase, mDrift);
- }
-
- private static float computeLog(float t, int base, int drift) {
- return (float) -Math.pow(base, -t) + 1 + (drift * t);
- }
-
- @Override
- public float getInterpolation(float t) {
- return 1 - computeLog(1 - t, mBase, mDrift) * mLogScale;
- }
- }
-
- public interface Callback {
- void onAnimatingChanged(boolean animating);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
deleted file mode 100644
index 80e162983a65..000000000000
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * 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 android.animation.LayoutTransition;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.provider.Settings.Global;
-import android.service.notification.ZenModeConfig;
-import android.transition.AutoTransition;
-import android.transition.TransitionManager;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.systemui.Prefs;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.ZenModeController;
-
-import java.util.Objects;
-
-/**
- * Zen mode information (and end button) attached to the bottom of the volume dialog.
- */
-public class ZenFooter extends LinearLayout {
- private static final String TAG = Util.logTag(ZenFooter.class);
-
- private final Context mContext;
- private final ConfigurableTexts mConfigurableTexts;
-
- private ImageView mIcon;
- private TextView mSummaryLine1;
- private TextView mSummaryLine2;
- private TextView mEndNowButton;
- private View mZenIntroduction;
- private View mZenIntroductionConfirm;
- private TextView mZenIntroductionMessage;
- private int mZen = -1;
- private ZenModeConfig mConfig;
- private ZenModeController mController;
-
- public ZenFooter(Context context, AttributeSet attrs) {
- super(context, attrs);
- mContext = context;
- mConfigurableTexts = new ConfigurableTexts(mContext);
- final LayoutTransition layoutTransition = new LayoutTransition();
- layoutTransition.setDuration(new ValueAnimator().getDuration() / 2);
- setLayoutTransition(layoutTransition);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mIcon = findViewById(R.id.volume_zen_icon);
- mSummaryLine1 = findViewById(R.id.volume_zen_summary_line_1);
- mSummaryLine2 = findViewById(R.id.volume_zen_summary_line_2);
- mEndNowButton = findViewById(R.id.volume_zen_end_now);
- mZenIntroduction = findViewById(R.id.zen_introduction);
- mZenIntroductionMessage = findViewById(R.id.zen_introduction_message);
- mConfigurableTexts.add(mZenIntroductionMessage, R.string.zen_alarms_introduction);
- mZenIntroductionConfirm = findViewById(R.id.zen_introduction_confirm);
- mZenIntroductionConfirm.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- confirmZenIntroduction();
- }
- });
- Util.setVisOrGone(mZenIntroduction, shouldShowIntroduction());
- mConfigurableTexts.add(mSummaryLine1);
- mConfigurableTexts.add(mSummaryLine2);
- mConfigurableTexts.add(mEndNowButton, R.string.volume_zen_end_now);
- }
-
- public void init(final ZenModeController controller) {
- mEndNowButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- setZen(Global.ZEN_MODE_OFF);
- controller.setZen(Global.ZEN_MODE_OFF, null, TAG);
- }
- });
- mZen = controller.getZen();
- mConfig = controller.getConfig();
- mController = controller;
- mController.addCallback(mZenCallback);
- update();
- updateIntroduction();
- }
-
- public void cleanup() {
- mController.removeCallback(mZenCallback);
- }
-
- private void setZen(int zen) {
- if (mZen == zen) return;
- mZen = zen;
- update();
- post(() -> {
- updateIntroduction();
- });
- }
-
- private void setConfig(ZenModeConfig config) {
- if (Objects.equals(mConfig, config)) return;
- mConfig = config;
- update();
- }
-
- private void confirmZenIntroduction() {
- Prefs.putBoolean(mContext, Prefs.Key.DND_CONFIRMED_ALARM_INTRODUCTION, true);
- updateIntroduction();
- }
-
- private boolean isZenPriority() {
- return mZen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- }
-
- private boolean isZenAlarms() {
- return mZen == Global.ZEN_MODE_ALARMS;
- }
-
- private boolean isZenNone() {
- return mZen == Global.ZEN_MODE_NO_INTERRUPTIONS;
- }
-
- public void update() {
- mIcon.setImageResource(isZenNone() ? R.drawable.ic_dnd_total_silence : R.drawable.ic_dnd);
- final String line1 =
- isZenPriority() ? mContext.getString(R.string.interruption_level_priority)
- : isZenAlarms() ? mContext.getString(R.string.interruption_level_alarms)
- : isZenNone() ? mContext.getString(R.string.interruption_level_none)
- : null;
- Util.setText(mSummaryLine1, line1);
-
- final CharSequence line2 = ZenModeConfig.getConditionSummary(mContext, mConfig,
- mController.getCurrentUser(), true /*shortVersion*/);
- Util.setText(mSummaryLine2, line2);
- }
-
- public boolean shouldShowIntroduction() {
- final boolean confirmed = Prefs.getBoolean(mContext,
- Prefs.Key.DND_CONFIRMED_ALARM_INTRODUCTION, false);
- return !confirmed && isZenAlarms();
- }
-
- public void updateIntroduction() {
- Util.setVisOrGone(mZenIntroduction, shouldShowIntroduction());
- }
-
- public void onConfigurationChanged() {
- mConfigurableTexts.update();
- }
-
- private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
- @Override
- public void onZenChanged(int zen) {
- setZen(zen);
- }
- @Override
- public void onConfigChanged(ZenModeConfig config) {
- setConfig(config);
- }
- };
-}
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 67fae5bb0dfb..e74736ab2fcc 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -43,6 +43,9 @@
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.STATUS_BAR" />
+ <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
+ <uses-permission android:name="android.permission.REAL_GET_TASKS" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 65d969932ef5..fbcbd2096db7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
+import android.os.ParcelFileDescriptor;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.testing.LeakCheck;
@@ -34,6 +35,8 @@ import org.junit.Rule;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import java.io.FileInputStream;
+import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@@ -84,6 +87,16 @@ public abstract class SysuiTestCase {
return mContext;
}
+ protected void runShellCommand(String command) throws IOException {
+ ParcelFileDescriptor pfd = mRealInstrumentation.getUiAutomation()
+ .executeShellCommand(command);
+
+ // Read the input stream fully.
+ FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+ while (fis.read() != -1);
+ fis.close();
+ }
+
protected void waitForIdleSync() {
if (mHandler == null) {
mHandler = new Handler(Looper.getMainLooper());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
index 720e9f0a62d5..a17a95f6543d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
@@ -70,7 +70,7 @@ public class DozeScreenStatePreventingAdapterTest extends SysuiTestCase {
@Test
public void forwards_setDozeScreenState_doze_suspend() throws Exception {
mWrapper.setDozeScreenState(Display.STATE_DOZE_SUSPEND);
- verify(mInner).setDozeScreenState(Display.STATE_ON);
+ verify(mInner).setDozeScreenState(Display.STATE_ON_SUSPEND);
}
@Test
@@ -95,4 +95,4 @@ public class DozeScreenStatePreventingAdapterTest extends SysuiTestCase {
assertSame(mInner, DozeScreenStatePreventingAdapter.wrapIfNeeded(mInner, params));
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
index d78e739fce00..ed935619b2f6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
@@ -74,6 +74,12 @@ public class DozeSuspendScreenStatePreventingAdapterTest extends SysuiTestCase {
}
@Test
+ public void forwards_setDozeScreenState_on_suspend() throws Exception {
+ mWrapper.setDozeScreenState(Display.STATE_ON_SUSPEND);
+ verify(mInner).setDozeScreenState(Display.STATE_ON_SUSPEND);
+ }
+
+ @Test
public void forwards_requestWakeUp() throws Exception {
mWrapper.requestWakeUp();
verify(mInner).requestWakeUp();
@@ -95,4 +101,4 @@ public class DozeSuspendScreenStatePreventingAdapterTest extends SysuiTestCase {
assertSame(mInner, DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(mInner, params));
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
new file mode 100644
index 000000000000..4437aaca521d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.keyguard;
+
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Handler;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper(setAsMainLooper = true)
+public class KeyguardSliceProviderTest extends SysuiTestCase {
+
+ private TestableKeyguardSliceProvider mProvider;
+
+ @Before
+ public void setup() {
+ mProvider = new TestableKeyguardSliceProvider();
+ mProvider.attachInfo(getContext(), null);
+ }
+
+ @Test
+ public void registersClockUpdate() {
+ Assert.assertTrue("registerClockUpdate should have been called during initialization.",
+ mProvider.isRegistered());
+ }
+
+ @Test
+ public void unregisterClockUpdate() {
+ mProvider.unregisterClockUpdate();
+ Assert.assertFalse("Clock updates should have been unregistered.",
+ mProvider.isRegistered());
+ }
+
+ @Test
+ public void returnsValidSlice() {
+ Slice slice = mProvider.onBindSlice(Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI));
+ SliceItem text = SliceQuery.find(slice, SliceItem.TYPE_TEXT, Slice.HINT_TITLE,
+ null /* nonHints */);
+ Assert.assertNotNull("Slice must provide a title.", text);
+ }
+
+ @Test
+ public void cleansDateFormat() {
+ mProvider.mIntentReceiver.onReceive(getContext(), new Intent(Intent.ACTION_TIMEZONE_CHANGED));
+ TestableLooper.get(this).processAllMessages();
+ Assert.assertEquals("Date format should have been cleaned.", 1 /* expected */,
+ mProvider.mCleanDateFormatInvokations);
+ }
+
+ @Test
+ public void updatesClock() {
+ mProvider.mIntentReceiver.onReceive(getContext(), new Intent(Intent.ACTION_TIME_TICK));
+ TestableLooper.get(this).processAllMessages();
+ Assert.assertEquals("Clock should have been updated.", 2 /* expected */,
+ mProvider.mUpdateClockInvokations);
+ }
+
+ private class TestableKeyguardSliceProvider extends KeyguardSliceProvider {
+ int mCleanDateFormatInvokations;
+ int mUpdateClockInvokations;
+
+ TestableKeyguardSliceProvider() {
+ super(new Handler(TestableLooper.get(KeyguardSliceProviderTest.this).getLooper()));
+ }
+
+ @Override
+ void cleanDateFormat() {
+ super.cleanDateFormat();
+ mCleanDateFormatInvokations++;
+ }
+
+ @Override
+ protected void updateClock() {
+ super.updateClock();
+ mUpdateClockInvokations++;
+ }
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
index d7583149ccc6..cf32760dc803 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
@@ -41,7 +41,7 @@ import android.support.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
-import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import org.junit.Before;
import org.junit.Test;
@@ -61,7 +61,7 @@ public class WorkLockActivityControllerTest extends SysuiTestCase {
private static final int TASK_ID = 444;
private @Mock Context mContext;
- private @Mock SystemServicesProxy mSystemServicesProxy;
+ private @Mock ActivityManagerWrapper mActivityManager;
private @Mock IActivityManager mIActivityManager;
private WorkLockActivityController mController;
@@ -77,10 +77,9 @@ public class WorkLockActivityControllerTest extends SysuiTestCase {
// Construct controller. Save the TaskStackListener for injecting events.
final ArgumentCaptor<SysUiTaskStackChangeListener> listenerCaptor =
ArgumentCaptor.forClass(SysUiTaskStackChangeListener.class);
- mController =
- new WorkLockActivityController(mContext, mSystemServicesProxy, mIActivityManager);
+ mController = new WorkLockActivityController(mContext, mActivityManager, mIActivityManager);
- verify(mSystemServicesProxy).registerTaskStackListener(listenerCaptor.capture());
+ verify(mActivityManager).registerTaskStackListener(listenerCaptor.capture());
mTaskStackListener = listenerCaptor.getValue();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTest.java
new file mode 100644
index 000000000000..bdbd24418d3f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTest.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.systemui.recents;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+
+import static com.android.systemui.recents.RecentsImpl.RECENTS_ACTIVITY;
+import static com.android.systemui.recents.RecentsImpl.RECENTS_PACKAGE;
+
+import static org.junit.Assert.fail;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.IActivityManager;
+import android.os.SystemClock;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class RecentsTest extends SysuiTestCase {
+
+ @Test
+ public void testRecentsActivityType() throws Exception {
+ // Clear the state
+ final IActivityManager am = ActivityManager.getService();
+ am.removeStacksWithActivityTypes(new int[] { ACTIVITY_TYPE_RECENTS });
+
+ // Toggle recents, use a shell command because it is not exported
+ runShellCommand("am start -n " + RECENTS_PACKAGE + "/" + RECENTS_ACTIVITY);
+
+ // Verify that an activity was launched with the right activity type
+ int retryCount = 0;
+ while (retryCount < 10) {
+ List<RunningTaskInfo> tasks = am.getTasks(Integer.MAX_VALUE);
+ for (RunningTaskInfo info : tasks) {
+ if (info.configuration.windowConfiguration.getActivityType()
+ == ACTIVITY_TYPE_RECENTS) {
+ // Found a recents activity with the right activity type
+ return;
+ }
+ }
+ SystemClock.sleep(50);
+ retryCount++;
+ }
+ fail("Expected Recents activity with ACTIVITY_TYPE_RECENTS");
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index 88fa659cd0e4..672193835ac3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -745,7 +745,7 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
- (Runnable saveImportance) -> {
+ (Runnable saveImportance, StatusBarNotification sbn) -> {
},
Collections.singleton(TEST_PACKAGE_NAME));
@@ -762,7 +762,7 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
- (Runnable saveImportance) -> {
+ (Runnable saveImportance, StatusBarNotification sbn) -> {
saveImportance.run();
},
Collections.singleton(TEST_PACKAGE_NAME));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 3b401a5d9b0c..a95e3dbb1e3b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -24,7 +24,7 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
-import com.android.internal.app.NightDisplayController;
+import com.android.internal.app.ColorDisplayController;
import com.android.systemui.Dependency;
import com.android.systemui.Prefs;
import com.android.systemui.Prefs.Key;
@@ -61,49 +61,49 @@ public class AutoTileManagerTest extends SysuiTestCase {
@Test
public void nightTileAdded_whenActivated() {
- if (!NightDisplayController.isAvailable(mContext)) {
+ if (!ColorDisplayController.isAvailable(mContext)) {
return;
}
- mAutoTileManager.mNightDisplayCallback.onActivated(true);
+ mAutoTileManager.mColorDisplayCallback.onActivated(true);
verify(mQsTileHost).addTile("night");
}
@Test
public void nightTileNotAdded_whenDeactivated() {
- if (!NightDisplayController.isAvailable(mContext)) {
+ if (!ColorDisplayController.isAvailable(mContext)) {
return;
}
- mAutoTileManager.mNightDisplayCallback.onActivated(false);
+ mAutoTileManager.mColorDisplayCallback.onActivated(false);
verify(mQsTileHost, never()).addTile("night");
}
@Test
public void nightTileAdded_whenNightModeTwilight() {
- if (!NightDisplayController.isAvailable(mContext)) {
+ if (!ColorDisplayController.isAvailable(mContext)) {
return;
}
- mAutoTileManager.mNightDisplayCallback.onAutoModeChanged(
- NightDisplayController.AUTO_MODE_TWILIGHT);
+ mAutoTileManager.mColorDisplayCallback.onAutoModeChanged(
+ ColorDisplayController.AUTO_MODE_TWILIGHT);
verify(mQsTileHost).addTile("night");
}
@Test
public void nightTileAdded_whenNightModeCustom() {
- if (!NightDisplayController.isAvailable(mContext)) {
+ if (!ColorDisplayController.isAvailable(mContext)) {
return;
}
- mAutoTileManager.mNightDisplayCallback.onAutoModeChanged(
- NightDisplayController.AUTO_MODE_CUSTOM);
+ mAutoTileManager.mColorDisplayCallback.onAutoModeChanged(
+ ColorDisplayController.AUTO_MODE_CUSTOM);
verify(mQsTileHost).addTile("night");
}
@Test
public void nightTileNotAdded_whenNightModeDisabled() {
- if (!NightDisplayController.isAvailable(mContext)) {
+ if (!ColorDisplayController.isAvailable(mContext)) {
return;
}
- mAutoTileManager.mNightDisplayCallback.onAutoModeChanged(
- NightDisplayController.AUTO_MODE_DISABLED);
+ mAutoTileManager.mColorDisplayCallback.onAutoModeChanged(
+ ColorDisplayController.AUTO_MODE_DISABLED);
verify(mQsTileHost, never()).addTile("night");
}
}
diff --git a/packages/VpnDialogs/res/values-ta/strings.xml b/packages/VpnDialogs/res/values-ta/strings.xml
index 81a198440c44..7daa11b4a173 100644
--- a/packages/VpnDialogs/res/values-ta/strings.xml
+++ b/packages/VpnDialogs/res/values-ta/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="3183836924226407828">"இணைப்புக் கோரிக்கை"</string>
- <string name="warning" msgid="809658604548412033">"VPN இணைப்பை அமைக்க <xliff:g id="APP">%s</xliff:g> விழைகிறது அதன்மூலம் இது நெட்வொர்க் ட்ராஃபிக்கைக் கண்காணிக்கும் அனுமதியைப் பெறும். நம்பகமான மூலத்தை மட்டுமே ஏற்கவும். VPN இயக்கத்தில் உள்ளபோது திரையில் மேல் பகுதியில் &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; தோன்றும்."</string>
+ <string name="warning" msgid="809658604548412033">"VPN இணைப்பை அமைக்க <xliff:g id="APP">%s</xliff:g> விழைகிறது அதன்மூலம் இது நெட்வொர்க் ட்ராஃபிக்கைக் கண்காணிக்கும் அனுமதியைப் பெறும். நம்பகமான மூலத்தை மட்டுமே ஏற்கவும். &lt;br /&gt; &lt;br /&gt; VPN இயக்கத்தில் உள்ளபோது திரையில் மேல் பகுதியில் &lt;img src=vpn_icon /&gt; தோன்றும்."</string>
<string name="legacy_title" msgid="192936250066580964">"VPN இணைக்கப்பட்டது"</string>
<string name="session" msgid="6470628549473641030">"அமர்வு:"</string>
<string name="duration" msgid="3584782459928719435">"காலஅளவு:"</string>
diff --git a/proto/src/ipconnectivity.proto b/proto/src/ipconnectivity.proto
index 437da8f3f17a..0e39446a81ea 100644
--- a/proto/src/ipconnectivity.proto
+++ b/proto/src/ipconnectivity.proto
@@ -50,9 +50,10 @@ message Pair {
optional int32 value = 2;
};
-// An event record when the system default network disconnects or the system
-// switches to a new default network.
-// Next tag: 10.
+// An event recorded when the system default network disconnects or the system
+// switches to a new default network. An event is also recorded to cover gaps
+// without a default network.
+// Next tag: 12
message DefaultNetworkEvent {
// Reason why this network stopped being the default.
@@ -72,26 +73,34 @@ message DefaultNetworkEvent {
};
// Duration in milliseconds when this network was the default.
- // Since version 4
+ // Since P.
optional int64 default_network_duration_ms = 5;
- // Duration in milliseconds without a default network before this network
- // became the default.
- // Since version 4
- optional int64 no_default_network_duration_ms = 6;
+ // Duration in milliseconds when this default network Internet access was
+ // validated. This field is equal to 0 for DefaultNetworkEvents representing
+ // lack of a default network.
+ // Since P.
+ optional int64 validation_duration_ms = 11;
// Network score of this network when it became the default network.
- // Since version 4
+ // Or 0 if this event represents a period without a default network.
+ // Since P.
optional int64 initial_score = 7;
// Network score of this network when it stopped being the default network.
- // Since version 4
+ // Or 0 if this event represents a period without a default network.
+ // Since P.
optional int64 final_score = 8;
// Best available information about IP support of this default network.
- // Since version 4
+ // Or NONE if this event represents a period without a default network.
+ // Since P.
optional IPSupport ip_support = 9;
+ // LinkLayer of the previous default network. Ignores any previous period
+ // without a default network.
+ // Since P
+ optional LinkLayer previous_default_network_link_layer = 10;
// Deprecated fields
@@ -112,6 +121,11 @@ message DefaultNetworkEvent {
// TRANSPORT_* constants as defined in NetworkCapabilities.
// Deprecated since version 3. Replaced by top-level transports field.
repeated int32 transport_types = 4 [deprecated = true];
+
+ // Duration in milliseconds without a default network. This field is non-zero
+ // only for DefaultNetworkEvents representing lack of a default network.
+ // Since P.
+ optional int64 no_default_network_duration_ms = 6 [deprecated = true];
};
// Logs IpReachabilityMonitor probe events and NUD_FAILED events.
@@ -475,7 +489,7 @@ message NetworkStats {
// Represents statistics from NFLOG wakeup events due to ingress packets.
// Since oc-mr1.
-// Next tag: 8.
+// Next tag: 13.
message WakeupStats {
// The time duration in seconds covered by these stats, for deriving
// exact wakeup rates.
@@ -503,6 +517,24 @@ message WakeupStats {
// The total number of wakeup packets with no associated socket or uid.
optional int64 no_uid_wakeups = 7;
+
+ // Counts of all different ethertype values from wakeup packets received.
+ repeated Pair ethertype_counts = 8;
+
+ // Counts of all different IP next header values from wakeup packets received.
+ repeated Pair ip_next_header_counts = 9;
+
+ // The total number of wakeup packets whose destination hardware address was
+ // a unicast address.
+ optional int64 l2_unicast_count = 10;
+
+ // The total number of wakeup packets whose destination hardware address was
+ // a multicast address.
+ optional int64 l2_multicast_count = 11;
+
+ // The total number of wakeup packets whose destination hardware address was
+ // a broadcast address.
+ optional int64 l2_broadcast_count = 12;
}
// Represents one of the IP connectivity event defined in this file.
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index fad6bd1b3f83..98efd522970b 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -171,6 +171,12 @@ message MetricsEvent {
TEXT_CLASSIFIER_TYPE_URL = 6;
}
+ // Selection invocation methods. Used as sub-type for TEXT_SELECTION_SESSION events.
+ enum TextSelectionInvocationMethod {
+ TEXT_SELECTION_INVOCATION_MANUAL = 1;
+ TEXT_SELECTION_INVOCATION_LINK = 2;
+ }
+
// Known visual elements: views or controls.
enum View {
// Unknown view
@@ -2799,420 +2805,316 @@ message MetricsEvent {
// OS: O
TEXT_LONGPRESS = 629;
- // ACTION: An app requested an unknown permission
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_UNKNOWN = 630;
- // ACTION: An app was granted an unknown permission
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_UNKNOWN = 631;
- // ACTION: An app requested an unknown permission and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_UNKNOWN = 632;
- // ACTION: An unknown permission was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_UNKNOWN = 633;
- // ACTION: An app requested the permission READ_CALENDAR
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_CALENDAR = 634;
- // ACTION: An app was granted the permission READ_CALENDAR
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_CALENDAR = 635;
- // ACTION: An app requested the permission READ_CALENDAR and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_CALENDAR = 636;
- // ACTION: The permission READ_CALENDAR was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_CALENDAR = 637;
- // ACTION: An app requested the permission WRITE_CALENDAR
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_WRITE_CALENDAR = 638;
- // ACTION: An app was granted the permission WRITE_CALENDAR
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_WRITE_CALENDAR = 639;
- // ACTION: An app requested the permission WRITE_CALENDAR and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_WRITE_CALENDAR = 640;
- // ACTION: The permission WRITE_CALENDAR was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_WRITE_CALENDAR = 641;
- // ACTION: An app requested the permission CAMERA
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_CAMERA = 642;
- // ACTION: An app was granted the permission CAMERA
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_CAMERA = 643;
- // ACTION: An app requested the permission CAMERA and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_CAMERA = 644;
- // ACTION: The permission CAMERA was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_CAMERA = 645;
- // ACTION: An app requested the permission READ_CONTACTS
- // PACKAGE: The package name of the app requesting the permission
+ // AOBSOLETE
ACTION_PERMISSION_REQUEST_READ_CONTACTS = 646;
- // ACTION: An app was granted the permission READ_CONTACTS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_CONTACTS = 647;
- // ACTION: An app requested the permission READ_CONTACTS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_CONTACTS = 648;
- // ACTION: The permission READ_CONTACTS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_CONTACTS = 649;
- // ACTION: An app requested the permission WRITE_CONTACTS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_WRITE_CONTACTS = 650;
- // ACTION: An app was granted the permission WRITE_CONTACTS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_WRITE_CONTACTS = 651;
- // ACTION: An app requested the permission WRITE_CONTACTS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_WRITE_CONTACTS = 652;
- // ACTION: The permission WRITE_CONTACTS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_WRITE_CONTACTS = 653;
- // ACTION: An app requested the permission GET_ACCOUNTS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_GET_ACCOUNTS = 654;
- // ACTION: An app was granted the permission GET_ACCOUNTS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_GET_ACCOUNTS = 655;
- // ACTION: An app requested the permission GET_ACCOUNTS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_GET_ACCOUNTS = 656;
- // ACTION: The permission GET_ACCOUNTS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_GET_ACCOUNTS = 657;
- // ACTION: An app requested the permission ACCESS_FINE_LOCATION
- // PACKAGE: The package name of the app requesting the permission
+ // AOBSOLETE
ACTION_PERMISSION_REQUEST_ACCESS_FINE_LOCATION = 658;
- // ACTION: An app was granted the permission ACCESS_FINE_LOCATION
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_ACCESS_FINE_LOCATION = 659;
- // ACTION: An app requested the permission ACCESS_FINE_LOCATION and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_ACCESS_FINE_LOCATION = 660;
- // ACTION: The permission ACCESS_FINE_LOCATION was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_ACCESS_FINE_LOCATION = 661;
- // ACTION: An app requested the permission ACCESS_COARSE_LOCATION
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_ACCESS_COARSE_LOCATION = 662;
- // ACTION: An app was granted the permission ACCESS_COARSE_LOCATION
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_ACCESS_COARSE_LOCATION = 663;
- // ACTION: An app requested the permission ACCESS_COARSE_LOCATION and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_ACCESS_COARSE_LOCATION = 664;
- // ACTION: The permission ACCESS_COARSE_LOCATION was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_ACCESS_COARSE_LOCATION = 665;
- // ACTION: An app requested the permission RECORD_AUDIO
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_RECORD_AUDIO = 666;
- // ACTION: An app was granted the permission RECORD_AUDIO
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_RECORD_AUDIO = 667;
- // ACTION: An app requested the permission RECORD_AUDIO and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_RECORD_AUDIO = 668;
- // ACTION: The permission RECORD_AUDIO was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_RECORD_AUDIO = 669;
- // ACTION: An app requested the permission READ_PHONE_STATE
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_PHONE_STATE = 670;
- // ACTION: An app was granted the permission READ_PHONE_STATE
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_PHONE_STATE = 671;
- // ACTION: An app requested the permission READ_PHONE_STATE and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_PHONE_STATE = 672;
- // ACTION: The permission READ_PHONE_STATE was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_PHONE_STATE = 673;
- // ACTION: An app requested the permission CALL_PHONE
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_CALL_PHONE = 674;
- // ACTION: An app was granted the permission CALL_PHONE
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_CALL_PHONE = 675;
- // ACTION: An app requested the permission CALL_PHONE and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_CALL_PHONE = 676;
- // ACTION: The permission CALL_PHONE was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_CALL_PHONE = 677;
- // ACTION: An app requested the permission READ_CALL_LOG
- // PACKAGE: The package name of the app requesting the permission
+ // AOBSOLETE
ACTION_PERMISSION_REQUEST_READ_CALL_LOG = 678;
- // ACTION: An app was granted the permission READ_CALL_LOG
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_CALL_LOG = 679;
- // ACTION: An app requested the permission READ_CALL_LOG and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_CALL_LOG = 680;
- // ACTION: The permission READ_CALL_LOG was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_CALL_LOG = 681;
- // ACTION: An app requested the permission WRITE_CALL_LOG
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_WRITE_CALL_LOG = 682;
- // ACTION: An app was granted the permission WRITE_CALL_LOG
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_WRITE_CALL_LOG = 683;
- // ACTION: An app requested the permission WRITE_CALL_LOG and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_WRITE_CALL_LOG = 684;
- // ACTION: The permission WRITE_CALL_LOG was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_WRITE_CALL_LOG = 685;
- // ACTION: An app requested the permission ADD_VOICEMAIL
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_ADD_VOICEMAIL = 686;
- // ACTION: An app was granted the permission ADD_VOICEMAIL
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_ADD_VOICEMAIL = 687;
- // ACTION: An app requested the permission ADD_VOICEMAIL and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_ADD_VOICEMAIL = 688;
- // ACTION: The permission ADD_VOICEMAIL was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_ADD_VOICEMAIL = 689;
- // ACTION: An app requested the permission USE_SIP
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_USE_SIP = 690;
- // ACTION: An app was granted the permission USE_SIP
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_USE_SIP = 691;
- // ACTION: An app requested the permission USE_SIP and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_USE_SIP = 692;
- // ACTION: The permission USE_SIP was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_USE_SIP = 693;
- // ACTION: An app requested the permission PROCESS_OUTGOING_CALLS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_PROCESS_OUTGOING_CALLS = 694;
- // ACTION: An app was granted the permission PROCESS_OUTGOING_CALLS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_PROCESS_OUTGOING_CALLS = 695;
- // ACTION: An app requested the permission PROCESS_OUTGOING_CALLS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_PROCESS_OUTGOING_CALLS = 696;
- // ACTION: The permission PROCESS_OUTGOING_CALLS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_PROCESS_OUTGOING_CALLS = 697;
- // ACTION: An app requested the permission READ_CELL_BROADCASTS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_CELL_BROADCASTS = 698;
- // ACTION: An app was granted the permission READ_CELL_BROADCASTS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_CELL_BROADCASTS = 699;
- // ACTION: An app requested the permission READ_CELL_BROADCASTS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_CELL_BROADCASTS = 700;
- // ACTION: The permission READ_CELL_BROADCASTS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_CELL_BROADCASTS = 701;
- // ACTION: An app requested the permission BODY_SENSORS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_BODY_SENSORS = 702;
- // ACTION: An app was granted the permission BODY_SENSORS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_BODY_SENSORS = 703;
- // ACTION: An app requested the permission BODY_SENSORS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_BODY_SENSORS = 704;
- // ACTION: The permission BODY_SENSORS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_BODY_SENSORS = 705;
- // ACTION: An app requested the permission SEND_SMS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_SEND_SMS = 706;
- // ACTION: An app was granted the permission SEND_SMS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_SEND_SMS = 707;
- // ACTION: An app requested the permission SEND_SMS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_SEND_SMS = 708;
- // ACTION: The permission SEND_SMS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_SEND_SMS = 709;
- // ACTION: An app requested the permission RECEIVE_SMS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_RECEIVE_SMS = 710;
- // ACTION: An app was granted the permission RECEIVE_SMS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_RECEIVE_SMS = 711;
- // ACTION: An app requested the permission RECEIVE_SMS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_RECEIVE_SMS = 712;
- // ACTION: The permission RECEIVE_SMS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_RECEIVE_SMS = 713;
- // ACTION: An app requested the permission READ_SMS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_SMS = 714;
- // ACTION: An app was granted the permission READ_SMS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_SMS = 715;
- // ACTION: An app requested the permission READ_SMS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_SMS = 716;
- // ACTION: The permission READ_SMS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_SMS = 717;
- // ACTION: An app requested the permission RECEIVE_WAP_PUSH
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_RECEIVE_WAP_PUSH = 718;
- // ACTION: An app was granted the permission RECEIVE_WAP_PUSH
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_RECEIVE_WAP_PUSH = 719;
- // ACTION: An app requested the permission RECEIVE_WAP_PUSH and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_RECEIVE_WAP_PUSH = 720;
- // ACTION: The permission RECEIVE_WAP_PUSH was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_RECEIVE_WAP_PUSH = 721;
- // ACTION: An app requested the permission RECEIVE_MMS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_RECEIVE_MMS = 722;
- // ACTION: An app was granted the permission RECEIVE_MMS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_RECEIVE_MMS = 723;
- // ACTION: An app requested the permission RECEIVE_MMS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_RECEIVE_MMS = 724;
- // ACTION: The permission RECEIVE_MMS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_RECEIVE_MMS = 725;
- // ACTION: An app requested the permission READ_EXTERNAL_STORAGE
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 726;
- // ACTION: An app was granted the permission READ_EXTERNAL_STORAGE
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_EXTERNAL_STORAGE = 727;
- // ACTION: An app requested the permission READ_EXTERNAL_STORAGE and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_EXTERNAL_STORAGE = 728;
- // ACTION: The permission READ_EXTERNAL_STORAGE was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_EXTERNAL_STORAGE = 729;
- // ACTION: An app requested the permission WRITE_EXTERNAL_STORAGE
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 730;
- // ACTION: An app was granted the permission WRITE_EXTERNAL_STORAGE
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_WRITE_EXTERNAL_STORAGE = 731;
- // ACTION: An app requested the permission WRITE_EXTERNAL_STORAGE and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_WRITE_EXTERNAL_STORAGE = 732;
- // ACTION: The permission WRITE_EXTERNAL_STORAGE was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_WRITE_EXTERNAL_STORAGE = 733;
// ACTION: Logged when a provisioning session has started
@@ -3221,20 +3123,16 @@ message MetricsEvent {
// ACTION: Logged when a provisioning session has completed
PROVISIONING_SESSION_COMPLETED = 735;
- // ACTION: An app requested the permission READ_PHONE_NUMBERS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_PHONE_NUMBERS = 736;
- // ACTION: An app was granted the permission READ_PHONE_NUMBERS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_PHONE_NUMBERS = 737;
- // ACTION: An app requested the permission READ_PHONE_NUMBERS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_PHONE_NUMBERS = 738;
- // ACTION: The permission READ_PHONE_NUMBERS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_PHONE_NUMBERS = 739;
// ACTION: QS Brightness Slider (with auto brightness disabled, and VR enabled)
@@ -3726,68 +3624,52 @@ message MetricsEvent {
// CATEGORY: SETTINGS
SETTINGS_LOCK_SCREEN_PREFERENCES = 882;
- // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_REQUEST_ACCESS_NOTIFICATIONS = 883;
- // ACTION: An app was granted the app-op permission ACCESS_NOTIFICATIONS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_APPOP_GRANT_ACCESS_NOTIFICATIONS = 884;
- // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_DENIED_ACCESS_NOTIFICATIONS = 885;
- // ACTION: The app-op permission ACCESS_NOTIFICATIONS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_APPOP_REVOKE_ACCESS_NOTIFICATIONS = 886;
- // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_REQUEST_SYSTEM_ALERT_WINDOW = 887;
- // ACTION: An app was granted the app-op permission SYSTEM_ALERT_WINDOW
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_APPOP_GRANT_SYSTEM_ALERT_WINDOW = 888;
- // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_DENIED_SYSTEM_ALERT_WINDOW = 889;
- // ACTION: The app-op permission SYSTEM_ALERT_WINDOW was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_APPOP_REVOKE_SYSTEM_ALERT_WINDOW = 890;
- // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_REQUEST_WRITE_SETTINGS = 891;
- // ACTION: An app was granted the app-op permission REQUEST_WRITE_SETTINGS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_APPOP_GRANT_WRITE_SETTINGS = 892;
- // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_DENIED_WRITE_SETTINGS = 893;
- // ACTION: The app-op permission REQUEST_WRITE_SETTINGS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_APPOP_REVOKE_WRITE_SETTINGS = 894;
- // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_REQUEST_REQUEST_INSTALL_PACKAGES = 895;
- // ACTION: An app was granted the app-op permission REQUEST_INSTALL_PACKAGES
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_APPOP_GRANT_REQUEST_INSTALL_PACKAGES = 896;
- // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_DENIED_REQUEST_INSTALL_PACKAGES = 897;
- // ACTION: The app-op permission REQUEST_INSTALL_PACKAGES was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_APPOP_REVOKE_REQUEST_INSTALL_PACKAGES = 898;
// ACTION: Phase 1 of instant application resolution occurred
@@ -4567,6 +4449,10 @@ message MetricsEvent {
// OS: O MR
COLOR_MODE_SETTINGS = 1143;
+ // Enclosing category for group of APP_TRANSITION_FOO events,
+ // logged when we cancel an app transition.
+ APP_TRANSITION_CANCELLED = 1144;
+
// ---- End O-MR1 Constants, all O-MR1 constants go above this line ----
// OPEN: Settings > Network & Internet > Mobile network
@@ -4764,6 +4650,119 @@ message MetricsEvent {
// OS: P
DIALOG_IMEI_INFO = 1240;
+ // In permission action fields tagged like this reference the permission affected
+ FIELD_PERMISSION = 1241;
+
+ // ACTION: An app requested a permission and we asked to user to approve the request
+ // PACKAGE: The package name of the app requesting the permission
+ // Tag FIELD_PERMISSION: Name of the permission requested
+ ACTION_PERMISSION_REQUESTED = 1242;
+
+ // ACTION: An app was granted the a permission. This can happen after a user approved a request
+ // or automatically. In the second case there will not be an
+ // ACTION_PERMISSION_REQUESTED.
+ // PACKAGE: The package name of the app that was granted the permission
+ // Tag FIELD_PERMISSION: Name of the permission granted
+ ACTION_PERMISSION_GRANTED = 1243;
+
+ // ACTION: An app requested the a permission and the request was denied by the user or a device
+ // policy
+ // PACKAGE: The package name of the app requesting the permission
+ // Tag FIELD_PERMISSION: Name of the permission denied
+ ACTION_PERMISSION_DENIED = 1244;
+
+ // ACTION: A permission was revoked
+ // PACKAGE: The package name of the app the permission was revoked for
+ // Tag FIELD_PERMISSION: Name of the permission revoked
+ ACTION_PERMISSION_REVOKED = 1245;
+
+ // OPEN: Settings > System > About Phone > Sim status
+ // CATEGORY: SETTINGS
+ // OS: P
+ DIALOG_SIM_STATUS = 1246;
+
+ // OPEN: Settings > System > About Phone > Android Version
+ // CATEGORY: SETTINGS
+ // OS: P
+ DIALOG_FIRMWARE_VERSION = 1247;
+
+ // OPEN: Settings > Network & internet > Menu > Private DNS
+ // CATEGORY: SETTINGS
+ // OS: P
+ DIALOG_PRIVATE_DNS = 1248;
+
+ // ACTION: A private dns mode been selected by user
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_PRIVATE_DNS_MODE = 1249;
+
+ // FIELD: text select start offset in words (as defined by the ICU BreakIterator).
+ // CATEGORY: TEXT_SELECTION_SESSION
+ // OS: P
+ FIELD_SELECTION_RANGE_START = 1250;
+
+ // FIELD: text select end offset in words (as defined by the ICU BreakIterator).
+ // CATEGORY: TEXT_SELECTION_SESSION
+ // OS: P
+ FIELD_SELECTION_RANGE_END = 1251;
+
+ // FIELD: smart text selection start offset in words (as defined by the ICU BreakIterator),
+ // stored as two packed 16bit integers. (start in MSBs, end in LSBs)
+ // CATEGORY: TEXT_SELECTION_SESSION
+ // OS: P
+ FIELD_SELECTION_SMART_RANGE_START = 1252;
+
+ // FIELD: smart text selection end offset in words (as defined by the ICU BreakIterator),
+ // stored as two packed 16bit integers. (start in MSBs, end in LSBs)
+ // CATEGORY: TEXT_SELECTION_SESSION
+ // OS: P
+ FIELD_SELECTION_SMART_RANGE_END = 1253;
+
+ // FIELD: the entity type of the text currently selected.
+ // CATEGORY: TEXT_SELECTION_SESSION
+ // OS: P
+ FIELD_SELECTION_ENTITY_TYPE = 1254;
+
+ // FIELD: the type of widget the selection was made in.
+ // CATEGORY: TEXT_SELECTION_SESSION
+ // OS: P
+ FIELD_SELECTION_WIDGET_TYPE = 1255;
+
+ // FIELD: the name of the text classifier model used.
+ // CATEGORY: TEXT_SELECTION_SESSION
+ // OS: P
+ FIELD_TEXTCLASSIFIER_MODEL = 1256;
+
+ // OPEN: Settings > Sound & notification > Do Not Disturb > Behavior > Messages
+ // CATEGORY: SETTINGS
+ // OS: P
+ NOTIFICATION_ZEN_MODE_MESSAGES = 1257;
+
+ // OPEN: Settings > Sound & notification > Do Not Disturb > Behavior > Calls
+ // CATEGORY: SETTINGS
+ // OS: P
+ NOTIFICATION_ZEN_MODE_CALLS = 1258;
+
+ // OPEN: Settings > Sound & notification > Do Not Disturb > TURN ON -> Until you turn off
+ // CATEGORY: SETTINGS
+ // OS: P
+ NOTIFICATION_ZEN_MODE_TOGGLE_ON_FOREVER = 1259;
+
+ // OPEN: Settings > Sound & notification > Do Not Disturb > TURN ON -> Time countdown manual rule (ie: for one hour)
+ // CATEGORY: SETTINGS
+ // OS: P
+ NOTIFICATION_ZEN_MODE_TOGGLE_ON_COUNTDOWN = 1260;
+
+ // OPEN: Settings > Sound & notification > Do Not Disturb > TURN ON -> Next Alarm (ie: Until Tue 7:20 AM)
+ // CATEGORY: SETTINGS
+ // OS: P
+ NOTIFICATION_ZEN_MODE_TOGGLE_ON_ALARM = 1261;
+
+ // FIELD: the version of the widget the selection was made in.
+ // CATEGORY: TEXT_SELECTION_SESSION
+ // OS: P
+ FIELD_SELECTION_WIDGET_VERSION = 1262;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 9d25055d6d5a..f5349df0bd94 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -364,6 +364,15 @@ message WifiLog {
// (one value added per unique ESS - potentially multiple counts per single
// scan!)
repeated NumConnectableNetworksBucket observed_hotspot_r2_aps_per_ess_in_scan_histogram = 88;
+
+ // SoftAP event list tracking sessions and client counts in tethered mode
+ repeated SoftApConnectedClientsEvent soft_ap_connected_clients_events_tethered = 89;
+
+ // SoftAP event list tracking sessions and client counts in local only mode
+ repeated SoftApConnectedClientsEvent soft_ap_connected_clients_events_local_only = 90;
+
+ // Wps connection metrics
+ optional WpsMetrics wps_metrics = 91;
}
// Information that gets logged for every WiFi connection.
@@ -1071,3 +1080,57 @@ message ConnectToNetworkNotificationAndActionCount {
// Occurrences of this action.
optional int32 count = 4;
}
+
+// SoftAP event tracking sessions and client counts
+message SoftApConnectedClientsEvent {
+
+ // Soft AP event Types
+ enum SoftApEventType {
+
+ // Soft AP is Up and ready for use
+ SOFT_AP_UP = 0;
+
+ // Soft AP is Down
+ SOFT_AP_DOWN = 1;
+
+ // Number of connected soft AP clients has changed
+ NUM_CLIENTS_CHANGED = 2;
+ }
+
+ // Type of event being recorded
+ optional SoftApEventType event_type = 1;
+
+ // Absolute time when event happened
+ optional int64 time_stamp_millis = 2;
+
+ // Number of connected clients if event_type is NUM_CLIENTS_CHANGED, otherwise zero.
+ optional int32 num_connected_clients = 3;
+}
+
+// Wps connection metrics
+// Keeps track of Wi-Fi Protected Setup usage
+message WpsMetrics {
+ // Total number of wps connection attempts
+ optional int32 num_wps_attempts = 1;
+
+ // Total number of wps connection successes
+ optional int32 num_wps_success = 2;
+
+ // Total number of wps failures on start
+ optional int32 num_wps_start_failure = 3;
+
+ // Total number of wps overlap failure
+ optional int32 num_wps_overlap_failure = 4;
+
+ // Total number of wps timeout failure
+ optional int32 num_wps_timeout_failure = 5;
+
+ // Total number of other wps failure during connection
+ optional int32 num_wps_other_connection_failure = 6;
+
+ // Total number of supplicant failure after wps
+ optional int32 num_wps_supplicant_failure = 7;
+
+ // Total number of wps cancellation
+ optional int32 num_wps_cancellation = 8;
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 06c110de6db2..d661754a059d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1318,7 +1318,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private void unbindAllServicesLocked(UserState userState) {
List<AccessibilityServiceConnection> services = userState.mBoundServices;
- for (int count = services.size(); count > 1; count--) {
+ for (int count = services.size(); count > 0; count--) {
// When the service is unbound, it disappears from the list, so there's no need to
// keep track of the index
services.get(0).unbindLocked();
diff --git a/services/art-profile b/services/art-profile
index ac5ecaff2cc4..301918fbe1c8 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -2374,6 +2374,9 @@ HPLcom/android/server/display/AutomaticBrightnessController;->nextAmbientLightDa
HPLcom/android/server/display/AutomaticBrightnessController;->updateAmbientLux()V
HPLcom/android/server/display/AutomaticBrightnessController;->updateAmbientLux(J)V
HPLcom/android/server/display/AutomaticBrightnessController;->weightIntegral(J)F
+HPLcom/android/server/display/ColorDisplayService$3;->onAnimationUpdate(Landroid/animation/ValueAnimator;)V
+HPLcom/android/server/display/ColorDisplayService$ColorMatrixEvaluator;->evaluate(FLjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+HPLcom/android/server/display/ColorDisplayService$ColorMatrixEvaluator;->evaluate(F[F[F)[F
HPLcom/android/server/display/DisplayBlanker;->requestDisplayState(II)V
HPLcom/android/server/display/DisplayManagerService$BinderService;->getDisplayIds()[I
HPLcom/android/server/display/DisplayManagerService$CallbackRecord;->binderDied()V
@@ -2430,9 +2433,6 @@ HPLcom/android/server/display/DisplayTransformManager;->setColorMatrix(I[F)V
HPLcom/android/server/display/LogicalDisplay;->getRequestedModeIdLocked()I
HPLcom/android/server/display/LogicalDisplay;->hasContentLocked()Z
HPLcom/android/server/display/LogicalDisplay;->setDisplayInfoOverrideFromWindowManagerLocked(Landroid/view/DisplayInfo;)Z
-HPLcom/android/server/display/NightDisplayService$3;->onAnimationUpdate(Landroid/animation/ValueAnimator;)V
-HPLcom/android/server/display/NightDisplayService$ColorMatrixEvaluator;->evaluate(FLjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-HPLcom/android/server/display/NightDisplayService$ColorMatrixEvaluator;->evaluate(F[F[F)[F
HPLcom/android/server/display/RampAnimator$1;->run()V
HPLcom/android/server/display/RampAnimator$Listener;->onAnimationEnd()V
HPLcom/android/server/display/RampAnimator;->-get0(Lcom/android/server/display/RampAnimator;)F
@@ -10133,6 +10133,25 @@ PLcom/android/server/display/AutomaticBrightnessController;->setAmbientLux(F)V
PLcom/android/server/display/AutomaticBrightnessController;->setLightSensorEnabled(Z)Z
PLcom/android/server/display/AutomaticBrightnessController;->setScreenAutoBrightnessAdjustment(F)Z
PLcom/android/server/display/AutomaticBrightnessController;->updateAutoBrightness(Z)V
+PLcom/android/server/display/ColorDisplayService$1;-><init>(Lcom/android/server/display/ColorDisplayService;)V
+PLcom/android/server/display/ColorDisplayService$3;-><init>(Lcom/android/server/display/ColorDisplayService;Lcom/android/server/display/DisplayTransformManager;)V
+PLcom/android/server/display/ColorDisplayService$4;-><init>(Lcom/android/server/display/ColorDisplayService;Lcom/android/server/display/DisplayTransformManager;[F)V
+PLcom/android/server/display/ColorDisplayService$4;->onAnimationCancel(Landroid/animation/Animator;)V
+PLcom/android/server/display/ColorDisplayService$4;->onAnimationEnd(Landroid/animation/Animator;)V
+PLcom/android/server/display/ColorDisplayService$ColorMatrixEvaluator;-><init>()V
+PLcom/android/server/display/ColorDisplayService$ColorMatrixEvaluator;-><init>(Lcom/android/server/display/ColorDisplayService$ColorMatrixEvaluator;)V
+PLcom/android/server/display/ColorDisplayService;->-set0(Lcom/android/server/display/ColorDisplayService;Landroid/animation/ValueAnimator;)Landroid/animation/ValueAnimator;
+PLcom/android/server/display/ColorDisplayService;-><init>(Landroid/content/Context;)V
+PLcom/android/server/display/ColorDisplayService;->applyTint(Z)V
+PLcom/android/server/display/ColorDisplayService;->isUserSetupCompleted(Landroid/content/ContentResolver;I)Z
+PLcom/android/server/display/ColorDisplayService;->onActivated(Z)V
+PLcom/android/server/display/ColorDisplayService;->onAutoModeChanged(I)V
+PLcom/android/server/display/ColorDisplayService;->onBootPhase(I)V
+PLcom/android/server/display/ColorDisplayService;->onStart()V
+PLcom/android/server/display/ColorDisplayService;->onStartUser(I)V
+PLcom/android/server/display/ColorDisplayService;->onUserChanged(I)V
+PLcom/android/server/display/ColorDisplayService;->setMatrix(I[F)V
+PLcom/android/server/display/ColorDisplayService;->setUp()V
PLcom/android/server/display/ColorFade;-><init>(I)V
PLcom/android/server/display/ColorFade;->createNativeFloatBuffer(I)Ljava/nio/FloatBuffer;
PLcom/android/server/display/ColorFade;->dismiss()V
@@ -10230,25 +10249,6 @@ PLcom/android/server/display/LogicalDisplay;->configureDisplayInTransactionLocke
PLcom/android/server/display/LogicalDisplay;->getDisplayIdLocked()I
PLcom/android/server/display/LogicalDisplay;->getNonOverrideDisplayInfoLocked(Landroid/view/DisplayInfo;)V
PLcom/android/server/display/LogicalDisplay;->setHasContentLocked(Z)V
-PLcom/android/server/display/NightDisplayService$1;-><init>(Lcom/android/server/display/NightDisplayService;)V
-PLcom/android/server/display/NightDisplayService$3;-><init>(Lcom/android/server/display/NightDisplayService;Lcom/android/server/display/DisplayTransformManager;)V
-PLcom/android/server/display/NightDisplayService$4;-><init>(Lcom/android/server/display/NightDisplayService;Lcom/android/server/display/DisplayTransformManager;[F)V
-PLcom/android/server/display/NightDisplayService$4;->onAnimationCancel(Landroid/animation/Animator;)V
-PLcom/android/server/display/NightDisplayService$4;->onAnimationEnd(Landroid/animation/Animator;)V
-PLcom/android/server/display/NightDisplayService$ColorMatrixEvaluator;-><init>()V
-PLcom/android/server/display/NightDisplayService$ColorMatrixEvaluator;-><init>(Lcom/android/server/display/NightDisplayService$ColorMatrixEvaluator;)V
-PLcom/android/server/display/NightDisplayService;->-set0(Lcom/android/server/display/NightDisplayService;Landroid/animation/ValueAnimator;)Landroid/animation/ValueAnimator;
-PLcom/android/server/display/NightDisplayService;-><init>(Landroid/content/Context;)V
-PLcom/android/server/display/NightDisplayService;->applyTint(Z)V
-PLcom/android/server/display/NightDisplayService;->isUserSetupCompleted(Landroid/content/ContentResolver;I)Z
-PLcom/android/server/display/NightDisplayService;->onActivated(Z)V
-PLcom/android/server/display/NightDisplayService;->onAutoModeChanged(I)V
-PLcom/android/server/display/NightDisplayService;->onBootPhase(I)V
-PLcom/android/server/display/NightDisplayService;->onStart()V
-PLcom/android/server/display/NightDisplayService;->onStartUser(I)V
-PLcom/android/server/display/NightDisplayService;->onUserChanged(I)V
-PLcom/android/server/display/NightDisplayService;->setMatrix(I[F)V
-PLcom/android/server/display/NightDisplayService;->setUp()V
PLcom/android/server/display/OverlayDisplayAdapter$1$1;-><init>(Lcom/android/server/display/OverlayDisplayAdapter$1;Landroid/os/Handler;)V
PLcom/android/server/display/OverlayDisplayAdapter$1;-><init>(Lcom/android/server/display/OverlayDisplayAdapter;)V
PLcom/android/server/display/OverlayDisplayAdapter$1;->run()V
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index caff0ba9bea2..23e4f504735b 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -512,6 +512,16 @@ public final class AutofillManagerService extends SystemService {
}
@Override
+ public void removeClient(IAutoFillManagerClient client, int userId) {
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ service.removeClientLocked(client);
+ }
+ }
+ }
+
+ @Override
public void setAuthenticationResult(Bundle data, int sessionId, int authenticationId,
int userId) {
synchronized (mLock) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index d8eaccc13532..21e27220b621 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -273,6 +273,12 @@ final class AutofillManagerServiceImpl {
return isEnabled();
}
+ void removeClientLocked(IAutoFillManagerClient client) {
+ if (mClients != null) {
+ mClients.unregister(client);
+ }
+ }
+
void setAuthenticationResultLocked(Bundle data, int sessionId, int authenticationId, int uid) {
if (!isEnabled()) {
return;
@@ -548,6 +554,10 @@ final class AutofillManagerServiceImpl {
}
sendStateToClients(true);
+ if (mClients != null) {
+ mClients.kill();
+ mClients = null;
+ }
}
@NonNull
@@ -602,7 +612,7 @@ final class AutofillManagerServiceImpl {
if (isValidEventLocked("setAuthenticationSelected()", sessionId)) {
mEventHistory.addEvent(
new Event(Event.TYPE_AUTHENTICATION_SELECTED, null, clientState, null, null,
- null, null, null, null));
+ null, null, null, null, null, -1));
}
}
}
@@ -616,7 +626,7 @@ final class AutofillManagerServiceImpl {
if (isValidEventLocked("logDatasetAuthenticationSelected()", sessionId)) {
mEventHistory.addEvent(
new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset,
- clientState, null, null, null, null, null, null));
+ clientState, null, null, null, null, null, null, null, -1));
}
}
}
@@ -628,7 +638,7 @@ final class AutofillManagerServiceImpl {
synchronized (mLock) {
if (isValidEventLocked("logSaveShown()", sessionId)) {
mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null, clientState, null,
- null, null, null, null, null));
+ null, null, null, null, null, null, -1));
}
}
}
@@ -642,7 +652,7 @@ final class AutofillManagerServiceImpl {
if (isValidEventLocked("logDatasetSelected()", sessionId)) {
mEventHistory.addEvent(
new Event(Event.TYPE_DATASET_SELECTED, selectedDataset, clientState, null,
- null, null, null, null, null));
+ null, null, null, null, null, null, -1));
}
}
}
@@ -656,13 +666,15 @@ final class AutofillManagerServiceImpl {
@Nullable ArrayList<AutofillId> changedFieldIds,
@Nullable ArrayList<String> changedDatasetIds,
@Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
- @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds) {
+ @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
+ @Nullable String detectedRemoteId, int detectedFieldScore) {
synchronized (mLock) {
if (isValidEventLocked("logDatasetNotSelected()", sessionId)) {
mEventHistory.addEvent(new Event(Event.TYPE_CONTEXT_COMMITTED, null,
clientState, selectedDatasets, ignoredDatasets,
changedFieldIds, changedDatasetIds,
- manuallyFilledFieldIds, manuallyFilledDatasetIds));
+ manuallyFilledFieldIds, manuallyFilledDatasetIds,
+ detectedRemoteId, detectedFieldScore));
}
}
}
@@ -695,6 +707,7 @@ final class AutofillManagerServiceImpl {
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("Setup complete: "); pw.println(mSetupComplete);
pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
@@ -749,6 +762,9 @@ final class AutofillManagerServiceImpl {
}
}
+ pw.print(prefix); pw.println("Clients");
+ mClients.dump(pw, prefix2);
+
if (mEventHistory == null || mEventHistory.getEvents() == null
|| mEventHistory.getEvents().size() == 0) {
pw.print(prefix); pw.println("No event on last fill response");
@@ -935,6 +951,13 @@ final class AutofillManagerServiceImpl {
return false;
}
+ // TODO(b/67867469): remove once feature is finished
+ boolean isFieldDetectionEnabled() {
+ return Settings.Secure.getIntForUser(
+ mContext.getContentResolver(), Settings.Secure.AUTOFILL_FEATURE_FIELD_DETECTION, 0,
+ mUserId) == 1;
+ }
+
@Override
public String toString() {
return "AutofillManagerServiceImpl: [userId=" + mUserId
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 3564432e6b93..af4668a63c03 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -36,6 +36,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.IAssistDataReceiver;
import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.AutofillOverlay;
import android.app.assist.AssistStructure.ViewNode;
@@ -54,6 +55,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.service.autofill.AutofillService;
import android.service.autofill.Dataset;
+import android.service.autofill.FieldsDetection;
import android.service.autofill.FillContext;
import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
@@ -75,7 +77,6 @@ import android.view.autofill.IAutoFillManagerClient;
import android.view.autofill.IAutofillWindowPresenter;
import com.android.internal.R;
-import com.android.internal.app.IAssistDataReceiver;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -492,6 +493,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
}
+ // TODO(b/67867469): remove once feature is finished
+ if (response.getFieldsDetection() != null && !mService.isFieldDetectionEnabled()) {
+ Slog.w(TAG, "Ignoring " + response + " because field detection is disabled");
+ processNullResponseLocked(requestFlags);
+ return;
+ }
+
mService.setLastResponse(serviceUid, id, response);
int sessionFinishedState = 0;
@@ -913,11 +921,29 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
}
}
- if (!hasAtLeastOneDataset) {
- if (sVerbose) Slog.v(TAG, "logContextCommittedLocked(): skipped (no datasets)");
+ final FieldsDetection fieldsDetection = lastResponse.getFieldsDetection();
+
+ if (!hasAtLeastOneDataset && fieldsDetection == null) {
+ if (sVerbose) {
+ Slog.v(TAG, "logContextCommittedLocked(): skipped (no datasets nor fields "
+ + "detection)");
+ }
return;
}
+ final AutofillId detectableFieldId;
+ final String detectableRemoteId;
+ String detectedRemoteId = null;
+ if (fieldsDetection == null) {
+ detectableFieldId = null;
+ detectableRemoteId = null;
+ } else {
+ detectableFieldId = fieldsDetection.getFieldId();
+ detectableRemoteId = fieldsDetection.getRemoteId();
+ }
+
+ int detectedFieldScore = -1;
+
for (int i = 0; i < mViewStates.size(); i++) {
final ViewState viewState = mViewStates.valueAt(i);
final int state = viewState.getState();
@@ -926,7 +952,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// - autofilled -> changedDatasetIds
// - not autofilled but matches a dataset value -> manuallyFilledIds
if ((state & ViewState.STATE_CHANGED) != 0) {
-
// Check if autofilled value was changed
if ((state & ViewState.STATE_AUTOFILLED) != 0) {
final String datasetId = viewState.getDatasetId();
@@ -958,7 +983,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
changedFieldIds.add(viewState.id);
changedDatasetIds.add(datasetId);
} else {
- // Check if value match a dataset.
final AutofillValue currentValue = viewState.getCurrentValue();
if (currentValue == null) {
if (sDebug) {
@@ -967,58 +991,78 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
continue;
}
- for (int j = 0; j < responseCount; j++) {
- final FillResponse response = mResponses.valueAt(j);
- final List<Dataset> datasets = response.getDatasets();
- if (datasets == null || datasets.isEmpty()) {
- if (sVerbose) Slog.v(TAG, "logContextCommitted() no datasets at " + j);
- } else {
- for (int k = 0; k < datasets.size(); k++) {
- final Dataset dataset = datasets.get(k);
- final String datasetId = dataset.getId();
- if (datasetId == null) {
- if (sVerbose) {
- Slog.v(TAG, "logContextCommitted() skipping idless dataset "
- + dataset);
- }
- } else {
- final ArrayList<AutofillValue> values = dataset.getFieldValues();
- for (int l = 0; l < values.size(); l++) {
- final AutofillValue candidate = values.get(l);
- if (currentValue.equals(candidate)) {
- if (sDebug) {
- Slog.d(TAG, "field " + viewState.id
- + " was manually filled with value set by "
- + "dataset " + datasetId);
+ // Check if value match a dataset.
+ if (hasAtLeastOneDataset) {
+ for (int j = 0; j < responseCount; j++) {
+ final FillResponse response = mResponses.valueAt(j);
+ final List<Dataset> datasets = response.getDatasets();
+ if (datasets == null || datasets.isEmpty()) {
+ if (sVerbose) {
+ Slog.v(TAG, "logContextCommitted() no datasets at " + j);
+ }
+ } else {
+ for (int k = 0; k < datasets.size(); k++) {
+ final Dataset dataset = datasets.get(k);
+ final String datasetId = dataset.getId();
+ if (datasetId == null) {
+ if (sVerbose) {
+ Slog.v(TAG, "logContextCommitted() skipping idless "
+ + "dataset " + dataset);
+ }
+ } else {
+ final ArrayList<AutofillValue> values =
+ dataset.getFieldValues();
+ for (int l = 0; l < values.size(); l++) {
+ final AutofillValue candidate = values.get(l);
+ if (currentValue.equals(candidate)) {
+ if (sDebug) {
+ Slog.d(TAG, "field " + viewState.id + " was "
+ + "manually filled with value set by "
+ + "dataset " + datasetId);
+ }
+ if (manuallyFilledIds == null) {
+ manuallyFilledIds = new ArrayMap<>();
+ }
+ ArraySet<String> datasetIds =
+ manuallyFilledIds.get(viewState.id);
+ if (datasetIds == null) {
+ datasetIds = new ArraySet<>(1);
+ manuallyFilledIds.put(viewState.id, datasetIds);
+ }
+ datasetIds.add(datasetId);
}
- if (manuallyFilledIds == null) {
- manuallyFilledIds = new ArrayMap<>();
+ } // for l
+ if (mSelectedDatasetIds == null
+ || !mSelectedDatasetIds.contains(datasetId)) {
+ if (sVerbose) {
+ Slog.v(TAG, "adding ignored dataset " + datasetId);
}
- ArraySet<String> datasetIds =
- manuallyFilledIds.get(viewState.id);
- if (datasetIds == null) {
- datasetIds = new ArraySet<>(1);
- manuallyFilledIds.put(viewState.id, datasetIds);
+ if (ignoredDatasets == null) {
+ ignoredDatasets = new ArraySet<>();
}
- datasetIds.add(datasetId);
- }
- }
- if (mSelectedDatasetIds == null
- || !mSelectedDatasetIds.contains(datasetId)) {
- if (sVerbose) {
- Slog.v(TAG, "adding ignored dataset " + datasetId);
- }
- if (ignoredDatasets == null) {
- ignoredDatasets = new ArraySet<>();
- }
- ignoredDatasets.add(datasetId);
- }
- }
- }
+ ignoredDatasets.add(datasetId);
+ } // if
+ } // if
+ } // for k
+ } // else
+ } // 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
}
- }
- }
+ } // else
+ } // else
}
if (sVerbose) {
@@ -1027,7 +1071,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
+ ", ignoredDatasetIds=" + ignoredDatasets
+ ", changedAutofillIds=" + changedFieldIds
+ ", changedDatasetIds=" + changedDatasetIds
- + ", manuallyFilledIds=" + manuallyFilledIds);
+ + ", manuallyFilledIds=" + manuallyFilledIds
+ + ", detectableFieldId=" + detectableFieldId
+ + ", detectedFieldScore=" + detectedFieldScore
+ );
}
ArrayList<AutofillId> manuallyFilledFieldIds = null;
@@ -1045,9 +1092,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
manuallyFilledDatasetIds.add(new ArrayList<>(datasetIds));
}
}
+
mService.logContextCommitted(id, mClientState, mSelectedDatasetIds, ignoredDatasets,
changedFieldIds, changedDatasetIds,
- manuallyFilledFieldIds, manuallyFilledDatasetIds);
+ manuallyFilledFieldIds, manuallyFilledDatasetIds,
+ detectedRemoteId, detectedFieldScore);
}
/**
@@ -1535,6 +1584,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
viewState = new ViewState(this, id, this,
isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL);
mViewStates.put(id, viewState);
+
+ // TODO(b/67867469): for optimization purposes, should also ignore if change is
+ // detectable, and batch-send them when the session is finished (but that will
+ // require tracking detectable fields on AutofillManager)
if (isIgnored) {
if (sDebug) Slog.d(TAG, "updateLocked(): ignoring view " + id);
return;
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 1d8110f08364..832a66b26b12 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -134,7 +134,11 @@ final class ViewState {
}
String getStateAsString() {
- return DebugUtils.flagsToString(ViewState.class, "STATE_", mState);
+ return getStateAsString(mState);
+ }
+
+ static String getStateAsString(int state) {
+ return DebugUtils.flagsToString(ViewState.class, "STATE_", state);
}
void setState(int state) {
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 622b84239711..e92a56477579 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -80,6 +80,7 @@ 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;
@@ -126,7 +127,6 @@ import com.android.server.EventLogTags;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
import com.android.server.backup.PackageManagerBackupAgent.Metadata;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import libcore.io.IoUtils;
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index 20f236908112..a45a4f0c35d3 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -71,6 +71,7 @@ import android.os.IBinder;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.Process;
import android.os.RemoteException;
@@ -120,7 +121,6 @@ import com.android.server.backup.utils.AppBackupUtils;
import com.android.server.backup.utils.BackupManagerMonitorUtils;
import com.android.server.backup.utils.BackupObserverUtils;
import com.android.server.backup.utils.SparseArrayUtils;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import com.google.android.collect.Sets;
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 8d8a0135e3df..a08c19e95914 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -158,16 +158,19 @@ public class ActiveRestoreSession extends IRestoreSession.Stub {
MSG_RESTORE_SESSION_TIMEOUT);
long oldId = Binder.clearCallingIdentity();
- backupManagerService.getWakelock().acquire();
- if (MORE_DEBUG) {
- Slog.d(TAG, "restoreAll() kicking off");
+ 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);
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
}
- Message msg = backupManagerService.getBackupHandler().obtainMessage(
- MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, dirName,
- observer, monitor, token);
- backupManagerService.getBackupHandler().sendMessage(msg);
- Binder.restoreCallingIdentity(oldId);
return 0;
}
}
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index ad308975e613..ea0ed2719ad0 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -38,7 +38,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.hidl.manager.V1_0.IServiceManager;
import android.hidl.manager.V1_0.IServiceNotification;
-import android.hardware.health.V2_0.HealthInfo;
+import android.hardware.health.V1_0.HealthInfo;
import android.hardware.health.V2_0.IHealthInfoCallback;
import android.hardware.health.V2_0.IHealth;
import android.hardware.health.V2_0.Result;
@@ -49,6 +49,7 @@ import android.os.BatteryProperty;
import android.os.Binder;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBatteryPropertiesListener;
import android.os.IBatteryPropertiesRegistrar;
import android.os.IBinder;
@@ -56,6 +57,7 @@ import android.os.DropBoxManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.UEventObserver;
import android.os.UserHandle;
import android.provider.Settings;
@@ -74,6 +76,7 @@ import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -175,6 +178,7 @@ public final class BatteryService extends SystemService {
private HealthServiceWrapper mHealthServiceWrapper;
private HealthHalCallback mHealthHalCallback;
private BatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
+ private HandlerThread mHandlerThread;
public BatteryService(Context context) {
super(context);
@@ -246,6 +250,7 @@ public final class BatteryService extends SystemService {
}
private void registerHealthCallback() {
+ traceBegin("HealthInitWrapper");
mHealthServiceWrapper = new HealthServiceWrapper();
mHealthHalCallback = new HealthHalCallback();
// IHealth is lazily retrieved.
@@ -259,8 +264,11 @@ public final class BatteryService extends SystemService {
} catch (NoSuchElementException ex) {
Slog.e(TAG, "health: cannot register callback. (no supported health HAL service)");
throw ex;
+ } finally {
+ traceEnd();
}
+ traceBegin("HealthInitWaitUpdate");
// init register for new service notifications, and IServiceManager should return the
// existing service in a near future. Wait for this.update() to instantiate
// the initial mHealthInfo.
@@ -280,6 +288,7 @@ public final class BatteryService extends SystemService {
Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait)
+ "ms and received the update.");
+ traceEnd();
}
private void updateBatteryWarningLevelLocked() {
@@ -302,16 +311,16 @@ public final class BatteryService extends SystemService {
private boolean isPoweredLocked(int plugTypeSet) {
// assume we are powered if battery state is unknown so
// the "stay on while plugged in" option will work.
- if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
+ if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
return true;
}
- if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mHealthInfo.legacy.chargerAcOnline) {
+ if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mHealthInfo.chargerAcOnline) {
return true;
}
- if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mHealthInfo.legacy.chargerUsbOnline) {
+ if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mHealthInfo.chargerUsbOnline) {
return true;
}
- if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mHealthInfo.legacy.chargerWirelessOnline) {
+ if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mHealthInfo.chargerWirelessOnline) {
return true;
}
return false;
@@ -328,15 +337,15 @@ public final class BatteryService extends SystemService {
* (becomes <= mLowBatteryWarningLevel).
*/
return !plugged
- && mHealthInfo.legacy.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
- && mHealthInfo.legacy.batteryLevel <= mLowBatteryWarningLevel
+ && mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
+ && mHealthInfo.batteryLevel <= mLowBatteryWarningLevel
&& (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
}
private void shutdownIfNoPowerLocked() {
// shut down gracefully if our battery is critically low and we are not powered.
// wait until the system has booted before attempting to display the shutdown dialog.
- if (mHealthInfo.legacy.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
+ if (mHealthInfo.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -357,7 +366,7 @@ public final class BatteryService extends SystemService {
// shut down gracefully if temperature is too high (> 68.0C by default)
// wait until the system has booted before attempting to display the
// shutdown dialog.
- if (mHealthInfo.legacy.batteryTemperature > mShutdownBatteryTemperature) {
+ if (mHealthInfo.batteryTemperature > mShutdownBatteryTemperature) {
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -375,6 +384,7 @@ public final class BatteryService extends SystemService {
}
private void update(HealthInfo info) {
+ traceBegin("HealthInfoUpdate");
synchronized (mLock) {
if (!mUpdatesStopped) {
mHealthInfo = info;
@@ -385,40 +395,38 @@ public final class BatteryService extends SystemService {
copy(mLastHealthInfo, info);
}
}
+ traceEnd();
}
private static void copy(HealthInfo dst, HealthInfo src) {
- dst.legacy.chargerAcOnline = src.legacy.chargerAcOnline;
- dst.legacy.chargerUsbOnline = src.legacy.chargerUsbOnline;
- dst.legacy.chargerWirelessOnline = src.legacy.chargerWirelessOnline;
- dst.legacy.maxChargingCurrent = src.legacy.maxChargingCurrent;
- dst.legacy.maxChargingVoltage = src.legacy.maxChargingVoltage;
- dst.legacy.batteryStatus = src.legacy.batteryStatus;
- dst.legacy.batteryHealth = src.legacy.batteryHealth;
- dst.legacy.batteryPresent = src.legacy.batteryPresent;
- dst.legacy.batteryLevel = src.legacy.batteryLevel;
- dst.legacy.batteryVoltage = src.legacy.batteryVoltage;
- dst.legacy.batteryTemperature = src.legacy.batteryTemperature;
- dst.legacy.batteryCurrent = src.legacy.batteryCurrent;
- dst.legacy.batteryCycleCount = src.legacy.batteryCycleCount;
- dst.legacy.batteryFullCharge = src.legacy.batteryFullCharge;
- dst.legacy.batteryChargeCounter = src.legacy.batteryChargeCounter;
- dst.legacy.batteryTechnology = src.legacy.batteryTechnology;
- dst.batteryCurrentAverage = src.batteryCurrentAverage;
- dst.batteryCapacity = src.batteryCapacity;
- dst.energyCounter = src.energyCounter;
+ dst.chargerAcOnline = src.chargerAcOnline;
+ dst.chargerUsbOnline = src.chargerUsbOnline;
+ dst.chargerWirelessOnline = src.chargerWirelessOnline;
+ dst.maxChargingCurrent = src.maxChargingCurrent;
+ dst.maxChargingVoltage = src.maxChargingVoltage;
+ dst.batteryStatus = src.batteryStatus;
+ dst.batteryHealth = src.batteryHealth;
+ dst.batteryPresent = src.batteryPresent;
+ dst.batteryLevel = src.batteryLevel;
+ dst.batteryVoltage = src.batteryVoltage;
+ dst.batteryTemperature = src.batteryTemperature;
+ dst.batteryCurrent = src.batteryCurrent;
+ dst.batteryCycleCount = src.batteryCycleCount;
+ dst.batteryFullCharge = src.batteryFullCharge;
+ dst.batteryChargeCounter = src.batteryChargeCounter;
+ dst.batteryTechnology = src.batteryTechnology;
}
private void processValuesLocked(boolean force) {
boolean logOutlier = false;
long dischargeDuration = 0;
- mBatteryLevelCritical = (mHealthInfo.legacy.batteryLevel <= mCriticalBatteryLevel);
- if (mHealthInfo.legacy.chargerAcOnline) {
+ mBatteryLevelCritical = (mHealthInfo.batteryLevel <= mCriticalBatteryLevel);
+ if (mHealthInfo.chargerAcOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
- } else if (mHealthInfo.legacy.chargerUsbOnline) {
+ } else if (mHealthInfo.chargerUsbOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
- } else if (mHealthInfo.legacy.chargerWirelessOnline) {
+ } else if (mHealthInfo.chargerWirelessOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
} else {
mPlugType = BATTERY_PLUGGED_NONE;
@@ -433,10 +441,10 @@ public final class BatteryService extends SystemService {
// Let the battery stats keep track of the current level.
try {
- mBatteryStats.setBatteryState(mHealthInfo.legacy.batteryStatus, mHealthInfo.legacy.batteryHealth,
- mPlugType, mHealthInfo.legacy.batteryLevel, mHealthInfo.legacy.batteryTemperature,
- mHealthInfo.legacy.batteryVoltage, mHealthInfo.legacy.batteryChargeCounter,
- mHealthInfo.legacy.batteryFullCharge);
+ mBatteryStats.setBatteryState(mHealthInfo.batteryStatus, mHealthInfo.batteryHealth,
+ mPlugType, mHealthInfo.batteryLevel, mHealthInfo.batteryTemperature,
+ mHealthInfo.batteryVoltage, mHealthInfo.batteryChargeCounter,
+ mHealthInfo.batteryFullCharge);
} catch (RemoteException e) {
// Should never happen.
}
@@ -444,16 +452,16 @@ public final class BatteryService extends SystemService {
shutdownIfNoPowerLocked();
shutdownIfOverTempLocked();
- if (force || (mHealthInfo.legacy.batteryStatus != mLastBatteryStatus ||
- mHealthInfo.legacy.batteryHealth != mLastBatteryHealth ||
- mHealthInfo.legacy.batteryPresent != mLastBatteryPresent ||
- mHealthInfo.legacy.batteryLevel != mLastBatteryLevel ||
+ if (force || (mHealthInfo.batteryStatus != mLastBatteryStatus ||
+ mHealthInfo.batteryHealth != mLastBatteryHealth ||
+ mHealthInfo.batteryPresent != mLastBatteryPresent ||
+ mHealthInfo.batteryLevel != mLastBatteryLevel ||
mPlugType != mLastPlugType ||
- mHealthInfo.legacy.batteryVoltage != mLastBatteryVoltage ||
- mHealthInfo.legacy.batteryTemperature != mLastBatteryTemperature ||
- mHealthInfo.legacy.maxChargingCurrent != mLastMaxChargingCurrent ||
- mHealthInfo.legacy.maxChargingVoltage != mLastMaxChargingVoltage ||
- mHealthInfo.legacy.batteryChargeCounter != mLastChargeCounter ||
+ mHealthInfo.batteryVoltage != mLastBatteryVoltage ||
+ mHealthInfo.batteryTemperature != mLastBatteryTemperature ||
+ mHealthInfo.maxChargingCurrent != mLastMaxChargingCurrent ||
+ mHealthInfo.maxChargingVoltage != mLastMaxChargingVoltage ||
+ mHealthInfo.batteryChargeCounter != mLastChargeCounter ||
mInvalidCharger != mLastInvalidCharger)) {
if (mPlugType != mLastPlugType) {
@@ -462,33 +470,33 @@ public final class BatteryService extends SystemService {
// There's no value in this data unless we've discharged at least once and the
// battery level has changed; so don't log until it does.
- if (mDischargeStartTime != 0 && mDischargeStartLevel != mHealthInfo.legacy.batteryLevel) {
+ if (mDischargeStartTime != 0 && mDischargeStartLevel != mHealthInfo.batteryLevel) {
dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
logOutlier = true;
EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,
- mDischargeStartLevel, mHealthInfo.legacy.batteryLevel);
+ mDischargeStartLevel, mHealthInfo.batteryLevel);
// make sure we see a discharge event before logging again
mDischargeStartTime = 0;
}
} else if (mPlugType == BATTERY_PLUGGED_NONE) {
// charging -> discharging or we just powered up
mDischargeStartTime = SystemClock.elapsedRealtime();
- mDischargeStartLevel = mHealthInfo.legacy.batteryLevel;
+ mDischargeStartLevel = mHealthInfo.batteryLevel;
}
}
- if (mHealthInfo.legacy.batteryStatus != mLastBatteryStatus ||
- mHealthInfo.legacy.batteryHealth != mLastBatteryHealth ||
- mHealthInfo.legacy.batteryPresent != mLastBatteryPresent ||
+ if (mHealthInfo.batteryStatus != mLastBatteryStatus ||
+ mHealthInfo.batteryHealth != mLastBatteryHealth ||
+ mHealthInfo.batteryPresent != mLastBatteryPresent ||
mPlugType != mLastPlugType) {
EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
- mHealthInfo.legacy.batteryStatus, mHealthInfo.legacy.batteryHealth, mHealthInfo.legacy.batteryPresent ? 1 : 0,
- mPlugType, mHealthInfo.legacy.batteryTechnology);
+ mHealthInfo.batteryStatus, mHealthInfo.batteryHealth, mHealthInfo.batteryPresent ? 1 : 0,
+ mPlugType, mHealthInfo.batteryTechnology);
}
- if (mHealthInfo.legacy.batteryLevel != mLastBatteryLevel) {
+ if (mHealthInfo.batteryLevel != mLastBatteryLevel) {
// Don't do this just from voltage or temperature changes, that is
// too noisy.
EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
- mHealthInfo.legacy.batteryLevel, mHealthInfo.legacy.batteryVoltage, mHealthInfo.legacy.batteryTemperature);
+ mHealthInfo.batteryLevel, mHealthInfo.batteryVoltage, mHealthInfo.batteryTemperature);
}
if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
mPlugType == BATTERY_PLUGGED_NONE) {
@@ -501,16 +509,16 @@ public final class BatteryService extends SystemService {
if (!mBatteryLevelLow) {
// Should we now switch in to low battery mode?
if (mPlugType == BATTERY_PLUGGED_NONE
- && mHealthInfo.legacy.batteryLevel <= mLowBatteryWarningLevel) {
+ && mHealthInfo.batteryLevel <= mLowBatteryWarningLevel) {
mBatteryLevelLow = true;
}
} else {
// Should we now switch out of low battery mode?
if (mPlugType != BATTERY_PLUGGED_NONE) {
mBatteryLevelLow = false;
- } else if (mHealthInfo.legacy.batteryLevel >= mLowBatteryCloseWarningLevel) {
+ } else if (mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) {
mBatteryLevelLow = false;
- } else if (force && mHealthInfo.legacy.batteryLevel >= mLowBatteryWarningLevel) {
+ } else if (force && mHealthInfo.batteryLevel >= mLowBatteryWarningLevel) {
// If being forced, the previous state doesn't matter, we will just
// absolutely check to see if we are now above the warning level.
mBatteryLevelLow = false;
@@ -557,7 +565,7 @@ public final class BatteryService extends SystemService {
}
});
} else if (mSentLowBatteryBroadcast &&
- mHealthInfo.legacy.batteryLevel >= mLowBatteryCloseWarningLevel) {
+ mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) {
mSentLowBatteryBroadcast = false;
final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -583,16 +591,16 @@ public final class BatteryService extends SystemService {
logOutlierLocked(dischargeDuration);
}
- mLastBatteryStatus = mHealthInfo.legacy.batteryStatus;
- mLastBatteryHealth = mHealthInfo.legacy.batteryHealth;
- mLastBatteryPresent = mHealthInfo.legacy.batteryPresent;
- mLastBatteryLevel = mHealthInfo.legacy.batteryLevel;
+ mLastBatteryStatus = mHealthInfo.batteryStatus;
+ mLastBatteryHealth = mHealthInfo.batteryHealth;
+ mLastBatteryPresent = mHealthInfo.batteryPresent;
+ mLastBatteryLevel = mHealthInfo.batteryLevel;
mLastPlugType = mPlugType;
- mLastBatteryVoltage = mHealthInfo.legacy.batteryVoltage;
- mLastBatteryTemperature = mHealthInfo.legacy.batteryTemperature;
- mLastMaxChargingCurrent = mHealthInfo.legacy.maxChargingCurrent;
- mLastMaxChargingVoltage = mHealthInfo.legacy.maxChargingVoltage;
- mLastChargeCounter = mHealthInfo.legacy.batteryChargeCounter;
+ mLastBatteryVoltage = mHealthInfo.batteryVoltage;
+ mLastBatteryTemperature = mHealthInfo.batteryTemperature;
+ mLastMaxChargingCurrent = mHealthInfo.maxChargingCurrent;
+ mLastMaxChargingVoltage = mHealthInfo.maxChargingVoltage;
+ mLastChargeCounter = mHealthInfo.batteryChargeCounter;
mLastBatteryLevelCritical = mBatteryLevelCritical;
mLastInvalidCharger = mInvalidCharger;
}
@@ -604,23 +612,23 @@ public final class BatteryService extends SystemService {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_REPLACE_PENDING);
- int icon = getIconLocked(mHealthInfo.legacy.batteryLevel);
+ int icon = getIconLocked(mHealthInfo.batteryLevel);
intent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
- intent.putExtra(BatteryManager.EXTRA_STATUS, mHealthInfo.legacy.batteryStatus);
- intent.putExtra(BatteryManager.EXTRA_HEALTH, mHealthInfo.legacy.batteryHealth);
- intent.putExtra(BatteryManager.EXTRA_PRESENT, mHealthInfo.legacy.batteryPresent);
- intent.putExtra(BatteryManager.EXTRA_LEVEL, mHealthInfo.legacy.batteryLevel);
+ intent.putExtra(BatteryManager.EXTRA_STATUS, mHealthInfo.batteryStatus);
+ intent.putExtra(BatteryManager.EXTRA_HEALTH, mHealthInfo.batteryHealth);
+ intent.putExtra(BatteryManager.EXTRA_PRESENT, mHealthInfo.batteryPresent);
+ intent.putExtra(BatteryManager.EXTRA_LEVEL, mHealthInfo.batteryLevel);
intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);
- intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.legacy.batteryVoltage);
- intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.legacy.batteryTemperature);
- intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mHealthInfo.legacy.batteryTechnology);
+ intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltage);
+ intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperature);
+ intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mHealthInfo.batteryTechnology);
intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
- intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.legacy.maxChargingCurrent);
- intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mHealthInfo.legacy.maxChargingVoltage);
- intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.legacy.batteryChargeCounter);
+ intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrent);
+ intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mHealthInfo.maxChargingVoltage);
+ intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounter);
if (DEBUG) {
Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. scale:" + BATTERY_SCALE
+ ", info:" + mHealthInfo.toString());
@@ -684,14 +692,14 @@ public final class BatteryService extends SystemService {
long durationThreshold = Long.parseLong(durationThresholdString);
int dischargeThreshold = Integer.parseInt(dischargeThresholdString);
if (duration <= durationThreshold &&
- mDischargeStartLevel - mHealthInfo.legacy.batteryLevel >= dischargeThreshold) {
+ mDischargeStartLevel - mHealthInfo.batteryLevel >= dischargeThreshold) {
// If the discharge cycle is bad enough we want to know about it.
logBatteryStatsLocked();
}
if (DEBUG) Slog.v(TAG, "duration threshold: " + durationThreshold +
" discharge threshold: " + dischargeThreshold);
if (DEBUG) Slog.v(TAG, "duration: " + duration + " discharge: " +
- (mDischargeStartLevel - mHealthInfo.legacy.batteryLevel));
+ (mDischargeStartLevel - mHealthInfo.batteryLevel));
} catch (NumberFormatException e) {
Slog.e(TAG, "Invalid DischargeThresholds GService string: " +
durationThresholdString + " or " + dischargeThresholdString);
@@ -700,14 +708,14 @@ public final class BatteryService extends SystemService {
}
private int getIconLocked(int level) {
- if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
+ if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
return com.android.internal.R.drawable.stat_sys_battery_charge;
- } else if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
+ } else if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
return com.android.internal.R.drawable.stat_sys_battery;
- } else if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
- || mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
+ } else if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
+ || mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
- && mHealthInfo.legacy.batteryLevel >= 100) {
+ && mHealthInfo.batteryLevel >= 100) {
return com.android.internal.R.drawable.stat_sys_battery_charge;
} else {
return com.android.internal.R.drawable.stat_sys_battery;
@@ -771,9 +779,9 @@ public final class BatteryService extends SystemService {
if (!mUpdatesStopped) {
copy(mLastHealthInfo, mHealthInfo);
}
- mHealthInfo.legacy.chargerAcOnline = false;
- mHealthInfo.legacy.chargerUsbOnline = false;
- mHealthInfo.legacy.chargerWirelessOnline = false;
+ mHealthInfo.chargerAcOnline = false;
+ mHealthInfo.chargerUsbOnline = false;
+ mHealthInfo.chargerWirelessOnline = false;
long ident = Binder.clearCallingIdentity();
try {
mUpdatesStopped = true;
@@ -805,25 +813,25 @@ public final class BatteryService extends SystemService {
boolean update = true;
switch (key) {
case "present":
- mHealthInfo.legacy.batteryPresent = Integer.parseInt(value) != 0;
+ mHealthInfo.batteryPresent = Integer.parseInt(value) != 0;
break;
case "ac":
- mHealthInfo.legacy.chargerAcOnline = Integer.parseInt(value) != 0;
+ mHealthInfo.chargerAcOnline = Integer.parseInt(value) != 0;
break;
case "usb":
- mHealthInfo.legacy.chargerUsbOnline = Integer.parseInt(value) != 0;
+ mHealthInfo.chargerUsbOnline = Integer.parseInt(value) != 0;
break;
case "wireless":
- mHealthInfo.legacy.chargerWirelessOnline = Integer.parseInt(value) != 0;
+ mHealthInfo.chargerWirelessOnline = Integer.parseInt(value) != 0;
break;
case "status":
- mHealthInfo.legacy.batteryStatus = Integer.parseInt(value);
+ mHealthInfo.batteryStatus = Integer.parseInt(value);
break;
case "level":
- mHealthInfo.legacy.batteryLevel = Integer.parseInt(value);
+ mHealthInfo.batteryLevel = Integer.parseInt(value);
break;
case "temp":
- mHealthInfo.legacy.batteryTemperature = Integer.parseInt(value);
+ mHealthInfo.batteryTemperature = Integer.parseInt(value);
break;
case "invalid":
mInvalidCharger = Integer.parseInt(value);
@@ -882,20 +890,20 @@ public final class BatteryService extends SystemService {
if (mUpdatesStopped) {
pw.println(" (UPDATES STOPPED -- use 'reset' to restart)");
}
- pw.println(" AC powered: " + mHealthInfo.legacy.chargerAcOnline);
- pw.println(" USB powered: " + mHealthInfo.legacy.chargerUsbOnline);
- pw.println(" Wireless powered: " + mHealthInfo.legacy.chargerWirelessOnline);
- pw.println(" Max charging current: " + mHealthInfo.legacy.maxChargingCurrent);
- pw.println(" Max charging voltage: " + mHealthInfo.legacy.maxChargingVoltage);
- pw.println(" Charge counter: " + mHealthInfo.legacy.batteryChargeCounter);
- pw.println(" status: " + mHealthInfo.legacy.batteryStatus);
- pw.println(" health: " + mHealthInfo.legacy.batteryHealth);
- pw.println(" present: " + mHealthInfo.legacy.batteryPresent);
- pw.println(" level: " + mHealthInfo.legacy.batteryLevel);
+ pw.println(" AC powered: " + mHealthInfo.chargerAcOnline);
+ pw.println(" USB powered: " + mHealthInfo.chargerUsbOnline);
+ pw.println(" Wireless powered: " + mHealthInfo.chargerWirelessOnline);
+ pw.println(" Max charging current: " + mHealthInfo.maxChargingCurrent);
+ pw.println(" Max charging voltage: " + mHealthInfo.maxChargingVoltage);
+ pw.println(" Charge counter: " + mHealthInfo.batteryChargeCounter);
+ pw.println(" status: " + mHealthInfo.batteryStatus);
+ pw.println(" health: " + mHealthInfo.batteryHealth);
+ pw.println(" present: " + mHealthInfo.batteryPresent);
+ pw.println(" level: " + mHealthInfo.batteryLevel);
pw.println(" scale: " + BATTERY_SCALE);
- pw.println(" voltage: " + mHealthInfo.legacy.batteryVoltage);
- pw.println(" temperature: " + mHealthInfo.legacy.batteryTemperature);
- pw.println(" technology: " + mHealthInfo.legacy.batteryTechnology);
+ pw.println(" voltage: " + mHealthInfo.batteryVoltage);
+ pw.println(" temperature: " + mHealthInfo.batteryTemperature);
+ pw.println(" technology: " + mHealthInfo.batteryTechnology);
} else {
Shell shell = new Shell();
shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null));
@@ -909,29 +917,37 @@ public final class BatteryService extends SystemService {
synchronized (mLock) {
proto.write(BatteryServiceDumpProto.ARE_UPDATES_STOPPED, mUpdatesStopped);
int batteryPluggedValue = BatteryManagerProto.PLUG_TYPE_NONE;
- if (mHealthInfo.legacy.chargerAcOnline) {
+ if (mHealthInfo.chargerAcOnline) {
batteryPluggedValue = BatteryManagerProto.PLUG_TYPE_AC;
- } else if (mHealthInfo.legacy.chargerUsbOnline) {
+ } else if (mHealthInfo.chargerUsbOnline) {
batteryPluggedValue = BatteryManagerProto.PLUG_TYPE_USB;
- } else if (mHealthInfo.legacy.chargerWirelessOnline) {
+ } else if (mHealthInfo.chargerWirelessOnline) {
batteryPluggedValue = BatteryManagerProto.PLUG_TYPE_WIRELESS;
}
proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue);
- proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mHealthInfo.legacy.maxChargingCurrent);
- proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mHealthInfo.legacy.maxChargingVoltage);
- proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.legacy.batteryChargeCounter);
- proto.write(BatteryServiceDumpProto.STATUS, mHealthInfo.legacy.batteryStatus);
- proto.write(BatteryServiceDumpProto.HEALTH, mHealthInfo.legacy.batteryHealth);
- proto.write(BatteryServiceDumpProto.IS_PRESENT, mHealthInfo.legacy.batteryPresent);
- proto.write(BatteryServiceDumpProto.LEVEL, mHealthInfo.legacy.batteryLevel);
+ proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrent);
+ proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mHealthInfo.maxChargingVoltage);
+ proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.batteryChargeCounter);
+ proto.write(BatteryServiceDumpProto.STATUS, mHealthInfo.batteryStatus);
+ proto.write(BatteryServiceDumpProto.HEALTH, mHealthInfo.batteryHealth);
+ proto.write(BatteryServiceDumpProto.IS_PRESENT, mHealthInfo.batteryPresent);
+ proto.write(BatteryServiceDumpProto.LEVEL, mHealthInfo.batteryLevel);
proto.write(BatteryServiceDumpProto.SCALE, BATTERY_SCALE);
- proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.legacy.batteryVoltage);
- proto.write(BatteryServiceDumpProto.TEMPERATURE, mHealthInfo.legacy.batteryTemperature);
- proto.write(BatteryServiceDumpProto.TECHNOLOGY, mHealthInfo.legacy.batteryTechnology);
+ proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.batteryVoltage);
+ proto.write(BatteryServiceDumpProto.TEMPERATURE, mHealthInfo.batteryTemperature);
+ proto.write(BatteryServiceDumpProto.TECHNOLOGY, mHealthInfo.batteryTechnology);
}
proto.flush();
}
+ private static void traceBegin(String name) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
+ }
+
+ private static void traceEnd() {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+
private final class Led {
private final Light mBatteryLight;
@@ -960,8 +976,8 @@ public final class BatteryService extends SystemService {
* Synchronize on BatteryService.
*/
public void updateLightsLocked() {
- final int level = mHealthInfo.legacy.batteryLevel;
- final int status = mHealthInfo.legacy.batteryStatus;
+ final int level = mHealthInfo.batteryLevel;
+ final int status = mHealthInfo.batteryStatus;
if (level < mLowBatteryWarningLevel) {
if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
// Solid red when battery is charging
@@ -997,6 +1013,7 @@ public final class BatteryService extends SystemService {
String instance) {
if (newService == null) return;
+ traceBegin("HealthUnregisterCallback");
try {
if (oldService != null) {
int r = oldService.unregisterCallback(this);
@@ -1008,8 +1025,11 @@ public final class BatteryService extends SystemService {
} catch (RemoteException ex) {
Slog.w(TAG, "health: cannot unregister previous callback (transaction error): "
+ ex.getMessage());
+ } finally {
+ traceEnd();
}
+ traceBegin("HealthRegisterCallback");
try {
int r = newService.registerCallback(this);
if (r != Result.SUCCESS) {
@@ -1022,6 +1042,8 @@ public final class BatteryService extends SystemService {
} catch (RemoteException ex) {
Slog.e(TAG, "health: cannot register callback (transaction error): "
+ ex.getMessage());
+ } finally {
+ traceEnd();
}
}
}
@@ -1054,53 +1076,63 @@ public final class BatteryService extends SystemService {
Slog.e(TAG, "health: must not call unregisterListener on battery properties");
}
public int getProperty(int id, final BatteryProperty prop) throws RemoteException {
- IHealth service = mHealthServiceWrapper.getLastService();
- if (service == null) throw new RemoteException("no health service");
- final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED);
- switch(id) {
- case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
- service.getChargeCounter((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
- service.getCurrentNow((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:
- service.getCurrentAverage((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_CAPACITY:
- service.getCapacity((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_STATUS:
- service.getChargeStatus((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
- service.getEnergyCounter((int result, long value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
+ traceBegin("HealthGetProperty");
+ try {
+ IHealth service = mHealthServiceWrapper.getLastService();
+ if (service == null) throw new RemoteException("no health service");
+ final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED);
+ switch(id) {
+ case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
+ service.getChargeCounter((int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
+ service.getCurrentNow((int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:
+ service.getCurrentAverage((int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_CAPACITY:
+ service.getCapacity((int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_STATUS:
+ service.getChargeStatus((int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
+ service.getEnergyCounter((int result, long value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ }
+ return outResult.value;
+ } finally {
+ traceEnd();
}
- return outResult.value;
}
public void scheduleUpdate() throws RemoteException {
- IHealth service = mHealthServiceWrapper.getLastService();
- if (service == null) throw new RemoteException("no health service");
- service.update();
+ traceBegin("HealthScheduleUpdate");
+ try {
+ IHealth service = mHealthServiceWrapper.getLastService();
+ if (service == null) throw new RemoteException("no health service");
+ service.update();
+ } finally {
+ traceEnd();
+ }
}
}
@@ -1122,7 +1154,7 @@ public final class BatteryService extends SystemService {
@Override
public int getBatteryLevel() {
synchronized (mLock) {
- return mHealthInfo.legacy.batteryLevel;
+ return mHealthInfo.batteryLevel;
}
}
@@ -1163,14 +1195,13 @@ public final class BatteryService extends SystemService {
Arrays.asList(INSTANCE_VENDOR, INSTANCE_HEALTHD);
private final IServiceNotification mNotification = new Notification();
+ private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceRefresh");
// These variables are fixed after init.
private Callback mCallback;
private IHealthSupplier mHealthSupplier;
private String mInstanceName;
- private final Object mLastServiceSetLock = new Object();
// Last IHealth service received.
- // set must be also be guarded with mLastServiceSetLock to ensure ordering.
private final AtomicReference<IHealth> mLastService = new AtomicReference<>();
/**
@@ -1188,6 +1219,10 @@ public final class BatteryService extends SystemService {
* Start monitoring registration of new IHealth services. Only instances that are in
* {@code sAllInstances} and in device / framework manifest are used. This function should
* only be called once.
+ *
+ * mCallback.onRegistration() is called synchronously (aka in init thread) before
+ * this method returns.
+ *
* @throws RemoteException transaction error when talking to IServiceManager
* @throws NoSuchElementException if one of the following cases:
* - No service manager;
@@ -1203,28 +1238,53 @@ public final class BatteryService extends SystemService {
if (callback == null || managerSupplier == null || healthSupplier == null)
throw new NullPointerException();
+ IServiceManager manager;
+
mCallback = callback;
mHealthSupplier = healthSupplier;
- IServiceManager manager = managerSupplier.get();
+ // Initialize mLastService and call callback for the first time (in init thread)
+ IHealth newService = null;
for (String name : sAllInstances) {
- if (manager.getTransport(IHealth.kInterfaceName, name) !=
- IServiceManager.Transport.EMPTY) {
+ traceBegin("HealthInitGetService_" + name);
+ try {
+ newService = healthSupplier.get(name);
+ } catch (NoSuchElementException ex) {
+ /* ignored, handled below */
+ } finally {
+ traceEnd();
+ }
+ if (newService != null) {
mInstanceName = name;
+ mLastService.set(newService);
break;
}
}
- if (mInstanceName == null) {
+ if (mInstanceName == null || newService == null) {
throw new NoSuchElementException(String.format(
"No IHealth service instance among %s is available. Perhaps no permission?",
sAllInstances.toString()));
}
+ mCallback.onRegistration(null, newService, mInstanceName);
- manager.registerForNotifications(IHealth.kInterfaceName, mInstanceName, mNotification);
+ // Register for future service registrations
+ traceBegin("HealthInitRegisterNotification");
+ mHandlerThread.start();
+ try {
+ managerSupplier.get().registerForNotifications(
+ IHealth.kInterfaceName, mInstanceName, mNotification);
+ } finally {
+ traceEnd();
+ }
Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + mInstanceName);
}
+ @VisibleForTesting
+ HandlerThread getHandlerThread() {
+ return mHandlerThread;
+ }
+
interface Callback {
/**
* This function is invoked asynchronously when a new and related IServiceNotification
@@ -1253,7 +1313,7 @@ public final class BatteryService extends SystemService {
*/
interface IHealthSupplier {
default IHealth get(String name) throws NoSuchElementException, RemoteException {
- return IHealth.getService(name);
+ return IHealth.getService(name, true /* retry */);
}
}
@@ -1263,18 +1323,27 @@ public final class BatteryService extends SystemService {
boolean preexisting) {
if (!IHealth.kInterfaceName.equals(interfaceName)) return;
if (!mInstanceName.equals(instanceName)) return;
- try {
- // ensures the order of multiple onRegistration on different threads.
- synchronized (mLastServiceSetLock) {
- IHealth newService = mHealthSupplier.get(instanceName);
- IHealth oldService = mLastService.getAndSet(newService);
- Slog.i(TAG, "health: new instance registered " + instanceName);
- mCallback.onRegistration(oldService, newService, instanceName);
+
+ // This runnable only runs on mHandlerThread and ordering is ensured, hence
+ // no locking is needed inside the runnable.
+ mHandlerThread.getThreadHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ IHealth newService = mHealthSupplier.get(mInstanceName);
+ IHealth oldService = mLastService.getAndSet(newService);
+
+ // preexisting may be inaccurate (race). Check for equality here.
+ if (Objects.equals(newService, oldService)) return;
+
+ Slog.i(TAG, "health: new instance registered " + mInstanceName);
+ mCallback.onRegistration(oldService, newService, mInstanceName);
+ } catch (NoSuchElementException | RemoteException ex) {
+ Slog.e(TAG, "health: Cannot get instance '" + mInstanceName
+ + "': " + ex.getMessage() + ". Perhaps no permission?");
+ }
}
- } catch (NoSuchElementException | RemoteException ex) {
- Slog.e(TAG, "health: Cannot get instance '" + instanceName + "': " +
- ex.getMessage() + ". Perhaps no permission?");
- }
+ });
}
}
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 75206e48aa8b..c34c30cf6e43 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -195,6 +195,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private LinkedList<ActiveLog> mActiveLogs;
private LinkedList<Long> mCrashTimestamps;
private int mCrashes;
+ private long mLastEnabledTime;
// configuration from external IBinder call which is used to
// synchronize with broadcast receiver.
@@ -2021,6 +2022,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
quietMode ? 1 : 0, 0));
addActiveLog(packageName, true);
+ mLastEnabledTime = SystemClock.elapsedRealtime();
}
private void addActiveLog(String packageName, boolean enable) {
@@ -2142,7 +2144,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
writer.println(" address: " + mAddress);
writer.println(" name: " + mName);
if (mEnable) {
- long onDuration = System.currentTimeMillis() - mActiveLogs.getLast().getTime();
+ long onDuration = SystemClock.elapsedRealtime() - mLastEnabledTime;
String onDurationString = String.format("%02d:%02d:%02d.%03d",
(int)(onDuration / (1000 * 60 * 60)),
(int)((onDuration / (1000 * 60)) % 60),
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7e65d36024e3..bccae062811c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -29,7 +29,10 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.Nullable;
@@ -70,6 +73,7 @@ import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.UidRange;
import android.net.Uri;
+import android.net.VpnService;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
import android.net.util.MultinetworkPolicyTracker;
@@ -2119,9 +2123,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
final boolean valid =
(msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
final boolean wasValidated = nai.lastValidated;
+ final boolean wasDefault = isDefaultNetwork(nai);
if (DBG) log(nai.name() + " validation " + (valid ? "passed" : "failed") +
(msg.obj == null ? "" : " with redirect to " + (String)msg.obj));
if (valid != nai.lastValidated) {
+ if (wasDefault) {
+ metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity(
+ SystemClock.elapsedRealtime(), valid);
+ }
final int oldScore = nai.getCurrentScore();
nai.lastValidated = valid;
nai.everValidated |= valid;
@@ -2293,7 +2302,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Let rematchAllNetworksAndRequests() below record a new default network event
// if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
// whose timestamps tell how long it takes to recover a default network.
- metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(null, nai);
+ long now = SystemClock.elapsedRealtime();
+ metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
}
notifyIfacesChangedForNetworkStats();
// TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
@@ -4675,10 +4685,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- final NetworkCapabilities prevNc = nai.networkCapabilities;
+ final NetworkCapabilities prevNc;
synchronized (nai) {
+ prevNc = nai.networkCapabilities;
nai.networkCapabilities = networkCapabilities;
}
+
if (nai.getCurrentScore() == oldScore &&
networkCapabilities.equalRequestableCapabilities(prevNc)) {
// If the requestable capabilities haven't changed, and the score hasn't changed, then
@@ -4692,6 +4704,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
rematchAllNetworksAndRequests(nai, oldScore);
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
+
+ // Report changes that are interesting for network statistics tracking.
+ if (prevNc != null) {
+ final boolean meteredChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_METERED) !=
+ networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED);
+ final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) !=
+ networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+ if (meteredChanged || roamingChanged) {
+ notifyIfacesChangedForNetworkStats();
+ }
+ }
+
+ if (!networkCapabilities.hasTransport(TRANSPORT_VPN)) {
+ // Tell VPNs about updated capabilities, since they may need to
+ // bubble those changes through.
+ synchronized (mVpns) {
+ for (int i = 0; i < mVpns.size(); i++) {
+ final Vpn vpn = mVpns.valueAt(i);
+ vpn.updateCapabilities();
+ }
+ }
+ }
}
public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
@@ -5024,7 +5058,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
makeDefault(newNetwork);
// Log 0 -> X and Y -> X default network transitions, where X is the new default.
metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
- newNetwork, oldDefaultNetwork);
+ now, newNetwork, oldDefaultNetwork);
// Have a new default network, release the transition wakelock in
scheduleReleaseNetworkTransitionWakelock();
}
@@ -5225,14 +5259,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
notifyLockdownVpn(networkAgent);
- if (oldInfo != null && oldInfo.getState() == state) {
- if (oldInfo.isRoaming() != newInfo.isRoaming()) {
- if (VDBG) log("roaming status changed, notifying NetworkStatsService");
- notifyIfacesChangedForNetworkStats();
- } else if (VDBG) log("ignoring duplicate network state non-change");
- // In either case, no further work should be needed.
- return;
- }
if (DBG) {
log(networkAgent.name() + " EVENT_NETWORK_INFO_CHANGED, going from " +
(oldInfo == null ? "null" : oldInfo.getState()) +
@@ -5590,7 +5616,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
private void logNetworkEvent(NetworkAgentInfo nai, int evtype) {
- mMetricsLog.log(new NetworkEvent(nai.network.netId, evtype));
+ int[] transports = nai.networkCapabilities.getTransportTypes();
+ mMetricsLog.log(nai.network.netId, transports, new NetworkEvent(evtype));
}
private static boolean toBool(int encodedBoolean) {
diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/ForceAppStandbyTracker.java
new file mode 100644
index 000000000000..5dd3ee05d66c
--- /dev/null
+++ b/services/core/java/com/android/server/ForceAppStandbyTracker.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.PackageOps;
+import android.app.IUidObserver;
+import android.content.Context;
+import android.os.Handler;
+import android.os.PowerManager.ServiceType;
+import android.os.PowerManagerInternal;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.SparseBooleanArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Class to track OP_RUN_ANY_IN_BACKGROUND, UID foreground state and "force all app standby".
+ *
+ * TODO Clean up cache when a user is deleted.
+ * TODO Add unit tests. b/68769804.
+ */
+public class ForceAppStandbyTracker {
+ private static final String TAG = "ForceAppStandbyTracker";
+
+ @GuardedBy("ForceAppStandbyTracker.class")
+ private static ForceAppStandbyTracker sInstance;
+
+ private final Object mLock = new Object();
+ private final Context mContext;
+
+ AppOpsManager mAppOpsManager;
+ IAppOpsService mAppOpsService;
+ PowerManagerInternal mPowerManagerInternal;
+
+ private final Handler mCallbackHandler;
+
+ /**
+ * Pair of (uid (not user-id), packageName) with OP_RUN_ANY_IN_BACKGROUND *not* allowed.
+ */
+ @GuardedBy("mLock")
+ final ArraySet<Pair<Integer, String>> mForcedAppStandbyUidPackages = new ArraySet<>();
+
+ @GuardedBy("mLock")
+ final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
+
+ @GuardedBy("mLock")
+ final ArraySet<Listener> mListeners = new ArraySet<>();
+
+ @GuardedBy("mLock")
+ boolean mStarted;
+
+ @GuardedBy("mLock")
+ boolean mForceAllAppsStandby;
+
+ public static abstract class Listener {
+ public void onRestrictionChanged(int uid, @Nullable String packageName) {
+ }
+
+ public void onGlobalRestrictionChanged() {
+ }
+ }
+
+ private ForceAppStandbyTracker(Context context) {
+ mContext = context;
+ mCallbackHandler = FgThread.getHandler();
+ }
+
+ /**
+ * Get the singleton instance.
+ */
+ public static synchronized ForceAppStandbyTracker getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new ForceAppStandbyTracker(context);
+ }
+ return sInstance;
+ }
+
+ /**
+ * Call it when the system is ready.
+ */
+ public void start() {
+ synchronized (mLock) {
+ if (mStarted) {
+ return;
+ }
+ mStarted = true;
+
+ mAppOpsManager = Preconditions.checkNotNull(
+ mContext.getSystemService(AppOpsManager.class));
+ mAppOpsService = Preconditions.checkNotNull(
+ IAppOpsService.Stub.asInterface(
+ ServiceManager.getService(Context.APP_OPS_SERVICE)));
+ mPowerManagerInternal = Preconditions.checkNotNull(
+ LocalServices.getService(PowerManagerInternal.class));
+
+ try {
+ ActivityManager.getService().registerUidObserver(new UidObserver(),
+ ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE
+ | ActivityManager.UID_OBSERVER_ACTIVE,
+ ActivityManager.PROCESS_STATE_UNKNOWN, null);
+ mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, null,
+ new AppOpsWatcher());
+ } catch (RemoteException e) {
+ // shouldn't happen.
+ }
+
+ mPowerManagerInternal.registerLowPowerModeObserver(
+ ServiceType.FORCE_ALL_APPS_STANDBY,
+ state -> updateForceAllAppsStandby(state.batterySaverEnabled));
+
+ updateForceAllAppsStandby(
+ mPowerManagerInternal.getLowPowerState(ServiceType.FORCE_ALL_APPS_STANDBY)
+ .batterySaverEnabled);
+
+ refreshForcedAppStandbyUidPackagesLocked();
+ }
+ }
+
+ /**
+ * Update {@link #mForcedAppStandbyUidPackages} with the current app ops state.
+ */
+ private void refreshForcedAppStandbyUidPackagesLocked() {
+ final int op = AppOpsManager.OP_RUN_ANY_IN_BACKGROUND;
+
+ mForcedAppStandbyUidPackages.clear();
+ final List<PackageOps> ops = mAppOpsManager.getPackagesForOps(new int[] {op});
+
+ if (ops == null) {
+ return;
+ }
+ final int size = ops.size();
+ for (int i = 0; i < size; i++) {
+ final AppOpsManager.PackageOps pkg = ops.get(i);
+ final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
+
+ for (int j = 0; j < entries.size(); j++) {
+ AppOpsManager.OpEntry ent = entries.get(j);
+ if (ent.getOp() != op) {
+ continue;
+ }
+ if (ent.getMode() != AppOpsManager.MODE_ALLOWED) {
+ mForcedAppStandbyUidPackages.add(Pair.create(
+ pkg.getUid(), pkg.getPackageName()));
+ }
+ }
+ }
+ }
+
+ boolean isRunAnyInBackgroundAppOpRestricted(int uid, @NonNull String packageName) {
+ try {
+ return mAppOpsService.checkOperation(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
+ uid, packageName) != AppOpsManager.MODE_ALLOWED;
+ } catch (RemoteException e) {
+ return false; // shouldn't happen.
+ }
+ }
+
+ private int findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName) {
+ // TODO Maybe we should switch to indexOf(Pair.create()) if the array size is too big.
+ final int size = mForcedAppStandbyUidPackages.size();
+ for (int i = 0; i < size; i++) {
+ final Pair<Integer, String> pair = mForcedAppStandbyUidPackages.valueAt(i);
+
+ if ((pair.first == uid) && packageName.equals(pair.second)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * @return whether a uid package-name pair is in mForcedAppStandbyUidPackages.
+ */
+ boolean isUidPackageRestrictedLocked(int uid, @NonNull String packageName) {
+ return findForcedAppStandbyUidPackageIndexLocked(uid, packageName) >= 0;
+ }
+
+ boolean updateRestrictedUidPackageLocked(int uid, @NonNull String packageName,
+ boolean restricted) {
+ final int index = findForcedAppStandbyUidPackageIndexLocked(uid, packageName);
+ final boolean wasRestricted = index >= 0;
+ if (wasRestricted == restricted) {
+ return false;
+ }
+ if (restricted) {
+ mForcedAppStandbyUidPackages.add(Pair.create(uid, packageName));
+ } else {
+ mForcedAppStandbyUidPackages.removeAt(index);
+ }
+ return true;
+ }
+
+ void uidToForeground(int uid) {
+ synchronized (mLock) {
+ if (!UserHandle.isApp(uid)) {
+ return;
+ }
+ // TODO This can be optimized by calling indexOfKey and sharing the index for get and
+ // put.
+ if (mForegroundUids.get(uid)) {
+ return;
+ }
+ mForegroundUids.put(uid, true);
+ notifyForUidPackage(uid, null);
+ }
+ }
+
+ void uidToBackground(int uid, boolean remove) {
+ synchronized (mLock) {
+ if (!UserHandle.isApp(uid)) {
+ return;
+ }
+ // TODO This can be optimized by calling indexOfKey and sharing the index for get and
+ // put.
+ if (!mForegroundUids.get(uid)) {
+ return;
+ }
+ if (remove) {
+ mForegroundUids.delete(uid);
+ } else {
+ mForegroundUids.put(uid, false);
+ }
+ notifyForUidPackage(uid, null);
+ }
+ }
+
+ // Event handlers
+
+ final class UidObserver extends IUidObserver.Stub {
+ @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+ }
+
+ @Override public void onUidGone(int uid, boolean disabled) {
+ uidToBackground(uid, /*remove=*/ true);
+ }
+
+ @Override public void onUidActive(int uid) {
+ uidToForeground(uid);
+ }
+
+ @Override public void onUidIdle(int uid, boolean disabled) {
+ // Just to avoid excessive memcpy, don't remove from the array in this case.
+ uidToBackground(uid, /*remove=*/ false);
+ }
+
+ @Override public void onUidCachedChanged(int uid, boolean cached) {
+ }
+ };
+
+ private final class AppOpsWatcher extends IAppOpsCallback.Stub {
+ @Override
+ public void opChanged(int op, int uid, String packageName) throws RemoteException {
+ synchronized (mLock) {
+ final boolean restricted = isRunAnyInBackgroundAppOpRestricted(uid, packageName);
+
+ if (updateRestrictedUidPackageLocked(uid, packageName, restricted)) {
+ notifyForUidPackage(uid, packageName);
+ }
+ }
+ }
+ }
+
+ private Listener[] cloneListeners() {
+ synchronized (mLock) {
+ return mListeners.toArray(new Listener[mListeners.size()]);
+ }
+ }
+
+ void notifyForUidPackage(int uid, String packageName) {
+ mCallbackHandler.post(() -> {
+ for (Listener l : cloneListeners()) {
+ l.onRestrictionChanged(uid, packageName);
+ }
+ });
+ }
+
+ void notifyGlobal() {
+ mCallbackHandler.post(() -> {
+ for (Listener l : cloneListeners()) {
+ l.onGlobalRestrictionChanged();
+ }
+ });
+ }
+
+ void updateForceAllAppsStandby(boolean forceAllAppsStandby) {
+ synchronized (mLock) {
+ if (mForceAllAppsStandby == forceAllAppsStandby) {
+ return;
+ }
+ mForceAllAppsStandby = forceAllAppsStandby;
+ Slog.i(TAG, "Force all app standby: " + mForceAllAppsStandby);
+ notifyGlobal();
+ }
+ }
+
+ // Public interface.
+
+ /**
+ * Register a new listener.
+ */
+ public void addListener(@NonNull Listener listener) {
+ synchronized (mLock) {
+ mListeners.add(listener);
+ }
+ }
+
+ /**
+ * Whether force-app-standby is effective for a UID package-name.
+ */
+ public boolean isRestricted(int uid, @NonNull String packageName) {
+ if (isInForeground(uid)) {
+ return false;
+ }
+ synchronized (mLock) {
+ if (mForceAllAppsStandby) {
+ return true;
+ }
+ return isUidPackageRestrictedLocked(uid, packageName);
+ }
+ }
+
+ /** For dumpsys -- otherwise the callers don't need to know it. */
+ public boolean isInForeground(int uid) {
+ if (!UserHandle.isApp(uid)) {
+ return true;
+ }
+ synchronized (mLock) {
+ return mForegroundUids.get(uid);
+ }
+ }
+
+ /** For dumpsys -- otherwise the callers don't need to know it. */
+ public boolean isForceAllAppsStandbyEnabled() {
+ synchronized (mLock) {
+ return mForceAllAppsStandby;
+ }
+ }
+
+ /** For dumpsys -- otherwise the callers don't need to know it. */
+ public boolean isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName) {
+ synchronized (mLock) {
+ return !isUidPackageRestrictedLocked(uid, packageName);
+ }
+ }
+
+ /** For dumpsys -- otherwise the callers don't need to know it. */
+ public SparseBooleanArray getForegroudUids() {
+ synchronized (mLock) {
+ return mForegroundUids.clone();
+ }
+ }
+
+ /** For dumpsys -- otherwise the callers don't need to know it. */
+ public ArraySet<Pair<Integer, String>> getRestrictedUidPackages() {
+ synchronized (mLock) {
+ return new ArraySet(mForcedAppStandbyUidPackages);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java
index d8bd0bb5a93c..1891ba9b1742 100644
--- a/services/core/java/com/android/server/MountServiceIdler.java
+++ b/services/core/java/com/android/server/MountServiceIdler.java
@@ -72,7 +72,7 @@ public class MountServiceIdler extends JobService {
synchronized (mFinishCallback) {
mStarted = true;
}
- ms.runIdleMaintenance(mFinishCallback);
+ ms.runIdleMaint(mFinishCallback);
}
return ms != null;
}
@@ -82,8 +82,12 @@ public class MountServiceIdler extends JobService {
// Once we kick off the fstrim we aren't actually interruptible; just note
// that we don't need to call jobFinished(), and let everything happen in
// the callback from the mount service.
- synchronized (mFinishCallback) {
- mStarted = false;
+ StorageManagerService ms = StorageManagerService.sSelf;
+ if (ms != null) {
+ ms.abortIdleMaint(mFinishCallback);
+ synchronized (mFinishCallback) {
+ mStarted = false;
+ }
}
return false;
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index c60d7b075ac6..8a15ded2960f 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -20,6 +20,9 @@ import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.SHUTDOWN;
+import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
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_NONE;
@@ -92,6 +95,7 @@ import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -1946,9 +1950,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
public void setDnsConfigurationForNetwork(int netId, String[] servers, String domains) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- ContentResolver resolver = mContext.getContentResolver();
+ final ContentResolver cr = mContext.getContentResolver();
- int sampleValidity = Settings.Global.getInt(resolver,
+ int sampleValidity = Settings.Global.getInt(cr,
Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
if (sampleValidity < 0 || sampleValidity > 65535) {
@@ -1957,7 +1961,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
sampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
}
- int successThreshold = Settings.Global.getInt(resolver,
+ int successThreshold = Settings.Global.getInt(cr,
Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
if (successThreshold < 0 || successThreshold > 100) {
@@ -1966,9 +1970,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
successThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
}
- int minSamples = Settings.Global.getInt(resolver,
+ int minSamples = Settings.Global.getInt(cr,
Settings.Global.DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
- int maxSamples = Settings.Global.getInt(resolver,
+ int maxSamples = Settings.Global.getInt(cr,
Settings.Global.DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
if (minSamples < 0 || minSamples > maxSamples || maxSamples > 64) {
Slog.w(TAG, "Invalid sample count (min, max)=(" + minSamples + ", " + maxSamples +
@@ -1980,8 +1984,24 @@ public class NetworkManagementService extends INetworkManagementService.Stub
final String[] domainStrs = domains == null ? new String[0] : domains.split(" ");
final int[] params = { sampleValidity, successThreshold, minSamples, maxSamples };
- final boolean useTls = Settings.Global.getInt(resolver,
- Settings.Global.DNS_TLS_DISABLED, 0) == 0;
+ final boolean useTls = shouldUseTls(cr);
+ // TODO: Populate tlsHostname once it's decided how the hostname's IP
+ // addresses will be resolved:
+ //
+ // [1] network-provided DNS servers are included here with the
+ // hostname and netd will use the network-provided servers to
+ // resolve the hostname and fix up its internal structures, or
+ //
+ // [2] network-provided DNS servers are included here without the
+ // hostname, the ConnectivityService layer resolves the given
+ // hostname, and then reconfigures netd with this information.
+ //
+ // In practice, there will always be a need for ConnectivityService or
+ // the captive portal app to use the network-provided services to make
+ // some queries. This argues in favor of [1], in concert with another
+ // mechanism, perhaps setting a high bit in the netid, to indicate
+ // via existing DNS APIs which set of servers (network-provided or
+ // non-network-provided private DNS) should be queried.
final String tlsHostname = "";
final String[] tlsFingerprints = new String[0];
try {
@@ -1992,6 +2012,15 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
}
+ private static boolean shouldUseTls(ContentResolver cr) {
+ String privateDns = Settings.Global.getString(cr, Settings.Global.PRIVATE_DNS_MODE);
+ if (TextUtils.isEmpty(privateDns)) {
+ privateDns = PRIVATE_DNS_DEFAULT_MODE;
+ }
+ return privateDns.equals(PRIVATE_DNS_MODE_OPPORTUNISTIC) ||
+ privateDns.startsWith(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
+ }
+
@Override
public void addVpnUidRanges(int netId, UidRange[] ranges) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index 1924a861e002..a9f190c84cca 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+
import android.content.ContentResolver;
import android.content.Context;
import android.os.Build;
@@ -146,7 +148,7 @@ public class RescueParty {
SystemProperties.set(PROP_RESCUE_LEVEL, Integer.toString(level));
EventLogTags.writeRescueLevel(level, triggerUid);
- PackageManagerService.logCriticalInfo(Log.WARN, "Incremented rescue level to "
+ logCriticalInfo(Log.WARN, "Incremented rescue level to "
+ levelToString(level) + " triggered by UID " + triggerUid);
}
@@ -166,12 +168,12 @@ public class RescueParty {
try {
executeRescueLevelInternal(context, level);
EventLogTags.writeRescueSuccess(level);
- PackageManagerService.logCriticalInfo(Log.DEBUG,
+ logCriticalInfo(Log.DEBUG,
"Finished rescue level " + levelToString(level));
} catch (Throwable t) {
final String msg = ExceptionUtils.getCompleteMessage(t);
EventLogTags.writeRescueFailure(level, msg);
- PackageManagerService.logCriticalInfo(Log.ERROR,
+ logCriticalInfo(Log.ERROR,
"Failed rescue level " + levelToString(level) + ": " + msg);
}
}
diff --git a/services/core/java/com/android/server/ServiceThread.java b/services/core/java/com/android/server/ServiceThread.java
index bce64afd0c5e..26703c514a96 100644
--- a/services/core/java/com/android/server/ServiceThread.java
+++ b/services/core/java/com/android/server/ServiceThread.java
@@ -19,7 +19,6 @@ package com.android.server;
import android.os.HandlerThread;
import android.os.Process;
import android.os.StrictMode;
-import android.util.Slog;
/**
* Special handler thread that we create for system services that require their own loopers.
@@ -38,11 +37,10 @@ public class ServiceThread extends HandlerThread {
public void run() {
Process.setCanSelfBackground(false);
- // For debug builds, log event loop stalls to dropbox for analysis.
- if (!mAllowIo && StrictMode.conditionallyEnableDebugLogging()) {
- Slog.i(TAG, "Enabled StrictMode logging for " + getName() + " looper.");
+ if (!mAllowIo) {
+ StrictMode.initThreadDefaults(null);
}
super.run();
}
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index 2ff036be4b4b..f20ca43585fd 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -397,9 +398,29 @@ public class ServiceWatcher implements ServiceConnection {
}
}
- public @Nullable IBinder getBinder() {
+ /**
+ * The runner that runs on the binder retrieved from {@link ServiceWatcher}.
+ */
+ public interface BinderRunner {
+ /**
+ * Runs on the retrieved binder.
+ * @param binder the binder retrieved from the {@link ServiceWatcher}.
+ */
+ public void run(@NonNull IBinder binder);
+ }
+
+ /**
+ * Retrieves the binder from {@link ServiceWatcher} and runs it.
+ * @return whether a valid service exists.
+ */
+ public boolean runOnBinder(@NonNull BinderRunner runner) {
synchronized (mLock) {
- return mBoundService;
+ if (mBoundService == null) {
+ return false;
+ } else {
+ runner.run(mBoundService);
+ return true;
+ }
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index bfbce408cb28..3c955eb0f0db 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -56,6 +56,7 @@ import android.os.FileUtils;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.IProgressListener;
import android.os.IStoraged;
import android.os.IVold;
import android.os.IVoldListener;
@@ -541,6 +542,8 @@ class StorageManagerService extends IStorageManager.Stub implements Watchdog.Mon
private static final int H_VOLUME_UNMOUNT = 8;
private static final int H_PARTITION_FORGET = 9;
private static final int H_RESET = 10;
+ private static final int H_RUN_IDLE_MAINT = 11;
+ private static final int H_ABORT_IDLE_MAINT = 12;
class StorageManagerServiceHandler extends Handler {
public StorageManagerServiceHandler(Looper looper) {
@@ -570,7 +573,7 @@ class StorageManagerService extends IStorageManager.Stub implements Watchdog.Mon
}
// TODO: Reintroduce shouldBenchmark() test
- fstrim(0);
+ fstrim(0, null);
// invoke the completion callback, if any
// TODO: fstrim is non-blocking, so remove this useless callback
@@ -649,6 +652,17 @@ class StorageManagerService extends IStorageManager.Stub implements Watchdog.Mon
resetIfReadyAndConnected();
break;
}
+ case H_RUN_IDLE_MAINT: {
+ Slog.i(TAG, "Running idle maintenance");
+ runIdleMaint((Runnable)msg.obj);
+ break;
+ }
+ case H_ABORT_IDLE_MAINT: {
+ Slog.i(TAG, "Aborting idle maintenance");
+ abortIdleMaint((Runnable)msg.obj);
+ break;
+ }
+
}
}
}
@@ -1576,21 +1590,19 @@ class StorageManagerService extends IStorageManager.Stub implements Watchdog.Mon
}
@Override
- public long benchmark(String volId) {
+ public void benchmark(String volId, IVoldTaskListener listener) {
enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
- // TODO: refactor for callers to provide a listener
try {
- final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
mVold.benchmark(volId, new IVoldTaskListener.Stub() {
@Override
public void onStatus(int status, PersistableBundle extras) {
- // Not currently used
+ dispatchOnStatus(listener, status, extras);
}
@Override
public void onFinished(int status, PersistableBundle extras) {
- result.complete(extras);
+ dispatchOnFinished(listener, status, extras);
final String path = extras.getString("path");
final String ident = extras.getString("ident");
@@ -1611,10 +1623,8 @@ class StorageManagerService extends IStorageManager.Stub implements Watchdog.Mon
}
}
});
- return result.get(3, TimeUnit.MINUTES).getLong("run", Long.MAX_VALUE);
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return Long.MAX_VALUE;
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
}
}
@@ -1742,13 +1752,15 @@ class StorageManagerService extends IStorageManager.Stub implements Watchdog.Mon
}
@Override
- public void fstrim(int flags) {
+ public void fstrim(int flags, IVoldTaskListener listener) {
enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
try {
mVold.fstrim(flags, new IVoldTaskListener.Stub() {
@Override
public void onStatus(int status, PersistableBundle extras) {
+ dispatchOnStatus(listener, status, extras);
+
// Ignore trim failures
if (status != 0) return;
@@ -1770,15 +1782,68 @@ class StorageManagerService extends IStorageManager.Stub implements Watchdog.Mon
@Override
public void onFinished(int status, PersistableBundle extras) {
- // Not currently used
+ dispatchOnFinished(listener, status, extras);
+
// TODO: benchmark when desired
}
});
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ void runIdleMaint(Runnable callback) {
+ enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
+
+ try {
+ mVold.runIdleMaint(new IVoldTaskListener.Stub() {
+ @Override
+ public void onStatus(int status, PersistableBundle extras) {
+ // Not currently used
+ }
+ @Override
+ public void onFinished(int status, PersistableBundle extras) {
+ if (callback != null) {
+ BackgroundThread.getHandler().post(callback);
+ }
+ }
+ });
} catch (Exception e) {
Slog.wtf(TAG, e);
}
}
+ @Override
+ public void runIdleMaintenance() {
+ runIdleMaint(null);
+ }
+
+ void abortIdleMaint(Runnable callback) {
+ enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
+
+ try {
+ mVold.abortIdleMaint(new IVoldTaskListener.Stub() {
+ @Override
+ public void onStatus(int status, PersistableBundle extras) {
+ // Not currently used
+ }
+ @Override
+ public void onFinished(int status, PersistableBundle extras) {
+ if (callback != null) {
+ BackgroundThread.getHandler().post(callback);
+ }
+ }
+ });
+ } catch (Exception e) {
+ Slog.wtf(TAG, e);
+ }
+ }
+
+ @Override
+ public void abortIdleMaintenance() {
+ abortIdleMaint(null);
+ }
+
private void remountUidExternalStorage(int uid, int mode) {
try {
mVold.remountUid(uid, mode);
@@ -3239,6 +3304,26 @@ class StorageManagerService extends IStorageManager.Stub implements Watchdog.Mon
}
}
+ private void dispatchOnStatus(IVoldTaskListener listener, int status,
+ PersistableBundle extras) {
+ if (listener != null) {
+ try {
+ listener.onStatus(status, extras);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ private void dispatchOnFinished(IVoldTaskListener listener, int status,
+ PersistableBundle extras) {
+ if (listener != null) {
+ try {
+ listener.onFinished(status, extras);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
private static class Callbacks extends Handler {
private static final int MSG_STORAGE_STATE_CHANGED = 1;
private static final int MSG_VOLUME_STATE_CHANGED = 2;
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index e609bd7889d3..831c9cbc2ef5 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1356,31 +1356,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- public void notifyOemHookRawEventForSubscriber(int subId, byte[] rawData) {
- if (!checkNotifyPermission("notifyOemHookRawEventForSubscriber")) {
- return;
- }
-
- synchronized (mRecords) {
- for (Record r : mRecords) {
- if (VDBG) {
- log("notifyOemHookRawEventForSubscriber: r=" + r + " subId=" + subId);
- }
- if ((r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT)) &&
- ((r.subId == subId) ||
- (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID))) {
- try {
- r.callback.onOemHookRawEvent(rawData);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
- }
- }
- }
- handleRemoveListLocked();
- }
- }
-
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
@@ -1673,11 +1648,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
}
-
- if ((events & PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT) != 0) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
- }
}
private void handleRemoveListLocked() {
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 8b79b9ddfef2..0e51fda0f39f 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -27,6 +27,7 @@ import android.database.ContentObserver;
import android.hardware.input.InputManager;
import android.hardware.vibrator.V1_0.Constants.EffectStrength;
import android.media.AudioManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.BatteryStats;
import android.os.Handler;
@@ -56,7 +57,6 @@ import android.media.AudioAttributes;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.DumpUtils;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 2131731de045..701c574f64ea 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1043,8 +1043,8 @@ public final class ActiveServices {
try {
if (AppGlobals.getPackageManager().checkPermission(
android.Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
- r.appInfo.packageName,
- r.appInfo.uid) != PackageManager.PERMISSION_GRANTED) {
+ r.appInfo.packageName, UserHandle.getUserId(r.appInfo.uid))
+ != PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Instant app " + r.appInfo.packageName
+ " does not have permission to create foreground"
+ "services");
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index c04ddf8ae6de..2289f8572b93 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -276,17 +276,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
if (windowingMode == WINDOWING_MODE_PINNED) {
return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop);
}
- final T stack = (T) new ActivityStack(
+ return (T) new ActivityStack(
this, stackId, mSupervisor, windowingMode, activityType, onTop);
-
- if (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 on that.
- // TODO: Not sure if this is needed after we change to calculate visibility based on
- // stack z-order vs. id.
- getOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_RECENTS, onTop);
- }
- return stack;
}
/**
@@ -365,6 +356,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
+ " already exist on display=" + this + " stack=" + stack);
}
mSplitScreenPrimaryStack = stack;
+ onSplitScreenModeActivated();
}
}
@@ -377,6 +369,42 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
mPinnedStack = null;
} else if (stack == mSplitScreenPrimaryStack) {
mSplitScreenPrimaryStack = null;
+ // Inform the reset of the system that split-screen mode was dismissed so things like
+ // resizing all the other stacks can take place.
+ onSplitScreenModeDismissed();
+ }
+ }
+
+ private void onSplitScreenModeDismissed() {
+ mSupervisor.mWindowManager.deferSurfaceLayout();
+ try {
+ // Adjust the windowing mode of any stack in secondary split-screen to fullscreen.
+ for (int i = mStacks.size() - 1; i >= 0; --i) {
+ final ActivityStack otherStack = mStacks.get(i);
+ if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
+ continue;
+ }
+ otherStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ }
+ } finally {
+ mSupervisor.mWindowManager.continueSurfaceLayout();
+ }
+ }
+
+ private void onSplitScreenModeActivated() {
+ mSupervisor.mWindowManager.deferSurfaceLayout();
+ try {
+ // Adjust the windowing mode of any affected by split-screen to split-screen secondary.
+ for (int i = mStacks.size() - 1; i >= 0; --i) {
+ final ActivityStack otherStack = mStacks.get(i);
+ if (otherStack == mSplitScreenPrimaryStack
+ || !otherStack.affectedBySplitScreenResize()) {
+ continue;
+ }
+ otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ }
+ } finally {
+ mSupervisor.mWindowManager.continueSurfaceLayout();
}
}
@@ -404,8 +432,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
|| windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
- return supportsSplitScreen && WindowConfiguration.supportSplitScreenWindowingMode(
- windowingMode, activityType);
+ return supportsSplitScreen
+ && WindowConfiguration.supportSplitScreenWindowingMode(activityType);
}
if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
@@ -475,22 +503,10 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
supportsFreeform, supportsPip, activityType)) {
return windowingMode;
}
- // Return the display's windowing mode
- return getWindowingMode();
- }
-
- /** Returns the top visible stack activity type that isn't in the exclude windowing mode. */
- int getTopVisibleStackActivityType(int excludeWindowingMode) {
- for (int i = mStacks.size() - 1; i >= 0; --i) {
- final ActivityStack stack = mStacks.get(i);
- if (stack.getWindowingMode() == excludeWindowingMode) {
- continue;
- }
- if (stack.shouldBeVisible(null /* starting */)) {
- return stack.getActivityType();
- }
- }
- return ACTIVITY_TYPE_UNDEFINED;
+ // Try to use the display's windowing mode otherwise fallback to fullscreen.
+ windowingMode = getWindowingMode();
+ return windowingMode != WINDOWING_MODE_UNDEFINED
+ ? windowingMode : WINDOWING_MODE_FULLSCREEN;
}
/**
@@ -599,7 +615,20 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
}
public void dump(PrintWriter pw, String prefix) {
- pw.println(prefix + "displayId=" + mDisplayId + " mStacks=" + mStacks);
+ pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size());
+ final String myPrefix = prefix + " ";
+ if (mHomeStack != null) {
+ pw.println(myPrefix + "mHomeStack=" + mHomeStack);
+ }
+ if (mRecentsStack != null) {
+ pw.println(myPrefix + "mRecentsStack=" + mRecentsStack);
+ }
+ if (mPinnedStack != null) {
+ pw.println(myPrefix + "mPinnedStack=" + mPinnedStack);
+ }
+ if (mSplitScreenPrimaryStack != null) {
+ pw.println(myPrefix + "mSplitScreenPrimaryStack=" + mSplitScreenPrimaryStack);
+ }
}
public void writeToProto(ProtoOutputStream proto, long fieldId) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index ceb2ad622b8d..0a7d3fdb5973 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -92,6 +92,7 @@ class ActivityManagerDebugConfig {
static final boolean DEBUG_USAGE_STATS = DEBUG_ALL || false;
static final boolean DEBUG_PERMISSIONS_REVIEW = DEBUG_ALL || false;
static final boolean DEBUG_WHITELISTS = DEBUG_ALL || false;
+ static final boolean DEBUG_METRICS = DEBUG_ALL || false;
static final String POSTFIX_ADD_REMOVE = (APPEND_CATEGORY_NAME) ? "_AddRemove" : "";
static final String POSTFIX_APP = (APPEND_CATEGORY_NAME) ? "_App" : "";
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d2d9aab84065..43618564652c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -222,6 +222,7 @@ import android.app.Dialog;
import android.app.IActivityController;
import android.app.IActivityManager;
import android.app.IApplicationThread;
+import android.app.IAssistDataReceiver;
import android.app.IInstrumentationWatcher;
import android.app.INotificationManager;
import android.app.IProcessObserver;
@@ -373,7 +374,6 @@ import com.android.internal.app.AssistUtils;
import com.android.internal.app.DumpHeapActivity;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
-import com.android.internal.app.IAssistDataReceiver;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.SystemUserHomeActivity;
@@ -401,6 +401,7 @@ import com.android.server.AppOpsService;
import com.android.server.AttributeCache;
import com.android.server.DeviceIdleController;
import com.android.server.IntentResolver;
+import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.NetworkManagementInternal;
@@ -1011,15 +1012,6 @@ public class ActivityManagerService extends IActivityManager.Stub
private static final int MAX_DUP_SUPPRESSED_STACKS = 5000;
/**
- * Strict Mode background batched logging state.
- *
- * The string buffer is guarded by itself, and its lock is also
- * used to determine if another batched write is already
- * in-flight.
- */
- private final StringBuilder mStrictModeBuffer = new StringBuilder();
-
- /**
* Keeps track of all IIntentReceivers that have been registered for broadcasts.
* Hash keys are the receiver IBinder, hash value is a ReceiverList.
*/
@@ -2787,12 +2779,12 @@ public class ActivityManagerService extends IActivityManager.Stub
mConfigurationSeq = mTempConfig.seq = 1;
mStackSupervisor = createStackSupervisor();
mStackSupervisor.onConfigurationChanged(mTempConfig);
- mKeyguardController = mStackSupervisor.mKeyguardController;
+ mKeyguardController = mStackSupervisor.getKeyguardController();
mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
mTaskChangeNotificationController =
new TaskChangeNotificationController(this, mStackSupervisor, mHandler);
- mActivityStarter = new ActivityStarter(this);
+ mActivityStarter = new ActivityStarter(this, AppGlobals.getPackageManager());
mRecentTasks = createRecentTasks();
mStackSupervisor.setRecentTasks(mRecentTasks);
mLockTaskController = new LockTaskController(mContext, mStackSupervisor, mHandler);
@@ -2836,7 +2828,9 @@ public class ActivityManagerService extends IActivityManager.Stub
}
protected ActivityStackSupervisor createStackSupervisor() {
- return new ActivityStackSupervisor(this, mHandler.getLooper());
+ final ActivityStackSupervisor supervisor = new ActivityStackSupervisor(this, mHandler.getLooper());
+ supervisor.initialize();
+ return supervisor;
}
protected RecentTasks createRecentTasks() {
@@ -3848,6 +3842,10 @@ public class ActivityManagerService extends IActivityManager.Stub
gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
+
+ // Replace any invalid GIDs
+ if (gids[0] == UserHandle.ERR_GID) gids[0] = gids[2];
+ if (gids[1] == UserHandle.ERR_GID) gids[1] = gids[2];
}
checkTime(startTime, "startProcess: building args");
if (mFactoryTest != FactoryTest.FACTORY_TEST_OFF) {
@@ -3897,7 +3895,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (app.info.isPrivilegedApp() &&
- !SystemProperties.getBoolean("pm.dexopt.priv-apps", true)) {
+ SystemProperties.getBoolean("pm.dexopt.priv-apps-oob", false)) {
runtimeFlags |= Zygote.DISABLE_VERIFIER;
runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
}
@@ -4714,8 +4712,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public int startRecentsActivity(IAssistDataReceiver assistDataReceiver, Bundle bOptions,
- int userId) {
+ public int startRecentsActivity(IAssistDataReceiver assistDataReceiver, Bundle options,
+ Bundle activityOptions, int userId) {
if (!mRecentTasks.isCallerRecents(Binder.getCallingUid())) {
String msg = "Permission Denial: startRecentsActivity() from pid="
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
@@ -4741,14 +4739,17 @@ public class ActivityManagerService extends IActivityManager.Stub
mWindowManager, appOpsManager, proxy, this,
OP_ASSIST_STRUCTURE, OP_NONE);
requester.requestAssistData(mStackSupervisor.getTopVisibleActivities(),
- true, false /* fetchScreenshots */, recentsUid, recentsPackage);
+ true /* fetchData */, false /* fetchScreenshots */,
+ true /* allowFetchData */, false /* alloweFetchScreenshots */,
+ recentsUid, recentsPackage);
}
final Intent intent = new Intent();
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, bOptions,
+ intent, null, null, null, null, null, 0, 0, null, null, null, activityOptions,
false, userId, null, "startRecentsActivity");
}
} finally {
@@ -4761,7 +4762,7 @@ public class ActivityManagerService extends IActivityManager.Stub
throws RemoteException {
Slog.i(TAG, "Activity tried to startVoiceInteraction");
synchronized (this) {
- ActivityRecord activity = getFocusedStack().topActivity();
+ ActivityRecord activity = getFocusedStack().getTopActivity();
if (ActivityRecord.forTokenLocked(callingActivity) != activity) {
throw new SecurityException("Only focused activity can call startVoiceInteraction");
}
@@ -5356,8 +5357,7 @@ public class ActivityManagerService extends IActivityManager.Stub
return -1;
}
- final ProcessRecord getRecordForAppLocked(
- IApplicationThread thread) {
+ ProcessRecord getRecordForAppLocked(IApplicationThread thread) {
if (thread == null) {
return null;
}
@@ -7081,10 +7081,12 @@ public class ActivityManagerService extends IActivityManager.Stub
}
// We deprecated Build.SERIAL and it is not accessible to
- // apps that target the v2 security sandbox. Since access to
- // the serial is now behind a permission we push down the value.
- String buildSerial = appInfo.targetSandboxVersion < 2
- ? sTheRealBuildSerial : Build.UNKNOWN;
+ // apps that target the v2 security sandbox and to apps that
+ // target APIs higher than O MR1. Since access to the serial
+ // is now behind a permission we push down the value.
+ final String buildSerial = (appInfo.targetSandboxVersion < 2
+ && appInfo.targetSdkVersion <= Build.VERSION_CODES.O_MR1)
+ ? sTheRealBuildSerial : Build.UNKNOWN;
// Check if this is a secondary process that should be incorporated into some
// currently active instrumentation. (Note we do this AFTER all of the profiling
@@ -7121,7 +7123,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
- mStackSupervisor.mActivityMetricsLogger.notifyBindApplication(app);
+ mStackSupervisor.getActivityMetricsLogger().notifyBindApplication(app);
if (app.isolatedEntryPoint != null) {
// This is an isolated process which should just call an entry point instead of
// being bound to an application.
@@ -10435,13 +10437,7 @@ public class ActivityManagerService extends IActivityManager.Stub
"exitFreeformMode: You can only go fullscreen from freeform.");
}
- final ActivityStack fullscreenStack = stack.getDisplay().getOrCreateStack(
- WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), ON_TOP);
-
- if (DEBUG_STACK) Slog.d(TAG_STACK, "exitFreeformMode: " + r);
- // TODO: Should just change windowing mode vs. re-parenting...
- r.getTask().reparent(fullscreenStack, ON_TOP,
- REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME, "exitFreeformMode");
+ stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -10450,6 +10446,11 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
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 */);
+ return;
+ }
enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setTaskWindowingMode()");
synchronized (this) {
final long ident = Binder.clearCallingIdentity();
@@ -10462,56 +10463,16 @@ public class ActivityManagerService extends IActivityManager.Stub
if (DEBUG_STACK) Slog.d(TAG_STACK, "setTaskWindowingMode: moving task=" + taskId
+ " to windowingMode=" + windowingMode + " toTop=" + toTop);
- if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- mWindowManager.setDockedStackCreateState(SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT,
- null /* initialBounds */);
- }
if (!task.isActivityTypeStandardOrUndefined()) {
- throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move task "
- + taskId + " to non-standard windowin mode=" + windowingMode);
+ throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move"
+ + " non-standard task " + taskId + " to windowing mode="
+ + windowingMode);
}
final ActivityDisplay display = task.getStack().getDisplay();
final ActivityStack stack = display.getOrCreateStack(windowingMode,
task.getStack().getActivityType(), toTop);
- // TODO: We should just change the windowing mode for the task vs. creating and
- // moving it to a stack.
- task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
- "moveTaskToStack");
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- }
-
- @Override
- public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
- synchronized (this) {
- long ident = Binder.clearCallingIdentity();
- try {
- final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
- if (task == null) {
- Slog.w(TAG, "moveTaskToStack: No task for id=" + taskId);
- return;
- }
-
- if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
- + " to stackId=" + stackId + " toTop=" + toTop);
-
- final ActivityStack stack = mStackSupervisor.getStack(stackId);
- if (stack == null) {
- throw new IllegalStateException(
- "moveTaskToStack: No stack for stackId=" + stackId);
- }
- if (!stack.isActivityTypeStandardOrUndefined()) {
- throw new IllegalArgumentException("moveTaskToStack: Attempt to move task "
- + taskId + " to stack " + stackId);
- }
- if (stack.inSplitScreenPrimaryWindowingMode()) {
- mWindowManager.setDockedStackCreateState(
- SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
- }
+ // TODO: Use ActivityStack.setWindowingMode instead of re-parenting.
task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
"moveTaskToStack");
} finally {
@@ -10521,7 +10482,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
/**
- * Moves the input task to the primary-split-screen stack.
+ * Moves the specified task to the primary-split-screen stack.
*
* @param taskId Id of task to move.
* @param createMode The mode the primary split screen stack should be created in if it doesn't
@@ -10530,7 +10491,7 @@ public class ActivityManagerService extends IActivityManager.Stub
* and
* {@link android.app.ActivityManager#SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT}
* @param toTop If the task and stack should be moved to the top.
- * @param animate Whether we should play an animation for the moving the task
+ * @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.
*/
@@ -10550,22 +10511,55 @@ public class ActivityManagerService extends IActivityManager.Stub
if (DEBUG_STACK) Slog.d(TAG_STACK,
"setTaskWindowingModeSplitScreenPrimary: moving task=" + taskId
+ " to createMode=" + createMode + " toTop=" + toTop);
+ if (!task.isActivityTypeStandardOrUndefined()) {
+ throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move"
+ + " non-standard task " + taskId + " to split-screen windowing mode");
+ }
+
mWindowManager.setDockedStackCreateState(createMode, initialBounds);
+ final int windowingMode = task.getWindowingMode();
+ final ActivityStack stack = task.getStack();
+ if (toTop) {
+ stack.moveToFront("setTaskWindowingModeSplitScreenPrimary", task);
+ }
+ stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, animate);
+ return windowingMode != task.getWindowingMode();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
- final ActivityDisplay display = task.getStack().getDisplay();
- final ActivityStack stack = display.getOrCreateStack(
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, task.getStack().getActivityType(),
- toTop);
-
- // Defer resuming until we move the home stack to the front below
- // TODO: Should just change windowing mode vs. re-parenting...
- final boolean moved = task.reparent(stack, toTop,
- REPARENT_KEEP_STACK_AT_FRONT, animate, !DEFER_RESUME,
- "setTaskWindowingModeSplitScreenPrimary");
- if (moved) {
- mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+ @Override
+ public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
+ synchronized (this) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+ if (task == null) {
+ Slog.w(TAG, "moveTaskToStack: No task for id=" + taskId);
+ return;
+ }
+
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
+ + " to stackId=" + stackId + " toTop=" + toTop);
+
+ final ActivityStack stack = mStackSupervisor.getStack(stackId);
+ if (stack == null) {
+ throw new IllegalStateException(
+ "moveTaskToStack: No stack for stackId=" + stackId);
}
- return moved;
+ if (!stack.isActivityTypeStandardOrUndefined()) {
+ throw new IllegalArgumentException("moveTaskToStack: Attempt to move task "
+ + taskId + " to stack " + stackId);
+ }
+ if (stack.inSplitScreenPrimaryWindowingMode()) {
+ mWindowManager.setDockedStackCreateState(
+ SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
+ }
+ task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
+ "moveTaskToStack");
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -10588,14 +10582,11 @@ public class ActivityManagerService extends IActivityManager.Stub
Slog.w(TAG, "dismissSplitScreenMode: primary split-screen stack not found.");
return;
}
+
if (toTop) {
- mStackSupervisor.resizeStackLocked(stack, null /* destBounds */,
- null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
- true /* preserveWindows */, true /* allowResizeInDockedMode */,
- !DEFER_RESUME);
- } else {
- mStackSupervisor.moveTasksToFullscreenStackLocked(stack, false /* onTop */);
+ stack.moveToFront("dismissSplitScreenMode");
}
+ stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -12951,7 +12942,7 @@ public class ActivityManagerService extends IActivityManager.Stub
return false;
}
- final ActivityRecord activity = focusedStack.topActivity();
+ final ActivityRecord activity = focusedStack.getTopActivity();
if (activity == null) {
return false;
}
@@ -12968,7 +12959,7 @@ public class ActivityManagerService extends IActivityManager.Stub
try {
synchronized (this) {
ActivityRecord caller = ActivityRecord.forTokenLocked(token);
- ActivityRecord top = getFocusedStack().topActivity();
+ ActivityRecord top = getFocusedStack().getTopActivity();
if (top != caller) {
Slog.w(TAG, "showAssistFromActivity failed: caller " + caller
+ " is not current top " + top);
@@ -13011,7 +13002,7 @@ public class ActivityManagerService extends IActivityManager.Stub
"enqueueAssistContext()");
synchronized (this) {
- ActivityRecord activity = getFocusedStack().topActivity();
+ ActivityRecord activity = getFocusedStack().getTopActivity();
if (activity == null) {
Slog.w(TAG, "getAssistContextExtras failed: no top activity");
return null;
@@ -14271,10 +14262,9 @@ public class ActivityManagerService extends IActivityManager.Stub
IBinder app,
int violationMask,
StrictMode.ViolationInfo info) {
- ProcessRecord r = findAppProcess(app, "StrictMode");
- if (r == null) {
- return;
- }
+ // We're okay if the ProcessRecord is missing; it probably means that
+ // we're reporting a violation from the system process itself.
+ final ProcessRecord r = findAppProcess(app, "StrictMode");
if ((violationMask & StrictMode.PENALTY_DROPBOX) != 0) {
Integer stackFingerprint = info.hashCode();
@@ -14336,18 +14326,15 @@ public class ActivityManagerService extends IActivityManager.Stub
(process.info.flags & (ApplicationInfo.FLAG_SYSTEM |
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0;
final String processName = process == null ? "unknown" : process.processName;
- final String dropboxTag = isSystemApp ? "system_app_strictmode" : "data_app_strictmode";
final DropBoxManager dbox = (DropBoxManager)
mContext.getSystemService(Context.DROPBOX_SERVICE);
// Exit early if the dropbox isn't configured to accept this report type.
+ final String dropboxTag = processClass(process) + "_strictmode";
if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
- boolean bufferWasEmpty;
- boolean needsFlush;
- final StringBuilder sb = isSystemApp ? mStrictModeBuffer : new StringBuilder(1024);
+ final StringBuilder sb = new StringBuilder(1024);
synchronized (sb) {
- bufferWasEmpty = sb.length() == 0;
appendDropBoxProcessHeaders(process, processName, sb);
sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
sb.append("System-App: ").append(isSystemApp).append("\n");
@@ -14373,75 +14360,18 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
sb.append("\n");
- if (info.hasStackTrace()) {
- sb.append(info.getStackTrace());
- sb.append("\n");
- }
+ sb.append(info.getStackTrace());
+ sb.append("\n");
if (info.getViolationDetails() != null) {
sb.append(info.getViolationDetails());
sb.append("\n");
}
-
- // Only buffer up to ~64k. Various logging bits truncate
- // things at 128k.
- needsFlush = (sb.length() > 64 * 1024);
- }
-
- // Flush immediately if the buffer's grown too large, or this
- // is a non-system app. Non-system apps are isolated with a
- // different tag & policy and not batched.
- //
- // Batching is useful during internal testing with
- // StrictMode settings turned up high. Without batching,
- // thousands of separate files could be created on boot.
- if (!isSystemApp || needsFlush) {
- new Thread("Error dump: " + dropboxTag) {
- @Override
- public void run() {
- String report;
- synchronized (sb) {
- report = sb.toString();
- sb.delete(0, sb.length());
- sb.trimToSize();
- }
- if (report.length() != 0) {
- dbox.addText(dropboxTag, report);
- }
- }
- }.start();
- return;
- }
-
- // System app batching:
- if (!bufferWasEmpty) {
- // An existing dropbox-writing thread is outstanding, so
- // we don't need to start it up. The existing thread will
- // catch the buffer appends we just did.
- return;
}
- // Worker thread to both batch writes and to avoid blocking the caller on I/O.
- // (After this point, we shouldn't access AMS internal data structures.)
- new Thread("Error dump: " + dropboxTag) {
- @Override
- public void run() {
- // 5 second sleep to let stacks arrive and be batched together
- try {
- Thread.sleep(5000); // 5 seconds
- } catch (InterruptedException e) {}
-
- String errorReport;
- synchronized (mStrictModeBuffer) {
- errorReport = mStrictModeBuffer.toString();
- if (errorReport.length() == 0) {
- return;
- }
- mStrictModeBuffer.delete(0, mStrictModeBuffer.length());
- mStrictModeBuffer.trimToSize();
- }
- dbox.addText(dropboxTag, errorReport);
- }
- }.start();
+ final String res = sb.toString();
+ IoThread.getHandler().post(() -> {
+ dbox.addText(dropboxTag, res);
+ });
}
/**
@@ -14708,7 +14638,12 @@ public class ActivityManagerService extends IActivityManager.Stub
if (process == null) {
// If process is null, we are being called from some internal code
// and may be about to die -- run this synchronously.
- worker.run();
+ final int oldMask = StrictMode.allowThreadDiskWritesMask();
+ try {
+ worker.run();
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
+ }
} else {
worker.start();
}
@@ -20779,9 +20714,10 @@ public class ActivityManagerService extends IActivityManager.Stub
// the current [or imminent] receiver on.
private boolean isReceivingBroadcastLocked(ProcessRecord app,
ArraySet<BroadcastQueue> receivingQueues) {
- if (!app.curReceivers.isEmpty()) {
- for (BroadcastRecord r : app.curReceivers) {
- receivingQueues.add(r.queue);
+ final int N = app.curReceivers.size();
+ if (N > 0) {
+ for (int i = 0; i < N; i++) {
+ receivingQueues.add(app.curReceivers.valueAt(i).queue);
}
return true;
}
@@ -23945,7 +23881,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void notifyAppTransitionStarting(SparseIntArray reasons, long timestamp) {
synchronized (ActivityManagerService.this) {
- mStackSupervisor.mActivityMetricsLogger.notifyTransitionStarting(
+ mStackSupervisor.getActivityMetricsLogger().notifyTransitionStarting(
reasons, timestamp);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 93c0f77235c4..eb022b78d958 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -13,6 +13,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_BIND_APPLICATION_DELAY_MS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CALLING_PACKAGE_NAME;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CANCELLED;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DELAY_MS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_IS_EPHEMERAL;
@@ -28,16 +29,22 @@ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_T
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_METRICS;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import android.content.Context;
import android.metrics.LogMaker;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.SystemClock;
+import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.os.SomeArgs;
import java.util.ArrayList;
@@ -58,6 +65,8 @@ class ActivityMetricsLogger {
private static final long INVALID_START_TIME = -1;
+ private static final int MSG_CHECK_VISIBILITY = 0;
+
// Preallocated strings we are sending to tron, so we don't have to allocate a new one every
// time we log.
private static final String[] TRON_WINDOW_STATE_VARZ_STRINGS = {
@@ -78,6 +87,23 @@ class ActivityMetricsLogger {
private final SparseArray<StackTransitionInfo> mStackTransitionInfo = new SparseArray<>();
private final SparseArray<StackTransitionInfo> mLastStackTransitionInfo = new SparseArray<>();
+ private final H mHandler;
+ private final class H extends Handler {
+
+ public H(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_CHECK_VISIBILITY:
+ final SomeArgs args = (SomeArgs) msg.obj;
+ checkVisibility((TaskRecord) args.arg1, (ActivityRecord) args.arg2);
+ break;
+ }
+ }
+ };
private final class StackTransitionInfo {
private ActivityRecord launchedActivity;
@@ -91,10 +117,11 @@ class ActivityMetricsLogger {
private boolean loggedStartingWindowDrawn;
}
- ActivityMetricsLogger(ActivityStackSupervisor supervisor, Context context) {
+ ActivityMetricsLogger(ActivityStackSupervisor supervisor, Context context, Looper looper) {
mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
mSupervisor = supervisor;
mContext = context;
+ mHandler = new H(looper);
}
void logWindowState() {
@@ -145,6 +172,7 @@ class ActivityMetricsLogger {
*/
void notifyActivityLaunching() {
if (!isAnyTransitionActive()) {
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunching");
mCurrentTransitionStartTime = SystemClock.uptimeMillis();
mLastTransitionStartTime = mCurrentTransitionStartTime;
}
@@ -202,6 +230,12 @@ class ActivityMetricsLogger {
private void notifyActivityLaunched(int resultCode, ActivityRecord launchedActivity,
boolean processRunning, boolean processSwitch) {
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched"
+ + " resultCode=" + resultCode
+ + " launchedActivity=" + launchedActivity
+ + " processRunning=" + processRunning
+ + " processSwitch=" + processSwitch);
+
// If we are already in an existing transition, only update the activity name, but not the
// other attributes.
final int stackId = launchedActivity != null && launchedActivity.getStack() != null
@@ -230,6 +264,8 @@ class ActivityMetricsLogger {
return;
}
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched successful");
+
final StackTransitionInfo newInfo = new StackTransitionInfo();
newInfo.launchedActivity = launchedActivity;
newInfo.currentTransitionProcessRunning = processRunning;
@@ -243,6 +279,8 @@ class ActivityMetricsLogger {
* Notifies the tracker that all windows of the app have been drawn.
*/
void notifyWindowsDrawn(int stackId, long timestamp) {
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn stackId=" + stackId);
+
final StackTransitionInfo info = mStackTransitionInfo.get(stackId);
if (info == null || info.loggedWindowsDrawn) {
return;
@@ -276,6 +314,7 @@ class ActivityMetricsLogger {
if (!isAnyTransitionActive() || mLoggedTransitionStarting) {
return;
}
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting");
mCurrentTransitionDelayMs = calculateDelay(timestamp);
mLoggedTransitionStarting = true;
for (int index = stackIdReasons.size() - 1; index >= 0; index--) {
@@ -295,17 +334,37 @@ class ActivityMetricsLogger {
* Notifies the tracker that the visibility of an app is changing.
*
* @param activityRecord the app that is changing its visibility
- * @param visible whether it's going to be visible or not
*/
- void notifyVisibilityChanged(ActivityRecord activityRecord, boolean visible) {
+ void notifyVisibilityChanged(ActivityRecord activityRecord) {
final StackTransitionInfo info = mStackTransitionInfo.get(activityRecord.getStackId());
+ if (info == null) {
+ return;
+ }
+ if (info.launchedActivity != activityRecord) {
+ return;
+ }
+ final TaskRecord t = activityRecord.getTask();
+ final SomeArgs args = SomeArgs.obtain();
+ args.arg1 = t;
+ args.arg2 = activityRecord;
+ mHandler.obtainMessage(MSG_CHECK_VISIBILITY, args).sendToTarget();
+ }
- // If we have an active transition that's waiting on a certain activity that will be
- // invisible now, we'll never get onWindowsDrawn, so abort the transition if necessary.
- if (info != null && !visible && info.launchedActivity == activityRecord) {
- mStackTransitionInfo.remove(activityRecord.getStackId());
- if (mStackTransitionInfo.size() == 0) {
- reset(true /* abort */);
+ private void checkVisibility(TaskRecord t, ActivityRecord r) {
+ synchronized (mSupervisor.mService) {
+
+ final StackTransitionInfo info = mStackTransitionInfo.get(r.getStackId());
+
+ // If we have an active transition that's waiting on a certain activity that will be
+ // invisible now, we'll never get onWindowsDrawn, so abort the transition if necessary.
+ if (info != null && !t.isVisible()) {
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyVisibilityChanged to invisible"
+ + " activity=" + r);
+ logAppTransitionCancel(info);
+ mStackTransitionInfo.remove(r.getStackId());
+ if (mStackTransitionInfo.size() == 0) {
+ reset(true /* abort */);
+ }
}
}
}
@@ -341,6 +400,7 @@ class ActivityMetricsLogger {
}
private void reset(boolean abort) {
+ if (DEBUG_METRICS) Slog.i(TAG, "reset abort=" + abort);
if (!abort && isAnyTransitionActive()) {
logAppTransitionMultiEvents();
}
@@ -361,7 +421,20 @@ class ActivityMetricsLogger {
return (int) (timestamp - mCurrentTransitionStartTime);
}
+ private void logAppTransitionCancel(StackTransitionInfo info) {
+ final int type = getTransitionType(info);
+ if (type == -1) {
+ return;
+ }
+ final LogMaker builder = new LogMaker(APP_TRANSITION_CANCELLED);
+ builder.setPackageName(info.launchedActivity.packageName);
+ builder.setType(type);
+ builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name);
+ mMetricsLogger.write(builder);
+ }
+
private void logAppTransitionMultiEvents() {
+ if (DEBUG_METRICS) Slog.i(TAG, "logging transition events");
for (int index = mStackTransitionInfo.size() - 1; index >= 0; index--) {
final StackTransitionInfo info = mStackTransitionInfo.valueAt(index);
final int type = getTransitionType(info);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 481575e88c70..9a16745c9ca3 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -201,6 +201,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
private static final String TAG_STATES = TAG + POSTFIX_STATES;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
+ // TODO(b/67864419): Remove once recents component is overridden
+ private static final String LEGACY_RECENTS_PACKAGE_NAME = "com.android.systemui.recents";
private static final boolean SHOW_ACTIVITY_START_TIME = true;
@@ -1057,7 +1059,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
// We only allow home activities to be resizeable if they explicitly requested it.
info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
}
- } else if (service.getRecentTasks().isRecentsComponent(realActivity, appInfo.uid)) {
+ } else if (realActivity.getClassName().contains(LEGACY_RECENTS_PACKAGE_NAME) ||
+ service.getRecentTasks().isRecentsComponent(realActivity, appInfo.uid)) {
activityType = ACTIVITY_TYPE_RECENTS;
} else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_ASSISTANT
&& canLaunchAssistActivity(launchedFromPackage)) {
@@ -1526,7 +1529,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
void setVisibility(boolean visible) {
mWindowContainerController.setVisibility(visible, mDeferHidingClient);
- mStackSupervisor.mActivityMetricsLogger.notifyVisibilityChanged(this, visible);
+ mStackSupervisor.getActivityMetricsLogger().notifyVisibilityChanged(this);
}
// TODO: Look into merging with #setVisibility()
@@ -1807,7 +1810,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
stack.mFullyDrawnStartTime = 0;
}
- mStackSupervisor.mActivityMetricsLogger.logAppTransitionReportedDrawn(this,
+ mStackSupervisor.getActivityMetricsLogger().logAppTransitionReportedDrawn(this,
restoredFromBundle);
fullyDrawnStartTime = 0;
}
@@ -1849,7 +1852,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
@Override
public void onStartingWindowDrawn(long timestamp) {
synchronized (service) {
- mStackSupervisor.mActivityMetricsLogger.notifyStartingWindowDrawn(
+ mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(
getStackId(), timestamp);
}
}
@@ -1857,7 +1860,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
@Override
public void onWindowsDrawn(long timestamp) {
synchronized (service) {
- mStackSupervisor.mActivityMetricsLogger.notifyWindowsDrawn(getStackId(), timestamp);
+ mStackSupervisor.getActivityMetricsLogger().notifyWindowsDrawn(getStackId(), timestamp);
if (displayStartTime != 0) {
reportLaunchTimeLocked(timestamp);
}
@@ -2179,26 +2182,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
mTmpConfig.unset();
computeBounds(mTmpBounds);
if (mTmpBounds.equals(mBounds)) {
- final ActivityStack stack = getStack();
- if (!mBounds.isEmpty() || task == null || stack == null || !task.mFullscreen) {
- // We don't want to influence the override configuration here if our task is in
- // multi-window mode or there is a bounds specified to calculate the override
- // config. In both of this cases the app should be compatible with whatever the
- // current configuration is or will be.
- return;
- }
-
- // Currently limited to the top activity for now to avoid situations where non-top
- // visible activity and top might have conflicting requests putting the non-top activity
- // windows in an odd state.
- final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
- final Configuration parentConfig = getParent().getConfiguration();
- if (top != this || isConfigurationCompatible(parentConfig)) {
- onOverrideConfigurationChanged(mTmpConfig);
- } else if (isConfigurationCompatible(
- mLastReportedConfiguration.getMergedConfiguration())) {
- onOverrideConfigurationChanged(mLastReportedConfiguration.getMergedConfiguration());
- }
return;
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 88403fc5dde7..c086c5292059 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -16,10 +16,14 @@
package com.android.server.am;
+import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
+import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
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.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -94,7 +98,6 @@ import static java.lang.Integer.MAX_VALUE;
import android.app.Activity;
import android.app.ActivityManager;
-import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IActivityController;
@@ -344,6 +347,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>();
private final Rect mTmpRect2 = new Rect();
+ private final ActivityOptions mTmpOptions = ActivityOptions.makeBasic();
/** Run all ActivityStacks through this */
protected final ActivityStackSupervisor mStackSupervisor;
@@ -451,8 +455,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
mStackId = stackId;
mCurrentUser = mService.mUserController.getCurrentUserId();
mTmpRect2.setEmpty();
- setWindowingMode(windowingMode);
setActivityType(activityType);
+ setWindowingMode(windowingMode);
mWindowContainerController = createStackWindowController(display.mDisplayId, onTop,
mTmpRect2);
postAddToDisplay(display, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop);
@@ -478,6 +482,125 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
@Override
+ public void setWindowingMode(int windowingMode) {
+ setWindowingMode(windowingMode, false /* animate */);
+ }
+
+ void setWindowingMode(int preferredWindowingMode, boolean animate) {
+ 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());;
+ 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;
+ }
+
+ // 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.
+ mService.mTaskChangeNotificationController.notifyActivityDismissingDockedStack();
+ display.getSplitScreenPrimaryStack().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ }
+ }
+
+ if (currentMode == windowingMode) {
+ // You are already in the window mode silly...
+ return;
+ }
+
+ final WindowManagerService wm = mService.mWindowManager;
+ final ActivityRecord topActivity = getTopActivity();
+
+ if (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;
+ mService.mTaskChangeNotificationController.notifyActivityForcedResizable(
+ topTask.taskId, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN, packageName);
+ }
+
+ wm.deferSurfaceLayout();
+ try {
+ if (!animate && topActivity != null) {
+ mNoAnimActivities.add(topActivity);
+ }
+ super.setWindowingMode(windowingMode);
+
+ if (mWindowContainerController == null) {
+ // Nothing else to do if we don't have a window container yet. E.g. call from ctor.
+ return;
+ }
+
+ if (windowingMode == WINDOWING_MODE_PINNED || currentMode == WINDOWING_MODE_PINNED) {
+ // TODO: Need to remove use of PinnedActivityStack for this to be supported.
+ // NOTE: Need to ASS.scheduleUpdatePictureInPictureModeIfNeeded() in
+ // setWindowModeUnchecked() when this support is added. See TaskRecord.reparent()
+ throw new IllegalArgumentException(
+ "Changing pinned windowing mode not currently supported");
+ }
+
+ if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && splitScreenStack != null) {
+ // We already have a split-screen stack in this display, so just move the tasks over.
+ // TODO: Figure-out how to do all the stuff in
+ // AMS.setTaskWindowingModeSplitScreenPrimary
+ throw new IllegalArgumentException("Setting primary split-screen windowing mode"
+ + " while there is already one isn't currently supported");
+ //return;
+ }
+
+ mTmpRect2.setEmpty();
+ if (windowingMode != WINDOWING_MODE_FULLSCREEN) {
+ mWindowContainerController.getRawBounds(mTmpRect2);
+ if (windowingMode == WINDOWING_MODE_FREEFORM) {
+ if (topTask != null) {
+ // TODO: Can we consolidate this and other sites that call this methods?
+ Rect bounds = topTask().getLaunchBounds();
+ if (bounds != null) {
+ mTmpRect2.set(bounds);
+ }
+ }
+ }
+ }
+
+ if (!Objects.equals(mBounds, mTmpRect2)) {
+ resize(mTmpRect2, null /* tempTaskBounds */, null /* tempTaskInsetBounds */);
+ }
+ } finally {
+ if (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
+ // on that.
+ // TODO: This is only here to help out with the case where recents stack doesn't
+ // exist yet. For that case the initial size of the split-screen stack will be the
+ // 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 */);
+ // 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();
+ }
+
+ @Override
public boolean isCompatible(int windowingMode, int activityType) {
// TODO: Should we just move this to ConfigurationContainer?
if (activityType == ACTIVITY_TYPE_UNDEFINED) {
@@ -537,12 +660,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
* either destroyed completely or re-parented.
*/
private void removeFromDisplay() {
- if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- // If we removed a docked stack we want to resize it so it resizes all other stacks
- // in the system to fullscreen.
- mStackSupervisor.resizeDockedStackLocked(
- null, null, null, null, null, PRESERVE_WINDOWS);
- }
final ActivityDisplay display = getDisplay();
if (display != null) {
display.removeChild(this);
@@ -729,14 +846,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
return null;
}
- final ActivityRecord topActivity() {
+ ActivityRecord getTopActivity() {
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
- ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
- for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = activities.get(activityNdx);
- if (!r.finishing) {
- return r;
- }
+ final ActivityRecord r = mTaskHistory.get(taskNdx).getTopActivity();
+ if (r != null) {
+ return r;
}
}
return null;
@@ -750,7 +864,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
return null;
}
- final TaskRecord bottomTask() {
+ private TaskRecord bottomTask() {
if (mTaskHistory.isEmpty()) {
return null;
}
@@ -870,6 +984,29 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
}
+ /**
+ * @param reason The reason for moving the stack to the back.
+ * @param task If non-null, the task will be moved to the bottom of the stack.
+ **/
+ void moveToBack(String reason, TaskRecord task) {
+ if (!isAttached()) {
+ return;
+ }
+
+ getDisplay().positionChildAtBottom(this);
+ mStackSupervisor.setFocusStackUnchecked(reason, getDisplay().getTopStack());
+ if (task != null) {
+ insertTaskAtBottom(task);
+ return;
+ } else {
+ task = bottomTask();
+ if (task != null) {
+ mWindowContainerController.positionChildAtBottom(
+ task.getWindowContainerController(), true /* includingParents */);
+ }
+ }
+ }
+
boolean isFocusable() {
if (getWindowConfiguration().canReceiveKeys()) {
return true;
@@ -1583,8 +1720,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
final int otherWindowingMode = other.getWindowingMode();
- // TODO: Can be removed once we are no longer using returnToType for back functionality
- final ActivityStack stackBehind = i > 0 ? display.getChildAt(i - 1) : null;
if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) {
if (other.isStackTranslucent(starting)) {
@@ -1645,7 +1780,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
boolean preserveWindows) {
mTopActivityOccludesKeyguard = false;
mTopDismissingKeyguardActivity = null;
- mStackSupervisor.mKeyguardController.beginActivityVisibilityUpdate();
+ mStackSupervisor.getKeyguardController().beginActivityVisibilityUpdate();
try {
ActivityRecord top = topRunningActivityLocked();
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + top
@@ -1753,7 +1888,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
notifyActivityDrawnLocked(null);
}
} finally {
- mStackSupervisor.mKeyguardController.endActivityVisibilityUpdate();
+ mStackSupervisor.getKeyguardController().endActivityVisibilityUpdate();
}
}
@@ -1778,6 +1913,22 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
return inPinnedWindowingMode();
}
+ @Override
+ public boolean supportsSplitScreenWindowingMode() {
+ final TaskRecord topTask = topTask();
+ return super.supportsSplitScreenWindowingMode()
+ && (topTask == null || topTask.supportsSplitScreenWindowingMode());
+ }
+
+ /** @return True if the resizing of the primary-split-screen stack affects this stack size. */
+ boolean affectedBySplitScreenResize() {
+ if (!supportsSplitScreenWindowingMode()) {
+ return false;
+ }
+ final int windowingMode = getWindowingMode();
+ return windowingMode != WINDOWING_MODE_FREEFORM && windowingMode != WINDOWING_MODE_PINNED;
+ }
+
/**
* @return the top most visible activity that wants to dismiss Keyguard
*/
@@ -1795,9 +1946,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible,
boolean isTop) {
final boolean isInPinnedStack = r.inPinnedWindowingMode();
- final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing(
+ final boolean keyguardShowing = mStackSupervisor.getKeyguardController().isKeyguardShowing(
mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
- final boolean keyguardLocked = mStackSupervisor.mKeyguardController.isKeyguardLocked();
+ final boolean keyguardLocked = mStackSupervisor.getKeyguardController().isKeyguardLocked();
final boolean showWhenLocked = r.canShowWhenLocked() && !isInPinnedStack;
final boolean dismissKeyguard = r.hasDismissKeyguardWindows();
if (shouldBeVisible) {
@@ -1812,7 +1963,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
final boolean canShowWithKeyguard = canShowWithInsecureKeyguard()
- && mStackSupervisor.mKeyguardController.canDismissKeyguard();
+ && mStackSupervisor.getKeyguardController().canDismissKeyguard();
if (canShowWithKeyguard) {
return true;
}
@@ -1821,10 +1972,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// If keyguard is showing, nothing is visible, except if we are able to dismiss Keyguard
// right away.
- return shouldBeVisible && mStackSupervisor.mKeyguardController
+ return shouldBeVisible && mStackSupervisor.getKeyguardController()
.canShowActivityWhileKeyguardShowing(r, dismissKeyguard);
} else if (keyguardLocked) {
- return shouldBeVisible && mStackSupervisor.mKeyguardController.canShowWhileOccluded(
+ return shouldBeVisible && mStackSupervisor.getKeyguardController().canShowWhileOccluded(
dismissKeyguard, showWhenLocked);
} else {
return shouldBeVisible;
@@ -2388,7 +2539,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// if needed to get the correct rotation behavior.
// TODO: Remove this once visibilities are set correctly immediately when
// starting an activity.
- if (mStackSupervisor.mKeyguardController.isKeyguardLocked()) {
+ if (mStackSupervisor.getKeyguardController().isKeyguardLocked()) {
mStackSupervisor.ensureActivitiesVisibleLocked(null /* starting */,
0 /* configChanges */, false /* preserveWindows */);
}
@@ -2581,6 +2732,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (position >= mTaskHistory.size()) {
insertTaskAtTop(task, null);
return;
+ } else if (position <= 0) {
+ insertTaskAtBottom(task);
+ return;
}
position = getAdjustedPositionForTask(task, position, null /* starting */);
mTaskHistory.remove(task);
@@ -2601,6 +2755,16 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
true /* includingParents */);
}
+ private void insertTaskAtBottom(TaskRecord task) {
+ // Unlike insertTaskAtPosition, this will also position parents of the windowcontroller.
+ mTaskHistory.remove(task);
+ final int position = getAdjustedPositionForTask(task, 0, null);
+ mTaskHistory.add(position, task);
+ updateTaskMovement(task, true);
+ mWindowContainerController.positionChildAtBottom(task.getWindowContainerController(),
+ true /* includingParents */);
+ }
+
final void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
TaskRecord rTask = r.getTask();
@@ -4253,7 +4417,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
final ActivityStack topStack = getDisplay().getTopStack();
- final ActivityRecord topActivity = topStack != null ? topStack.topActivity() : null;
+ final ActivityRecord topActivity = topStack != null ? topStack.getTopActivity() : null;
final int numTasks = mTaskHistory.size();
final int index = mTaskHistory.indexOf(tr);
if (numTasks == 0 || index < 0) {
@@ -4370,8 +4534,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
updateTaskMovement(tr, false);
mWindowManager.prepareAppTransition(TRANSIT_TASK_TO_BACK, false);
- mWindowContainerController.positionChildAtBottom(tr.getWindowContainerController(),
- true /* includingParents */);
+ moveToBack("moveTaskToBackLocked", tr);
if (inPinnedWindowingMode()) {
mStackSupervisor.removeStack(this);
@@ -4457,6 +4620,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
final TaskRecord task = mTaskHistory.get(i);
if (task.isResizeable()) {
if (inFreeformWindowingMode()) {
+ // TODO: Can be removed now since each freeform task is in its own stack.
// For freeform stack we don't adjust the size of the tasks to match that
// of the stack, but we do try to make sure the tasks are still contained
// with the bounds of the stack.
@@ -4844,7 +5008,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
voiceInteractor);
// add the task to stack first, mTaskPositioner might need the stack association
addTask(task, toTop, "createTaskRecord");
- final boolean isLockscreenShown = mService.mStackSupervisor.mKeyguardController
+ final boolean isLockscreenShown = mService.mStackSupervisor.getKeyguardController()
.isKeyguardShowing(mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY);
if (!mStackSupervisor.getLaunchingBoundsController().layoutTask(task, info.windowLayout)
&& mBounds != null && task.isResizeable() && !isLockscreenShown) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 43a2a9f1f9bd..745e9fbc9b9d 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -295,7 +295,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
WindowManagerService mWindowManager;
DisplayManager mDisplayManager;
- private final LaunchingBoundsController mLaunchingBoundsController;
+ private LaunchingBoundsController mLaunchingBoundsController;
/** Counter for next free stack ID to use for dynamic activity stacks. */
private int mNextFreeStackId = 0;
@@ -395,7 +395,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
private final SparseArray<IntArray> mDisplayAccessUIDs = new SparseArray<>();
private DisplayManagerInternal mDisplayManagerInternal;
- private InputManagerInternal mInputManagerInternal;
/** Used to keep resumeTopActivityUncheckedLocked() from being entered recursively */
boolean inResumeTopActivity;
@@ -414,7 +413,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// Whether tasks have moved and we need to rank the tasks before next OOM scoring
private boolean mTaskLayersChanged = true;
- final ActivityMetricsLogger mActivityMetricsLogger;
+ private ActivityMetricsLogger mActivityMetricsLogger;
private final ArrayList<ActivityRecord> mTmpActivityList = new ArrayList<>();
@@ -534,11 +533,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
*/
boolean mIsDockMinimized;
- final KeyguardController mKeyguardController;
+ private KeyguardController mKeyguardController;
private PowerManager mPowerManager;
private int mDeferResumeCount;
+ private boolean mInitialized;
+
/**
* Description of a request to start a new activity, which has been held
* due to app switches being disabled.
@@ -574,14 +575,32 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
public ActivityStackSupervisor(ActivityManagerService service, Looper looper) {
mService = service;
mHandler = new ActivityStackSupervisorHandler(looper);
+ }
+
+ public void initialize() {
+ if (mInitialized) {
+ return;
+ }
+
+ mInitialized = true;
mRunningTasks = createRunningTasks();
- mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext);
- mKeyguardController = new KeyguardController(service, this);
+ mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext,
+ mHandler.getLooper());
+ mKeyguardController = new KeyguardController(mService, this);
mLaunchingBoundsController = new LaunchingBoundsController();
mLaunchingBoundsController.registerDefaultPositioners(this);
}
+
+ public ActivityMetricsLogger getActivityMetricsLogger() {
+ return mActivityMetricsLogger;
+ }
+
+ public KeyguardController getKeyguardController() {
+ return mKeyguardController;
+ }
+
void setRecentTasks(RecentTasks recentTasks) {
mRecentTasks = recentTasks;
mRecentTasks.registerCallback(this);
@@ -624,8 +643,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mHomeStack = mFocusedStack = mLastFocusedStack = getDefaultDisplay().getOrCreateStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
-
- mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
}
}
@@ -2441,7 +2458,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stack.mStackId);
mWindowManager.deferSurfaceLayout();
try {
- if (stack.supportsSplitScreenWindowingMode()) {
+ if (stack.affectedBySplitScreenResize()) {
if (bounds == null && stack.inSplitScreenWindowingMode()) {
// null bounds = fullscreen windowing mode...at least for now.
stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
@@ -2541,8 +2558,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
null, mTmpOptions, task, task.getActivityType(), onTop);
if (onTop) {
- final int returnToType =
- toDisplay.getTopVisibleStackActivityType(WINDOWING_MODE_PINNED);
final boolean isTopTask = i == (size - 1);
// Defer resume until all the tasks have been moved to the fullscreen stack
task.reparent(toStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT,
@@ -2631,7 +2646,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
if (current.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
continue;
}
- if (!current.supportsSplitScreenWindowingMode()) {
+ if (!current.affectedBySplitScreenResize()) {
continue;
}
// Need to set windowing mode here before we try to get the dock bounds.
@@ -2947,6 +2962,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
* Returns the reparent target stack, creating the stack if necessary. This call also enforces
* the various checks on tasks that are going to be reparented from one stack to another.
*/
+ // TODO: Look into changing users to this method to ActivityDisplay.resolveWindowingMode()
ActivityStack getReparentTargetStack(TaskRecord task, ActivityStack stack, boolean toTop) {
final ActivityStack prevStack = task.getStack();
final int stackId = stack.mStackId;
@@ -2973,8 +2989,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
+ " reparent task=" + task + " to stackId=" + stackId);
}
- // Ensure that we aren't trying to move into a freeform stack without freeform
- // support
+ // Ensure that we aren't trying to move into a freeform stack without freeform support
if (stack.getWindowingMode() == WINDOWING_MODE_FREEFORM
&& !mService.mSupportsFreeformWindowManagement) {
throw new IllegalArgumentException("Device doesn't support freeform, can not reparent"
@@ -3378,7 +3393,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// When launching tasks behind, update the last active time of the top task after the new
// task has been shown briefly
- final ActivityRecord top = stack.topActivity();
+ final ActivityRecord top = stack.getTopActivity();
if (top != null) {
top.getTask().touchActiveTime();
}
@@ -4177,8 +4192,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
// Handle incorrect launch/move to secondary display if needed.
- final boolean launchOnSecondaryDisplayFailed;
if (isSecondaryDisplayPreferred) {
+ final boolean launchOnSecondaryDisplayFailed;
final int actualDisplayId = task.getStack().mDisplayId;
if (!task.canBeLaunchedOnDisplay(actualDisplayId)) {
// The task landed on an inappropriate display somehow, move it to the default
@@ -4193,34 +4208,34 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
|| (preferredDisplayId != INVALID_DISPLAY
&& preferredDisplayId != actualDisplayId);
}
- } else {
- // The task wasn't requested to be on a secondary display.
- launchOnSecondaryDisplayFailed = false;
- }
-
- final ActivityRecord topActivity = task.getTopActivity();
- if (launchOnSecondaryDisplayFailed
- || !task.supportsSplitScreenWindowingMode() || forceNonResizable) {
if (launchOnSecondaryDisplayFailed) {
// Display a warning toast that we tried to put a non-resizeable task on a secondary
// display with config different from global config.
mService.mTaskChangeNotificationController
.notifyActivityLaunchOnSecondaryDisplayFailed();
- } else {
- // Display a warning toast that we tried to put a non-dockable task in the docked
- // stack.
- mService.mTaskChangeNotificationController.notifyActivityDismissingDockedStack();
+ return;
}
+ }
+
+ if (!task.supportsSplitScreenWindowingMode() || forceNonResizable) {
+ // Display a warning toast that we tried to put an app that doesn't support split-screen
+ // in split-screen.
+ mService.mTaskChangeNotificationController.notifyActivityDismissingDockedStack();
// Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
// we need to move it to top of fullscreen stack, otherwise it will be covered.
- final ActivityStack dockedStack = task.getStack().getDisplay().getSplitScreenPrimaryStack();
+ final ActivityStack dockedStack =
+ task.getStack().getDisplay().getSplitScreenPrimaryStack();
if (dockedStack != null) {
moveTasksToFullscreenStackLocked(dockedStack, actualStack == dockedStack);
}
- } else if (topActivity != null && topActivity.isNonResizableOrForcedResizable()
- && !topActivity.noDisplay) {
+ return;
+ }
+
+ final ActivityRecord topActivity = task.getTopActivity();
+ if (topActivity != null && topActivity.isNonResizableOrForcedResizable()
+ && !topActivity.noDisplay) {
final String packageName = topActivity.appInfo.packageName;
final int reason = isSecondaryDisplayPreferred
? FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY
@@ -4489,9 +4504,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
"startActivityFromRecents: Task " + taskId + " not found.");
}
- // We always want to return to the home activity instead of the recents activity from
- // whatever is started from the recents activity, so move the home stack forward.
- moveHomeStackToFront("startActivityFromRecents");
+ if (windowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ // We always want to return to the home activity instead of the recents activity
+ // from whatever is started from the recents activity, so move the home stack
+ // forward.
+ moveHomeStackToFront("startActivityFromRecents");
+ }
// If the user must confirm credentials (e.g. when first launching a work app and the
// Work Challenge is present) let startActivityInPackage handle the intercepting.
@@ -4502,9 +4520,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mService.mActivityStarter.sendPowerHintForLaunchStartIfNeeded(true /* forceSend */,
targetActivity);
mActivityMetricsLogger.notifyActivityLaunching();
- mService.moveTaskToFrontLocked(task.taskId, 0, bOptions, true /* fromRecents */);
- mActivityMetricsLogger.notifyActivityLaunched(ActivityManager.START_TASK_TO_FRONT,
- targetActivity);
+ try {
+ mService.moveTaskToFrontLocked(task.taskId, 0, bOptions,
+ true /* fromRecents */);
+ } finally {
+ mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
+ targetActivity);
+ }
// If we are launching the task in the docked stack, put it into resizing mode so
// the window renders full-screen with the background filling the void. Also only
@@ -4547,7 +4569,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
final ActivityStack stack = display.getChildAt(j);
// Get top activity from a visible stack and add it to the list.
if (stack.shouldBeVisible(null /* starting */)) {
- final ActivityRecord top = stack.topActivity();
+ final ActivityRecord top = stack.getTopActivity();
if (top != null) {
if (stack == mFocusedStack) {
topActivityTokens.add(0, top.appToken);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 1c8028270f97..9b8cbc1043a5 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -90,6 +90,7 @@ import android.content.IntentSender;
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;
@@ -133,6 +134,7 @@ class ActivityStarter {
private static final int INVALID_LAUNCH_MODE = -1;
private final ActivityManagerService mService;
+ private final IPackageManager mPackageManager;
private final ActivityStackSupervisor mSupervisor;
private final ActivityStartInterceptor mInterceptor;
@@ -232,8 +234,9 @@ class ActivityStarter {
mIntentDelivered = false;
}
- ActivityStarter(ActivityManagerService service) {
+ ActivityStarter(ActivityManagerService service, IPackageManager packageManager) {
mService = service;
+ mPackageManager = packageManager;
mSupervisor = mService.mStackSupervisor;
mInterceptor = new ActivityStartInterceptor(mService, mSupervisor);
}
@@ -264,8 +267,12 @@ class ActivityStarter {
outActivity[0] = mLastStartActivityRecord[0];
}
+ return getExternalResult(mLastStartActivityResult);
+ }
+
+ public static int getExternalResult(int result) {
// Aborted results are treated as successes externally, but we must track them internally.
- return mLastStartActivityResult != START_ABORTED ? mLastStartActivityResult : START_SUCCESS;
+ return result != START_ABORTED ? result : START_SUCCESS;
}
/** DO NOT call this method directly. Use {@link #startActivityLocked} instead. */
@@ -295,7 +302,8 @@ class ActivityStarter {
}
}
- final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
+ final int userId = aInfo != null && aInfo.applicationInfo != null
+ ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
if (err == ActivityManager.START_SUCCESS) {
Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
@@ -371,7 +379,7 @@ class ActivityStarter {
&& sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
try {
intent.addCategory(Intent.CATEGORY_VOICE);
- if (!AppGlobals.getPackageManager().activitySupportsIntent(
+ if (!mPackageManager.activitySupportsIntent(
intent.getComponent(), intent, resolvedType)) {
Slog.w(TAG,
"Activity being started in current voice task does not support voice: "
@@ -389,7 +397,7 @@ class ActivityStarter {
// If the caller is starting a new voice session, just make sure the target
// is actually allowing it to run this way.
try {
- if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(),
+ if (!mPackageManager.activitySupportsIntent(intent.getComponent(),
intent, resolvedType)) {
Slog.w(TAG,
"Activity being started in new voice task does not support: "
@@ -665,7 +673,7 @@ class ActivityStarter {
if (intent != null && intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
- mSupervisor.mActivityMetricsLogger.notifyActivityLaunching();
+ mSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
boolean componentSpecified = intent.getComponent() != null;
// Save a copy in case ephemeral needs it
@@ -859,7 +867,7 @@ class ActivityStarter {
}
}
- mSupervisor.mActivityMetricsLogger.notifyActivityLaunched(res, outRecord[0]);
+ mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outRecord[0]);
return res;
}
}
@@ -1119,7 +1127,7 @@ class ActivityStarter {
// If the activity being launched is the same as the one currently at the top, then
// we need to check if it should only be launched once.
final ActivityStack topStack = mSupervisor.mFocusedStack;
- final ActivityRecord topFocused = topStack.topActivity();
+ final ActivityRecord topFocused = topStack.getTopActivity();
final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
final boolean dontStart = top != null && mStartActivity.resultTo == null
&& top.realActivity.equals(mStartActivity.realActivity)
@@ -1565,8 +1573,8 @@ class ActivityStarter {
&& (topTask != intentActivity.getTask() || topTask != focusStack.topTask())
&& !mAvoidMoveToFront) {
mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
- if (mSourceRecord == null || (mSourceStack.topActivity() != null &&
- mSourceStack.topActivity().getTask() == mSourceRecord.getTask())) {
+ if (mSourceRecord == null || (mSourceStack.getTopActivity() != null &&
+ mSourceStack.getTopActivity().getTask() == mSourceRecord.getTask())) {
// We really do want to push this one into the user's face, right now.
if (mLaunchTaskBehind && mSourceRecord != null) {
intentActivity.setTaskToAffiliateWith(mSourceRecord.getTask());
@@ -1956,7 +1964,7 @@ class ActivityStarter {
if (mDoResume) {
mTargetStack.moveToFront("addingToTopTask");
}
- final ActivityRecord prev = mTargetStack.topActivity();
+ final ActivityRecord prev = mTargetStack.getTopActivity();
final TaskRecord task = (prev != null) ? prev.getTask() : mTargetStack.createTaskRecord(
mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId), mStartActivity.info,
mIntent, null, null, true);
diff --git a/services/core/java/com/android/server/am/AssistDataReceiverProxy.java b/services/core/java/com/android/server/am/AssistDataReceiverProxy.java
index 8306731b7635..9991ce174e07 100644
--- a/services/core/java/com/android/server/am/AssistDataReceiverProxy.java
+++ b/services/core/java/com/android/server/am/AssistDataReceiverProxy.java
@@ -19,13 +19,13 @@ package com.android.server.am;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import android.app.IAssistDataReceiver;
import android.graphics.Bitmap;
import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
-import com.android.internal.app.IAssistDataReceiver;
import com.android.server.am.AssistDataRequester.AssistDataRequesterCallbacks;
/**
@@ -37,17 +37,12 @@ class AssistDataReceiverProxy implements AssistDataRequesterCallbacks,
private static final String TAG = TAG_WITH_CLASS_NAME ? "AssistDataReceiverProxy" : TAG_AM;
private String mCallerPackage;
- private boolean mBinderDied;
private IAssistDataReceiver mReceiver;
public AssistDataReceiverProxy(IAssistDataReceiver receiver, String callerPackage) {
- try {
- receiver.asBinder().linkToDeath(this, 0);
- } catch (RemoteException e) {
- Log.w(TAG, "Could not link to client death", e);
- }
mReceiver = receiver;
mCallerPackage = callerPackage;
+ linkToDeath();
}
@Override
@@ -58,7 +53,7 @@ class AssistDataReceiverProxy implements AssistDataRequesterCallbacks,
@Override
public void onAssistDataReceivedLocked(Bundle data, int activityIndex, int activityCount) {
- if (!mBinderDied) {
+ if (mReceiver != null) {
try {
mReceiver.onHandleAssistData(data);
} catch (RemoteException e) {
@@ -70,7 +65,7 @@ class AssistDataReceiverProxy implements AssistDataRequesterCallbacks,
@Override
public void onAssistScreenshotReceivedLocked(Bitmap screenshot) {
- if (!mBinderDied) {
+ if (mReceiver != null) {
try {
mReceiver.onHandleAssistScreenshot(screenshot);
} catch (RemoteException e) {
@@ -81,7 +76,27 @@ class AssistDataReceiverProxy implements AssistDataRequesterCallbacks,
}
@Override
+ public void onAssistRequestCompleted() {
+ unlinkToDeath();
+ }
+
+ @Override
public void binderDied() {
- mBinderDied = true;
+ unlinkToDeath();
+ }
+
+ private void linkToDeath() {
+ try {
+ mReceiver.asBinder().linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not link to client death", e);
+ }
+ }
+
+ private void unlinkToDeath() {
+ if (mReceiver != null) {
+ mReceiver.asBinder().unlinkToDeath(this, 0);
+ }
+ mReceiver = null;
}
} \ No newline at end of file
diff --git a/services/core/java/com/android/server/am/AssistDataRequester.java b/services/core/java/com/android/server/am/AssistDataRequester.java
index e32ff6e9cb0b..9f7621f2e78e 100644
--- a/services/core/java/com/android/server/am/AssistDataRequester.java
+++ b/services/core/java/com/android/server/am/AssistDataRequester.java
@@ -23,6 +23,7 @@ import static android.app.AppOpsManager.OP_NONE;
import android.app.AppOpsManager;
import android.app.IActivityManager;
+import android.app.IAssistDataReceiver;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
@@ -31,7 +32,6 @@ import android.os.RemoteException;
import android.view.IWindowManager;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.IAssistDataReceiver;
import com.android.internal.logging.MetricsLogger;
import java.io.PrintWriter;
@@ -94,6 +94,17 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub {
*/
@GuardedBy("mCallbacksLock")
void onAssistScreenshotReceivedLocked(Bitmap screenshot);
+
+ /**
+ * Called when there is no more pending assist data or screenshots for the last request.
+ * If the request was canceled, then this callback will not be made. In addition, the
+ * callback will be made with the {@param mCallbacksLock} held, and only if
+ * {@link #canHandleReceivedAssistDataLocked()} is true.
+ */
+ @GuardedBy("mCallbacksLock")
+ default void onAssistRequestCompleted() {
+ // Do nothing
+ }
}
/**
@@ -131,15 +142,21 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub {
* @param fetchScreenshot whether or not to fetch the screenshot, only applies if fetchData is
* true, the caller is allowed to fetch the assist data, and the current activity allows
* assist data to be fetched from it
+ * @param allowFetchData to be joined with other checks, determines whether or not the requester
+ * is allowed to fetch the assist data
+ * @param allowFetchScreenshot to be joined with other checks, determines whether or not the
+ * requester is allowed to fetch the assist screenshot
*/
- public void requestAssistData(List<IBinder> activityTokens, boolean fetchData,
- boolean fetchScreenshot, int callingUid, String callingPackage) {
- // TODO: Better handle the cancel case if a request can be reused
- // TODO: Known issue, if the assist data is not allowed on the current activity, then no
- // assist data is requested for any of the other activities
+ public void requestAssistData(List<IBinder> activityTokens, final boolean fetchData,
+ final boolean fetchScreenshot, boolean allowFetchData, boolean allowFetchScreenshot,
+ int callingUid, String callingPackage) {
+ // TODO(b/34090158): Known issue, if the assist data is not allowed on the current activity,
+ // then no assist data is requested for any of the other activities
// Early exit if there are no activity to fetch for
if (activityTokens.isEmpty()) {
+ // No activities, just dispatch request-complete
+ tryDispatchRequestComplete();
return;
}
@@ -150,8 +167,8 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub {
} catch (RemoteException e) {
// Should never happen
}
- fetchData &= isAssistDataAllowed;
- fetchScreenshot &= fetchData && isAssistDataAllowed
+ allowFetchData &= isAssistDataAllowed;
+ allowFetchScreenshot &= fetchData && isAssistDataAllowed
&& (mRequestScreenshotAppOps != OP_NONE);
mCanceled = false;
@@ -162,7 +179,7 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub {
if (fetchData) {
if (mAppOpsManager.checkOpNoThrow(mRequestStructureAppOps, callingUid, callingPackage)
- == MODE_ALLOWED) {
+ == MODE_ALLOWED && allowFetchData) {
final int numActivities = activityTokens.size();
for (int i = 0; i < numActivities; i++) {
IBinder topActivity = activityTokens.get(i);
@@ -177,8 +194,12 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub {
mPendingDataCount++;
} else if (i == 0) {
// Wasn't allowed... given that, let's not do the screenshot either.
- dispatchAssistDataReceived(null);
- fetchScreenshot = false;
+ if (mCallbacks.canHandleReceivedAssistDataLocked()) {
+ dispatchAssistDataReceived(null);
+ } else {
+ mAssistData.add(null);
+ }
+ allowFetchScreenshot = false;
break;
}
} catch (RemoteException e) {
@@ -187,14 +208,18 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub {
}
} else {
// Wasn't allowed... given that, let's not do the screenshot either.
- dispatchAssistDataReceived(null);
- fetchScreenshot = false;
+ if (mCallbacks.canHandleReceivedAssistDataLocked()) {
+ dispatchAssistDataReceived(null);
+ } else {
+ mAssistData.add(null);
+ }
+ allowFetchScreenshot = false;
}
}
if (fetchScreenshot) {
if (mAppOpsManager.checkOpNoThrow(mRequestScreenshotAppOps, callingUid, callingPackage)
- == MODE_ALLOWED) {
+ == MODE_ALLOWED && allowFetchScreenshot) {
try {
MetricsLogger.count(mContext, "assist_with_screen", 1);
mPendingScreenshotCount++;
@@ -203,24 +228,38 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub {
// Can't happen
}
} else {
- dispatchAssistScreenshotReceived(null);
+ if (mCallbacks.canHandleReceivedAssistDataLocked()) {
+ dispatchAssistScreenshotReceived(null);
+ } else {
+ mAssistScreenshot.add(null);
+ }
}
}
+ // For the cases where we dispatch null data/screenshot due to permissions, just dispatch
+ // request-complete after those are made
+ tryDispatchRequestComplete();
}
/**
* This call should only be made when the callbacks are capable of handling the received assist
- * data.
+ * data. The owner is also responsible for locking before calling this method.
*/
public void processPendingAssistData() {
+ flushPendingAssistData();
+ tryDispatchRequestComplete();
+ }
+
+ private void flushPendingAssistData() {
final int dataCount = mAssistData.size();
for (int i = 0; i < dataCount; i++) {
dispatchAssistDataReceived(mAssistData.get(i));
}
+ mAssistData.clear();
final int screenshotsCount = mAssistScreenshot.size();
for (int i = 0; i < screenshotsCount; i++) {
dispatchAssistScreenshotReceived(mAssistScreenshot.get(i));
}
+ mAssistScreenshot.clear();
}
public int getPendingDataCount() {
@@ -254,8 +293,9 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub {
if (mCallbacks.canHandleReceivedAssistDataLocked()) {
// Process any pending data and dispatch the new data as well
- processPendingAssistData();
+ flushPendingAssistData();
dispatchAssistDataReceived(data);
+ tryDispatchRequestComplete();
} else {
// Queue up the data for processing later
mAssistData.add(data);
@@ -273,8 +313,9 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub {
if (mCallbacks.canHandleReceivedAssistDataLocked()) {
// Process any pending data and dispatch the new data as well
- processPendingAssistData();
+ flushPendingAssistData();
dispatchAssistScreenshotReceived(screenshot);
+ tryDispatchRequestComplete();
} else {
// Queue up the data for processing later
mAssistScreenshot.add(screenshot);
@@ -298,6 +339,13 @@ public class AssistDataRequester extends IAssistDataReceiver.Stub {
mCallbacks.onAssistScreenshotReceivedLocked(screenshot);
}
+ private void tryDispatchRequestComplete() {
+ if (mPendingDataCount == 0 && mPendingScreenshotCount == 0 &&
+ mAssistData.isEmpty() && mAssistScreenshot.isEmpty()) {
+ mCallbacks.onAssistRequestCompleted();
+ }
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("mPendingDataCount="); pw.println(mPendingDataCount);
pw.print(prefix); pw.print("mAssistData="); pw.println(mAssistData);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 52f97020b5a7..a035bd026fea 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.wifi.WifiActivityEnergyInfo;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
@@ -53,7 +54,6 @@ import com.android.internal.os.PowerProfile;
import com.android.internal.os.RpmStats;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import android.util.StatsLog;
import java.io.File;
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index c3fed17126b7..76b46796baa5 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -41,10 +41,8 @@ import android.os.RemoteException;
import android.os.Trace;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
-
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.server.wm.WindowManagerService;
-
import java.io.PrintWriter;
/**
@@ -236,24 +234,33 @@ class KeyguardController {
final ActivityRecord lastDismissingKeyguardActivity = mDismissingKeyguardActivity;
mOccluded = false;
mDismissingKeyguardActivity = null;
- final ActivityDisplay display = mStackSupervisor.getDefaultDisplay();
- for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getChildAt(stackNdx);
-
- // Only the focused stack top activity may control occluded state
- if (mStackSupervisor.isFocusedStack(stack)) {
-
- // A dismissing activity occludes Keyguard in the insecure case for legacy reasons.
- final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
- mOccluded = stack.topActivityOccludesKeyguard()
- || (topDismissing != null
- && stack.topRunningActivityLocked() == topDismissing
- && canShowWhileOccluded(true /* dismissKeyguard */,
- false /* showWhenLocked */));
- }
- if (mDismissingKeyguardActivity == null
- && stack.getTopDismissingKeyguardActivity() != null) {
- mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
+
+ for (int displayNdx = mStackSupervisor.getChildCount() - 1; displayNdx >= 0; displayNdx--) {
+ final ActivityDisplay display = mStackSupervisor.getChildAt(displayNdx);
+ for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = display.getChildAt(stackNdx);
+
+ // Only the top activity of the focused stack on the default display may control
+ // occluded state.
+ if (display.mDisplayId == DEFAULT_DISPLAY
+ && mStackSupervisor.isFocusedStack(stack)) {
+
+ // A dismissing activity occludes Keyguard in the insecure case for legacy
+ // reasons.
+ final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
+ mOccluded =
+ stack.topActivityOccludesKeyguard()
+ || (topDismissing != null
+ && stack.topRunningActivityLocked() == topDismissing
+ && canShowWhileOccluded(
+ true /* dismissKeyguard */,
+ false /* showWhenLocked */));
+ }
+
+ if (mDismissingKeyguardActivity == null
+ && stack.getTopDismissingKeyguardActivity() != null) {
+ mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
+ }
}
}
mOccluded |= mWindowManager.isShowingDream();
diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
index 5a7e7ced930c..7896e2dd9883 100644
--- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
@@ -95,8 +95,8 @@ class TaskChangeNotificationController {
};
private final TaskStackConsumer mNotifyActivityPinned = (l, m) -> {
- final ActivityRecord r = (ActivityRecord) m.obj;
- l.onActivityPinned(r.packageName, r.userId, r.getTask().taskId, r.getStackId());
+ l.onActivityPinned((String) m.obj /* packageName */, m.sendingUid /* userId */,
+ m.arg1 /* taskId */, m.arg2 /* stackId */);
};
private final TaskStackConsumer mNotifyActivityUnpinned = (l, m) -> {
@@ -281,7 +281,9 @@ class TaskChangeNotificationController {
/** Notifies all listeners when an Activity is pinned. */
void notifyActivityPinned(ActivityRecord r) {
mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG);
- final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG, r);
+ final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG,
+ r.getTask().taskId, r.getStackId(), r.packageName);
+ msg.sendingUid = r.userId;
forAllLocalListeners(mNotifyActivityPinned, msg);
msg.sendToTarget();
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 1a4f9d4fbd5b..949f51fe1b09 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -606,9 +606,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
final int toStackWindowingMode = toStack.getWindowingMode();
final ActivityRecord topActivity = getTopActivity();
- final boolean mightReplaceWindow =
- replaceWindowsOnTaskMove(getWindowingMode(), toStackWindowingMode)
- && topActivity != null;
+ final boolean mightReplaceWindow = topActivity != null
+ && replaceWindowsOnTaskMove(getWindowingMode(), toStackWindowingMode);
if (mightReplaceWindow) {
// We are about to relaunch the activity because its configuration changed due to
// being maximized, i.e. size change. The activity will first remove the old window
@@ -722,7 +721,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
}
// TODO: Handle incorrect request to move before the actual move, not after.
- final boolean inSplitScreenMode = supervisor.getDefaultDisplay().hasSplitScreenPrimaryStack();
supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(),
DEFAULT_DISPLAY, toStack);
@@ -735,10 +733,9 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
}
/**
- * Returns true if the windows of tasks being moved to the target stack from the source
- * stack should be replaced, meaning that window manager will keep the old window around
- * until the new is ready.
- * @hide
+ * @return True if the windows of tasks being moved to the target stack from the source stack
+ * should be replaced, meaning that window manager will keep the old window around until the new
+ * is ready.
*/
private static boolean replaceWindowsOnTaskMove(
int sourceWindowingMode, int targetWindowingMode) {
@@ -1036,6 +1033,16 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
return null;
}
+ boolean isVisible() {
+ for (int i = mActivities.size() - 1; i >= 0; --i) {
+ final ActivityRecord r = mActivities.get(i);
+ if (r.visible) {
+ return true;
+ }
+ }
+ return false;
+ }
+
void getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities) {
if (mStack != null) {
for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
@@ -1129,6 +1136,9 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
mActivities.remove(newTop);
mActivities.add(newTop);
+
+ // Make sure window manager is aware of the position change.
+ mWindowContainerController.positionChildAtTop(newTop.mWindowContainerController);
updateEffectiveIntent();
setFrontOfTask();
@@ -2049,11 +2059,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
}
static Rect validateBounds(Rect bounds) {
- if (bounds != null && bounds.isEmpty()) {
- Slog.wtf(TAG, "Received strange task bounds: " + bounds, new Throwable());
- return null;
- }
- return bounds;
+ // TODO: Not needed once we have bounds in WindowConfiguration.
+ return (bounds != null && bounds.isEmpty()) ? null : bounds;
}
/** Updates the task's bounds and override configuration to match what is expected for the
@@ -2082,7 +2089,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
}
/** Returns the bounds that should be used to launch this task. */
- private Rect getLaunchBounds() {
+ Rect getLaunchBounds() {
if (mStack == null) {
return null;
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 2df5dc93768c..4e3d8d27e0f9 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -89,6 +89,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.LockPatternUtils;
+import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemServiceManager;
import com.android.server.pm.UserManagerService;
@@ -355,27 +356,35 @@ class UserController implements Handler.Callback {
// Only keep marching forward if user is actually unlocked
if (!StorageManager.isUserKeyUnlocked(userId)) return;
synchronized (mLock) {
- // Bail if we ended up with a stale user
- if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;
-
- // Do not proceed if unexpected state
- if (!uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) {
+ // Do not proceed if unexpected state or a stale user
+ if (mStartedUsers.get(userId) != uss || uss.state != STATE_RUNNING_LOCKED) {
return;
}
}
- mInjector.getUserManagerInternal().setUserState(userId, uss.state);
uss.mUnlockProgress.start();
// Prepare app storage before we go any further
uss.mUnlockProgress.setProgress(5,
mInjector.getContext().getString(R.string.android_start_title));
- mInjector.getUserManager().onBeforeUnlockUser(userId);
- uss.mUnlockProgress.setProgress(20);
- // Dispatch unlocked to system services; when fully dispatched,
- // that calls through to the next "unlocked" phase
- mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
- .sendToTarget();
+ // Call onBeforeUnlockUser on a worker thread that allows disk I/O
+ FgThread.getHandler().post(() -> {
+ mInjector.getUserManager().onBeforeUnlockUser(userId);
+ synchronized (mLock) {
+ // Do not proceed if unexpected state
+ if (!uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) {
+ return;
+ }
+ }
+ mInjector.getUserManagerInternal().setUserState(userId, uss.state);
+
+ uss.mUnlockProgress.setProgress(20);
+
+ // Dispatch unlocked to system services; when fully dispatched,
+ // that calls through to the next "unlocked" phase
+ mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
+ .sendToTarget();
+ });
}
/**
@@ -1819,7 +1828,10 @@ class UserController implements Handler.Callback {
case SYSTEM_USER_UNLOCK_MSG:
final int userId = msg.arg1;
mInjector.getSystemServiceManager().unlockUser(userId);
- mInjector.loadUserRecents(userId);
+ // Loads recents on a worker thread that allows disk I/O
+ FgThread.getHandler().post(() -> {
+ mInjector.loadUserRecents(userId);
+ });
if (userId == UserHandle.USER_SYSTEM) {
mInjector.startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 5eb2a8d2066f..15a418dca6e9 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -122,6 +122,7 @@ import android.util.SparseIntArray;
import android.view.KeyEvent;
import android.view.accessibility.AccessibilityManager;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.XmlUtils;
import com.android.server.EventLogTags;
@@ -398,8 +399,9 @@ public class AudioService extends IAudioService.Stub
* {@link AudioManager#RINGER_MODE_SILENT}, or
* {@link AudioManager#RINGER_MODE_VIBRATE}.
*/
- // protected by mSettingsLock
+ @GuardedBy("mSettingsLock")
private int mRingerMode; // internal ringer mode, affects muting of underlying streams
+ @GuardedBy("mSettingsLock")
private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager)
/** @see System#MODE_RINGER_STREAMS_AFFECTED */
@@ -929,8 +931,11 @@ public class AudioService extends IAudioService.Stub
mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_RECORD, mForcedUseForComm,
"onAudioServerDied"));
AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
- final int forSys = mCameraSoundForced ?
- AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE;
+ final int forSys;
+ synchronized (mSettingsLock) {
+ forSys = mCameraSoundForced ?
+ AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE;
+ }
mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_SYSTEM, forSys,
"onAudioServerDied"));
AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, forSys);
@@ -1340,8 +1345,9 @@ public class AudioService extends IAudioService.Stub
} else {
final int maybeActiveStreamType = getActiveStreamType(suggestedStreamType);
final boolean activeForReal;
- if (maybeActiveStreamType == AudioSystem.STREAM_MUSIC) {
- activeForReal = isAfMusicActiveRecently(0);
+ if (maybeActiveStreamType == AudioSystem.STREAM_RING
+ || maybeActiveStreamType == AudioSystem.STREAM_NOTIFICATION) {
+ activeForReal = wasStreamActiveRecently(maybeActiveStreamType, 0);
} else {
activeForReal = AudioSystem.isStreamActive(maybeActiveStreamType, 0);
}
@@ -3797,6 +3803,7 @@ public class AudioService extends IAudioService.Stub
return (mRingerModeMutedStreams & (1 << streamType)) != 0;
}
+ @GuardedBy("mSettingsLock")
private boolean updateRingerModeAffectedStreams() {
int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
Settings.System.MODE_RINGER_STREAMS_AFFECTED,
@@ -3810,12 +3817,10 @@ public class AudioService extends IAudioService.Stub
ringerModeAffectedStreams = mRingerModeDelegate
.getRingerModeAffectedStreams(ringerModeAffectedStreams);
}
- synchronized (mCameraSoundForced) {
- if (mCameraSoundForced) {
- ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
- } else {
- ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
- }
+ if (mCameraSoundForced) {
+ ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ } else {
+ ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
}
if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
@@ -3879,13 +3884,13 @@ public class AudioService extends IAudioService.Stub
/**
* For code clarity for getActiveStreamType(int)
- * @param delay_ms max time since last STREAM_MUSIC activity to consider
- * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
+ * @param delay_ms max time since last stream activity to consider
+ * @return true if stream is active in streams handled by AudioFlinger now or
* in the last "delay_ms" ms.
*/
- private boolean isAfMusicActiveRecently(int delay_ms) {
- return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
- || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
+ private boolean wasStreamActiveRecently(int stream, int delay_ms) {
+ return AudioSystem.isStreamActive(stream, delay_ms)
+ || AudioSystem.isStreamActiveRemotely(stream, delay_ms);
}
private int getActiveStreamType(int suggestedStreamType) {
@@ -3906,21 +3911,30 @@ public class AudioService extends IAudioService.Stub
return AudioSystem.STREAM_VOICE_CALL;
}
} else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
- if (isAfMusicActiveRecently(sStreamOverrideDelayMs)) {
+ if (wasStreamActiveRecently(AudioSystem.STREAM_RING, sStreamOverrideDelayMs)) {
if (DEBUG_VOL)
- Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
+ Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING stream active");
+ return AudioSystem.STREAM_RING;
+ } else if (wasStreamActiveRecently(
+ AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
+ if (DEBUG_VOL)
+ Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION stream active");
+ return AudioSystem.STREAM_NOTIFICATION;
+ } else {
+ if (DEBUG_VOL)
+ Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC b/c default");
return AudioSystem.STREAM_MUSIC;
- } else {
- if (DEBUG_VOL)
- Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
- return AudioSystem.STREAM_RING;
}
- } else if (isAfMusicActiveRecently(0)) {
+ } else if (
+ wasStreamActiveRecently(AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
if (DEBUG_VOL)
- Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
- return AudioSystem.STREAM_MUSIC;
+ Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION stream active");
+ return AudioSystem.STREAM_NOTIFICATION;
+ } else if (wasStreamActiveRecently(AudioSystem.STREAM_RING, sStreamOverrideDelayMs)) {
+ if (DEBUG_VOL)
+ Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING stream active");
+ return AudioSystem.STREAM_RING;
}
- break;
default:
if (isInCommunication()) {
if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
@@ -3931,20 +3945,26 @@ public class AudioService extends IAudioService.Stub
if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
return AudioSystem.STREAM_VOICE_CALL;
}
- } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
- sStreamOverrideDelayMs) ||
- AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
- sStreamOverrideDelayMs)) {
+ } else if (AudioSystem.isStreamActive(
+ AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
return AudioSystem.STREAM_NOTIFICATION;
+ } else if (AudioSystem.isStreamActive(
+ AudioSystem.STREAM_RING, sStreamOverrideDelayMs)) {
+ if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING");
+ return AudioSystem.STREAM_RING;
} else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
- if (isAfMusicActiveRecently(sStreamOverrideDelayMs)) {
- if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
- return AudioSystem.STREAM_MUSIC;
- } else {
- if (DEBUG_VOL) Log.v(TAG,
- "getActiveStreamType: using STREAM_NOTIFICATION as default");
+ if (AudioSystem.isStreamActive(
+ AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
+ if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
return AudioSystem.STREAM_NOTIFICATION;
+ } else if (AudioSystem.isStreamActive(
+ AudioSystem.STREAM_RING, sStreamOverrideDelayMs)) {
+ if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING");
+ return AudioSystem.STREAM_RING;
+ } else {
+ if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default");
+ return AudioSystem.STREAM_MUSIC;
}
}
break;
@@ -4185,7 +4205,6 @@ public class AudioService extends IAudioService.Stub
// 2 mSetModeDeathHandlers
// 3 mSettingsLock
// 4 VolumeStreamState.class
- // 5 mCameraSoundForced
public class VolumeStreamState {
private final int mStreamType;
private final int mIndexMin;
@@ -4252,27 +4271,28 @@ public class AudioService extends IAudioService.Stub
}
public void readSettings() {
- synchronized (VolumeStreamState.class) {
- // force maximum volume on all streams if fixed volume property is set
- if (mUseFixedVolume) {
- mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
- return;
- }
- // do not read system stream volume from settings: this stream is always aliased
- // to another stream type and its volume is never persisted. Values in settings can
- // only be stale values
- if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
- (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
- int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
- synchronized (mCameraSoundForced) {
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ // force maximum volume on all streams if fixed volume property is set
+ if (mUseFixedVolume) {
+ mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
+ return;
+ }
+ // do not read system stream volume from settings: this stream is always aliased
+ // to another stream type and its volume is never persisted. Values in settings can
+ // only be stale values
+ if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
+ (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
+ int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
if (mCameraSoundForced) {
index = mIndexMax;
}
+ mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
+ return;
}
- mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
- return;
}
-
+ }
+ synchronized (VolumeStreamState.class) {
int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
for (int i = 0; remainingDevices != 0; i++) {
@@ -4385,34 +4405,34 @@ public class AudioService extends IAudioService.Stub
public boolean setIndex(int index, int device, String caller) {
boolean changed = false;
int oldIndex;
- synchronized (VolumeStreamState.class) {
- oldIndex = getIndex(device);
- index = getValidIndex(index);
- synchronized (mCameraSoundForced) {
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ oldIndex = getIndex(device);
+ index = getValidIndex(index);
if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
index = mIndexMax;
}
- }
- mIndexMap.put(device, index);
-
- changed = oldIndex != index;
- // Apply change to all streams using this one as alias if:
- // - the index actually changed OR
- // - there is no volume index stored for this device on alias stream.
- // If changing volume of current device, also change volume of current
- // device on aliased stream
- final boolean currentDevice = (device == getDeviceForStream(mStreamType));
- final int numStreamTypes = AudioSystem.getNumStreamTypes();
- for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
- final VolumeStreamState aliasStreamState = mStreamStates[streamType];
- if (streamType != mStreamType &&
- mStreamVolumeAlias[streamType] == mStreamType &&
- (changed || !aliasStreamState.hasIndexForDevice(device))) {
- final int scaledIndex = rescaleIndex(index, mStreamType, streamType);
- aliasStreamState.setIndex(scaledIndex, device, caller);
- if (currentDevice) {
- aliasStreamState.setIndex(scaledIndex,
- getDeviceForStream(streamType), caller);
+ mIndexMap.put(device, index);
+
+ changed = oldIndex != index;
+ // Apply change to all streams using this one as alias if:
+ // - the index actually changed OR
+ // - there is no volume index stored for this device on alias stream.
+ // If changing volume of current device, also change volume of current
+ // device on aliased stream
+ final boolean currentDevice = (device == getDeviceForStream(mStreamType));
+ final int numStreamTypes = AudioSystem.getNumStreamTypes();
+ for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+ final VolumeStreamState aliasStreamState = mStreamStates[streamType];
+ if (streamType != mStreamType &&
+ mStreamVolumeAlias[streamType] == mStreamType &&
+ (changed || !aliasStreamState.hasIndexForDevice(device))) {
+ final int scaledIndex = rescaleIndex(index, mStreamType, streamType);
+ aliasStreamState.setIndex(scaledIndex, device, caller);
+ if (currentDevice) {
+ aliasStreamState.setIndex(scaledIndex,
+ getDeviceForStream(streamType), caller);
+ }
}
}
}
@@ -6022,13 +6042,8 @@ public class AudioService extends IAudioService.Stub
boolean cameraSoundForced = readCameraSoundForced();
synchronized (mSettingsLock) {
- boolean cameraSoundForcedChanged = false;
- synchronized (mCameraSoundForced) {
- if (cameraSoundForced != mCameraSoundForced) {
- mCameraSoundForced = cameraSoundForced;
- cameraSoundForcedChanged = true;
- }
- }
+ final boolean cameraSoundForcedChanged = (cameraSoundForced != mCameraSoundForced);
+ mCameraSoundForced = cameraSoundForced;
if (cameraSoundForcedChanged) {
if (!mIsSingleVolume) {
VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
@@ -6350,10 +6365,10 @@ public class AudioService extends IAudioService.Stub
// stream override timeout when adjusting volume
//---------------------------------------------------------------------------------
- // AudioService.getActiveStreamType() will return:
// - STREAM_NOTIFICATION on tablets during this period after a notification stopped
- // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
- // stopped
+ // - STREAM_RING on phones during this period after a notification stopped
+ // - STREAM_MUSIC otherwise
+
private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
@@ -6408,11 +6423,12 @@ public class AudioService extends IAudioService.Stub
//==========================================================================================
// cached value of com.android.internal.R.bool.config_camera_sound_forced
- private Boolean mCameraSoundForced;
+ @GuardedBy("mSettingsLock")
+ private boolean mCameraSoundForced;
// called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
public boolean isCameraSoundForced() {
- synchronized (mCameraSoundForced) {
+ synchronized (mSettingsLock) {
return mCameraSoundForced;
}
}
@@ -6734,7 +6750,9 @@ public class AudioService extends IAudioService.Stub
public void setRingerModeDelegate(RingerModeDelegate delegate) {
mRingerModeDelegate = delegate;
if (mRingerModeDelegate != null) {
- updateRingerModeAffectedStreams();
+ synchronized (mSettingsLock) {
+ updateRingerModeAffectedStreams();
+ }
setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
}
}
diff --git a/services/core/java/com/android/server/broadcastradio/Tuner.java b/services/core/java/com/android/server/broadcastradio/Tuner.java
index e6ae320cf38d..2ea4271864f2 100644
--- a/services/core/java/com/android/server/broadcastradio/Tuner.java
+++ b/services/core/java/com/android/server/broadcastradio/Tuner.java
@@ -27,8 +27,10 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
class Tuner extends ITuner.Stub {
private static final String TAG = "BroadcastRadioService.Tuner";
@@ -96,6 +98,10 @@ class Tuner extends ITuner.Stub {
private native boolean nativeIsAnalogForced(long nativeContext);
private native void nativeSetAnalogForced(long nativeContext, boolean isForced);
+ private native Map<String, String> nativeSetParameters(long nativeContext,
+ Map<String, String> parameters);
+ private native Map<String, String> nativeGetParameters(long nativeContext, List<String> keys);
+
private native boolean nativeIsAntennaConnected(long nativeContext);
@Override
@@ -273,6 +279,31 @@ class Tuner extends ITuner.Stub {
}
@Override
+ public Map setParameters(Map parameters) {
+ Map<String, String> results;
+ synchronized (mLock) {
+ checkNotClosedLocked();
+ results = nativeSetParameters(mNativeContext, Objects.requireNonNull(parameters));
+ }
+ if (results == null) return Collections.emptyMap();
+ return results;
+ }
+
+ @Override
+ public Map getParameters(List<String> keys) {
+ if (keys == null) {
+ throw new IllegalArgumentException("The argument must not be a null pointer");
+ }
+ Map<String, String> results;
+ synchronized (mLock) {
+ checkNotClosedLocked();
+ results = nativeGetParameters(mNativeContext, keys);
+ }
+ if (results == null) return Collections.emptyMap();
+ return results;
+ }
+
+ @Override
public boolean isAntennaConnected() {
synchronized (mLock) {
checkNotClosedLocked();
diff --git a/services/core/java/com/android/server/broadcastradio/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/TunerCallback.java
index a87ae8d65bf8..2460c67a64a2 100644
--- a/services/core/java/com/android/server/broadcastradio/TunerCallback.java
+++ b/services/core/java/com/android/server/broadcastradio/TunerCallback.java
@@ -26,6 +26,9 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
+import java.util.List;
+import java.util.Map;
+
class TunerCallback implements ITunerCallback {
private static final String TAG = "BroadcastRadioService.TunerCallback";
@@ -121,6 +124,11 @@ class TunerCallback implements ITunerCallback {
}
@Override
+ public void onParametersUpdated(Map parameters) {
+ dispatch(() -> mClientCallback.onParametersUpdated(parameters));
+ }
+
+ @Override
public IBinder asBinder() {
throw new RuntimeException("Not a binder");
}
diff --git a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
index 8981db11f7f8..28c358582dbe 100644
--- a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
+++ b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
@@ -18,9 +18,11 @@ package com.android.server.connectivity;
import android.net.LinkProperties;
import android.net.metrics.DefaultNetworkEvent;
-import android.net.metrics.IpConnectivityLog;
+import android.os.SystemClock;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.BitUtils;
+import com.android.internal.util.RingBuffer;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
import java.io.PrintWriter;
@@ -35,19 +37,49 @@ public class DefaultNetworkMetrics {
private static final int ROLLING_LOG_SIZE = 64;
+ public final long creationTimeMs = SystemClock.elapsedRealtime();
+
// Event buffer used for metrics upload. The buffer is cleared when events are collected.
@GuardedBy("this")
private final List<DefaultNetworkEvent> mEvents = new ArrayList<>();
+ // Rolling event buffer used for dumpsys and bugreports.
+ @GuardedBy("this")
+ private final RingBuffer<DefaultNetworkEvent> mEventsLog =
+ new RingBuffer(DefaultNetworkEvent.class, ROLLING_LOG_SIZE);
+
+ // Information about the current status of the default network.
+ @GuardedBy("this")
+ private DefaultNetworkEvent mCurrentDefaultNetwork;
+ @GuardedBy("this")
+ private boolean mIsCurrentlyValid;
+ @GuardedBy("this")
+ private long mLastValidationTimeMs;
+ // Transport information about the last default network.
+ @GuardedBy("this")
+ private int mLastTransports;
+
+ public DefaultNetworkMetrics() {
+ newDefaultNetwork(creationTimeMs, null);
+ }
+
public synchronized void listEvents(PrintWriter pw) {
+ pw.println("default network events:");
long localTimeMs = System.currentTimeMillis();
- for (DefaultNetworkEvent ev : mEvents) {
- pw.println(ev);
+ long timeMs = SystemClock.elapsedRealtime();
+ for (DefaultNetworkEvent ev : mEventsLog.toArray()) {
+ printEvent(localTimeMs, pw, ev);
+ }
+ mCurrentDefaultNetwork.updateDuration(timeMs);
+ if (mIsCurrentlyValid) {
+ updateValidationTime(timeMs);
+ mLastValidationTimeMs = timeMs;
}
+ printEvent(localTimeMs, pw, mCurrentDefaultNetwork);
}
public synchronized void listEventsAsProto(PrintWriter pw) {
- for (DefaultNetworkEvent ev : mEvents) {
+ for (DefaultNetworkEvent ev : mEventsLog.toArray()) {
pw.print(IpConnectivityEventBuilder.toProto(ev));
}
}
@@ -59,20 +91,75 @@ public class DefaultNetworkMetrics {
mEvents.clear();
}
- public synchronized void logDefaultNetworkEvent(
- NetworkAgentInfo newNai, NetworkAgentInfo prevNai) {
- DefaultNetworkEvent ev = new DefaultNetworkEvent();
- if (newNai != null) {
- ev.netId = newNai.network().netId;
- ev.transportTypes = newNai.networkCapabilities.getTransportTypes();
+ public synchronized void logDefaultNetworkValidity(long timeMs, boolean isValid) {
+ if (!isValid && mIsCurrentlyValid) {
+ mIsCurrentlyValid = false;
+ updateValidationTime(timeMs);
}
- if (prevNai != null) {
- ev.prevNetId = prevNai.network().netId;
- final LinkProperties lp = prevNai.linkProperties;
- ev.prevIPv4 = lp.hasIPv4Address() && lp.hasIPv4DefaultRoute();
- ev.prevIPv6 = lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute();
+
+ if (isValid && !mIsCurrentlyValid) {
+ mIsCurrentlyValid = true;
+ mLastValidationTimeMs = timeMs;
}
+ }
+
+ private void updateValidationTime(long timeMs) {
+ mCurrentDefaultNetwork.validatedMs += timeMs - mLastValidationTimeMs;
+ }
+
+ public synchronized void logDefaultNetworkEvent(
+ long timeMs, NetworkAgentInfo newNai, NetworkAgentInfo oldNai) {
+ logCurrentDefaultNetwork(timeMs, oldNai);
+ newDefaultNetwork(timeMs, newNai);
+ }
+ private void logCurrentDefaultNetwork(long timeMs, NetworkAgentInfo oldNai) {
+ DefaultNetworkEvent ev = mCurrentDefaultNetwork;
+ ev.updateDuration(timeMs);
+ ev.previousTransports = mLastTransports;
+ // oldNai is null if the system had no default network before the transition.
+ if (oldNai != null) {
+ // 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.
+ // This allows to log pairs of transports for successive default networks regardless of
+ // whether or not the system experienced a period without any default network.
+ if (ev.transports != 0) {
+ mLastTransports = ev.transports;
+ }
mEvents.add(ev);
+ mEventsLog.append(ev);
+ }
+
+ private void newDefaultNetwork(long timeMs, NetworkAgentInfo newNai) {
+ DefaultNetworkEvent ev = new DefaultNetworkEvent(timeMs);
+ ev.durationMs = timeMs;
+ // newNai is null if the system has no default network after the transition.
+ if (newNai != null) {
+ fillLinkInfo(ev, newNai);
+ ev.initialScore = newNai.getCurrentScore();
+ if (newNai.lastValidated) {
+ mIsCurrentlyValid = true;
+ mLastValidationTimeMs = timeMs;
+ }
+ }
+ mCurrentDefaultNetwork = ev;
+ }
+
+ private static void fillLinkInfo(DefaultNetworkEvent ev, NetworkAgentInfo nai) {
+ LinkProperties lp = nai.linkProperties;
+ ev.netId = nai.network().netId;
+ ev.transports |= BitUtils.packBits(nai.networkCapabilities.getTransportTypes());
+ ev.ipv4 |= lp.hasIPv4Address() && lp.hasIPv4DefaultRoute();
+ ev.ipv6 |= lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute();
+ }
+
+ private static void printEvent(long localTimeMs, PrintWriter pw, DefaultNetworkEvent ev) {
+ long localCreationTimeMs = localTimeMs - ev.durationMs;
+ pw.println(String.format("%tT.%tL: %s", localCreationTimeMs, localCreationTimeMs, ev));
}
}
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
index 3d71ecb50d9f..397af7ba2991 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
@@ -25,6 +25,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
+import android.net.ConnectivityManager;
import android.net.ConnectivityMetricsEvent;
import android.net.metrics.ApfProgramEvent;
import android.net.metrics.ApfStats;
@@ -45,7 +46,6 @@ import android.util.SparseIntArray;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
-import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.NetworkId;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.Pair;
import java.io.IOException;
import java.util.ArrayList;
@@ -127,6 +127,11 @@ final public class IpConnectivityEventBuilder {
wakeupStats.nonApplicationWakeups = in.nonApplicationWakeups;
wakeupStats.applicationWakeups = in.applicationWakeups;
wakeupStats.noUidWakeups = in.noUidWakeups;
+ wakeupStats.l2UnicastCount = in.l2UnicastCount;
+ wakeupStats.l2MulticastCount = in.l2MulticastCount;
+ wakeupStats.l2BroadcastCount = in.l2BroadcastCount;
+ wakeupStats.ethertypeCounts = toPairArray(in.ethertypes);
+ wakeupStats.ipNextHeaderCounts = toPairArray(in.ipNextHeaders);
final IpConnectivityEvent out = buildEvent(0, 0, in.iface);
out.setWakeupStats(wakeupStats);
return out;
@@ -135,11 +140,17 @@ final public class IpConnectivityEventBuilder {
public static IpConnectivityEvent toProto(DefaultNetworkEvent in) {
IpConnectivityLogClass.DefaultNetworkEvent ev =
new IpConnectivityLogClass.DefaultNetworkEvent();
- ev.networkId = netIdOf(in.netId);
- ev.previousNetworkId = netIdOf(in.prevNetId);
- ev.transportTypes = in.transportTypes;
- ev.previousNetworkIpSupport = ipSupportOf(in);
- final IpConnectivityEvent out = buildEvent(in.netId, 0, null);
+ ev.finalScore = in.finalScore;
+ ev.initialScore = in.initialScore;
+ ev.ipSupport = ipSupportOf(in);
+ ev.defaultNetworkDurationMs = in.durationMs;
+ ev.validationDurationMs = in.validatedMs;
+ ev.previousDefaultNetworkLinkLayer = transportsToLinkLayer(in.previousTransports);
+ final IpConnectivityEvent out = buildEvent(in.netId, in.transports, null);
+ if (in.transports == 0) {
+ // Set link layer to NONE for events representing the absence of a default network.
+ out.linkLayer = IpConnectivityLogClass.NONE;
+ }
out.setDefaultNetworkEvent(ev);
return out;
}
@@ -235,7 +246,6 @@ final public class IpConnectivityEventBuilder {
private static void setNetworkEvent(IpConnectivityEvent out, NetworkEvent in) {
IpConnectivityLogClass.NetworkEvent networkEvent =
new IpConnectivityLogClass.NetworkEvent();
- networkEvent.networkId = netIdOf(in.netId);
networkEvent.eventType = in.eventType;
networkEvent.latencyMs = (int) in.durationMs;
out.setNetworkEvent(networkEvent);
@@ -314,20 +324,14 @@ final public class IpConnectivityEventBuilder {
return pairs;
}
- private static NetworkId netIdOf(int netid) {
- final NetworkId ni = new NetworkId();
- ni.networkId = netid;
- return ni;
- }
-
private static int ipSupportOf(DefaultNetworkEvent in) {
- if (in.prevIPv4 && in.prevIPv6) {
+ if (in.ipv4 && in.ipv6) {
return IpConnectivityLogClass.DefaultNetworkEvent.DUAL;
}
- if (in.prevIPv6) {
+ if (in.ipv6) {
return IpConnectivityLogClass.DefaultNetworkEvent.IPV6;
}
- if (in.prevIPv4) {
+ if (in.ipv4) {
return IpConnectivityLogClass.DefaultNetworkEvent.IPV4;
}
return IpConnectivityLogClass.DefaultNetworkEvent.NONE;
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index 24217e6eef0b..f4278196b576 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -23,8 +23,6 @@ import android.net.INetdEventCallback;
import android.net.metrics.ApfProgramEvent;
import android.net.metrics.IpConnectivityLog;
import android.os.Binder;
-import android.os.IBinder;
-import android.os.Parcelable;
import android.os.Process;
import android.provider.Settings;
import android.text.TextUtils;
@@ -45,6 +43,7 @@ import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.function.ToIntFunction;
@@ -214,86 +213,66 @@ final public class IpConnectivityMetrics extends SystemService {
}
/**
- * Clears the event buffer and prints its content as a protobuf serialized byte array
+ * Clear the event buffer and prints its content as a protobuf serialized byte array
* inside a base64 encoded string.
*/
- private void cmdFlush(FileDescriptor fd, PrintWriter pw, String[] args) {
+ private void cmdFlush(PrintWriter pw) {
pw.print(flushEncodedOutput());
}
/**
- * Prints the content of the event buffer, either using the events ASCII representation
- * or using protobuf text format.
+ * Print the content of the rolling event buffer in human readable format.
+ * Also print network dns/connect statistics and recent default network events.
*/
- private void cmdList(FileDescriptor fd, PrintWriter pw, String[] args) {
- final ArrayList<ConnectivityMetricsEvent> events;
- synchronized (mLock) {
- events = new ArrayList(mBuffer);
- }
-
- if (args.length > 1 && args[1].equals("proto")) {
- for (IpConnectivityEvent ev : IpConnectivityEventBuilder.toProto(events)) {
- pw.print(ev.toString());
- }
- if (mNetdListener != null) {
- mNetdListener.listAsProtos(pw);
- }
- mDefaultNetworkMetrics.listEventsAsProto(pw);
- return;
- }
-
+ private void cmdList(PrintWriter pw) {
+ pw.println("metrics events:");
+ final List<ConnectivityMetricsEvent> events = getEvents();
for (ConnectivityMetricsEvent ev : events) {
pw.println(ev.toString());
}
+ pw.println("");
if (mNetdListener != null) {
mNetdListener.list(pw);
}
+ pw.println("");
mDefaultNetworkMetrics.listEvents(pw);
}
- /**
- * Prints for bug reports the content of the rolling event log and the
- * content of Netd event listener.
+ /*
+ * Print the content of the rolling event buffer in text proto format.
*/
- private void cmdDumpsys(FileDescriptor fd, PrintWriter pw, String[] args) {
- final ConnectivityMetricsEvent[] events;
- synchronized (mLock) {
- events = mEventLog.toArray();
- }
- for (ConnectivityMetricsEvent ev : events) {
- pw.println(ev.toString());
+ private void cmdListAsProto(PrintWriter pw) {
+ final List<ConnectivityMetricsEvent> events = getEvents();
+ for (IpConnectivityEvent ev : IpConnectivityEventBuilder.toProto(events)) {
+ pw.print(ev.toString());
}
if (mNetdListener != null) {
- mNetdListener.list(pw);
+ mNetdListener.listAsProtos(pw);
}
- mDefaultNetworkMetrics.listEvents(pw);
+ mDefaultNetworkMetrics.listEventsAsProto(pw);
}
- private void cmdStats(FileDescriptor fd, PrintWriter pw, String[] args) {
+ /*
+ * Return a copy of metrics events stored in buffer for metrics uploading.
+ */
+ private List<ConnectivityMetricsEvent> getEvents() {
synchronized (mLock) {
- pw.println("Buffered events: " + mBuffer.size());
- pw.println("Buffer capacity: " + mCapacity);
- pw.println("Dropped events: " + mDropped);
- }
- if (mNetdListener != null) {
- mNetdListener.dump(pw);
+ return Arrays.asList(mEventLog.toArray());
}
}
- private void cmdDefault(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (args.length == 0) {
- pw.println("No command");
- return;
- }
- pw.println("Unknown command " + TextUtils.join(" ", args));
- }
-
public final class Impl extends IIpConnectivityMetrics.Stub {
- static final String CMD_FLUSH = "flush";
- static final String CMD_LIST = "list";
- static final String CMD_STATS = "stats";
- static final String CMD_DUMPSYS = "-a"; // dumpsys.cpp dumps services with "-a" as arguments
- static final String CMD_DEFAULT = CMD_STATS;
+ // Dump and flushes the metrics event buffer in base64 encoded serialized proto output.
+ static final String CMD_FLUSH = "flush";
+ // Dump the rolling buffer of metrics event in human readable proto text format.
+ static final String CMD_PROTO = "proto";
+ // Dump the rolling buffer of metrics event and pretty print events using a human readable
+ // format. Also print network dns/connect statistics and default network event time series.
+ static final String CMD_LIST = "list";
+ // By default any other argument will fall into the default case which is remapped to the
+ // "list" command. This includes most notably bug reports collected by dumpsys.cpp with
+ // the "-a" argument.
+ static final String CMD_DEFAULT = CMD_LIST;
@Override
public int logEvent(ConnectivityMetricsEvent event) {
@@ -308,19 +287,15 @@ final public class IpConnectivityMetrics extends SystemService {
final String cmd = (args.length > 0) ? args[0] : CMD_DEFAULT;
switch (cmd) {
case CMD_FLUSH:
- cmdFlush(fd, pw, args);
+ cmdFlush(pw);
return;
- case CMD_DUMPSYS:
- cmdDumpsys(fd, pw, args);
- return;
- case CMD_LIST:
- cmdList(fd, pw, args);
- return;
- case CMD_STATS:
- cmdStats(fd, pw, args);
+ case CMD_PROTO:
+ cmdListAsProto(pw);
return;
+ case CMD_LIST: // fallthrough
default:
- cmdDefault(fd, pw, args);
+ cmdList(pw);
+ return;
}
}
@@ -345,22 +320,22 @@ final public class IpConnectivityMetrics extends SystemService {
}
@Override
- public boolean registerNetdEventCallback(INetdEventCallback callback) {
+ public boolean addNetdEventCallback(int callerType, INetdEventCallback callback) {
enforceNetdEventListeningPermission();
if (mNetdListener == null) {
return false;
}
- return mNetdListener.registerNetdEventCallback(callback);
+ return mNetdListener.addNetdEventCallback(callerType, callback);
}
@Override
- public boolean unregisterNetdEventCallback() {
+ public boolean removeNetdEventCallback(int callerType) {
enforceNetdEventListeningPermission();
if (mNetdListener == null) {
// if the service is null, we aren't registered anyway
return true;
}
- return mNetdListener.unregisterNetdEventCallback();
+ return mNetdListener.removeNetdEventCallback(callerType);
}
};
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 05c6e69c1895..4bdbbe3959b7 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -58,7 +58,6 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
private static final String TAG = NetdEventListenerService.class.getSimpleName();
private static final boolean DBG = false;
- private static final boolean VDBG = false;
// Rate limit connect latency logging to 1 measurement per 15 seconds (5760 / day) with maximum
// bursts of 5000 measurements.
@@ -98,21 +97,55 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
@GuardedBy("this")
private final TokenBucket mConnectTb =
new TokenBucket(CONNECT_LATENCY_FILL_RATE, CONNECT_LATENCY_BURST_LIMIT);
- // Callback should only be registered/unregistered when logging is being enabled/disabled in DPM
- // by the device owner. It's DevicePolicyManager's responsibility to ensure that.
+
+
+ /**
+ * There are only 2 possible callbacks.
+ *
+ * mNetdEventCallbackList[CALLBACK_CALLER_DEVICE_POLICY].
+ * Callback registered/unregistered when logging is being enabled/disabled in DPM
+ * by the device owner. It's DevicePolicyManager's responsibility to ensure that.
+ *
+ * mNetdEventCallbackList[CALLBACK_CALLER_NETWORK_WATCHLIST]
+ * Callback registered/unregistered by NetworkWatchlistService.
+ */
+ @GuardedBy("this")
+ private static final int[] ALLOWED_CALLBACK_TYPES = {
+ INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY,
+ INetdEventCallback.CALLBACK_CALLER_NETWORK_WATCHLIST
+ };
+
@GuardedBy("this")
- private INetdEventCallback mNetdEventCallback;
+ private INetdEventCallback[] mNetdEventCallbackList =
+ new INetdEventCallback[ALLOWED_CALLBACK_TYPES.length];
- public synchronized boolean registerNetdEventCallback(INetdEventCallback callback) {
- mNetdEventCallback = callback;
+ public synchronized boolean addNetdEventCallback(int callerType, INetdEventCallback callback) {
+ if (!isValidCallerType(callerType)) {
+ Log.e(TAG, "Invalid caller type: " + callerType);
+ return false;
+ }
+ mNetdEventCallbackList[callerType] = callback;
return true;
}
- public synchronized boolean unregisterNetdEventCallback() {
- mNetdEventCallback = null;
+ public synchronized boolean removeNetdEventCallback(int callerType) {
+ if (!isValidCallerType(callerType)) {
+ Log.e(TAG, "Invalid caller type: " + callerType);
+ return false;
+ }
+ mNetdEventCallbackList[callerType] = null;
return true;
}
+ private static boolean isValidCallerType(int callerType) {
+ for (int i = 0; i < ALLOWED_CALLBACK_TYPES.length; i++) {
+ if (callerType == ALLOWED_CALLBACK_TYPES[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public NetdEventListenerService(Context context) {
this(context.getSystemService(ConnectivityManager.class));
}
@@ -164,13 +197,13 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
public synchronized void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs,
String hostname, String[] ipAddresses, int ipAddressesCount, int uid)
throws RemoteException {
- maybeVerboseLog("onDnsEvent(%d, %d, %d, %dms)", netId, eventType, returnCode, latencyMs);
-
long timestamp = System.currentTimeMillis();
getMetricsForNetwork(timestamp, netId).addDnsResult(eventType, returnCode, latencyMs);
- if (mNetdEventCallback != null) {
- mNetdEventCallback.onDnsEvent(hostname, ipAddresses, ipAddressesCount, timestamp, uid);
+ for (INetdEventCallback callback : mNetdEventCallbackList) {
+ if (callback != null) {
+ callback.onDnsEvent(hostname, ipAddresses, ipAddressesCount, timestamp, uid);
+ }
}
}
@@ -179,22 +212,23 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
// This method must not block or perform long-running operations.
public synchronized void onConnectEvent(int netId, int error, int latencyMs, String ipAddr,
int port, int uid) throws RemoteException {
- maybeVerboseLog("onConnectEvent(%d, %d, %dms)", netId, error, latencyMs);
-
long timestamp = System.currentTimeMillis();
getMetricsForNetwork(timestamp, netId).addConnectResult(error, latencyMs, ipAddr);
- if (mNetdEventCallback != null) {
- mNetdEventCallback.onConnectEvent(ipAddr, port, timestamp, uid);
+ for (INetdEventCallback callback : mNetdEventCallbackList) {
+ if (callback != null) {
+ // TODO(rickywai): Remove this checking to collect ip in watchlist.
+ if (callback ==
+ mNetdEventCallbackList[INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY]) {
+ callback.onConnectEvent(ipAddr, port, timestamp, uid);
+ }
+ }
}
}
@Override
- public synchronized void onWakeupEvent(String prefix, int uid, int gid, long timestampNs) {
- maybeVerboseLog("onWakeupEvent(%s, %d, %d, %sns)", prefix, uid, gid, timestampNs);
-
- // TODO: add ip protocol and port
-
+ public synchronized void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader,
+ byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs) {
String iface = prefix.replaceFirst(WAKEUP_EVENT_IFACE_PREFIX, "");
final long timestampMs;
if (timestampNs > 0) {
@@ -203,15 +237,22 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
timestampMs = System.currentTimeMillis();
}
- addWakeupEvent(iface, timestampMs, uid);
- }
-
- @GuardedBy("this")
- private void addWakeupEvent(String iface, long timestampMs, int uid) {
WakeupEvent event = new WakeupEvent();
event.iface = iface;
event.timestampMs = timestampMs;
event.uid = uid;
+ event.ethertype = ethertype;
+ event.dstHwAddr = dstHw;
+ event.srcIp = srcIp;
+ event.dstIp = dstIp;
+ event.ipNextHeader = ipNextHeader;
+ event.srcPort = srcPort;
+ event.dstPort = dstPort;
+ addWakeupEvent(event);
+ }
+
+ private void addWakeupEvent(WakeupEvent event) {
+ String iface = event.iface;
mWakeupEvents.append(event);
WakeupStats stats = mWakeupStats.get(iface);
if (stats == null) {
@@ -243,24 +284,21 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
mWakeupStats.clear();
}
- public synchronized void dump(PrintWriter writer) {
- IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
- pw.println(TAG + ":");
- pw.increaseIndent();
- list(pw);
- pw.decreaseIndent();
- }
-
public synchronized void list(PrintWriter pw) {
+ pw.println("dns/connect events:");
for (int i = 0; i < mNetworkMetrics.size(); i++) {
pw.println(mNetworkMetrics.valueAt(i).connectMetrics);
}
for (int i = 0; i < mNetworkMetrics.size(); i++) {
pw.println(mNetworkMetrics.valueAt(i).dnsMetrics);
}
+ pw.println("");
+ pw.println("network statistics:");
for (NetworkMetricsSnapshot s : getNetworkMetricsSnapshots()) {
pw.println(s);
}
+ pw.println("");
+ pw.println("packet wakeup events:");
for (int i = 0; i < mWakeupStats.size(); i++) {
pw.println(mWakeupStats.valueAt(i));
}
@@ -294,10 +332,6 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
if (DBG) Log.d(TAG, String.format(s, args));
}
- private static void maybeVerboseLog(String s, Object... args) {
- if (VDBG) Log.d(TAG, String.format(s, args));
- }
-
/** Helper class for buffering summaries of NetworkMetrics at regular time intervals */
static class NetworkMetricsSnapshot {
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 8b886d6b3cff..768403024353 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -1129,7 +1129,8 @@ public class NetworkMonitor extends StateMachine {
}
private void logNetworkEvent(int evtype) {
- mMetricsLog.log(new NetworkEvent(mNetId, evtype));
+ int[] transports = mNetworkAgentInfo.networkCapabilities.getTransportTypes();
+ mMetricsLog.log(mNetId, transports, new NetworkEvent(evtype));
}
private int networkEventType(ValidationStage s, EvaluationResult r) {
@@ -1150,7 +1151,8 @@ public class NetworkMonitor extends StateMachine {
private void maybeLogEvaluationResult(int evtype) {
if (mEvaluationTimer.isRunning()) {
- mMetricsLog.log(new NetworkEvent(mNetId, evtype, mEvaluationTimer.stop()));
+ int[] transports = mNetworkAgentInfo.networkCapabilities.getTransportTypes();
+ mMetricsLog.log(mNetId, transports, new NetworkEvent(evtype, mEvaluationTimer.stop()));
mEvaluationTimer.reset();
}
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index a44b18dc2d8c..7715727f6d73 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -18,6 +18,8 @@ package com.android.server.connectivity;
import static android.Manifest.permission.BIND_VPN_SERVICE;
import static android.net.ConnectivityManager.NETID_UNSET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
@@ -90,6 +92,8 @@ import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.ConnectivityService;
import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.android.server.net.BaseNetworkObserver;
@@ -245,10 +249,10 @@ public class Vpn {
}
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0, NETWORKTYPE, "");
- // TODO: Copy metered attribute and bandwidths from physical transport, b/16207332
mNetworkCapabilities = new NetworkCapabilities();
mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
+ updateCapabilities();
loadAlwaysOnPackage();
}
@@ -275,6 +279,62 @@ public class Vpn {
updateAlwaysOnNotification(detailedState);
}
+ public void updateCapabilities() {
+ final Network[] underlyingNetworks = (mConfig != null) ? mConfig.underlyingNetworks : null;
+ updateCapabilities(mContext.getSystemService(ConnectivityManager.class), underlyingNetworks,
+ mNetworkCapabilities);
+
+ if (mNetworkAgent != null) {
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
+ }
+
+ @VisibleForTesting
+ public static void updateCapabilities(ConnectivityManager cm, Network[] underlyingNetworks,
+ NetworkCapabilities caps) {
+ int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
+ int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+ int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+ boolean metered = false;
+ boolean roaming = false;
+
+ if (ArrayUtils.isEmpty(underlyingNetworks)) {
+ // No idea what the underlying networks are; assume sane defaults
+ metered = true;
+ roaming = false;
+ } else {
+ for (Network underlying : underlyingNetworks) {
+ final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying);
+ for (int underlyingType : underlyingCaps.getTransportTypes()) {
+ transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType);
+ }
+
+ // When we have multiple networks, we have to assume the
+ // worst-case link speed and restrictions.
+ downKbps = NetworkCapabilities.minBandwidth(downKbps,
+ underlyingCaps.getLinkDownstreamBandwidthKbps());
+ upKbps = NetworkCapabilities.minBandwidth(upKbps,
+ underlyingCaps.getLinkUpstreamBandwidthKbps());
+ metered |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_METERED);
+ roaming |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+ }
+ }
+
+ caps.setTransportTypes(transportTypes);
+ caps.setLinkDownstreamBandwidthKbps(downKbps);
+ caps.setLinkUpstreamBandwidthKbps(upKbps);
+ if (metered) {
+ caps.removeCapability(NET_CAPABILITY_NOT_METERED);
+ } else {
+ caps.addCapability(NET_CAPABILITY_NOT_METERED);
+ }
+ if (roaming) {
+ caps.removeCapability(NET_CAPABILITY_NOT_ROAMING);
+ } else {
+ caps.addCapability(NET_CAPABILITY_NOT_ROAMING);
+ }
+ }
+
/**
* Chooses whether to force all connections to go though VPN.
*
@@ -1344,6 +1404,7 @@ public class Vpn {
}
}
}
+ updateCapabilities();
return true;
}
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
new file mode 100644
index 000000000000..361d92843de9
--- /dev/null
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -0,0 +1,639 @@
+/*
+ * 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 android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ParceledListSlice;
+import android.database.ContentObserver;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.hardware.display.BrightnessChangeEvent;
+import android.net.Uri;
+import android.os.BatteryManager;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.RingBuffer;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+
+import java.util.Deque;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Class that tracks recent brightness settings changes and stores
+ * associated information such as light sensor readings.
+ */
+public class BrightnessTracker {
+
+ private static final String TAG = "BrightnessTracker";
+ private static final boolean DEBUG = false;
+
+ private static final String EVENTS_FILE = "brightness_events.xml";
+ private static final int MAX_EVENTS = 100;
+ // Discard events when reading or writing that are older than this.
+ private static final long MAX_EVENT_AGE = TimeUnit.DAYS.toMillis(30);
+ // Time over which we keep lux sensor readings.
+ private static final long LUX_EVENT_HORIZON = TimeUnit.SECONDS.toNanos(10);
+
+ private static final String TAG_EVENTS = "events";
+ private static final String TAG_EVENT = "event";
+ private static final String ATTR_BRIGHTNESS = "brightness";
+ private static final String ATTR_TIMESTAMP = "timestamp";
+ private static final String ATTR_PACKAGE_NAME = "packageName";
+ private static final String ATTR_USER = "user";
+ private static final String ATTR_LUX = "lux";
+ private static final String ATTR_LUX_TIMESTAMPS = "luxTimestamps";
+ private static final String ATTR_BATTERY_LEVEL = "batteryLevel";
+ private static final String ATTR_NIGHT_MODE = "nightMode";
+ private static final String ATTR_COLOR_TEMPERATURE = "colorTemperature";
+ private static final String ATTR_LAST_BRIGHTNESS = "lastBrightness";
+
+ // Lock held while accessing mEvents, is held while writing events to flash.
+ private final Object mEventsLock = new Object();
+ @GuardedBy("mEventsLock")
+ private RingBuffer<BrightnessChangeEvent> mEvents
+ = new RingBuffer<>(BrightnessChangeEvent.class, MAX_EVENTS);
+ private final Runnable mEventsWriter = () -> writeEvents();
+ private volatile boolean mWriteEventsScheduled;
+
+ private UserManager mUserManager;
+ private final Context mContext;
+ private final ContentResolver mContentResolver;
+ private Handler mBgHandler;
+ // mSettingsObserver, mBroadcastReceiver and mSensorListener should only be used on
+ // the mBgHandler thread.
+ private SettingsObserver mSettingsObserver;
+ private BroadcastReceiver mBroadcastReceiver;
+ private SensorListener mSensorListener;
+
+ // Lock held while collecting data related to brightness changes.
+ private final Object mDataCollectionLock = new Object();
+ @GuardedBy("mDataCollectionLock")
+ private Deque<LightData> mLastSensorReadings = new ArrayDeque<>();
+ @GuardedBy("mDataCollectionLock")
+ private float mLastBatteryLevel = Float.NaN;
+ @GuardedBy("mDataCollectionLock")
+ private int mIgnoreBrightness = -1;
+ @GuardedBy("mDataCollectionLock")
+ private int mLastBrightness = -1;
+
+ private final Injector mInjector;
+
+ public BrightnessTracker(Context context, @Nullable Injector injector) {
+ // Note this will be called very early in boot, other system
+ // services may not be present.
+ mContext = context;
+ mContentResolver = context.getContentResolver();
+ if (injector != null) {
+ mInjector = injector;
+ } else {
+ mInjector = new Injector();
+ }
+ }
+
+ /** Start listening for brightness slider events */
+ public void start() {
+ if (DEBUG) {
+ Slog.d(TAG, "Start");
+ }
+ mBgHandler = mInjector.getBackgroundHandler();
+ mUserManager = mContext.getSystemService(UserManager.class);
+
+ mBgHandler.post(() -> backgroundStart());
+ }
+
+ private void backgroundStart() {
+ readEvents();
+
+ mLastBrightness = mInjector.getSystemIntForUser(mContentResolver,
+ Settings.System.SCREEN_BRIGHTNESS, -1,
+ UserHandle.USER_CURRENT);
+
+ mSensorListener = new SensorListener();
+ mInjector.registerSensorListener(mContext, mSensorListener);
+
+ mSettingsObserver = new SettingsObserver(mBgHandler);
+ mInjector.registerBrightnessObserver(mContentResolver, mSettingsObserver);
+
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_SHUTDOWN);
+ intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ mBroadcastReceiver = new Receiver();
+ mInjector.registerReceiver(mContext, mBroadcastReceiver, intentFilter);
+ }
+
+ /** Stop listening for events */
+ @VisibleForTesting
+ void stop() {
+ if (DEBUG) {
+ Slog.d(TAG, "Stop");
+ }
+ mInjector.unregisterSensorListener(mContext, mSensorListener);
+ mInjector.unregisterReceiver(mContext, mBroadcastReceiver);
+ mInjector.unregisterBrightnessObserver(mContext, mSettingsObserver);
+ }
+
+ /**
+ * @param userId userId to fetch data for.
+ * @return List of recent {@link BrightnessChangeEvent}s
+ */
+ public ParceledListSlice<BrightnessChangeEvent> getEvents(int userId) {
+ // TODO include apps from any managed profiles in the brightness information.
+ BrightnessChangeEvent[] events;
+ synchronized (mEventsLock) {
+ events = mEvents.toArray();
+ }
+ ArrayList<BrightnessChangeEvent> out = new ArrayList<>(events.length);
+ for (int i = 0; i < events.length; ++i) {
+ if (events[i].userId == userId) {
+ out.add(events[i]);
+ }
+ }
+ return new ParceledListSlice<>(out);
+ }
+
+ /** Sets brightness without logging the brightness change event */
+ public void setBrightness(int brightness, int userId) {
+ synchronized (mDataCollectionLock) {
+ mIgnoreBrightness = brightness;
+ }
+ mInjector.putSystemIntForUser(mContentResolver, Settings.System.SCREEN_BRIGHTNESS,
+ brightness, userId);
+ }
+
+ private void handleBrightnessChanged() {
+ if (DEBUG) {
+ Slog.d(TAG, "Brightness change");
+ }
+ final BrightnessChangeEvent event = new BrightnessChangeEvent();
+ event.timeStamp = mInjector.currentTimeMillis();
+
+ int brightness = mInjector.getSystemIntForUser(mContentResolver,
+ Settings.System.SCREEN_BRIGHTNESS, -1,
+ UserHandle.USER_CURRENT);
+
+ synchronized (mDataCollectionLock) {
+ int previousBrightness = mLastBrightness;
+ mLastBrightness = brightness;
+
+ if (brightness == -1 || brightness == mIgnoreBrightness) {
+ // Notified of brightness change but no setting or self change so ignore.
+ mIgnoreBrightness = -1;
+ return;
+ }
+
+ final int readingCount = mLastSensorReadings.size();
+ if (readingCount == 0) {
+ // No sensor data so ignore this.
+ return;
+ }
+
+ event.luxValues = new float[readingCount];
+ event.luxTimestamps = new long[readingCount];
+
+ int pos = 0;
+
+ // Convert sensor timestamp in elapsed time nanos to current time millis.
+ long currentTimeMillis = mInjector.currentTimeMillis();
+ long elapsedTimeNanos = mInjector.elapsedRealtimeNanos();
+ for (LightData reading : mLastSensorReadings) {
+ event.luxValues[pos] = reading.lux;
+ event.luxTimestamps[pos] = currentTimeMillis -
+ TimeUnit.NANOSECONDS.toMillis(elapsedTimeNanos - reading.timestamp);
+ ++pos;
+ }
+
+ event.batteryLevel = mLastBatteryLevel;
+ event.lastBrightness = previousBrightness;
+ }
+
+ event.brightness = brightness;
+
+ try {
+ final ActivityManager.StackInfo focusedStack = mInjector.getFocusedStack();
+ event.userId = focusedStack.userId;
+ event.packageName = focusedStack.topActivity.getPackageName();
+ } catch (RemoteException e) {
+ // Really shouldn't be possible.
+ }
+
+ event.nightMode = mInjector.getSecureIntForUser(mContentResolver,
+ Settings.Secure.NIGHT_DISPLAY_ACTIVATED, 0, UserHandle.USER_CURRENT)
+ == 1;
+ event.colorTemperature = mInjector.getSecureIntForUser(mContentResolver,
+ Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE,
+ 0, UserHandle.USER_CURRENT);
+
+ if (DEBUG) {
+ Slog.d(TAG, "Event " + event.brightness + " " + event.packageName);
+ }
+ synchronized (mEventsLock) {
+ mEvents.append(event);
+ }
+ }
+
+ private void scheduleWriteEvents() {
+ if (!mWriteEventsScheduled) {
+ mBgHandler.post(mEventsWriter);
+ mWriteEventsScheduled = true;
+ }
+ }
+
+ private void writeEvents() {
+ mWriteEventsScheduled = false;
+ // TODO kick off write on handler thread e.g. every 24 hours.
+ synchronized (mEventsLock) {
+ final AtomicFile writeTo = mInjector.getFile();
+ if (writeTo == null) {
+ return;
+ }
+ if (mEvents.isEmpty()) {
+ if (writeTo.exists()) {
+ writeTo.delete();
+ }
+ } else {
+ FileOutputStream output = null;
+ try {
+ output = writeTo.startWrite();
+ writeEventsLocked(output);
+ writeTo.finishWrite(output);
+ } catch (IOException e) {
+ writeTo.failWrite(output);
+ Slog.e(TAG, "Failed to write change mEvents.", e);
+ }
+ }
+ }
+ }
+
+ private void readEvents() {
+ synchronized (mEventsLock) {
+ mEvents.clear();
+ final AtomicFile readFrom = mInjector.getFile();
+ if (readFrom != null && readFrom.exists()) {
+ FileInputStream input = null;
+ try {
+ input = readFrom.openRead();
+ readEventsLocked(input);
+ } catch (IOException e) {
+ readFrom.delete();
+ Slog.e(TAG, "Failed to read change mEvents.", e);
+ } finally {
+ IoUtils.closeQuietly(input);
+ }
+ }
+ }
+ }
+
+ @VisibleForTesting
+ @GuardedBy("mEventsLock")
+ void writeEventsLocked(OutputStream stream) throws IOException {
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, StandardCharsets.UTF_8.name());
+ out.startDocument(null, true);
+ out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+ out.startTag(null, TAG_EVENTS);
+ BrightnessChangeEvent[] toWrite = mEvents.toArray();
+ if (DEBUG) {
+ Slog.d(TAG, "Writing events " + toWrite.length);
+ }
+ final long timeCutOff = System.currentTimeMillis() - MAX_EVENT_AGE;
+ for (int i = 0; i < toWrite.length; ++i) {
+ int userSerialNo = mInjector.getUserSerialNumber(mUserManager, toWrite[i].userId);
+ if (userSerialNo != -1 && toWrite[i].timeStamp > timeCutOff) {
+ out.startTag(null, TAG_EVENT);
+ out.attribute(null, ATTR_BRIGHTNESS, Integer.toString(toWrite[i].brightness));
+ out.attribute(null, ATTR_TIMESTAMP, Long.toString(toWrite[i].timeStamp));
+ out.attribute(null, ATTR_PACKAGE_NAME, toWrite[i].packageName);
+ out.attribute(null, ATTR_USER, Integer.toString(userSerialNo));
+ out.attribute(null, ATTR_BATTERY_LEVEL, Float.toString(toWrite[i].batteryLevel));
+ out.attribute(null, ATTR_NIGHT_MODE, Boolean.toString(toWrite[i].nightMode));
+ out.attribute(null, ATTR_COLOR_TEMPERATURE, Integer.toString(
+ toWrite[i].colorTemperature));
+ out.attribute(null, ATTR_LAST_BRIGHTNESS,
+ Integer.toString(toWrite[i].lastBrightness));
+ StringBuilder luxValues = new StringBuilder();
+ StringBuilder luxTimestamps = new StringBuilder();
+ for (int j = 0; j < toWrite[i].luxValues.length; ++j) {
+ if (j > 0) {
+ luxValues.append(',');
+ luxTimestamps.append(',');
+ }
+ luxValues.append(Float.toString(toWrite[i].luxValues[j]));
+ luxTimestamps.append(Long.toString(toWrite[i].luxTimestamps[j]));
+ }
+ out.attribute(null, ATTR_LUX, luxValues.toString());
+ out.attribute(null, ATTR_LUX_TIMESTAMPS, luxTimestamps.toString());
+ out.endTag(null, TAG_EVENT);
+ }
+ }
+ out.endTag(null, TAG_EVENTS);
+ out.endDocument();
+ stream.flush();
+ }
+
+ @VisibleForTesting
+ @GuardedBy("mEventsLock")
+ void readEventsLocked(InputStream stream) throws IOException {
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, StandardCharsets.UTF_8.name());
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ }
+ String tag = parser.getName();
+ if (!TAG_EVENTS.equals(tag)) {
+ throw new XmlPullParserException(
+ "Events not found in brightness tracker file " + tag);
+ }
+
+ final long timeCutOff = mInjector.currentTimeMillis() - MAX_EVENT_AGE;
+
+ parser.next();
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ tag = parser.getName();
+ if (TAG_EVENT.equals(tag)) {
+ BrightnessChangeEvent event = new BrightnessChangeEvent();
+
+ String brightness = parser.getAttributeValue(null, ATTR_BRIGHTNESS);
+ event.brightness = Integer.parseInt(brightness);
+ String timestamp = parser.getAttributeValue(null, ATTR_TIMESTAMP);
+ event.timeStamp = Long.parseLong(timestamp);
+ event.packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
+ String user = parser.getAttributeValue(null, ATTR_USER);
+ event.userId = mInjector.getUserId(mUserManager, Integer.parseInt(user));
+ String batteryLevel = parser.getAttributeValue(null, ATTR_BATTERY_LEVEL);
+ event.batteryLevel = Float.parseFloat(batteryLevel);
+ String nightMode = parser.getAttributeValue(null, ATTR_NIGHT_MODE);
+ event.nightMode = Boolean.parseBoolean(nightMode);
+ String colorTemperature =
+ parser.getAttributeValue(null, ATTR_COLOR_TEMPERATURE);
+ event.colorTemperature = Integer.parseInt(colorTemperature);
+ String lastBrightness = parser.getAttributeValue(null, ATTR_LAST_BRIGHTNESS);
+ event.lastBrightness = Integer.parseInt(lastBrightness);
+
+ String luxValue = parser.getAttributeValue(null, ATTR_LUX);
+ String luxTimestamp = parser.getAttributeValue(null, ATTR_LUX_TIMESTAMPS);
+
+ String[] luxValues = luxValue.split(",");
+ String[] luxTimestamps = luxTimestamp.split(",");
+ if (luxValues.length != luxTimestamps.length) {
+ continue;
+ }
+ event.luxValues = new float[luxValues.length];
+ event.luxTimestamps = new long[luxValues.length];
+ for (int i = 0; i < luxValues.length; ++i) {
+ event.luxValues[i] = Float.parseFloat(luxValues[i]);
+ event.luxTimestamps[i] = Long.parseLong(luxTimestamps[i]);
+ }
+
+ if (DEBUG) {
+ Slog.i(TAG, "Read event " + event.brightness
+ + " " + event.packageName);
+ }
+
+ if (event.userId != -1 && event.timeStamp > timeCutOff
+ && event.luxValues.length > 0) {
+ mEvents.append(event);
+ }
+ }
+ }
+ } catch (NullPointerException | NumberFormatException | XmlPullParserException
+ | IOException e) {
+ // Failed to parse something, just start with an empty event log.
+ mEvents = new RingBuffer<>(BrightnessChangeEvent.class, MAX_EVENTS);
+ Slog.e(TAG, "Failed to parse brightness event", e);
+ // Re-throw so we will delete the bad file.
+ throw new IOException("failed to parse file", e);
+ }
+ }
+
+ // Not allowed to keep the SensorEvent so used to copy the data we care about.
+ private static class LightData {
+ public float lux;
+ // Time in elapsedRealtimeNanos
+ public long timestamp;
+ }
+
+ private void recordSensorEvent(SensorEvent event) {
+ long horizon = mInjector.elapsedRealtimeNanos() - LUX_EVENT_HORIZON;
+ synchronized (mDataCollectionLock) {
+ if (DEBUG) {
+ Slog.v(TAG, "Sensor event " + event);
+ }
+ if (!mLastSensorReadings.isEmpty()
+ && event.timestamp < mLastSensorReadings.getLast().timestamp) {
+ // Ignore event that came out of order.
+ return;
+ }
+ LightData data = null;
+ while (!mLastSensorReadings.isEmpty()
+ && mLastSensorReadings.getFirst().timestamp < horizon) {
+ // Remove data that has fallen out of the window.
+ data = mLastSensorReadings.removeFirst();
+ }
+ // We put back the last one we removed so we know how long
+ // the first sensor reading was valid for.
+ if (data != null) {
+ mLastSensorReadings.addFirst(data);
+ }
+
+ data = new LightData();
+ data.timestamp = event.timestamp;
+ data.lux = event.values[0];
+ mLastSensorReadings.addLast(data);
+ }
+ }
+
+ private void batteryLevelChanged(int level, int scale) {
+ synchronized (mDataCollectionLock) {
+ mLastBatteryLevel = (float) level / (float) scale;
+ }
+ }
+
+ private final class SensorListener implements SensorEventListener {
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ recordSensorEvent(event);
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+
+ }
+ }
+
+ private final class SettingsObserver extends ContentObserver {
+ public SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (DEBUG) {
+ Slog.v(TAG, "settings change " + uri);
+ }
+ // Self change is based on observer passed to notifyObserver, SettingsProvider
+ // passes null so no changes are self changes.
+ handleBrightnessChanged();
+ }
+ }
+
+ private final class Receiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) {
+ Slog.d(TAG, "Received " + intent.getAction());
+ }
+ String action = intent.getAction();
+ if (Intent.ACTION_SHUTDOWN.equals(action)) {
+ stop();
+ scheduleWriteEvents();
+ } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
+ int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
+ int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
+ if (level != -1 && scale != 0) {
+ batteryLevelChanged(level, scale);
+ }
+ }
+ }
+ }
+
+ @VisibleForTesting
+ static class Injector {
+ public void registerSensorListener(Context context,
+ SensorEventListener sensorListener) {
+ SensorManager sensorManager = context.getSystemService(SensorManager.class);
+ Sensor lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+ sensorManager.registerListener(sensorListener,
+ lightSensor, SensorManager.SENSOR_DELAY_NORMAL);
+ }
+
+ public void unregisterSensorListener(Context context, SensorEventListener sensorListener) {
+ SensorManager sensorManager = context.getSystemService(SensorManager.class);
+ sensorManager.unregisterListener(sensorListener);
+ }
+
+ public void registerBrightnessObserver(ContentResolver resolver,
+ ContentObserver settingsObserver) {
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.SCREEN_BRIGHTNESS),
+ false, settingsObserver, UserHandle.USER_ALL);
+ }
+
+ public void unregisterBrightnessObserver(Context context,
+ ContentObserver settingsObserver) {
+ context.getContentResolver().unregisterContentObserver(settingsObserver);
+ }
+
+ public void registerReceiver(Context context,
+ BroadcastReceiver receiver, IntentFilter filter) {
+ context.registerReceiver(receiver, filter);
+ }
+
+ public void unregisterReceiver(Context context,
+ BroadcastReceiver receiver) {
+ context.unregisterReceiver(receiver);
+ }
+
+ public Handler getBackgroundHandler() {
+ return BackgroundThread.getHandler();
+ }
+
+ public int getSystemIntForUser(ContentResolver resolver, String setting, int defaultValue,
+ int userId) {
+ return Settings.System.getIntForUser(resolver, setting, defaultValue, userId);
+ }
+
+ public void putSystemIntForUser(ContentResolver resolver, String setting, int value,
+ int userId) {
+ Settings.System.putIntForUser(resolver, setting, value, userId);
+ }
+
+ public int getSecureIntForUser(ContentResolver resolver, String setting, int defaultValue,
+ int userId) {
+ return Settings.Secure.getIntForUser(resolver, setting, defaultValue, userId);
+ }
+
+ public AtomicFile getFile() {
+ return new AtomicFile(new File(Environment.getDataSystemDeDirectory(), EVENTS_FILE));
+ }
+
+ public long currentTimeMillis() {
+ return System.currentTimeMillis();
+ }
+
+ public long elapsedRealtimeNanos() {
+ return SystemClock.elapsedRealtimeNanos();
+ }
+
+ public int getUserSerialNumber(UserManager userManager, int userId) {
+ return userManager.getUserSerialNumber(userId);
+ }
+
+ public int getUserId(UserManager userManager, int userSerialNumber) {
+ return userManager.getUserHandle(userSerialNumber);
+ }
+
+ public ActivityManager.StackInfo getFocusedStack() throws RemoteException {
+ return ActivityManager.getService().getFocusedStackInfo();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index a7c3ff9e0104..af8ecadd3c97 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -42,7 +42,7 @@ import android.util.MathUtils;
import android.util.Slog;
import android.view.animation.AnimationUtils;
-import com.android.internal.app.NightDisplayController;
+import com.android.internal.app.ColorDisplayController;
import com.android.server.SystemService;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
@@ -60,10 +60,10 @@ import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MAT
/**
* Tints the display at night.
*/
-public final class NightDisplayService extends SystemService
- implements NightDisplayController.Callback {
+public final class ColorDisplayService extends SystemService
+ implements ColorDisplayController.Callback {
- private static final String TAG = "NightDisplayService";
+ private static final String TAG = "ColorDisplayService";
/**
* The transition time, in milliseconds, for Night Display to turn on/off.
@@ -119,12 +119,12 @@ public final class NightDisplayService extends SystemService
private ContentObserver mUserSetupObserver;
private boolean mBootCompleted;
- private NightDisplayController mController;
+ private ColorDisplayController mController;
private ValueAnimator mColorMatrixAnimator;
private Boolean mIsActivated;
private AutoMode mAutoMode;
- public NightDisplayService(Context context) {
+ public ColorDisplayService(Context context) {
super(context);
mHandler = new Handler(Looper.getMainLooper());
}
@@ -228,7 +228,7 @@ public final class NightDisplayService extends SystemService
Slog.d(TAG, "setUp: currentUser=" + mCurrentUser);
// Create a new controller for the current user and start listening for changes.
- mController = new NightDisplayController(getContext(), mCurrentUser);
+ mController = new ColorDisplayController(getContext(), mCurrentUser);
mController.setListener(this);
setCoefficientMatrix(getContext());
@@ -293,9 +293,9 @@ public final class NightDisplayService extends SystemService
mAutoMode = null;
}
- if (autoMode == NightDisplayController.AUTO_MODE_CUSTOM) {
+ if (autoMode == ColorDisplayController.AUTO_MODE_CUSTOM) {
mAutoMode = new CustomAutoMode();
- } else if (autoMode == NightDisplayController.AUTO_MODE_TWILIGHT) {
+ } else if (autoMode == ColorDisplayController.AUTO_MODE_TWILIGHT) {
mAutoMode = new TwilightAutoMode();
}
@@ -463,7 +463,7 @@ public final class NightDisplayService extends SystemService
return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
}
- private abstract class AutoMode implements NightDisplayController.Callback {
+ private abstract class AutoMode implements ColorDisplayController.Callback {
public abstract void onStart();
public abstract void onStop();
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index d0a1d9e63141..f1e20116d4ed 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -31,9 +31,11 @@ import android.Manifest;
import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
import android.graphics.Point;
import android.hardware.SensorManager;
+import android.hardware.display.BrightnessChangeEvent;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayViewport;
@@ -58,6 +60,7 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.util.IntArray;
import android.util.Slog;
@@ -139,6 +142,7 @@ public final class DisplayManagerService extends SystemService {
private static final int MSG_DELIVER_DISPLAY_EVENT = 3;
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 final Context mContext;
private final DisplayManagerHandler mHandler;
@@ -256,6 +260,8 @@ public final class DisplayManagerService extends SystemService {
private final Injector mInjector;
+ private final BrightnessTracker mBrightnessTracker;
+
public DisplayManagerService(Context context) {
this(context, new Injector());
}
@@ -274,6 +280,7 @@ public final class DisplayManagerService extends SystemService {
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
+ mBrightnessTracker = new BrightnessTracker(context, null);
}
public void setupSchedulerPolicies() {
@@ -350,6 +357,7 @@ public final class DisplayManagerService extends SystemService {
}
mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
+ mHandler.sendEmptyMessage(MSG_REGISTER_BRIGHTNESS_TRACKER);
}
@VisibleForTesting
@@ -1352,6 +1360,10 @@ public final class DisplayManagerService extends SystemService {
mTempExternalTouchViewport, mTempVirtualTouchViewports);
break;
}
+
+ case MSG_REGISTER_BRIGHTNESS_TRACKER:
+ mBrightnessTracker.start();
+ break;
}
}
}
@@ -1736,6 +1748,35 @@ public final class DisplayManagerService extends SystemService {
}
}
+ @Override // Binder call
+ public ParceledListSlice<BrightnessChangeEvent> getBrightnessEvents() {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.BRIGHTNESS_SLIDER_USAGE,
+ "Permission to read brightness events.");
+ int userId = UserHandle.getUserId(Binder.getCallingUid());
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return mBrightnessTracker.getEvents(userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
+ public void setBrightness(int brightness) {
+ // STOPSHIP - remove when adaptive brightness controller accepts curves.
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.BRIGHTNESS_SLIDER_USAGE,
+ "Permission to set brightness.");
+ int userId = UserHandle.getUserId(Binder.getCallingUid());
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mBrightnessTracker.setBrightness(brightness, userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private boolean validatePackageName(int uid, String packageName) {
if (packageName != null) {
String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index f930b523e626..600bc42e970c 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1120,6 +1120,27 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Dismiss the black surface without fanfare.
mPowerState.setColorFadeLevel(1.0f);
mPowerState.dismissColorFade();
+ } else if (target == Display.STATE_ON_SUSPEND) {
+ // Want screen full-power and suspended.
+ // Wait for brightness animation to complete beforehand unless already
+ // suspended because we may not be able to change it after suspension.
+ if (mScreenBrightnessRampAnimator.isAnimating()
+ && mPowerState.getScreenState() != Display.STATE_ON_SUSPEND) {
+ return;
+ }
+
+ // If not already suspending, temporarily set the state to on until the
+ // screen on is unblocked, then suspend.
+ if (mPowerState.getScreenState() != Display.STATE_ON_SUSPEND) {
+ if (!setScreenState(Display.STATE_ON)) {
+ return;
+ }
+ setScreenState(Display.STATE_ON_SUSPEND);
+ }
+
+ // Dismiss the black surface without fanfare.
+ mPowerState.setColorFadeLevel(1.0f);
+ mPowerState.dismissColorFade();
} else {
// Want screen off.
mPendingScreenOff = true;
diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java
index bef6898a4ecf..338e3311fe3b 100644
--- a/services/core/java/com/android/server/display/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/DisplayTransformManager.java
@@ -29,7 +29,7 @@ import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.NightDisplayController;
+import com.android.internal.app.ColorDisplayController;
import java.util.Arrays;
/**
@@ -223,13 +223,13 @@ public class DisplayTransformManager {
}
public boolean setColorMode(int colorMode) {
- if (colorMode == NightDisplayController.COLOR_MODE_NATURAL) {
+ if (colorMode == ColorDisplayController.COLOR_MODE_NATURAL) {
applySaturation(COLOR_SATURATION_NATURAL);
setNativeMode(false);
- } else if (colorMode == NightDisplayController.COLOR_MODE_BOOSTED) {
+ } else if (colorMode == ColorDisplayController.COLOR_MODE_BOOSTED) {
applySaturation(COLOR_SATURATION_BOOSTED);
setNativeMode(false);
- } else if (colorMode == NightDisplayController.COLOR_MODE_SATURATED) {
+ } else if (colorMode == ColorDisplayController.COLOR_MODE_SATURATED) {
applySaturation(COLOR_SATURATION_NATURAL);
setNativeMode(true);
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index d61a418c30a2..eb9ff589d5f6 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -22,6 +22,7 @@ import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
import android.content.Context;
+import android.hardware.sidekick.SidekickInternal;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
@@ -35,7 +36,6 @@ import android.view.Display;
import android.view.DisplayEventReceiver;
import android.view.Surface;
import android.view.SurfaceControl;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -148,6 +148,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return SurfaceControl.POWER_MODE_DOZE;
case Display.STATE_DOZE_SUSPEND:
return SurfaceControl.POWER_MODE_DOZE_SUSPEND;
+ case Display.STATE_ON_SUSPEND:
+ return SurfaceControl.POWER_MODE_ON_SUSPEND;
default:
return SurfaceControl.POWER_MODE_NORMAL;
}
@@ -170,6 +172,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private int mActiveColorMode;
private boolean mActiveColorModeInvalid;
private Display.HdrCapabilities mHdrCapabilities;
+ private boolean mSidekickActive;
+ private SidekickInternal mSidekickInternal;
private SurfaceControl.PhysicalDisplayInfo mDisplayInfos[];
@@ -181,6 +185,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
updatePhysicalDisplayInfoLocked(physicalDisplayInfos, activeDisplayInfo,
colorModes, activeColorMode);
updateColorModesLocked(colorModes, activeColorMode);
+ mSidekickInternal = LocalServices.getService(SidekickInternal.class);
if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
LightsManager lights = LocalServices.getService(LightsManager.class);
mBacklight = lights.getLight(LightsManager.LIGHT_ID_BACKLIGHT);
@@ -467,6 +472,10 @@ final class LocalDisplayAdapter extends DisplayAdapter {
|| oldState == Display.STATE_DOZE_SUSPEND) {
setDisplayState(Display.STATE_DOZE);
currentState = Display.STATE_DOZE;
+ } else if (state == Display.STATE_ON_SUSPEND
+ || oldState == Display.STATE_ON_SUSPEND) {
+ setDisplayState(Display.STATE_ON);
+ currentState = Display.STATE_ON;
} else {
return; // old state and new state is off
}
@@ -510,16 +519,40 @@ final class LocalDisplayAdapter extends DisplayAdapter {
+ ", state=" + Display.stateToString(state) + ")");
}
+ // We must tell sidekick to stop controlling the display before we
+ // can change its power mode, so do that first.
+ if (mSidekickActive) {
+ Trace.traceBegin(Trace.TRACE_TAG_POWER,
+ "SidekickInternal#endDisplayControl");
+ try {
+ mSidekickInternal.endDisplayControl();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
+ mSidekickActive = false;
+ }
+ final int mode = getPowerModeForState(state);
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayState("
+ "id=" + displayId
+ ", state=" + Display.stateToString(state) + ")");
try {
- final int mode = getPowerModeForState(state);
SurfaceControl.setDisplayPowerMode(token, mode);
Trace.traceCounter(Trace.TRACE_TAG_POWER, "DisplayPowerMode", mode);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
+ // If we're entering a suspended (but not OFF) power state and we
+ // have a sidekick available, tell it now that it can take control.
+ if (Display.isSuspendedState(state) && state != Display.STATE_OFF
+ && mSidekickInternal != null && !mSidekickActive) {
+ Trace.traceBegin(Trace.TRACE_TAG_POWER,
+ "SidekickInternal#startDisplayControl");
+ try {
+ mSidekickActive = mSidekickInternal.startDisplayControl(state);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
+ }
}
private void setDisplayBrightness(int brightness) {
diff --git a/services/core/java/com/android/server/job/JobPackageTracker.java b/services/core/java/com/android/server/job/JobPackageTracker.java
index 025ff0b08341..296743b57103 100644
--- a/services/core/java/com/android/server/job/JobPackageTracker.java
+++ b/services/core/java/com/android/server/job/JobPackageTracker.java
@@ -16,15 +16,19 @@
package com.android.server.job;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+import static com.android.server.job.JobSchedulerService.sSystemClock;
+import static com.android.server.job.JobSchedulerService.sUptimeMillisClock;
+
import android.app.job.JobInfo;
import android.app.job.JobParameters;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
+
import com.android.internal.util.RingBufferIndices;
import com.android.server.job.controllers.JobStatus;
@@ -57,7 +61,7 @@ public final class JobPackageTracker {
public void addEvent(int cmd, int uid, String tag, int jobId, int stopReason) {
int index = mEventIndices.add();
mEventCmds[index] = cmd | ((stopReason<<EVENT_STOP_REASON_SHIFT) & EVENT_STOP_REASON_MASK);
- mEventTimes[index] = SystemClock.elapsedRealtime();
+ mEventTimes[index] = sElapsedRealtimeClock.millis();
mEventUids[index] = uid;
mEventTags[index] = tag;
mEventJobIds[index] = jobId;
@@ -125,9 +129,9 @@ public final class JobPackageTracker {
}
public DataSet() {
- mStartUptimeTime = SystemClock.uptimeMillis();
- mStartElapsedTime = SystemClock.elapsedRealtime();
- mStartClockTime = System.currentTimeMillis();
+ mStartUptimeTime = sUptimeMillisClock.millis();
+ mStartElapsedTime = sElapsedRealtimeClock.millis();
+ mStartClockTime = sSystemClock.millis();
}
private PackageEntry getOrCreateEntry(int uid, String pkg) {
@@ -376,20 +380,20 @@ public final class JobPackageTracker {
}
public void notePending(JobStatus job) {
- final long now = SystemClock.uptimeMillis();
+ final long now = sUptimeMillisClock.millis();
job.madePending = now;
rebatchIfNeeded(now);
mCurDataSet.incPending(job.getSourceUid(), job.getSourcePackageName(), now);
}
public void noteNonpending(JobStatus job) {
- final long now = SystemClock.uptimeMillis();
+ final long now = sUptimeMillisClock.millis();
mCurDataSet.decPending(job.getSourceUid(), job.getSourcePackageName(), now);
rebatchIfNeeded(now);
}
public void noteActive(JobStatus job) {
- final long now = SystemClock.uptimeMillis();
+ final long now = sUptimeMillisClock.millis();
job.madeActive = now;
rebatchIfNeeded(now);
if (job.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
@@ -402,7 +406,7 @@ public final class JobPackageTracker {
}
public void noteInactive(JobStatus job, int stopReason) {
- final long now = SystemClock.uptimeMillis();
+ final long now = sUptimeMillisClock.millis();
if (job.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
mCurDataSet.decActiveTop(job.getSourceUid(), job.getSourcePackageName(), now,
stopReason);
@@ -431,7 +435,7 @@ public final class JobPackageTracker {
if (cur == null && last == null) {
return 0;
}
- final long now = SystemClock.uptimeMillis();
+ final long now = sUptimeMillisClock.millis();
long time = 0;
if (cur != null) {
time += cur.getActiveTime(now) + cur.getPendingTime(now);
@@ -445,8 +449,8 @@ public final class JobPackageTracker {
}
public void dump(PrintWriter pw, String prefix, int filterUid) {
- final long now = SystemClock.uptimeMillis();
- final long nowEllapsed = SystemClock.elapsedRealtime();
+ final long now = sUptimeMillisClock.millis();
+ final long nowEllapsed = sElapsedRealtimeClock.millis();
final DataSet total;
if (mLastDataSets[0] != null) {
total = new DataSet(mLastDataSets[0]);
@@ -470,7 +474,7 @@ public final class JobPackageTracker {
return false;
}
pw.println(" Job history:");
- final long now = SystemClock.elapsedRealtime();
+ final long now = sElapsedRealtimeClock.millis();
for (int i=0; i<size; i++) {
final int index = mEventIndices.indexOf(i);
final int uid = mEventUids[index];
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 78aa2f946ffc..b9777ec0d968 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -19,24 +19,15 @@ package com.android.server.job;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.IUidObserver;
+import android.app.job.IJobScheduler;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
-import android.app.job.IJobScheduler;
import android.app.job.JobWorkItem;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -46,8 +37,8 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.BatteryStats;
@@ -55,8 +46,8 @@ import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.Process;
import android.os.PowerManager;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -71,6 +62,7 @@ import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.util.ArrayUtils;
@@ -93,6 +85,16 @@ import com.android.server.job.controllers.TimeController;
import libcore.util.EmptyArray;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.time.Clock;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
/**
* Responsible for taking jobs representing work to be performed by a client app, and determining
* based on the criteria specified when that job should be run against the client application's
@@ -117,6 +119,12 @@ public final class JobSchedulerService extends com.android.server.SystemService
/** The maximum number of jobs that we allow an unprivileged app to schedule */
private static final int MAX_JOBS_PER_APP = 100;
+ @VisibleForTesting
+ public static Clock sSystemClock = Clock.systemUTC();
+ @VisibleForTesting
+ public static Clock sUptimeMillisClock = SystemClock.uptimeMillisClock();
+ @VisibleForTesting
+ public static Clock sElapsedRealtimeClock = SystemClock.elapsedRealtimeClock();
/** Global local for all job scheduler state. */
final Object mLock = new Object();
@@ -614,24 +622,15 @@ public final class JobSchedulerService extends com.android.server.SystemService
if (disabled) {
cancelJobsForUid(uid, "uid gone");
}
- synchronized (mLock) {
- mBackgroundJobsController.setUidActiveLocked(uid, false);
- }
}
@Override public void onUidActive(int uid) throws RemoteException {
- synchronized (mLock) {
- mBackgroundJobsController.setUidActiveLocked(uid, true);
- }
}
@Override public void onUidIdle(int uid, boolean disabled) {
if (disabled) {
cancelJobsForUid(uid, "app uid idle");
}
- synchronized (mLock) {
- mBackgroundJobsController.setUidActiveLocked(uid, false);
- }
}
@Override public void onUidCachedChanged(int uid, boolean cached) {
@@ -960,7 +959,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) {
// When we reach clock sanity, recalculate the temporal windows
// of all affected jobs.
- if (mJobs.clockNowValidToInflate(System.currentTimeMillis())) {
+ if (mJobs.clockNowValidToInflate(sSystemClock.millis())) {
Slog.i(TAG, "RTC now valid; recalculating persisted job windows");
// We've done our job now, so stop watching the time.
@@ -1068,7 +1067,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
if (!jobStatus.isPreparedLocked()) {
Slog.wtf(TAG, "Not yet prepared when started tracking: " + jobStatus);
}
- jobStatus.enqueueTime = SystemClock.elapsedRealtime();
+ jobStatus.enqueueTime = sElapsedRealtimeClock.millis();
final boolean update = mJobs.add(jobStatus);
if (mReadyToRock) {
for (int i = 0; i < mControllers.size(); i++) {
@@ -1156,7 +1155,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
* @see #maybeQueueReadyJobsForExecutionLocked
*/
private JobStatus getRescheduleJobForFailureLocked(JobStatus failureToReschedule) {
- final long elapsedNowMillis = SystemClock.elapsedRealtime();
+ final long elapsedNowMillis = sElapsedRealtimeClock.millis();
final JobInfo job = failureToReschedule.getJob();
final long initialBackoffMillis = job.getInitialBackoffMillis();
@@ -1200,7 +1199,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
JobStatus newJob = new JobStatus(failureToReschedule, elapsedNowMillis + delayMillis,
JobStatus.NO_LATEST_RUNTIME, backoffAttempts,
- failureToReschedule.getLastSuccessfulRunTime(), System.currentTimeMillis());
+ failureToReschedule.getLastSuccessfulRunTime(), sSystemClock.millis());
for (int ic=0; ic<mControllers.size(); ic++) {
StateController controller = mControllers.get(ic);
controller.rescheduleForFailureLocked(newJob, failureToReschedule);
@@ -1220,7 +1219,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
* recurring job.
*/
private JobStatus getRescheduleJobForPeriodic(JobStatus periodicToReschedule) {
- final long elapsedNow = SystemClock.elapsedRealtime();
+ final long elapsedNow = sElapsedRealtimeClock.millis();
// Compute how much of the period is remaining.
long runEarly = 0L;
@@ -1239,7 +1238,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
}
return new JobStatus(periodicToReschedule, newEarliestRunTimeElapsed,
newLatestRuntimeElapsed, 0 /* backoffAttempt */,
- System.currentTimeMillis() /* lastSuccessfulRunTime */,
+ sSystemClock.millis() /* lastSuccessfulRunTime */,
periodicToReschedule.getLastFailedRunTime());
}
@@ -2367,8 +2366,8 @@ public final class JobSchedulerService extends com.android.server.SystemService
}
final int filterUidFinal = UserHandle.getAppId(filterUid);
- final long nowElapsed = SystemClock.elapsedRealtime();
- final long nowUptime = SystemClock.uptimeMillis();
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ final long nowUptime = sUptimeMillisClock.millis();
synchronized (mLock) {
mConstants.dump(pw);
pw.println();
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index a7e674b5a3a1..ac7297e611a7 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -16,11 +16,13 @@
package com.android.server.job;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+
import android.app.ActivityManager;
-import android.app.job.JobInfo;
-import android.app.job.JobParameters;
import android.app.job.IJobCallback;
import android.app.job.IJobService;
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
import android.app.job.JobWorkItem;
import android.content.ComponentName;
import android.content.Context;
@@ -34,7 +36,6 @@ import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
import android.util.Slog;
@@ -202,7 +203,7 @@ public final class JobServiceContext implements ServiceConnection {
mRunningCallback = new JobCallback();
final boolean isDeadlineExpired =
job.hasDeadlineConstraint() &&
- (job.getLatestRunTimeElapsed() < SystemClock.elapsedRealtime());
+ (job.getLatestRunTimeElapsed() < sElapsedRealtimeClock.millis());
Uri[] triggeredUris = null;
if (job.changedUris != null) {
triggeredUris = new Uri[job.changedUris.size()];
@@ -217,7 +218,7 @@ public final class JobServiceContext implements ServiceConnection {
mParams = new JobParameters(mRunningCallback, job.getJobId(), ji.getExtras(),
ji.getTransientExtras(), ji.getClipData(), ji.getClipGrantFlags(),
isDeadlineExpired, triggeredUris, triggeredAuthorities, job.network);
- mExecutionStartTimeElapsed = SystemClock.elapsedRealtime();
+ mExecutionStartTimeElapsed = sElapsedRealtimeClock.millis();
// Once we'e begun executing a job, we by definition no longer care whether
// it was inflated from disk with not-yet-coherent delay/deadline bounds.
@@ -428,7 +429,7 @@ public final class JobServiceContext implements ServiceConnection {
sb.append("Caller no longer running");
if (cb.mStoppedReason != null) {
sb.append(", last stopped ");
- TimeUtils.formatDuration(SystemClock.elapsedRealtime() - cb.mStoppedTime, sb);
+ TimeUtils.formatDuration(sElapsedRealtimeClock.millis() - cb.mStoppedTime, sb);
sb.append(" because: ");
sb.append(cb.mStoppedReason);
}
@@ -457,7 +458,7 @@ public final class JobServiceContext implements ServiceConnection {
sb.append("Ignoring timeout of no longer active job");
if (jc.mStoppedReason != null) {
sb.append(", stopped ");
- TimeUtils.formatDuration(SystemClock.elapsedRealtime()
+ TimeUtils.formatDuration(sElapsedRealtimeClock.millis()
- jc.mStoppedTime, sb);
sb.append(" because: ");
sb.append(jc.mStoppedReason);
@@ -740,7 +741,7 @@ public final class JobServiceContext implements ServiceConnection {
private void applyStoppedReasonLocked(String reason) {
if (reason != null && mStoppedReason == null) {
mStoppedReason = reason;
- mStoppedTime = SystemClock.elapsedRealtime();
+ mStoppedTime = sElapsedRealtimeClock.millis();
if (mRunningCallback != null) {
mRunningCallback.mStoppedReason = mStoppedReason;
mRunningCallback.mStoppedTime = mStoppedTime;
@@ -777,7 +778,7 @@ public final class JobServiceContext implements ServiceConnection {
}
Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT, mRunningCallback);
mCallbackHandler.sendMessageDelayed(m, timeoutMillis);
- mTimeoutElapsed = SystemClock.elapsedRealtime() + timeoutMillis;
+ mTimeoutElapsed = sElapsedRealtimeClock.millis() + timeoutMillis;
}
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index aa9f77c839e5..1af3b39e928b 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -16,20 +16,23 @@
package com.android.server.job;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+import static com.android.server.job.JobSchedulerService.sSystemClock;
+
import android.app.ActivityManager;
import android.app.IActivityManager;
-import android.content.ComponentName;
import android.app.job.JobInfo;
+import android.content.ComponentName;
import android.content.Context;
+import android.net.NetworkRequest;
import android.os.Environment;
import android.os.Handler;
import android.os.PersistableBundle;
import android.os.Process;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.text.format.DateUtils;
-import android.util.AtomicFile;
import android.util.ArraySet;
+import android.util.AtomicFile;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -37,11 +40,16 @@ import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.BitUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.IoThread;
import com.android.server.job.JobSchedulerInternal.JobStorePersistStats;
import com.android.server.job.controllers.JobStatus;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -53,10 +61,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Set;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
/**
* Maintains the master list of jobs that the job scheduler is tracking. These jobs are compared by
* reference, so none of the functions in this class should make a copy.
@@ -141,7 +145,7 @@ public final class JobStore {
// a *correct* timestamp, see a bunch of overdue jobs, and run them; then
// settle into normal operation.
mXmlTimestamp = mJobsFile.getLastModifiedTime();
- mRtcGood = (System.currentTimeMillis() > mXmlTimestamp);
+ mRtcGood = (sSystemClock.millis() > mXmlTimestamp);
readJobMapFromDisk(mJobSet, mRtcGood);
}
@@ -161,7 +165,7 @@ public final class JobStore {
*/
public void getRtcCorrectedJobsLocked(final ArrayList<JobStatus> toAdd,
final ArrayList<JobStatus> toRemove) {
- final long elapsedNow = SystemClock.elapsedRealtime();
+ final long elapsedNow = sElapsedRealtimeClock.millis();
// Find the jobs that need to be fixed up, collecting them for post-iteration
// replacement with their new versions
@@ -323,7 +327,7 @@ public final class JobStore {
private final Runnable mWriteRunnable = new Runnable() {
@Override
public void run() {
- final long startElapsed = SystemClock.elapsedRealtime();
+ final long startElapsed = sElapsedRealtimeClock.millis();
final List<JobStatus> storeCopy = new ArrayList<JobStatus>();
synchronized (mLock) {
// Clone the jobs so we can release the lock before writing.
@@ -338,7 +342,7 @@ public final class JobStore {
}
writeJobsMapImpl(storeCopy);
if (DEBUG) {
- Slog.v(TAG, "Finished writing, took " + (SystemClock.elapsedRealtime()
+ Slog.v(TAG, "Finished writing, took " + (sElapsedRealtimeClock.millis()
- startElapsed) + "ms");
}
}
@@ -454,17 +458,12 @@ public final class JobStore {
*/
private void writeConstraintsToXml(XmlSerializer out, JobStatus jobStatus) throws IOException {
out.startTag(null, XML_TAG_PARAMS_CONSTRAINTS);
- if (jobStatus.needsAnyConnectivity()) {
- out.attribute(null, "connectivity", Boolean.toString(true));
- }
- if (jobStatus.needsMeteredConnectivity()) {
- out.attribute(null, "metered", Boolean.toString(true));
- }
- if (jobStatus.needsUnmeteredConnectivity()) {
- out.attribute(null, "unmetered", Boolean.toString(true));
- }
- if (jobStatus.needsNonRoamingConnectivity()) {
- out.attribute(null, "not-roaming", Boolean.toString(true));
+ if (jobStatus.hasConnectivityConstraint()) {
+ final NetworkRequest network = jobStatus.getJob().getRequiredNetwork();
+ out.attribute(null, "net-capabilities", Long.toString(
+ BitUtils.packBits(network.networkCapabilities.getCapabilities())));
+ out.attribute(null, "net-transport-types", Long.toString(
+ BitUtils.packBits(network.networkCapabilities.getTransportTypes())));
}
if (jobStatus.hasIdleConstraint()) {
out.attribute(null, "idle", Boolean.toString(true));
@@ -497,8 +496,8 @@ public final class JobStore {
Slog.i(TAG, "storing original UTC timestamps for " + jobStatus);
}
- final long nowRTC = System.currentTimeMillis();
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long nowRTC = sSystemClock.millis();
+ final long nowElapsed = sElapsedRealtimeClock.millis();
if (jobStatus.hasDeadlineConstraint()) {
// Wall clock deadline.
final long deadlineWallclock = (utcJobTimes == null)
@@ -538,7 +537,7 @@ public final class JobStore {
*/
private static Pair<Long, Long> convertRtcBoundsToElapsed(Pair<Long, Long> rtcTimes,
long nowElapsed) {
- final long nowWallclock = System.currentTimeMillis();
+ final long nowWallclock = sSystemClock.millis();
final long earliest = (rtcTimes.first > JobStatus.NO_EARLIEST_RUNTIME)
? nowElapsed + Math.max(rtcTimes.first - nowWallclock, 0)
: JobStatus.NO_EARLIEST_RUNTIME;
@@ -581,7 +580,7 @@ public final class JobStore {
synchronized (mLock) {
jobs = readJobMapImpl(fis, rtcGood);
if (jobs != null) {
- long now = SystemClock.elapsedRealtime();
+ long now = sElapsedRealtimeClock.millis();
IActivityManager am = ActivityManager.getService();
for (int i=0; i<jobs.size(); i++) {
JobStatus js = jobs.get(i);
@@ -754,7 +753,7 @@ public final class JobStore {
return null;
}
- final long elapsedNow = SystemClock.elapsedRealtime();
+ final long elapsedNow = sElapsedRealtimeClock.millis();
Pair<Long, Long> elapsedRuntimes = convertRtcBoundsToElapsed(rtcRuntimes, elapsedNow);
if (XML_TAG_PERIODIC.equals(parser.getName())) {
@@ -862,22 +861,38 @@ public final class JobStore {
}
private void buildConstraintsFromXml(JobInfo.Builder jobBuilder, XmlPullParser parser) {
- String val = parser.getAttributeValue(null, "connectivity");
- if (val != null) {
- jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
- }
- val = parser.getAttributeValue(null, "metered");
- if (val != null) {
- jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_METERED);
- }
- val = parser.getAttributeValue(null, "unmetered");
- if (val != null) {
- jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
- }
- val = parser.getAttributeValue(null, "not-roaming");
- if (val != null) {
- jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_NOT_ROAMING);
+ String val;
+
+ final String netCapabilities = parser.getAttributeValue(null, "net-capabilities");
+ final String netTransportTypes = parser.getAttributeValue(null, "net-transport-types");
+ if (netCapabilities != null && netTransportTypes != null) {
+ final NetworkRequest request = new NetworkRequest.Builder().build();
+ // We're okay throwing NFE here; caught by caller
+ request.networkCapabilities.setCapabilities(
+ BitUtils.unpackBits(Long.parseLong(netCapabilities)));
+ request.networkCapabilities.setTransportTypes(
+ BitUtils.unpackBits(Long.parseLong(netTransportTypes)));
+ jobBuilder.setRequiredNetwork(request);
+ } else {
+ // Read legacy values
+ val = parser.getAttributeValue(null, "connectivity");
+ if (val != null) {
+ jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+ }
+ val = parser.getAttributeValue(null, "metered");
+ if (val != null) {
+ jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_METERED);
+ }
+ val = parser.getAttributeValue(null, "unmetered");
+ if (val != null) {
+ jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
+ }
+ val = parser.getAttributeValue(null, "not-roaming");
+ if (val != null) {
+ jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_NOT_ROAMING);
+ }
}
+
val = parser.getAttributeValue(null, "idle");
if (val != null) {
jobBuilder.setRequiresDeviceIdle(true);
@@ -937,8 +952,8 @@ public final class JobStore {
private Pair<Long, Long> buildExecutionTimesFromXml(XmlPullParser parser)
throws NumberFormatException {
// Pull out execution time data.
- final long nowWallclock = System.currentTimeMillis();
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long nowWallclock = sSystemClock.millis();
+ final long nowElapsed = sElapsedRealtimeClock.millis();
long earliestRunTimeElapsed = JobStatus.NO_EARLIEST_RUNTIME;
long latestRunTimeElapsed = JobStatus.NO_LATEST_RUNTIME;
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
index 39f2a96b30e3..caa8522089c6 100644
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -174,7 +174,7 @@ public final class AppIdleController extends StateController {
private final class AppIdleStateChangeListener
extends UsageStatsManagerInternal.AppIdleStateChangeListener {
@Override
- public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
+ public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket) {
boolean changed = false;
synchronized (mLock) {
if (mAppIdleParoleOn) {
diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
index 78b4160e8614..f67bd0469b24 100644
--- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -16,7 +16,6 @@
package com.android.server.job.controllers;
-import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -25,19 +24,20 @@ import android.os.IDeviceIdleController;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.os.UserHandle;
-import android.util.ArraySet;
+import android.util.Pair;
import android.util.Slog;
-import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import com.android.internal.app.IAppOpsCallback;
-import com.android.internal.app.IAppOpsService;
import com.android.internal.util.ArrayUtils;
+import com.android.server.ForceAppStandbyTracker;
+import com.android.server.ForceAppStandbyTracker.Listener;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.JobStore;
import java.io.PrintWriter;
+import java.util.function.Predicate;
public final class BackgroundJobsController extends StateController {
@@ -49,18 +49,13 @@ public final class BackgroundJobsController extends StateController {
private static volatile BackgroundJobsController sController;
private final JobSchedulerService mJobSchedulerService;
- private final IAppOpsService mAppOpsService;
private final IDeviceIdleController mDeviceIdleController;
- private final SparseBooleanArray mForegroundUids;
private int[] mPowerWhitelistedUserAppIds;
private int[] mTempWhitelistedAppIds;
- /**
- * Only tracks jobs for which source package app op RUN_ANY_IN_BACKGROUND is not ALLOWED.
- * Maps jobs to the sourceUid unlike the global {@link JobSchedulerService#mJobs JobStore}
- * which uses callingUid.
- */
- private SparseArray<ArraySet<JobStatus>> mTrackedJobs;
+
+ private final ForceAppStandbyTracker mForceAppStandbyTracker;
+
public static BackgroundJobsController get(JobSchedulerService service) {
synchronized (sCreationLock) {
@@ -89,9 +84,7 @@ public final class BackgroundJobsController extends StateController {
} catch (RemoteException rexc) {
Slog.e(LOG_TAG, "Device idle controller not reachable");
}
- if (checkAllTrackedJobsLocked()) {
- mStateChangedListener.onControllerStateChanged();
- }
+ updateAllJobRestrictionsLocked();
}
}
};
@@ -99,16 +92,12 @@ public final class BackgroundJobsController extends StateController {
private BackgroundJobsController(JobSchedulerService service, Context context, Object lock) {
super(service, context, lock);
mJobSchedulerService = service;
- mAppOpsService = IAppOpsService.Stub.asInterface(
- ServiceManager.getService(Context.APP_OPS_SERVICE));
mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
- mForegroundUids = new SparseBooleanArray();
- mTrackedJobs = new SparseArray<>();
+ mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
+
try {
- mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, null,
- new AppOpsWatcher());
mPowerWhitelistedUserAppIds = mDeviceIdleController.getAppIdUserWhitelist();
mTempWhitelistedAppIds = mDeviceIdleController.getAppIdTempWhitelist();
} catch (RemoteException rexc) {
@@ -120,184 +109,165 @@ public final class BackgroundJobsController extends StateController {
powerWhitelistFilter.addAction(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED);
context.registerReceiverAsUser(mDozeWhitelistReceiver, UserHandle.ALL, powerWhitelistFilter,
null, null);
+
+ mForceAppStandbyTracker.addListener(mForceAppStandbyListener);
+ mForceAppStandbyTracker.start();
}
@Override
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
- final int uid = jobStatus.getSourceUid();
- final String packageName = jobStatus.getSourcePackageName();
- try {
- final int mode = mAppOpsService.checkOperation(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
- uid, packageName);
- if (mode == AppOpsManager.MODE_ALLOWED) {
- jobStatus.setBackgroundNotRestrictedConstraintSatisfied(true);
- return;
- }
- } catch (RemoteException rexc) {
- Slog.e(LOG_TAG, "Cannot reach app ops service", rexc);
- }
- jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRunJobLocked(uid));
- startTrackingJobLocked(jobStatus);
+ updateSingleJobRestrictionLocked(jobStatus);
}
@Override
public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
boolean forUpdate) {
- stopTrackingJobLocked(jobStatus);
- }
-
- /* Called by JobSchedulerService to report uid state changes between active and idle */
- public void setUidActiveLocked(int uid, boolean active) {
- final boolean changed = (active != mForegroundUids.get(uid));
- if (!changed) {
- return;
- }
- if (DEBUG) {
- Slog.d(LOG_TAG, "uid " + uid + " going to " + (active ? "fg" : "bg"));
- }
- if (active) {
- mForegroundUids.put(uid, true);
- } else {
- mForegroundUids.delete(uid);
- }
- if (checkTrackedJobsForUidLocked(uid)) {
- mStateChangedListener.onControllerStateChanged();
- }
}
@Override
public void dumpControllerStateLocked(final PrintWriter pw, final int filterUid) {
pw.println("BackgroundJobsController");
+
+ pw.print("Force all apps standby: ");
+ pw.println(mForceAppStandbyTracker.isForceAllAppsStandbyEnabled());
+
pw.print("Foreground uids: [");
- for (int i = 0; i < mForegroundUids.size(); i++) {
- if (mForegroundUids.valueAt(i)) pw.print(mForegroundUids.keyAt(i) + " ");
+ final SparseBooleanArray foregroundUids = mForceAppStandbyTracker.getForegroudUids();
+
+ String sep = "";
+ for (int i = 0; i < foregroundUids.size(); i++) {
+ if (foregroundUids.valueAt(i)) {
+ pw.print(sep);
+ pw.print(UserHandle.formatUid(foregroundUids.keyAt(i)));
+ sep = " ";
+ }
}
pw.println("]");
- mJobSchedulerService.getJobStore().forEachJob(new JobStore.JobStatusFunctor() {
- @Override
- public void process(JobStatus jobStatus) {
- if (!jobStatus.shouldDump(filterUid)) {
- return;
- }
- final int uid = jobStatus.getSourceUid();
- pw.print(" #");
- jobStatus.printUniqueId(pw);
- pw.print(" from ");
- UserHandle.formatUid(pw, uid);
- pw.print(mForegroundUids.get(uid) ? " foreground" : " background");
- if (isWhitelistedLocked(uid)) {
- pw.print(", whitelisted");
- }
- pw.print(": ");
- pw.print(jobStatus.getSourcePackageName());
- pw.print(" [background restrictions");
- final ArraySet<JobStatus> jobsForUid = mTrackedJobs.get(uid);
- pw.print(jobsForUid != null && jobsForUid.contains(jobStatus) ? " on]" : " off]");
- if ((jobStatus.satisfiedConstraints
- & JobStatus.CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
- pw.println(" RUNNABLE");
- } else {
- pw.println(" WAITING");
- }
+
+ pw.println("Restricted packages:");
+ for (Pair<Integer, String> uidAndPackage
+ : mForceAppStandbyTracker.getRestrictedUidPackages()) {
+ pw.print(" ");
+ pw.print(UserHandle.formatUid(uidAndPackage.first));
+ pw.print(" ");
+ pw.print(uidAndPackage.second);
+ pw.println();
+ }
+
+ pw.println("Job state:");
+ mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> {
+ if (!jobStatus.shouldDump(filterUid)) {
+ return;
+ }
+ final int uid = jobStatus.getSourceUid();
+ pw.print(" #");
+ jobStatus.printUniqueId(pw);
+ pw.print(" from ");
+ UserHandle.formatUid(pw, uid);
+ pw.print(mForceAppStandbyTracker.isInForeground(uid) ? " foreground" : " background");
+ if (isWhitelistedLocked(uid)) {
+ pw.print(", whitelisted");
+ }
+ pw.print(": ");
+ pw.print(jobStatus.getSourcePackageName());
+
+ pw.print(" [background restrictions ");
+ pw.print(mForceAppStandbyTracker.isRunAnyInBackgroundAppOpsAllowed(
+ jobStatus.getSourceUid(), jobStatus.getSourcePackageName()) ? "off]" : "on]");
+
+ if ((jobStatus.satisfiedConstraints
+ & JobStatus.CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
+ pw.println(" RUNNABLE");
+ } else {
+ pw.println(" WAITING");
}
});
}
- void startTrackingJobLocked(JobStatus jobStatus) {
- final int uid = jobStatus.getSourceUid();
- ArraySet<JobStatus> jobsForUid = mTrackedJobs.get(uid);
- if (jobsForUid == null) {
- jobsForUid = new ArraySet<>();
- mTrackedJobs.put(uid, jobsForUid);
- }
- jobsForUid.add(jobStatus);
+ private void updateAllJobRestrictionsLocked() {
+ updateJobRestrictionsLocked(/*filterUid=*/ -1);
}
- void stopTrackingJobLocked(JobStatus jobStatus) {
- final int uid = jobStatus.getSourceUid();
- ArraySet<JobStatus> jobsForUid = mTrackedJobs.get(uid);
- if (jobsForUid != null) {
- jobsForUid.remove(jobStatus);
- }
+ private void updateJobRestrictionsForUidLocked(int uid) {
+
+ // TODO Use forEachJobForSourceUid() once we have it.
+
+ updateJobRestrictionsLocked(/*filterUid=*/ uid);
}
- boolean checkAllTrackedJobsLocked() {
- boolean changed = false;
- for (int i = 0; i < mTrackedJobs.size(); i++) {
- changed |= checkTrackedJobsForUidLocked(mTrackedJobs.keyAt(i));
+ private void updateJobRestrictionsLocked(int filterUid) {
+ final UpdateJobFunctor updateTrackedJobs =
+ new UpdateJobFunctor(filterUid);
+
+ final long start = DEBUG ? SystemClock.elapsedRealtimeNanos() : 0;
+
+ mJobSchedulerService.getJobStore().forEachJob(updateTrackedJobs);
+
+ final long time = DEBUG ? (SystemClock.elapsedRealtimeNanos() - start) : 0;
+ if (DEBUG) {
+ Slog.d(LOG_TAG, String.format(
+ "Job status updated: %d/%d checked/total jobs, %d us",
+ updateTrackedJobs.mCheckedCount,
+ updateTrackedJobs.mTotalCount,
+ (time / 1000)
+ ));
}
- return changed;
- }
- private boolean checkTrackedJobsForUidLocked(int uid) {
- final ArraySet<JobStatus> jobsForUid = mTrackedJobs.get(uid);
- boolean changed = false;
- if (jobsForUid != null) {
- for (int i = 0; i < jobsForUid.size(); i++) {
- JobStatus jobStatus = jobsForUid.valueAt(i);
- changed |= jobStatus.setBackgroundNotRestrictedConstraintSatisfied(
- canRunJobLocked(uid));
- }
+ if (updateTrackedJobs.mChanged) {
+ mStateChangedListener.onControllerStateChanged();
}
- return changed;
}
- boolean isWhitelistedLocked(int uid) {
- return ArrayUtils.contains(mTempWhitelistedAppIds, UserHandle.getAppId(uid))
- || ArrayUtils.contains(mPowerWhitelistedUserAppIds, UserHandle.getAppId(uid));
+ private boolean isWhitelistedLocked(int uid) {
+ final int appId = UserHandle.getAppId(uid);
+ return ArrayUtils.contains(mTempWhitelistedAppIds, appId)
+ || ArrayUtils.contains(mPowerWhitelistedUserAppIds, appId);
}
- boolean canRunJobLocked(int uid) {
- return mForegroundUids.get(uid) || isWhitelistedLocked(uid);
- }
+ boolean updateSingleJobRestrictionLocked(JobStatus jobStatus) {
- private final class AppOpsWatcher extends IAppOpsCallback.Stub {
- @Override
- public void opChanged(int op, int uid, String packageName) throws RemoteException {
- synchronized (mLock) {
- final int mode = mAppOpsService.checkOperation(op, uid, packageName);
- if (DEBUG) {
- Slog.d(LOG_TAG,
- "Appop changed for " + uid + ", " + packageName + " to " + mode);
- }
- final boolean shouldTrack = (mode != AppOpsManager.MODE_ALLOWED);
- UpdateTrackedJobsFunc updateTrackedJobs = new UpdateTrackedJobsFunc(uid,
- packageName, shouldTrack);
- mJobSchedulerService.getJobStore().forEachJob(updateTrackedJobs);
- if (updateTrackedJobs.mChanged) {
- mStateChangedListener.onControllerStateChanged();
- }
- }
- }
+ final int uid = jobStatus.getSourceUid();
+ final String packageName = jobStatus.getSourcePackageName();
+
+ final boolean canRun = isWhitelistedLocked(uid)
+ || !mForceAppStandbyTracker.isRestricted(uid, packageName);
+
+ return jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun);
}
- private final class UpdateTrackedJobsFunc implements JobStore.JobStatusFunctor {
- private final String mPackageName;
- private final int mUid;
- private final boolean mShouldTrack;
- private boolean mChanged = false;
+ private final class UpdateJobFunctor implements JobStore.JobStatusFunctor {
+ private final int mFilterUid;
- UpdateTrackedJobsFunc(int uid, String packageName, boolean shouldTrack) {
- mUid = uid;
- mPackageName = packageName;
- mShouldTrack = shouldTrack;
+ boolean mChanged = false;
+ int mTotalCount = 0;
+ int mCheckedCount = 0;
+
+ UpdateJobFunctor(int filterUid) {
+ mFilterUid = filterUid;
}
@Override
public void process(JobStatus jobStatus) {
- final String packageName = jobStatus.getSourcePackageName();
- final int uid = jobStatus.getSourceUid();
- if (mUid != uid || !mPackageName.equals(packageName)) {
+ mTotalCount++;
+ if ((mFilterUid > 0) && (mFilterUid != jobStatus.getSourceUid())) {
return;
}
- if (mShouldTrack) {
- mChanged |= jobStatus.setBackgroundNotRestrictedConstraintSatisfied(
- canRunJobLocked(uid));
- startTrackingJobLocked(jobStatus);
- } else {
- mChanged |= jobStatus.setBackgroundNotRestrictedConstraintSatisfied(true);
- stopTrackingJobLocked(jobStatus);
+ mCheckedCount++;
+ if (updateSingleJobRestrictionLocked(jobStatus)) {
+ mChanged = true;
}
}
}
+
+ private final Listener mForceAppStandbyListener = new Listener() {
+ @Override
+ public void onRestrictionChanged(int uid, String packageName) {
+ updateJobRestrictionsForUidLocked(uid);
+ }
+
+ @Override
+ public void onGlobalRestrictionChanged() {
+ updateAllJobRestrictionsLocked();
+ }
+ };
}
diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
index 91119690617a..76ff8348fa53 100644
--- a/services/core/java/com/android/server/job/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -16,13 +16,14 @@
package com.android.server.job.controllers;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Slog;
@@ -203,7 +204,7 @@ public final class BatteryController extends StateController {
if (Intent.ACTION_BATTERY_LOW.equals(action)) {
if (DEBUG) {
Slog.d(TAG, "Battery life too low to do work. @ "
- + SystemClock.elapsedRealtime());
+ + sElapsedRealtimeClock.millis());
}
// If we get this action, the battery is discharging => it isn't plugged in so
// there's no work to cancel. We track this variable for the case where it is
@@ -213,14 +214,14 @@ public final class BatteryController extends StateController {
} else if (Intent.ACTION_BATTERY_OKAY.equals(action)) {
if (DEBUG) {
Slog.d(TAG, "Battery life healthy enough to do work. @ "
- + SystemClock.elapsedRealtime());
+ + sElapsedRealtimeClock.millis());
}
mBatteryHealthy = true;
maybeReportNewChargingStateLocked();
} else if (BatteryManager.ACTION_CHARGING.equals(action)) {
if (DEBUG) {
Slog.d(TAG, "Received charging intent, fired @ "
- + SystemClock.elapsedRealtime());
+ + sElapsedRealtimeClock.millis());
}
mCharging = true;
maybeReportNewChargingStateLocked();
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index ddee345a1c42..da2876910ee5 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -54,7 +54,6 @@ public final class ConnectivityController extends StateController implements
private final ConnectivityManager mConnManager;
private final NetworkPolicyManager mNetPolicyManager;
private boolean mConnected;
- private boolean mValidated;
@GuardedBy("mLock")
private final ArraySet<JobStatus> mTrackedJobs = new ArraySet<>();
@@ -79,7 +78,7 @@ public final class ConnectivityController extends StateController implements
mConnManager = mContext.getSystemService(ConnectivityManager.class);
mNetPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
- mConnected = mValidated = false;
+ mConnected = false;
mConnManager.registerDefaultNetworkCallback(mNetworkCallback);
mNetPolicyManager.registerListener(mNetPolicyListener);
@@ -149,32 +148,21 @@ public final class ConnectivityController extends StateController implements
}
private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
+ // TODO: consider matching against non-active networks
+
final int jobUid = jobStatus.getSourceUid();
final boolean ignoreBlocked = (jobStatus.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
final Network network = mConnManager.getActiveNetworkForUid(jobUid, ignoreBlocked);
final NetworkInfo info = mConnManager.getNetworkInfoForUid(network, jobUid, ignoreBlocked);
-
- final NetworkCapabilities capabilities = (network != null)
- ? mConnManager.getNetworkCapabilities(network) : null;
+ final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network);
final boolean connected = (info != null) && info.isConnected();
- final boolean validated = (capabilities != null)
- && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
+ final boolean satisfied = jobStatus.getJob().getRequiredNetwork().networkCapabilities
+ .satisfiedByNetworkCapabilities(capabilities);
final boolean sane = isSane(jobStatus, capabilities);
- final boolean connectionUsable = connected && validated && sane;
-
- final boolean metered = connected && (capabilities != null)
- && !capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- final boolean unmetered = connected && (capabilities != null)
- && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- final boolean notRoaming = connected && (info != null)
- && !info.isRoaming();
- boolean changed = false;
- changed |= jobStatus.setConnectivityConstraintSatisfied(connectionUsable);
- changed |= jobStatus.setMeteredConstraintSatisfied(metered);
- changed |= jobStatus.setUnmeteredConstraintSatisfied(unmetered);
- changed |= jobStatus.setNotRoamingConstraintSatisfied(notRoaming);
+ final boolean changed = jobStatus
+ .setConnectivityConstraintSatisfied(connected && satisfied && sane);
// Pass along the evaluated network for job to use; prevents race
// conditions as default routes change over time, and opens the door to
@@ -185,17 +173,13 @@ public final class ConnectivityController extends StateController implements
// overall state of connectivity constraint satisfiability.
if (jobUid == Process.SYSTEM_UID) {
mConnected = connected;
- mValidated = validated;
}
if (DEBUG) {
Slog.i(TAG, "Connectivity " + (changed ? "CHANGED" : "unchanged")
- + " for " + jobStatus + ": usable=" + connectionUsable
- + " connected=" + connected
- + " validated=" + validated
- + " metered=" + metered
- + " unmetered=" + unmetered
- + " notRoaming=" + notRoaming);
+ + " for " + jobStatus + ": connected=" + connected
+ + " satisfied=" + satisfied
+ + " sane=" + sane);
}
return changed;
}
@@ -292,8 +276,6 @@ public final class ConnectivityController extends StateController implements
public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
pw.print("Connectivity: connected=");
pw.print(mConnected);
- pw.print(" validated=");
- pw.println(mValidated);
pw.print("Tracking ");
pw.print(mTrackedJobs.size());
pw.println(":");
@@ -304,10 +286,7 @@ public final class ConnectivityController extends StateController implements
js.printUniqueId(pw);
pw.print(" from ");
UserHandle.formatUid(pw, js.getSourceUid());
- pw.print(": C="); pw.print(js.needsAnyConnectivity());
- pw.print(": M="); pw.print(js.needsMeteredConnectivity());
- pw.print(": UM="); pw.print(js.needsUnmeteredConnectivity());
- pw.print(": NR="); pw.println(js.needsNonRoamingConnectivity());
+ pw.print(": "); pw.print(js.getJob().getRequiredNetwork());
}
}
}
diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java
index 9eda046fa1e4..7bde17449af7 100644
--- a/services/core/java/com/android/server/job/controllers/IdleController.java
+++ b/services/core/java/com/android/server/job/controllers/IdleController.java
@@ -16,7 +16,7 @@
package com.android.server.job.controllers;
-import java.io.PrintWriter;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import android.app.AlarmManager;
import android.app.PendingIntent;
@@ -24,7 +24,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Slog;
@@ -33,6 +32,8 @@ import com.android.server.am.ActivityManagerService;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.StateChangedListener;
+import java.io.PrintWriter;
+
public final class IdleController extends StateController {
private static final String TAG = "IdleController";
@@ -169,7 +170,7 @@ public final class IdleController extends StateController {
// when the screen goes off or dreaming starts, we schedule the
// alarm that will tell us when we have decided the device is
// truly idle.
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long nowElapsed = sElapsedRealtimeClock.millis();
final long when = nowElapsed + mInactivityIdleThreshold;
if (DEBUG) {
Slog.v(TAG, "Scheduling idle : " + action + " now:" + nowElapsed + " when="
@@ -182,7 +183,7 @@ public final class IdleController extends StateController {
// idle time starts now. Do not set mIdle if screen is on.
if (!mIdle && !mScreenOn) {
if (DEBUG) {
- Slog.v(TAG, "Idle trigger fired @ " + SystemClock.elapsedRealtime());
+ Slog.v(TAG, "Idle trigger fired @ " + sElapsedRealtimeClock.millis());
}
mIdle = true;
reportNewIdleState(mIdle);
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 46ed84e599e8..a5906cb1e9a1 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -16,6 +16,8 @@
package com.android.server.job.controllers;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+
import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.job.JobInfo;
@@ -25,7 +27,6 @@ import android.content.ComponentName;
import android.net.Network;
import android.net.Uri;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.text.format.Time;
import android.util.ArraySet;
@@ -64,19 +65,12 @@ public final class JobStatus {
static final int CONSTRAINT_STORAGE_NOT_LOW = JobInfo.CONSTRAINT_FLAG_STORAGE_NOT_LOW;
static final int CONSTRAINT_TIMING_DELAY = 1<<31;
static final int CONSTRAINT_DEADLINE = 1<<30;
- static final int CONSTRAINT_UNMETERED = 1<<29;
static final int CONSTRAINT_CONNECTIVITY = 1<<28;
static final int CONSTRAINT_APP_NOT_IDLE = 1<<27;
static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<25;
- static final int CONSTRAINT_NOT_ROAMING = 1<<24;
- static final int CONSTRAINT_METERED = 1<<23;
static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1<<22;
- static final int CONNECTIVITY_MASK =
- CONSTRAINT_UNMETERED | CONSTRAINT_CONNECTIVITY |
- CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED;
-
// Soft override: ignore constraints like time that don't affect API availability
public static final int OVERRIDE_SOFT = 1;
// Full override: ignore all constraints including API-affecting like connectivity
@@ -264,27 +258,9 @@ public final class JobStatus {
int requiredConstraints = job.getConstraintFlags();
- switch (job.getNetworkType()) {
- case JobInfo.NETWORK_TYPE_NONE:
- // No constraint.
- break;
- case JobInfo.NETWORK_TYPE_ANY:
- requiredConstraints |= CONSTRAINT_CONNECTIVITY;
- break;
- case JobInfo.NETWORK_TYPE_UNMETERED:
- requiredConstraints |= CONSTRAINT_UNMETERED;
- break;
- case JobInfo.NETWORK_TYPE_NOT_ROAMING:
- requiredConstraints |= CONSTRAINT_NOT_ROAMING;
- break;
- case JobInfo.NETWORK_TYPE_METERED:
- requiredConstraints |= CONSTRAINT_METERED;
- break;
- default:
- Slog.w(TAG, "Unrecognized networking constraint " + job.getNetworkType());
- break;
+ if (job.getRequiredNetwork() != null) {
+ requiredConstraints |= CONSTRAINT_CONNECTIVITY;
}
-
if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
requiredConstraints |= CONSTRAINT_TIMING_DELAY;
}
@@ -365,7 +341,7 @@ public final class JobStatus {
*/
public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePackageName,
int sourceUserId, String tag) {
- final long elapsedNow = SystemClock.elapsedRealtime();
+ final long elapsedNow = sElapsedRealtimeClock.millis();
final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis;
if (job.isPeriodic()) {
latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
@@ -610,25 +586,9 @@ public final class JobStatus {
/** Does this job have any sort of networking constraint? */
public boolean hasConnectivityConstraint() {
- return (requiredConstraints&CONNECTIVITY_MASK) != 0;
- }
-
- public boolean needsAnyConnectivity() {
return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0;
}
- public boolean needsUnmeteredConnectivity() {
- return (requiredConstraints&CONSTRAINT_UNMETERED) != 0;
- }
-
- public boolean needsMeteredConnectivity() {
- return (requiredConstraints&CONSTRAINT_METERED) != 0;
- }
-
- public boolean needsNonRoamingConnectivity() {
- return (requiredConstraints&CONSTRAINT_NOT_ROAMING) != 0;
- }
-
public boolean hasChargingConstraint() {
return (requiredConstraints&CONSTRAINT_CHARGING) != 0;
}
@@ -725,18 +685,6 @@ public final class JobStatus {
return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
}
- boolean setUnmeteredConstraintSatisfied(boolean state) {
- return setConstraintSatisfied(CONSTRAINT_UNMETERED, state);
- }
-
- boolean setMeteredConstraintSatisfied(boolean state) {
- return setConstraintSatisfied(CONSTRAINT_METERED, state);
- }
-
- boolean setNotRoamingConstraintSatisfied(boolean state) {
- return setConstraintSatisfied(CONSTRAINT_NOT_ROAMING, state);
- }
-
boolean setAppNotIdleConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_APP_NOT_IDLE, state);
}
@@ -817,12 +765,9 @@ public final class JobStatus {
&& notRestrictedInBg;
}
- static final int CONSTRAINTS_OF_INTEREST =
- CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW |
- CONSTRAINT_TIMING_DELAY |
- CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED |
- CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED |
- CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
+ static final int CONSTRAINTS_OF_INTEREST = CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW
+ | CONSTRAINT_STORAGE_NOT_LOW | CONSTRAINT_TIMING_DELAY | CONSTRAINT_CONNECTIVITY
+ | CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
// Soft override covers all non-"functional" constraints
static final int SOFT_OVERRIDE_CONSTRAINTS =
@@ -870,15 +815,14 @@ public final class JobStatus {
sb.append(getSourceUid());
if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME
|| latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
- long now = SystemClock.elapsedRealtime();
+ long now = sElapsedRealtimeClock.millis();
sb.append(" TIME=");
formatRunTime(sb, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, now);
sb.append(":");
formatRunTime(sb, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, now);
}
- if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
- sb.append(" NET=");
- sb.append(job.getNetworkType());
+ if (job.getRequiredNetwork() != null) {
+ sb.append(" NET");
}
if (job.isRequireCharging()) {
sb.append(" CHARGING");
@@ -985,15 +929,6 @@ public final class JobStatus {
if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
pw.print(" CONNECTIVITY");
}
- if ((constraints&CONSTRAINT_UNMETERED) != 0) {
- pw.print(" UNMETERED");
- }
- if ((constraints&CONSTRAINT_NOT_ROAMING) != 0) {
- pw.print(" NOT_ROAMING");
- }
- if ((constraints&CONSTRAINT_METERED) != 0) {
- pw.print(" METERED");
- }
if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) {
pw.print(" APP_NOT_IDLE");
}
@@ -1084,11 +1019,13 @@ public final class JobStatus {
pw.print(prefix); pw.println(" Granted URI permissions:");
uriPerms.dump(pw, prefix + " ");
}
- if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
- pw.print(prefix); pw.print(" Network type: "); pw.println(job.getNetworkType());
+ if (job.getRequiredNetwork() != null) {
+ pw.print(prefix); pw.print(" Network type: ");
+ pw.println(job.getRequiredNetwork());
}
if (totalNetworkBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
- pw.print(prefix); pw.print(" Network bytes: "); pw.println(totalNetworkBytes);
+ pw.print(prefix); pw.print(" Network bytes: ");
+ pw.println(totalNetworkBytes);
}
if (job.getMinLatencyMillis() != 0) {
pw.print(prefix); pw.print(" Minimum latency: ");
diff --git a/services/core/java/com/android/server/job/controllers/StorageController.java b/services/core/java/com/android/server/job/controllers/StorageController.java
index c24e563948d4..84782f59d142 100644
--- a/services/core/java/com/android/server/job/controllers/StorageController.java
+++ b/services/core/java/com/android/server/job/controllers/StorageController.java
@@ -16,11 +16,12 @@
package com.android.server.job.controllers;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Slog;
@@ -154,13 +155,13 @@ public final class StorageController extends StateController {
if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) {
if (DEBUG) {
Slog.d(TAG, "Available storage too low to do work. @ "
- + SystemClock.elapsedRealtime());
+ + sElapsedRealtimeClock.millis());
}
mStorageLow = true;
} else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
if (DEBUG) {
Slog.d(TAG, "Available stoage high enough to do work. @ "
- + SystemClock.elapsedRealtime());
+ + sElapsedRealtimeClock.millis());
}
mStorageLow = false;
maybeReportNewStorageState();
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index ee4c606fa6d3..cb9e43a13684 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -16,10 +16,11 @@
package com.android.server.job.controllers;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+
import android.app.AlarmManager;
import android.app.AlarmManager.OnAlarmListener;
import android.content.Context;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
import android.util.Slog;
@@ -84,7 +85,7 @@ public final class TimeController extends StateController {
// pattern of having a job with a 0 deadline constraint ("run immediately").
// Unlike most controllers, once one of our constraints has been satisfied, it
// will never be unsatisfied (our time base can not go backwards).
- final long nowElapsedMillis = SystemClock.elapsedRealtime();
+ final long nowElapsedMillis = sElapsedRealtimeClock.millis();
if (job.hasDeadlineConstraint() && evaluateDeadlineConstraint(job, nowElapsedMillis)) {
return;
} else if (job.hasTimingDelayConstraint() && evaluateTimingDelayConstraint(job,
@@ -157,7 +158,7 @@ public final class TimeController extends StateController {
long nextExpiryTime = Long.MAX_VALUE;
int nextExpiryUid = 0;
String nextExpiryPackageName = null;
- final long nowElapsedMillis = SystemClock.elapsedRealtime();
+ final long nowElapsedMillis = sElapsedRealtimeClock.millis();
Iterator<JobStatus> it = mTrackedJobs.iterator();
while (it.hasNext()) {
@@ -201,7 +202,7 @@ public final class TimeController extends StateController {
*/
private void checkExpiredDelaysAndResetAlarm() {
synchronized (mLock) {
- final long nowElapsedMillis = SystemClock.elapsedRealtime();
+ final long nowElapsedMillis = sElapsedRealtimeClock.millis();
long nextDelayTime = Long.MAX_VALUE;
int nextDelayUid = 0;
String nextDelayPackageName = null;
@@ -283,7 +284,7 @@ public final class TimeController extends StateController {
}
private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) {
- final long earliestWakeupTimeElapsed = SystemClock.elapsedRealtime();
+ final long earliestWakeupTimeElapsed = sElapsedRealtimeClock.millis();
if (proposedAlarmTimeElapsedMillis < earliestWakeupTimeElapsed) {
return earliestWakeupTimeElapsed;
}
@@ -328,9 +329,9 @@ public final class TimeController extends StateController {
@Override
public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long nowElapsed = sElapsedRealtimeClock.millis();
pw.print("Alarms: now=");
- pw.print(SystemClock.elapsedRealtime());
+ pw.print(sElapsedRealtimeClock.millis());
pw.println();
pw.print("Next delay alarm in ");
TimeUtils.formatDuration(mNextDelayExpiredElapsedMillis, nowElapsed, pw);
diff --git a/services/core/java/com/android/server/location/ActivityRecognitionProxy.java b/services/core/java/com/android/server/location/ActivityRecognitionProxy.java
index 55222dc305c3..f82b9761f569 100644
--- a/services/core/java/com/android/server/location/ActivityRecognitionProxy.java
+++ b/services/core/java/com/android/server/location/ActivityRecognitionProxy.java
@@ -103,51 +103,55 @@ public class ActivityRecognitionProxy {
* Helper function to bind the FusedLocationHardware to the appropriate FusedProvider instance.
*/
private void bindProvider() {
- IBinder binder = mServiceWatcher.getBinder();
- if (binder == null) {
- Log.e(TAG, "Null binder found on connection.");
- return;
- }
- String descriptor;
- try {
- descriptor = binder.getInterfaceDescriptor();
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to get interface descriptor.", e);
- return;
- }
+ if (!mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
+ @Override
+ public void run(IBinder binder) {
+ String descriptor;
+ try {
+ descriptor = binder.getInterfaceDescriptor();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to get interface descriptor.", e);
+ return;
+ }
- if (IActivityRecognitionHardwareWatcher.class.getCanonicalName().equals(descriptor)) {
- IActivityRecognitionHardwareWatcher watcher =
- IActivityRecognitionHardwareWatcher.Stub.asInterface(binder);
- if (watcher == null) {
- Log.e(TAG, "No watcher found on connection.");
- return;
- }
- if (mInstance == null) {
- // to keep backwards compatibility do not update the watcher when there is no
- // instance available, or it will cause an NPE
- Log.d(TAG, "AR HW instance not available, binding will be a no-op.");
- return;
+ if (IActivityRecognitionHardwareWatcher.class.getCanonicalName()
+ .equals(descriptor)) {
+ IActivityRecognitionHardwareWatcher watcher =
+ IActivityRecognitionHardwareWatcher.Stub.asInterface(binder);
+ if (watcher == null) {
+ Log.e(TAG, "No watcher found on connection.");
+ return;
+ }
+ if (mInstance == null) {
+ // to keep backwards compatibility do not update the watcher when there is
+ // no instance available, or it will cause an NPE
+ Log.d(TAG, "AR HW instance not available, binding will be a no-op.");
+ return;
+ }
+ try {
+ watcher.onInstanceChanged(mInstance);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error delivering hardware interface to watcher.", e);
+ }
+ } else if (IActivityRecognitionHardwareClient.class.getCanonicalName()
+ .equals(descriptor)) {
+ IActivityRecognitionHardwareClient client =
+ IActivityRecognitionHardwareClient.Stub.asInterface(binder);
+ if (client == null) {
+ Log.e(TAG, "No client found on connection.");
+ return;
+ }
+ try {
+ client.onAvailabilityChanged(mIsSupported, mInstance);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error delivering hardware interface to client.", e);
+ }
+ } else {
+ Log.e(TAG, "Invalid descriptor found on connection: " + descriptor);
+ }
}
- try {
- watcher.onInstanceChanged(mInstance);
- } catch (RemoteException e) {
- Log.e(TAG, "Error delivering hardware interface to watcher.", e);
- }
- } else if (IActivityRecognitionHardwareClient.class.getCanonicalName().equals(descriptor)) {
- IActivityRecognitionHardwareClient client =
- IActivityRecognitionHardwareClient.Stub.asInterface(binder);
- if (client == null) {
- Log.e(TAG, "No client found on connection.");
- return;
- }
- try {
- client.onAvailabilityChanged(mIsSupported, mInstance);
- } catch (RemoteException e) {
- Log.e(TAG, "Error delivering hardware interface to client.", e);
- }
- } else {
- Log.e(TAG, "Invalid descriptor found on connection: " + descriptor);
+ })) {
+ Log.e(TAG, "Null binder found on connection.");
}
}
}
diff --git a/services/core/java/com/android/server/location/FusedProxy.java b/services/core/java/com/android/server/location/FusedProxy.java
index f7fac774c979..b90f037a5046 100644
--- a/services/core/java/com/android/server/location/FusedProxy.java
+++ b/services/core/java/com/android/server/location/FusedProxy.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.hardware.location.IFusedLocationHardware;
import android.location.IFusedProvider;
import android.os.Handler;
+import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -112,17 +113,18 @@ public final class FusedProxy {
* @param locationHardware The FusedLocationHardware instance to use for the binding operation.
*/
private void bindProvider(IFusedLocationHardware locationHardware) {
- IFusedProvider provider = IFusedProvider.Stub.asInterface(mServiceWatcher.getBinder());
-
- if (provider == null) {
+ if (!mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
+ @Override
+ public void run(IBinder binder) {
+ IFusedProvider provider = IFusedProvider.Stub.asInterface(binder);
+ try {
+ provider.onFusedLocationHardwareChange(locationHardware);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ }
+ })) {
Log.e(TAG, "No instance of FusedProvider found on FusedLocationHardware connected.");
- return;
- }
-
- try {
- provider.onFusedLocationHardwareChange(locationHardware);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
}
}
}
diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java
index 422b94b335f8..9ad4aa190d16 100644
--- a/services/core/java/com/android/server/location/GeocoderProxy.java
+++ b/services/core/java/com/android/server/location/GeocoderProxy.java
@@ -21,6 +21,7 @@ import android.location.Address;
import android.location.GeocoderParams;
import android.location.IGeocodeProvider;
import android.os.Handler;
+import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -63,42 +64,47 @@ public class GeocoderProxy {
return mServiceWatcher.start();
}
- private IGeocodeProvider getService() {
- return IGeocodeProvider.Stub.asInterface(mServiceWatcher.getBinder());
- }
-
public String getConnectedPackageName() {
return mServiceWatcher.getBestPackageName();
}
public String getFromLocation(double latitude, double longitude, int maxResults,
GeocoderParams params, List<Address> addrs) {
- IGeocodeProvider provider = getService();
- if (provider != null) {
- try {
- return provider.getFromLocation(latitude, longitude, maxResults, params, addrs);
- } catch (RemoteException e) {
- Log.w(TAG, e);
+ final String[] result = new String[] {"Service not Available"};
+ mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
+ @Override
+ public void run(IBinder binder) {
+ IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
+ try {
+ result[0] = provider.getFromLocation(
+ latitude, longitude, maxResults, params, addrs);
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ }
}
- }
- return "Service not Available";
+ });
+ return result[0];
}
public String getFromLocationName(String locationName,
double lowerLeftLatitude, double lowerLeftLongitude,
double upperRightLatitude, double upperRightLongitude, int maxResults,
GeocoderParams params, List<Address> addrs) {
- IGeocodeProvider provider = getService();
- if (provider != null) {
- try {
- return provider.getFromLocationName(locationName, lowerLeftLatitude,
- lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
- maxResults, params, addrs);
- } catch (RemoteException e) {
- Log.w(TAG, e);
+ final String[] result = new String[] {"Service not Available"};
+ mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
+ @Override
+ public void run(IBinder binder) {
+ IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
+ try {
+ result[0] = provider.getFromLocationName(locationName, lowerLeftLatitude,
+ lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
+ maxResults, params, addrs);
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ }
}
- }
- return "Service not Available";
+ });
+ return result[0];
}
}
diff --git a/services/core/java/com/android/server/location/GeofenceProxy.java b/services/core/java/com/android/server/location/GeofenceProxy.java
index b3a001022556..eb47b2f8798c 100644
--- a/services/core/java/com/android/server/location/GeofenceProxy.java
+++ b/services/core/java/com/android/server/location/GeofenceProxy.java
@@ -116,15 +116,17 @@ public final class GeofenceProxy {
};
private void setGeofenceHardwareInProviderLocked() {
- try {
- IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(
- mServiceWatcher.getBinder());
- if (provider != null) {
- provider.setGeofenceHardware(mGeofenceHardware);
+ mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
+ @Override
+ public void run(IBinder binder) {
+ final IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(binder);
+ try {
+ provider.setGeofenceHardware(mGeofenceHardware);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Remote Exception: setGeofenceHardwareInProviderLocked: " + e);
+ }
}
- } catch (RemoteException e) {
- Log.e(TAG, "Remote Exception: setGeofenceHardwareInProviderLocked: " + e);
- }
+ });
}
private void setGpsGeofenceLocked() {
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 660659fdfa5c..0b511f235265 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -48,6 +48,7 @@ import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.BatteryStats;
import android.os.Binder;
@@ -84,7 +85,6 @@ import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.server.power.BatterySaverPolicy;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import libcore.io.IoUtils;
@@ -1361,24 +1361,26 @@ public class GnssLocationProvider implements LocationProviderInterface {
public boolean sendExtraCommand(String command, Bundle extras) {
long identity = Binder.clearCallingIdentity();
- boolean result = false;
+ try {
+ boolean result = false;
- if ("delete_aiding_data".equals(command)) {
- result = deleteAidingData(extras);
- } else if ("force_time_injection".equals(command)) {
- requestUtcTime();
- result = true;
- } else if ("force_xtra_injection".equals(command)) {
- if (mSupportsXtra) {
- xtraDownloadRequest();
+ if ("delete_aiding_data".equals(command)) {
+ result = deleteAidingData(extras);
+ } else if ("force_time_injection".equals(command)) {
+ requestUtcTime();
result = true;
+ } else if ("force_xtra_injection".equals(command)) {
+ if (mSupportsXtra) {
+ xtraDownloadRequest();
+ result = true;
+ }
+ } else {
+ Log.w(TAG, "sendExtraCommand: unknown command " + command);
}
- } else {
- Log.w(TAG, "sendExtraCommand: unknown command " + command);
+ return result;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
-
- Binder.restoreCallingIdentity(identity);
- return result;
}
private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index b44087c07c16..16eae6206d2d 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -24,6 +24,7 @@ import android.content.Context;
import android.location.LocationProvider;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.RemoteException;
import android.os.WorkSource;
import android.util.Log;
@@ -82,10 +83,6 @@ public class LocationProviderProxy implements LocationProviderInterface {
return mServiceWatcher.start();
}
- private ILocationProvider getService() {
- return ILocationProvider.Stub.asInterface(mServiceWatcher.getBinder());
- }
-
public String getConnectedPackageName() {
return mServiceWatcher.getBestPackageName();
}
@@ -101,43 +98,46 @@ public class LocationProviderProxy implements LocationProviderInterface {
if (D) Log.d(TAG, "applying state to connected service");
boolean enabled;
- ProviderProperties properties = null;
+ final ProviderProperties[] properties = new ProviderProperties[1];
ProviderRequest request;
WorkSource source;
- ILocationProvider service;
synchronized (mLock) {
enabled = mEnabled;
request = mRequest;
source = mWorksource;
- service = getService();
}
- if (service == null) return;
- try {
- // load properties from provider
- properties = service.getProperties();
- if (properties == null) {
- Log.e(TAG, mServiceWatcher.getBestPackageName() +
- " has invalid locatino provider properties");
- }
-
- // apply current state to new service
- if (enabled) {
- service.enable();
- if (request != null) {
- service.setRequest(request, source);
+ mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
+ @Override
+ public void run(IBinder binder) {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ try {
+ // load properties from provider
+ properties[0] = service.getProperties();
+ if (properties[0] == null) {
+ Log.e(TAG, mServiceWatcher.getBestPackageName() +
+ " has invalid location provider properties");
+ }
+
+ // apply current state to new service
+ if (enabled) {
+ service.enable();
+ if (request != null) {
+ service.setRequest(request, source);
+ }
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ } catch (Exception e) {
+ // never let remote service crash system server
+ Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
}
}
- } catch (RemoteException e) {
- Log.w(TAG, e);
- } catch (Exception e) {
- // never let remote service crash system server
- Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
- }
+ });
synchronized (mLock) {
- mProperties = properties;
+ mProperties = properties[0];
}
}
};
@@ -159,17 +159,20 @@ public class LocationProviderProxy implements LocationProviderInterface {
synchronized (mLock) {
mEnabled = true;
}
- ILocationProvider service = getService();
- if (service == null) return;
-
- try {
- service.enable();
- } catch (RemoteException e) {
- Log.w(TAG, e);
- } catch (Exception e) {
- // never let remote service crash system server
- Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
- }
+ mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
+ @Override
+ public void run(IBinder binder) {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ try {
+ service.enable();
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ } catch (Exception e) {
+ // never let remote service crash system server
+ Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
+ }
+ }
+ });
}
@Override
@@ -177,17 +180,20 @@ public class LocationProviderProxy implements LocationProviderInterface {
synchronized (mLock) {
mEnabled = false;
}
- ILocationProvider service = getService();
- if (service == null) return;
-
- try {
- service.disable();
- } catch (RemoteException e) {
- Log.w(TAG, e);
- } catch (Exception e) {
- // never let remote service crash system server
- Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
- }
+ mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
+ @Override
+ public void run(IBinder binder) {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ try {
+ service.disable();
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ } catch (Exception e) {
+ // never let remote service crash system server
+ Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
+ }
+ }
+ });
}
@Override
@@ -203,17 +209,20 @@ public class LocationProviderProxy implements LocationProviderInterface {
mRequest = request;
mWorksource = source;
}
- ILocationProvider service = getService();
- if (service == null) return;
-
- try {
- service.setRequest(request, source);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- } catch (Exception e) {
- // never let remote service crash system server
- Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
- }
+ mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
+ @Override
+ public void run(IBinder binder) {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ try {
+ service.setRequest(request, source);
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ } catch (Exception e) {
+ // never let remote service crash system server
+ Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
+ }
+ }
+ });
}
@Override
@@ -223,66 +232,78 @@ public class LocationProviderProxy implements LocationProviderInterface {
pw.append(" pkg=").append(mServiceWatcher.getBestPackageName());
pw.append(" version=").append("" + mServiceWatcher.getBestVersion());
pw.append('\n');
-
- ILocationProvider service = getService();
- if (service == null) {
+ if (!mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
+ @Override
+ public void run(IBinder binder) {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ try {
+ TransferPipe.dumpAsync(service.asBinder(), fd, args);
+ } catch (IOException | RemoteException e) {
+ pw.println("Failed to dump location provider: " + e);
+ }
+ }
+ })) {
pw.println("service down (null)");
- return;
- }
- pw.flush();
-
- try {
- TransferPipe.dumpAsync(service.asBinder(), fd, args);
- } catch (IOException | RemoteException e) {
- pw.println("Failed to dump location provider: " + e);
}
}
@Override
public int getStatus(Bundle extras) {
- ILocationProvider service = getService();
- if (service == null) return LocationProvider.TEMPORARILY_UNAVAILABLE;
-
- try {
- return service.getStatus(extras);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- } catch (Exception e) {
- // never let remote service crash system server
- Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
- }
- return LocationProvider.TEMPORARILY_UNAVAILABLE;
+ final int[] result = new int[] {LocationProvider.TEMPORARILY_UNAVAILABLE};
+ mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
+ @Override
+ public void run(IBinder binder) {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ try {
+ result[0] = service.getStatus(extras);
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ } catch (Exception e) {
+ // never let remote service crash system server
+ Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
+ }
+ }
+ });
+ return result[0];
}
@Override
public long getStatusUpdateTime() {
- ILocationProvider service = getService();
- if (service == null) return 0;
-
- try {
- return service.getStatusUpdateTime();
- } catch (RemoteException e) {
- Log.w(TAG, e);
- } catch (Exception e) {
- // never let remote service crash system server
- Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
- }
- return 0;
+ final long[] result = new long[] {0L};
+ mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
+ @Override
+ public void run(IBinder binder) {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ try {
+ result[0] = service.getStatusUpdateTime();
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ } catch (Exception e) {
+ // never let remote service crash system server
+ Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
+ }
+ }
+ });
+ return result[0];
}
@Override
public boolean sendExtraCommand(String command, Bundle extras) {
- ILocationProvider service = getService();
- if (service == null) return false;
-
- try {
- return service.sendExtraCommand(command, extras);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- } catch (Exception e) {
- // never let remote service crash system server
- Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
- }
- return false;
+ final boolean[] result = new boolean[] {false};
+ mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
+ @Override
+ public void run(IBinder binder) {
+ ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
+ try {
+ result[0] = service.sendExtraCommand(command, extras);
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ } catch (Exception e) {
+ // never let remote service crash system server
+ Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
+ }
+ }
+ });
+ return result[0];
}
}
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
index b7bca1fb1c4a..ef94000d3a6b 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
@@ -112,7 +112,7 @@ public class SyntheticPasswordCrypto {
}
}
- public static byte[] decryptBlob(String keyAlias, byte[] blob, byte[] applicationId) {
+ public static byte[] decryptBlobV1(String keyAlias, byte[] blob, byte[] applicationId) {
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
@@ -120,6 +120,20 @@ public class SyntheticPasswordCrypto {
SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null);
byte[] intermediate = decrypt(applicationId, APPLICATION_ID_PERSONALIZATION, blob);
return decrypt(decryptionKey, intermediate);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Failed to decrypt blob", e);
+ }
+ }
+
+ public static byte[] decryptBlob(String keyAlias, byte[] blob, byte[] applicationId) {
+ try {
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+
+ SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null);
+ byte[] intermediate = decrypt(decryptionKey, blob);
+ return decrypt(applicationId, APPLICATION_ID_PERSONALIZATION, intermediate);
} catch (CertificateException | IOException | BadPaddingException
| IllegalBlockSizeException
| KeyStoreException | NoSuchPaddingException | NoSuchAlgorithmException
@@ -150,9 +164,8 @@ public class SyntheticPasswordCrypto {
keyStore.setEntry(keyAlias,
new KeyStore.SecretKeyEntry(secretKey),
builder.build());
- byte[] intermediate = encrypt(secretKey, data);
- return encrypt(applicationId, APPLICATION_ID_PERSONALIZATION, intermediate);
-
+ byte[] intermediate = encrypt(applicationId, APPLICATION_ID_PERSONALIZATION, data);
+ return encrypt(secretKey, intermediate);
} catch (CertificateException | IOException | BadPaddingException
| IllegalBlockSizeException
| KeyStoreException | NoSuchPaddingException | NoSuchAlgorithmException
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 9440f17164aa..1a1aa569b249 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -101,7 +101,8 @@ public class SyntheticPasswordManager {
private static final byte WEAVER_VERSION = 1;
private static final int INVALID_WEAVER_SLOT = -1;
- private static final byte SYNTHETIC_PASSWORD_VERSION = 1;
+ private static final byte SYNTHETIC_PASSWORD_VERSION_V1 = 1;
+ private static final byte SYNTHETIC_PASSWORD_VERSION = 2;
private static final byte SYNTHETIC_PASSWORD_PASSWORD_BASED = 0;
private static final byte SYNTHETIC_PASSWORD_TOKEN_BASED = 1;
@@ -389,11 +390,9 @@ public class SyntheticPasswordManager {
}
public void removeUser(int userId) {
- if (isWeaverAvailable()) {
- for (long handle : mStorage.listSyntheticPasswordHandlesForUser(WEAVER_SLOT_NAME,
- userId)) {
- destroyWeaverSlot(handle, userId);
- }
+ for (long handle : mStorage.listSyntheticPasswordHandlesForUser(SP_BLOB_NAME, userId)) {
+ destroyWeaverSlot(handle, userId);
+ destroySPBlobKey(getHandleName(handle));
}
}
@@ -792,6 +791,7 @@ public class SyntheticPasswordManager {
byte[] pwdToken = computePasswordToken(credential, pwd);
final byte[] applicationId;
+ final long sid;
int weaverSlot = loadWeaverSlot(handle, userId);
if (weaverSlot != INVALID_WEAVER_SLOT) {
// Weaver based user password
@@ -804,6 +804,7 @@ public class SyntheticPasswordManager {
if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
return result;
}
+ sid = GateKeeper.INVALID_SECURE_USER_ID;
applicationId = transformUnderWeaverSecret(pwdToken, result.gkResponse.getPayload());
} else {
byte[] gkPwdToken = passwordTokenToGkInput(pwdToken);
@@ -836,12 +837,13 @@ public class SyntheticPasswordManager {
result.gkResponse = VerifyCredentialResponse.ERROR;
return result;
}
+ sid = sidFromPasswordHandle(pwd.passwordHandle);
applicationId = transformUnderSecdiscardable(pwdToken,
loadSecdiscardable(handle, userId));
}
result.authToken = unwrapSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_PASSWORD_BASED,
- applicationId, userId);
+ applicationId, sid, userId);
// Perform verifyChallenge to refresh auth tokens for GK if user password exists.
result.gkResponse = verifyChallenge(gatekeeper, result.authToken, 0L, userId);
@@ -877,7 +879,7 @@ public class SyntheticPasswordManager {
}
byte[] applicationId = transformUnderSecdiscardable(token, secdiscardable);
result.authToken = unwrapSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_TOKEN_BASED,
- applicationId, userId);
+ applicationId, 0L, userId);
if (result.authToken != null) {
result.gkResponse = verifyChallenge(gatekeeper, result.authToken, 0L, userId);
if (result.gkResponse == null) {
@@ -892,19 +894,26 @@ public class SyntheticPasswordManager {
}
private AuthenticationToken unwrapSyntheticPasswordBlob(long handle, byte type,
- byte[] applicationId, int userId) {
+ byte[] applicationId, long sid, int userId) {
byte[] blob = loadState(SP_BLOB_NAME, handle, userId);
if (blob == null) {
return null;
}
- if (blob[0] != SYNTHETIC_PASSWORD_VERSION) {
+ final byte version = blob[0];
+ if (version != SYNTHETIC_PASSWORD_VERSION && version != SYNTHETIC_PASSWORD_VERSION_V1) {
throw new RuntimeException("Unknown blob version");
}
if (blob[1] != type) {
throw new RuntimeException("Invalid blob type");
}
- byte[] secret = decryptSPBlob(getHandleName(handle),
+ final byte[] secret;
+ if (version == SYNTHETIC_PASSWORD_VERSION_V1) {
+ secret = SyntheticPasswordCrypto.decryptBlobV1(getHandleName(handle),
+ Arrays.copyOfRange(blob, 2, blob.length), applicationId);
+ } else {
+ secret = decryptSPBlob(getHandleName(handle),
Arrays.copyOfRange(blob, 2, blob.length), applicationId);
+ }
if (secret == null) {
Log.e(TAG, "Fail to decrypt SP for user " + userId);
return null;
@@ -919,6 +928,10 @@ public class SyntheticPasswordManager {
} else {
result.syntheticPassword = new String(secret);
}
+ if (version == SYNTHETIC_PASSWORD_VERSION_V1) {
+ Log.i(TAG, "Upgrade v1 SP blob for user " + userId + ", type = " + type);
+ createSyntheticPasswordBlob(handle, type, result, applicationId, sid, userId);
+ }
return result;
}
diff --git a/services/core/java/com/android/server/media/AudioPlaybackMonitor.java b/services/core/java/com/android/server/media/AudioPlaybackMonitor.java
deleted file mode 100644
index 791ee821b357..000000000000
--- a/services/core/java/com/android/server/media/AudioPlaybackMonitor.java
+++ /dev/null
@@ -1,289 +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.media;
-
-import android.content.Context;
-import android.media.AudioManager.AudioPlaybackCallback;
-import android.media.AudioPlaybackConfiguration;
-import android.media.IAudioService;
-import android.media.IPlaybackConfigDispatcher;
-import android.os.Binder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.IntArray;
-import android.util.Log;
-import android.util.SparseArray;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Monitors changes in audio playback, and notify the newly started audio playback through the
- * {@link OnAudioPlaybackStartedListener} and the activeness change through the
- * {@link OnAudioPlaybackActiveStateListener}.
- */
-class AudioPlaybackMonitor extends IPlaybackConfigDispatcher.Stub {
- private static boolean DEBUG = MediaSessionService.DEBUG;
- private static String TAG = "AudioPlaybackMonitor";
-
- private static AudioPlaybackMonitor sInstance;
-
- /**
- * Called when audio playback is started for a given UID.
- */
- interface OnAudioPlaybackStartedListener {
- void onAudioPlaybackStarted(int uid);
- }
-
- /**
- * Called when audio player state is changed.
- */
- interface OnAudioPlayerActiveStateChangedListener {
- void onAudioPlayerActiveStateChanged(int uid, boolean active);
- }
-
- private final Object mLock = new Object();
- private final Context mContext;
- private final List<OnAudioPlaybackStartedListener> mAudioPlaybackStartedListeners
- = new ArrayList<>();
- private final List<OnAudioPlayerActiveStateChangedListener>
- mAudioPlayerActiveStateChangedListeners = new ArrayList<>();
- private final Map<Integer, Integer> mAudioPlaybackStates = new HashMap<>();
- private final Set<Integer> mActiveAudioPlaybackClientUids = new HashSet<>();
-
- // Sorted array of UIDs that had active audio playback. (i.e. playing an audio/video)
- // The UID whose audio playback becomes active at the last comes first.
- // TODO(b/35278867): Find and use unique identifier for apps because apps may share the UID.
- private final IntArray mSortedAudioPlaybackClientUids = new IntArray();
-
- static AudioPlaybackMonitor getInstance(Context context, IAudioService audioService) {
- if (sInstance == null) {
- sInstance = new AudioPlaybackMonitor(context, audioService);
- }
- return sInstance;
- }
-
- private AudioPlaybackMonitor(Context context, IAudioService audioService) {
- mContext = context;
- try {
- audioService.registerPlaybackCallback(this);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failed to register playback callback", e);
- }
- }
-
- /**
- * Called when the {@link AudioPlaybackConfiguration} is updated.
- * <p>If an app starts audio playback, the app's local media session will be the media button
- * session. If the app has multiple media sessions, the playback active local session will be
- * picked.
- *
- * @param configs List of the current audio playback configuration
- */
- @Override
- public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
- boolean flush) {
- if (flush) {
- Binder.flushPendingCommands();
- }
- final long token = Binder.clearCallingIdentity();
- try {
- List<Integer> newActiveAudioPlaybackClientUids = new ArrayList<>();
- List<OnAudioPlayerActiveStateChangedListener> audioPlayerActiveStateChangedListeners;
- List<OnAudioPlaybackStartedListener> audioPlaybackStartedListeners;
- synchronized (mLock) {
- // Update mActiveAudioPlaybackClientUids and mSortedAudioPlaybackClientUids,
- // and find newly activated audio playbacks.
- mActiveAudioPlaybackClientUids.clear();
- for (AudioPlaybackConfiguration config : configs) {
- // Ignore inactive (i.e. not playing) or PLAYER_TYPE_JAM_SOUNDPOOL
- // (i.e. playback from the SoundPool class which is only for sound effects)
- // playback.
- // Note that we shouldn't ignore PLAYER_TYPE_UNKNOWN because it might be OEM
- // specific audio/video players.
- if (!config.isActive() || config.getPlayerType()
- == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
- continue;
- }
-
- mActiveAudioPlaybackClientUids.add(config.getClientUid());
- Integer oldState = mAudioPlaybackStates.get(config.getPlayerInterfaceId());
- if (!isActiveState(oldState)) {
- if (DEBUG) {
- Log.d(TAG, "Found a new active media playback. " +
- AudioPlaybackConfiguration.toLogFriendlyString(config));
- }
- // New active audio playback.
- newActiveAudioPlaybackClientUids.add(config.getClientUid());
- int index = mSortedAudioPlaybackClientUids.indexOf(config.getClientUid());
- if (index == 0) {
- // It's the lastly played music app already. Skip updating.
- continue;
- } else if (index > 0) {
- mSortedAudioPlaybackClientUids.remove(index);
- }
- mSortedAudioPlaybackClientUids.add(0, config.getClientUid());
- }
- }
- audioPlayerActiveStateChangedListeners = new ArrayList<>(
- mAudioPlayerActiveStateChangedListeners);
- audioPlaybackStartedListeners = new ArrayList<>(mAudioPlaybackStartedListeners);
- }
- // Notify the change of audio playback states.
- for (AudioPlaybackConfiguration config : configs) {
- boolean wasActive = isActiveState(
- mAudioPlaybackStates.get(config.getPlayerInterfaceId()));
- boolean isActive = config.isActive();
- if (wasActive != isActive) {
- for (OnAudioPlayerActiveStateChangedListener listener
- : audioPlayerActiveStateChangedListeners) {
- listener.onAudioPlayerActiveStateChanged(config.getClientUid(),
- isActive);
- }
- }
- }
- // Notify the start of audio playback
- for (int uid : newActiveAudioPlaybackClientUids) {
- for (OnAudioPlaybackStartedListener listener : audioPlaybackStartedListeners) {
- listener.onAudioPlaybackStarted(uid);
- }
- }
- mAudioPlaybackStates.clear();
- for (AudioPlaybackConfiguration config : configs) {
- mAudioPlaybackStates.put(config.getPlayerInterfaceId(), config.getPlayerState());
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /**
- * Registers OnAudioPlaybackStartedListener.
- */
- public void registerOnAudioPlaybackStartedListener(OnAudioPlaybackStartedListener listener) {
- synchronized (mLock) {
- mAudioPlaybackStartedListeners.add(listener);
- }
- }
-
- /**
- * Unregisters OnAudioPlaybackStartedListener.
- */
- public void unregisterOnAudioPlaybackStartedListener(OnAudioPlaybackStartedListener listener) {
- synchronized (mLock) {
- mAudioPlaybackStartedListeners.remove(listener);
- }
- }
-
- /**
- * Registers OnAudioPlayerActiveStateChangedListener.
- */
- public void registerOnAudioPlayerActiveStateChangedListener(
- OnAudioPlayerActiveStateChangedListener listener) {
- synchronized (mLock) {
- mAudioPlayerActiveStateChangedListeners.add(listener);
- }
- }
-
- /**
- * Unregisters OnAudioPlayerActiveStateChangedListener.
- */
- public void unregisterOnAudioPlayerActiveStateChangedListener(
- OnAudioPlayerActiveStateChangedListener listener) {
- synchronized (mLock) {
- mAudioPlayerActiveStateChangedListeners.remove(listener);
- }
- }
-
- /**
- * Returns the sorted list of UIDs that have had active audio playback. (i.e. playing an
- * audio/video) The UID whose audio playback becomes active at the last comes first.
- */
- public IntArray getSortedAudioPlaybackClientUids() {
- IntArray sortedAudioPlaybackClientUids = new IntArray();
- synchronized (mLock) {
- sortedAudioPlaybackClientUids.addAll(mSortedAudioPlaybackClientUids);
- }
- return sortedAudioPlaybackClientUids;
- }
-
- /**
- * Returns if the audio playback is active for the uid.
- */
- public boolean isPlaybackActive(int uid) {
- synchronized (mLock) {
- return mActiveAudioPlaybackClientUids.contains(uid);
- }
- }
-
- /**
- * Cleans up the sorted list of audio playback client UIDs with given {@param
- * mediaButtonSessionUid}.
- * <p>UIDs whose audio playback started after the media button session's audio playback
- * cannot be the lastly played media app. So they won't needed anymore.
- *
- * @param mediaButtonSessionUid UID of the media button session.
- */
- public void cleanUpAudioPlaybackUids(int mediaButtonSessionUid) {
- synchronized (mLock) {
- int userId = UserHandle.getUserId(mediaButtonSessionUid);
- for (int i = mSortedAudioPlaybackClientUids.size() - 1; i >= 0; i--) {
- if (mSortedAudioPlaybackClientUids.get(i) == mediaButtonSessionUid) {
- break;
- }
- int uid = mSortedAudioPlaybackClientUids.get(i);
- if (userId == UserHandle.getUserId(uid) && !isPlaybackActive(uid)) {
- // Clean up unnecessary UIDs.
- // It doesn't need to be managed profile aware because it's just to prevent
- // the list from increasing indefinitely. The media button session updating
- // shouldn't be affected by cleaning up.
- mSortedAudioPlaybackClientUids.remove(i);
- }
- }
- }
- }
-
- /**
- * Dumps {@link AudioPlaybackMonitor}.
- */
- public void dump(PrintWriter pw, String prefix) {
- synchronized (mLock) {
- pw.println(prefix + "Audio playback (lastly played comes first)");
- String indent = prefix + " ";
- for (int i = 0; i < mSortedAudioPlaybackClientUids.size(); i++) {
- int uid = mSortedAudioPlaybackClientUids.get(i);
- pw.print(indent + "uid=" + uid + " packages=");
- String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
- if (packages != null && packages.length > 0) {
- for (int j = 0; j < packages.length; j++) {
- pw.print(packages[j] + " ");
- }
- }
- pw.println();
- }
- }
- }
-
- private boolean isActiveState(Integer state) {
- return state != null && state.equals(AudioPlaybackConfiguration.PLAYER_STATE_STARTED);
- }
-}
diff --git a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
new file mode 100644
index 000000000000..be223f1e56df
--- /dev/null
+++ b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.media.AudioPlaybackConfiguration;
+import android.media.IAudioService;
+import android.media.IPlaybackConfigDispatcher;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.IntArray;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Monitors the state changes of audio players.
+ */
+class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub {
+ private static boolean DEBUG = MediaSessionService.DEBUG;
+ private static String TAG = "AudioPlayerStateMonitor";
+
+ private static AudioPlayerStateMonitor sInstance = new AudioPlayerStateMonitor();
+
+ /**
+ * Called when the state of audio player is changed.
+ */
+ interface OnAudioPlayerStateChangedListener {
+ void onAudioPlayerStateChanged(
+ int uid, int prevState, @Nullable AudioPlaybackConfiguration config);
+ }
+
+ private final static class MessageHandler extends Handler {
+ private static final int MSG_AUDIO_PLAYER_STATE_CHANGED = 1;
+
+ private final OnAudioPlayerStateChangedListener mListsner;
+
+ public MessageHandler(Looper looper, OnAudioPlayerStateChangedListener listener) {
+ super(looper);
+ mListsner = listener;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_AUDIO_PLAYER_STATE_CHANGED:
+ mListsner.onAudioPlayerStateChanged(
+ msg.arg1, msg.arg2, (AudioPlaybackConfiguration) msg.obj);
+ break;
+ }
+ }
+
+ public void sendAudioPlayerStateChangedMessage(int uid, int prevState,
+ AudioPlaybackConfiguration config) {
+ obtainMessage(MSG_AUDIO_PLAYER_STATE_CHANGED, uid, prevState, config).sendToTarget();
+ }
+ }
+
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private final Map<OnAudioPlayerStateChangedListener, MessageHandler> mListenerMap =
+ new HashMap<>();
+ @GuardedBy("mLock")
+ private final Map<Integer, Integer> mAudioPlayerStates = new HashMap<>();
+ @GuardedBy("mLock")
+ private final Map<Integer, HashSet<Integer>> mAudioPlayersForUid = new HashMap<>();
+ // Sorted array of UIDs that had active audio playback. (i.e. playing an audio/video)
+ // The UID whose audio playback becomes active at the last comes first.
+ // TODO(b/35278867): Find and use unique identifier for apps because apps may share the UID.
+ @GuardedBy("mLock")
+ private final IntArray mSortedAudioPlaybackClientUids = new IntArray();
+
+ @GuardedBy("mLock")
+ private boolean mRegisteredToAudioService;
+
+ static AudioPlayerStateMonitor getInstance() {
+ return sInstance;
+ }
+
+ private AudioPlayerStateMonitor() {
+ }
+
+ /**
+ * Called when the {@link AudioPlaybackConfiguration} is updated.
+ * <p>If an app starts audio playback, the app's local media session will be the media button
+ * session. If the app has multiple media sessions, the playback active local session will be
+ * picked.
+ *
+ * @param configs List of the current audio playback configuration
+ */
+ @Override
+ public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
+ boolean flush) {
+ if (flush) {
+ Binder.flushPendingCommands();
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final Map<Integer, Integer> prevAudioPlayerStates = new HashMap<>(mAudioPlayerStates);
+ final Map<Integer, HashSet<Integer>> prevAudioPlayersForUid =
+ new HashMap<>(mAudioPlayersForUid);
+ synchronized (mLock) {
+ mAudioPlayerStates.clear();
+ mAudioPlayersForUid.clear();
+ for (AudioPlaybackConfiguration config : configs) {
+ int pii = config.getPlayerInterfaceId();
+ int uid = config.getClientUid();
+ mAudioPlayerStates.put(pii, config.getPlayerState());
+ HashSet<Integer> players = mAudioPlayersForUid.get(uid);
+ if (players == null) {
+ players = new HashSet<Integer>();
+ players.add(pii);
+ mAudioPlayersForUid.put(uid, players);
+ } else {
+ players.add(pii);
+ }
+ }
+ for (AudioPlaybackConfiguration config : configs) {
+ if (!config.isActive()) {
+ continue;
+ }
+
+ int uid = config.getClientUid();
+ if (!isActiveState(prevAudioPlayerStates.get(config.getPlayerInterfaceId()))) {
+ if (DEBUG) {
+ Log.d(TAG, "Found a new active media playback. " +
+ AudioPlaybackConfiguration.toLogFriendlyString(config));
+ }
+ // New active audio playback.
+ int index = mSortedAudioPlaybackClientUids.indexOf(uid);
+ if (index == 0) {
+ // It's the lastly played music app already. Skip updating.
+ continue;
+ } else if (index > 0) {
+ mSortedAudioPlaybackClientUids.remove(index);
+ }
+ mSortedAudioPlaybackClientUids.add(0, uid);
+ }
+ }
+ // Notify the change of audio player states.
+ for (AudioPlaybackConfiguration config : configs) {
+ final Integer prevState = prevAudioPlayerStates.get(config.getPlayerInterfaceId());
+ final int prevStateInt =
+ (prevState == null) ? AudioPlaybackConfiguration.PLAYER_STATE_UNKNOWN :
+ prevState.intValue();
+ if (prevStateInt != config.getPlayerState()) {
+ sendAudioPlayerStateChangedMessageLocked(
+ config.getClientUid(), prevStateInt, config);
+ }
+ }
+ for (Integer prevUid : prevAudioPlayersForUid.keySet()) {
+ // If all players for prevUid is removed, notify the prev state was
+ // PLAYER_STATE_STARTED only when there were a player whose state was
+ // PLAYER_STATE_STARTED, otherwise any inactive state is okay to notify.
+ if (!mAudioPlayersForUid.containsKey(prevUid)) {
+ Set<Integer> prevPlayers = prevAudioPlayersForUid.get(prevUid);
+ int prevState = AudioPlaybackConfiguration.PLAYER_STATE_UNKNOWN;
+ for (int pii : prevPlayers) {
+ Integer state = prevAudioPlayerStates.get(pii);
+ if (state == null) {
+ continue;
+ }
+ if (state == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
+ prevState = state;
+ break;
+ } else if (prevState
+ == AudioPlaybackConfiguration.PLAYER_STATE_UNKNOWN) {
+ prevState = state;
+ }
+ }
+ sendAudioPlayerStateChangedMessageLocked(prevUid, prevState, null);
+ }
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
+ * Registers OnAudioPlayerStateChangedListener.
+ */
+ public void registerListener(OnAudioPlayerStateChangedListener listener, Handler handler) {
+ synchronized (mLock) {
+ mListenerMap.put(listener, new MessageHandler((handler == null) ?
+ Looper.myLooper() : handler.getLooper(), listener));
+ }
+ }
+
+ /**
+ * Unregisters OnAudioPlayerStateChangedListener.
+ */
+ public void unregisterListener(OnAudioPlayerStateChangedListener listener) {
+ synchronized (mLock) {
+ mListenerMap.remove(listener);
+ }
+ }
+
+ /**
+ * Returns the sorted list of UIDs that have had active audio playback. (i.e. playing an
+ * audio/video) The UID whose audio playback becomes active at the last comes first.
+ */
+ public IntArray getSortedAudioPlaybackClientUids() {
+ IntArray sortedAudioPlaybackClientUids = new IntArray();
+ synchronized (mLock) {
+ sortedAudioPlaybackClientUids.addAll(mSortedAudioPlaybackClientUids);
+ }
+ return sortedAudioPlaybackClientUids;
+ }
+
+ /**
+ * Returns if the audio playback is active for the uid.
+ */
+ public boolean isPlaybackActive(int uid) {
+ synchronized (mLock) {
+ Set<Integer> players = mAudioPlayersForUid.get(uid);
+ if (players == null) {
+ return false;
+ }
+ for (Integer pii : players) {
+ if (isActiveState(mAudioPlayerStates.get(pii))) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Cleans up the sorted list of audio playback client UIDs with given {@param
+ * mediaButtonSessionUid}.
+ * <p>UIDs whose audio playback are inactive and have started before the media button session's
+ * audio playback cannot be the lastly played media app. So they won't needed anymore.
+ *
+ * @param mediaButtonSessionUid UID of the media button session.
+ */
+ public void cleanUpAudioPlaybackUids(int mediaButtonSessionUid) {
+ synchronized (mLock) {
+ int userId = UserHandle.getUserId(mediaButtonSessionUid);
+ for (int i = mSortedAudioPlaybackClientUids.size() - 1; i >= 0; i--) {
+ if (mSortedAudioPlaybackClientUids.get(i) == mediaButtonSessionUid) {
+ break;
+ }
+ int uid = mSortedAudioPlaybackClientUids.get(i);
+ if (userId == UserHandle.getUserId(uid) && !isPlaybackActive(uid)) {
+ // Clean up unnecessary UIDs.
+ // It doesn't need to be managed profile aware because it's just to prevent
+ // the list from increasing indefinitely. The media button session updating
+ // shouldn't be affected by cleaning up.
+ mSortedAudioPlaybackClientUids.remove(i);
+ }
+ }
+ }
+ }
+
+ /**
+ * Dumps {@link AudioPlayerStateMonitor}.
+ */
+ public void dump(Context context, PrintWriter pw, String prefix) {
+ synchronized (mLock) {
+ pw.println(prefix + "Audio playback (lastly played comes first)");
+ String indent = prefix + " ";
+ for (int i = 0; i < mSortedAudioPlaybackClientUids.size(); i++) {
+ int uid = mSortedAudioPlaybackClientUids.get(i);
+ pw.print(indent + "uid=" + uid + " packages=");
+ String[] packages = context.getPackageManager().getPackagesForUid(uid);
+ if (packages != null && packages.length > 0) {
+ for (int j = 0; j < packages.length; j++) {
+ pw.print(packages[j] + " ");
+ }
+ }
+ pw.println();
+ }
+ }
+ }
+
+ public void registerSelfIntoAudioServiceIfNeeded(IAudioService audioService) {
+ synchronized (mLock) {
+ try {
+ if (!mRegisteredToAudioService) {
+ audioService.registerPlaybackCallback(this);
+ mRegisteredToAudioService = true;
+ }
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Failed to register playback callback", e);
+ mRegisteredToAudioService = false;
+ }
+ }
+ }
+
+ private void sendAudioPlayerStateChangedMessageLocked(
+ final int uid, final int prevState, final AudioPlaybackConfiguration config) {
+ for (MessageHandler messageHandler : mListenerMap.values()) {
+ messageHandler.sendAudioPlayerStateChangedMessage(uid, prevState, config);
+ }
+ }
+
+ private static boolean isActiveState(Integer state) {
+ return state != null && state.equals(AudioPlaybackConfiguration.PLAYER_STATE_STARTED);
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 1cfd5f02e810..3c9e1d456c6f 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -19,12 +19,14 @@ package com.android.server.media;
import com.android.internal.util.DumpUtils;
import com.android.server.Watchdog;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.media.AudioPlaybackConfiguration;
import android.media.AudioRoutesInfo;
import android.media.AudioSystem;
import android.media.IAudioRoutesObserver;
@@ -96,7 +98,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub
private int mCurrentUserId = -1;
private boolean mGlobalBluetoothA2dpOn = false;
private final IAudioService mAudioService;
- private final AudioPlaybackMonitor mAudioPlaybackMonitor;
+ private final AudioPlayerStateMonitor mAudioPlayerStateMonitor;
+ private final Handler mHandler = new Handler();
private final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo();
public MediaRouterService(Context context) {
@@ -106,31 +109,57 @@ public final class MediaRouterService extends IMediaRouterService.Stub
mAudioService = IAudioService.Stub.asInterface(
ServiceManager.getService(Context.AUDIO_SERVICE));
- mAudioPlaybackMonitor = AudioPlaybackMonitor.getInstance(context, mAudioService);
- mAudioPlaybackMonitor.registerOnAudioPlayerActiveStateChangedListener(
- new AudioPlaybackMonitor.OnAudioPlayerActiveStateChangedListener() {
+ mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
+ mAudioPlayerStateMonitor.registerListener(
+ new AudioPlayerStateMonitor.OnAudioPlayerStateChangedListener() {
+ static final long WAIT_MS = 500;
+ final Runnable mRestoreBluetoothA2dpRunnable = new Runnable() {
+ @Override
+ public void run() {
+ restoreBluetoothA2dp();
+ }
+ };
+
@Override
- public void onAudioPlayerActiveStateChanged(int uid, boolean active) {
+ public void onAudioPlayerStateChanged(
+ int uid, int prevState, @Nullable AudioPlaybackConfiguration config) {
+ int restoreUid = -1;
+ boolean active = config == null ? false : config.isActive();
if (active) {
- restoreRoute(uid);
+ restoreUid = uid;
+ } else if (prevState != AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
+ // Noting to do if the prev state is not an active state.
+ return;
} else {
IntArray sortedAudioPlaybackClientUids =
- mAudioPlaybackMonitor.getSortedAudioPlaybackClientUids();
- boolean restored = false;
- for (int i = 0; i < sortedAudioPlaybackClientUids.size(); i++) {
- if (mAudioPlaybackMonitor.isPlaybackActive(
+ mAudioPlayerStateMonitor.getSortedAudioPlaybackClientUids();
+ for (int i = 0; i < sortedAudioPlaybackClientUids.size(); ++i) {
+ if (mAudioPlayerStateMonitor.isPlaybackActive(
sortedAudioPlaybackClientUids.get(i))) {
- restoreRoute(sortedAudioPlaybackClientUids.get(i));
- restored = true;
+ restoreUid = sortedAudioPlaybackClientUids.get(i);
break;
}
}
- if (!restored) {
- restoreBluetoothA2dp();
+ }
+
+ mHandler.removeCallbacks(mRestoreBluetoothA2dpRunnable);
+ if (restoreUid >= 0) {
+ restoreRoute(restoreUid);
+ if (DEBUG) {
+ Slog.d(TAG, "onAudioPlayerStateChanged: " + "uid " + uid
+ + " active " + active + " restoring " + restoreUid);
+ }
+ } else {
+ mHandler.postDelayed(mRestoreBluetoothA2dpRunnable, WAIT_MS);
+ if (DEBUG) {
+ Slog.d(TAG, "onAudioPlayerStateChanged: " + "uid " + uid
+ + " active " + active + " delaying");
}
}
}
- });
+ }, mHandler);
+ mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService);
+
AudioRoutesInfo audioRoutes = null;
try {
audioRoutes = mAudioService.startWatchingRoutes(new IAudioRoutesObserver.Stub() {
@@ -261,9 +290,14 @@ public final class MediaRouterService extends IMediaRouterService.Stub
final long token = Binder.clearCallingIdentity();
try {
+ ClientRecord clientRecord;
synchronized (mLock) {
- return isPlaybackActiveLocked(client);
+ clientRecord = mAllClientRecords.get(client.asBinder());
+ }
+ if (clientRecord != null) {
+ return mAudioPlayerStateMonitor.isPlaybackActive(clientRecord.mUid);
}
+ return false;
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -480,14 +514,6 @@ public final class MediaRouterService extends IMediaRouterService.Stub
return null;
}
- private boolean isPlaybackActiveLocked(IMediaRouterClient client) {
- ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
- if (clientRecord != null) {
- return mAudioPlaybackMonitor.isPlaybackActive(clientRecord.mUid);
- }
- return false;
- }
-
private void setDiscoveryRequestLocked(IMediaRouterClient client,
int routeTypes, boolean activeScan) {
final IBinder binder = client.asBinder();
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index aa652445c45a..f6a81d07277a 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -16,6 +16,7 @@
package com.android.server.media;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.INotificationManager;
import android.app.KeyguardManager;
@@ -31,7 +32,7 @@ import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.media.AudioManager;
-import android.media.AudioManagerInternal;
+import android.media.AudioPlaybackConfiguration;
import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.IRemoteVolumeController;
@@ -68,7 +69,6 @@ import android.view.KeyEvent;
import android.view.ViewConfiguration;
import com.android.internal.util.DumpUtils;
-import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.Watchdog;
import com.android.server.Watchdog.Monitor;
@@ -104,7 +104,6 @@ public class MediaSessionService extends SystemService implements Monitor {
private KeyguardManager mKeyguardManager;
private IAudioService mAudioService;
- private AudioManagerInternal mAudioManagerInternal;
private ContentResolver mContentResolver;
private SettingsObserver mSettingsObserver;
private INotificationManager mNotificationManager;
@@ -114,7 +113,7 @@ public class MediaSessionService extends SystemService implements Monitor {
// It's always not null after the MediaSessionService is started.
private FullUserRecord mCurrentFullUserRecord;
private MediaSessionRecord mGlobalPrioritySession;
- private AudioPlaybackMonitor mAudioPlaybackMonitor;
+ private AudioPlayerStateMonitor mAudioPlayerStateMonitor;
// Used to notify system UI when remote volume was changed. TODO find a
// better way to handle this.
@@ -137,11 +136,16 @@ public class MediaSessionService extends SystemService implements Monitor {
mKeyguardManager =
(KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
mAudioService = getAudioService();
- mAudioPlaybackMonitor = AudioPlaybackMonitor.getInstance(getContext(), mAudioService);
- mAudioPlaybackMonitor.registerOnAudioPlaybackStartedListener(
- new AudioPlaybackMonitor.OnAudioPlaybackStartedListener() {
+ mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
+ mAudioPlayerStateMonitor.registerListener(
+ new AudioPlayerStateMonitor.OnAudioPlayerStateChangedListener() {
@Override
- public void onAudioPlaybackStarted(int uid) {
+ public void onAudioPlayerStateChanged(
+ int uid, int prevState, @Nullable AudioPlaybackConfiguration config) {
+ if (config == null || !config.isActive() || config.getPlayerType()
+ == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
+ return;
+ }
synchronized (mLock) {
FullUserRecord user =
getFullUserRecordLocked(UserHandle.getUserId(uid));
@@ -150,8 +154,8 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
}
- });
- mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
+ }, null /* handler */);
+ mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService);
mContentResolver = getContext().getContentResolver();
mSettingsObserver = new SettingsObserver();
mSettingsObserver.observe();
@@ -650,7 +654,7 @@ public class MediaSessionService extends SystemService implements Monitor {
public FullUserRecord(int fullUserId) {
mFullUserId = fullUserId;
- mPriorityStack = new MediaSessionStack(mAudioPlaybackMonitor, this);
+ mPriorityStack = new MediaSessionStack(mAudioPlayerStateMonitor, this);
// Restore the remembered media button receiver before the boot.
String mediaButtonReceiver = Settings.Secure.getStringForUser(mContentResolver,
Settings.System.MEDIA_BUTTON_RECEIVER, mFullUserId);
@@ -1309,7 +1313,7 @@ public class MediaSessionService extends SystemService implements Monitor {
for (int i = 0; i < count; i++) {
mUserRecords.valueAt(i).dumpLocked(pw, "");
}
- mAudioPlaybackMonitor.dump(pw, "");
+ mAudioPlayerStateMonitor.dump(getContext(), pw, "");
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index d9fe72e0c8bb..719ec362e6e8 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -75,7 +75,7 @@ class MediaSessionStack {
*/
private final List<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
- private final AudioPlaybackMonitor mAudioPlaybackMonitor;
+ private final AudioPlayerStateMonitor mAudioPlayerStateMonitor;
private final OnMediaButtonSessionChangedListener mOnMediaButtonSessionChangedListener;
/**
@@ -84,7 +84,6 @@ class MediaSessionStack {
*/
private MediaSessionRecord mMediaButtonSession;
- private MediaSessionRecord mCachedDefault;
private MediaSessionRecord mCachedVolumeDefault;
/**
@@ -93,8 +92,8 @@ class MediaSessionStack {
private final SparseArray<ArrayList<MediaSessionRecord>> mCachedActiveLists =
new SparseArray<>();
- MediaSessionStack(AudioPlaybackMonitor monitor, OnMediaButtonSessionChangedListener listener) {
- mAudioPlaybackMonitor = monitor;
+ MediaSessionStack(AudioPlayerStateMonitor monitor, OnMediaButtonSessionChangedListener listener) {
+ mAudioPlayerStateMonitor = monitor;
mOnMediaButtonSessionChangedListener = listener;
}
@@ -187,13 +186,13 @@ class MediaSessionStack {
if (DEBUG) {
Log.d(TAG, "updateMediaButtonSessionIfNeeded, callers=" + Debug.getCallers(2));
}
- IntArray audioPlaybackUids = mAudioPlaybackMonitor.getSortedAudioPlaybackClientUids();
+ IntArray audioPlaybackUids = mAudioPlayerStateMonitor.getSortedAudioPlaybackClientUids();
for (int i = 0; i < audioPlaybackUids.size(); i++) {
MediaSessionRecord mediaButtonSession =
findMediaButtonSession(audioPlaybackUids.get(i));
if (mediaButtonSession != null) {
// Found the media button session.
- mAudioPlaybackMonitor.cleanUpAudioPlaybackUids(mediaButtonSession.getUid());
+ mAudioPlayerStateMonitor.cleanUpAudioPlaybackUids(mediaButtonSession.getUid());
if (mMediaButtonSession != mediaButtonSession) {
updateMediaButtonSession(mediaButtonSession);
}
@@ -216,7 +215,7 @@ class MediaSessionStack {
for (MediaSessionRecord session : mSessions) {
if (uid == session.getUid()) {
if (session.getPlaybackState() != null && session.isPlaybackActive() ==
- mAudioPlaybackMonitor.isPlaybackActive(session.getUid())) {
+ mAudioPlayerStateMonitor.isPlaybackActive(session.getUid())) {
// If there's a media session whose PlaybackState matches
// the audio playback state, return it immediately.
return session;
@@ -376,7 +375,6 @@ class MediaSessionStack {
}
private void clearCache(int userId) {
- mCachedDefault = null;
mCachedVolumeDefault = null;
mCachedActiveLists.remove(userId);
// mCachedActiveLists may also include the list of sessions for UserHandle.USER_ALL,
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b4056b333fe5..3fa3cd49d393 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -142,6 +142,7 @@ import android.os.Message;
import android.os.MessageQueue.IdleHandler;
import android.os.PersistableBundle;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.Process;
@@ -192,7 +193,6 @@ import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import libcore.io.IoUtils;
@@ -3746,7 +3746,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
extends UsageStatsManagerInternal.AppIdleStateChangeListener {
@Override
- public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
+ public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket) {
try {
final int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
diff --git a/services/core/java/com/android/server/net/watchlist/DigestUtils.java b/services/core/java/com/android/server/net/watchlist/DigestUtils.java
new file mode 100644
index 000000000000..57becb002a59
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/DigestUtils.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.watchlist;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Utils for calculating digests.
+ */
+public class DigestUtils {
+
+ private static final int FILE_READ_BUFFER_SIZE = 16 * 1024;
+
+ private DigestUtils() {}
+
+ /** @return SHA256 hash of the provided file */
+ public static byte[] getSha256Hash(File apkFile) throws IOException, NoSuchAlgorithmException {
+ try (InputStream stream = new FileInputStream(apkFile)) {
+ return getSha256Hash(stream);
+ }
+ }
+
+ /** @return SHA256 hash of data read from the provided input stream */
+ public static byte[] getSha256Hash(InputStream stream)
+ throws IOException, NoSuchAlgorithmException {
+ MessageDigest digester = MessageDigest.getInstance("SHA256");
+
+ int bytesRead;
+ byte[] buf = new byte[FILE_READ_BUFFER_SIZE];
+ while ((bytesRead = stream.read(buf)) >= 0) {
+ digester.update(buf, 0, bytesRead);
+ }
+ return digester.digest();
+ }
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/net/watchlist/HarmfulDigests.java b/services/core/java/com/android/server/net/watchlist/HarmfulDigests.java
new file mode 100644
index 000000000000..27c22cea1782
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/HarmfulDigests.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.watchlist;
+
+import com.android.internal.util.HexDump;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Helper class to store all harmful digests in memory.
+ * TODO: Optimize memory usage using byte array with binary search.
+ */
+class HarmfulDigests {
+
+ private final Set<String> mDigestSet;
+
+ HarmfulDigests(List<byte[]> digests) {
+ final HashSet<String> tmpDigestSet = new HashSet<>();
+ final int size = digests.size();
+ for (int i = 0; i < size; i++) {
+ tmpDigestSet.add(HexDump.toHexString(digests.get(i)));
+ }
+ mDigestSet = Collections.unmodifiableSet(tmpDigestSet);
+ }
+
+ public boolean contains(byte[] digest) {
+ return mDigestSet.contains(HexDump.toHexString(digest));
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ for (String digest : mDigestSet) {
+ pw.println(digest);
+ }
+ pw.println("");
+ }
+}
diff --git a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
new file mode 100644
index 000000000000..171703ac8933
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.watchlist;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.net.IIpConnectivityMetrics;
+import android.net.INetdEventCallback;
+import android.net.NetworkWatchlistManager;
+import android.net.metrics.IpConnectivityLog;
+import android.os.Binder;
+import android.os.Process;
+import android.os.SharedMemory;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.net.INetworkWatchlistManager;
+import com.android.server.ServiceThread;
+import com.android.server.SystemService;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Implementation of network watchlist service.
+ */
+public class NetworkWatchlistService extends INetworkWatchlistManager.Stub {
+
+ private static final String TAG = NetworkWatchlistService.class.getSimpleName();
+ static final boolean DEBUG = false;
+
+ private static final String PROPERTY_NETWORK_WATCHLIST_ENABLED =
+ "ro.network_watchlist_enabled";
+
+ private static final int MAX_NUM_OF_WATCHLIST_DIGESTS = 10000;
+
+ public static class Lifecycle extends SystemService {
+ private NetworkWatchlistService mService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ if (!SystemProperties.getBoolean(PROPERTY_NETWORK_WATCHLIST_ENABLED, false)) {
+ // Watchlist service is disabled
+ return;
+ }
+ mService = new NetworkWatchlistService(getContext());
+ publishBinderService(Context.NETWORK_WATCHLIST_SERVICE, mService);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (!SystemProperties.getBoolean(PROPERTY_NETWORK_WATCHLIST_ENABLED, false)) {
+ // Watchlist service is disabled
+ return;
+ }
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ try {
+ mService.initIpConnectivityMetrics();
+ mService.startWatchlistLogging();
+ } catch (RemoteException e) {
+ // Should not happen
+ }
+ ReportWatchlistJobService.schedule(getContext());
+ }
+ }
+ }
+
+ private volatile boolean mIsLoggingEnabled = false;
+ private final Object mLoggingSwitchLock = new Object();
+
+ private final WatchlistSettings mSettings;
+ private final Context mContext;
+
+ // Separate thread to handle expensive watchlist logging work.
+ private final ServiceThread mHandlerThread;
+
+ @VisibleForTesting
+ IIpConnectivityMetrics mIpConnectivityMetrics;
+ @VisibleForTesting
+ WatchlistLoggingHandler mNetworkWatchlistHandler;
+
+ public NetworkWatchlistService(Context context) {
+ mContext = context;
+ mSettings = WatchlistSettings.getInstance();
+ mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
+ /* allowIo */ false);
+ mHandlerThread.start();
+ mNetworkWatchlistHandler = new WatchlistLoggingHandler(mContext,
+ mHandlerThread.getLooper());
+ mNetworkWatchlistHandler.reportWatchlistIfNecessary();
+ }
+
+ // For testing only
+ @VisibleForTesting
+ NetworkWatchlistService(Context context, ServiceThread handlerThread,
+ WatchlistLoggingHandler handler, IIpConnectivityMetrics ipConnectivityMetrics) {
+ mContext = context;
+ mSettings = WatchlistSettings.getInstance();
+ mHandlerThread = handlerThread;
+ mNetworkWatchlistHandler = handler;
+ mIpConnectivityMetrics = ipConnectivityMetrics;
+ }
+
+ private void initIpConnectivityMetrics() {
+ mIpConnectivityMetrics = (IIpConnectivityMetrics) IIpConnectivityMetrics.Stub.asInterface(
+ ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
+ }
+
+ private final INetdEventCallback mNetdEventCallback = new INetdEventCallback.Stub() {
+ @Override
+ public void onDnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount,
+ long timestamp, int uid) {
+ if (!mIsLoggingEnabled) {
+ return;
+ }
+ mNetworkWatchlistHandler.asyncNetworkEvent(hostname, ipAddresses, uid);
+ }
+
+ @Override
+ public void onConnectEvent(String ipAddr, int port, long timestamp, int uid) {
+ if (!mIsLoggingEnabled) {
+ return;
+ }
+ mNetworkWatchlistHandler.asyncNetworkEvent(null, new String[]{ipAddr}, uid);
+ }
+ };
+
+ @VisibleForTesting
+ protected boolean startWatchlistLoggingImpl() throws RemoteException {
+ if (DEBUG) {
+ Slog.i(TAG, "Starting watchlist logging.");
+ }
+ synchronized (mLoggingSwitchLock) {
+ if (mIsLoggingEnabled) {
+ Slog.w(TAG, "Watchlist logging is already running");
+ return true;
+ }
+ try {
+ if (mIpConnectivityMetrics.addNetdEventCallback(
+ INetdEventCallback.CALLBACK_CALLER_NETWORK_WATCHLIST, mNetdEventCallback)) {
+ mIsLoggingEnabled = true;
+ return true;
+ } else {
+ return false;
+ }
+ } catch (RemoteException re) {
+ // Should not happen
+ return false;
+ }
+ }
+ }
+
+ @Override
+ public boolean startWatchlistLogging() throws RemoteException {
+ enforceWatchlistLoggingPermission();
+ return startWatchlistLoggingImpl();
+ }
+
+ @VisibleForTesting
+ protected boolean stopWatchlistLoggingImpl() {
+ if (DEBUG) {
+ Slog.i(TAG, "Stopping watchlist logging");
+ }
+ synchronized (mLoggingSwitchLock) {
+ if (!mIsLoggingEnabled) {
+ Slog.w(TAG, "Watchlist logging is not running");
+ return true;
+ }
+ // stop the logging regardless of whether we fail to unregister listener
+ mIsLoggingEnabled = false;
+
+ try {
+ return mIpConnectivityMetrics.removeNetdEventCallback(
+ INetdEventCallback.CALLBACK_CALLER_NETWORK_WATCHLIST);
+ } catch (RemoteException re) {
+ // Should not happen
+ return false;
+ }
+ }
+ }
+
+ @Override
+ public boolean stopWatchlistLogging() throws RemoteException {
+ enforceWatchlistLoggingPermission();
+ return stopWatchlistLoggingImpl();
+ }
+
+ private void enforceWatchlistLoggingPermission() {
+ final int uid = Binder.getCallingUid();
+ if (uid != Process.SYSTEM_UID) {
+ throw new SecurityException(String.format("Uid %d has no permission to change watchlist"
+ + " setting.", uid));
+ }
+ }
+
+ /**
+ * Set a new network watchlist.
+ * This method should be called by ConfigUpdater only.
+ *
+ * @return True if network watchlist is updated.
+ */
+ public boolean setNetworkSecurityWatchlist(List<byte[]> domainsCrc32Digests,
+ List<byte[]> domainsSha256Digests,
+ List<byte[]> ipAddressesCrc32Digests,
+ List<byte[]> ipAddressesSha256Digests) {
+ Slog.i(TAG, "Setting network watchlist");
+ if (domainsCrc32Digests == null || domainsSha256Digests == null
+ || ipAddressesCrc32Digests == null || ipAddressesSha256Digests == null) {
+ Slog.e(TAG, "Parameters cannot be null");
+ return false;
+ }
+ if (domainsCrc32Digests.size() != domainsSha256Digests.size()
+ || ipAddressesCrc32Digests.size() != ipAddressesSha256Digests.size()) {
+ Slog.e(TAG, "Must need to have the same number of CRC32 and SHA256 digests");
+ return false;
+ }
+ if (domainsSha256Digests.size() + ipAddressesSha256Digests.size()
+ > MAX_NUM_OF_WATCHLIST_DIGESTS) {
+ Slog.e(TAG, "Total watchlist size cannot exceed " + MAX_NUM_OF_WATCHLIST_DIGESTS);
+ return false;
+ }
+ mSettings.writeSettingsToDisk(domainsCrc32Digests, domainsSha256Digests,
+ ipAddressesCrc32Digests, ipAddressesSha256Digests);
+ Slog.i(TAG, "Set network watchlist: Success");
+ return true;
+ }
+
+ @Override
+ public void reportWatchlistIfNecessary() {
+ // Allow any apps to trigger report event, as we won't run it if it's too early.
+ mNetworkWatchlistHandler.reportWatchlistIfNecessary();
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ mSettings.dump(fd, pw, args);
+ }
+
+}
diff --git a/services/core/java/com/android/server/net/watchlist/ReportWatchlistJobService.java b/services/core/java/com/android/server/net/watchlist/ReportWatchlistJobService.java
new file mode 100644
index 000000000000..dfeb1b2d2eab
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/ReportWatchlistJobService.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.watchlist;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.net.NetworkWatchlistManager;
+import android.util.Slog;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A job that periodically report watchlist records.
+ */
+public class ReportWatchlistJobService extends JobService {
+
+ private static final boolean DEBUG = NetworkWatchlistService.DEBUG;
+ private static final String TAG = "WatchlistJobService";
+
+ // Unique job id used in system service, other jobs should not use the same value.
+ public static final int REPORT_WATCHLIST_RECORDS_JOB_ID = 0xd7689;
+ public static final long REPORT_WATCHLIST_RECORDS_PERIOD_MILLIS =
+ TimeUnit.HOURS.toMillis(12);
+
+ @Override
+ public boolean onStartJob(final JobParameters jobParameters) {
+ if (jobParameters.getJobId() != REPORT_WATCHLIST_RECORDS_JOB_ID) {
+ return false;
+ }
+ if (DEBUG) Slog.d(TAG, "Start scheduled job.");
+ new NetworkWatchlistManager(this).reportWatchlistIfNecessary();
+ jobFinished(jobParameters, false);
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters jobParameters) {
+ return true; // Reschedule when possible.
+ }
+
+ /**
+ * Schedule the {@link ReportWatchlistJobService} to run periodically.
+ */
+ public static void schedule(Context context) {
+ if (DEBUG) Slog.d(TAG, "Scheduling records aggregator task");
+ final JobScheduler scheduler =
+ (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ scheduler.schedule(new JobInfo.Builder(REPORT_WATCHLIST_RECORDS_JOB_ID,
+ new ComponentName(context, ReportWatchlistJobService.class))
+ //.setOverrideDeadline(45 * 1000) // Schedule job soon, for testing.
+ .setPeriodic(REPORT_WATCHLIST_RECORDS_PERIOD_MILLIS)
+ .setRequiresDeviceIdle(true)
+ .setRequiresBatteryNotLow(true)
+ .setPersisted(false)
+ .build());
+ }
+
+}
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
new file mode 100644
index 000000000000..2247558476c4
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.watchlist;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.os.DropBoxManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A Handler class for network watchlist logging on a background thread.
+ */
+class WatchlistLoggingHandler extends Handler {
+
+ private static final String TAG = WatchlistLoggingHandler.class.getSimpleName();
+ private static final boolean DEBUG = NetworkWatchlistService.DEBUG;
+
+ @VisibleForTesting
+ static final int LOG_WATCHLIST_EVENT_MSG = 1;
+ @VisibleForTesting
+ static final int REPORT_RECORDS_IF_NECESSARY_MSG = 2;
+
+ private static final long ONE_DAY_MS = TimeUnit.DAYS.toMillis(1);
+ private static final String DROPBOX_TAG = "network_watchlist_report";
+
+ private final Context mContext;
+ private final ContentResolver mResolver;
+ private final PackageManager mPm;
+ private final WatchlistReportDbHelper mDbHelper;
+ private final WatchlistSettings mSettings;
+ // A cache for uid and apk digest mapping.
+ // As uid won't be reused until reboot, it's safe to assume uid is unique per signature and app.
+ // TODO: Use more efficient data structure.
+ private final HashMap<Integer, byte[]> mCachedUidDigestMap = new HashMap<>();
+
+ private interface WatchlistEventKeys {
+ String HOST = "host";
+ String IP_ADDRESSES = "ipAddresses";
+ String UID = "uid";
+ String TIMESTAMP = "timestamp";
+ }
+
+ WatchlistLoggingHandler(Context context, Looper looper) {
+ super(looper);
+ mContext = context;
+ mPm = mContext.getPackageManager();
+ mResolver = mContext.getContentResolver();
+ mDbHelper = WatchlistReportDbHelper.getInstance(context);
+ mSettings = WatchlistSettings.getInstance();
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case LOG_WATCHLIST_EVENT_MSG: {
+ final Bundle data = msg.getData();
+ handleNetworkEvent(
+ data.getString(WatchlistEventKeys.HOST),
+ data.getStringArray(WatchlistEventKeys.IP_ADDRESSES),
+ data.getInt(WatchlistEventKeys.UID),
+ data.getLong(WatchlistEventKeys.TIMESTAMP)
+ );
+ break;
+ }
+ case REPORT_RECORDS_IF_NECESSARY_MSG:
+ tryAggregateRecords();
+ break;
+ default: {
+ Slog.d(TAG, "WatchlistLoggingHandler received an unknown of message.");
+ break;
+ }
+ }
+ }
+
+ /**
+ * Report network watchlist records if we collected enough data.
+ */
+ public void reportWatchlistIfNecessary() {
+ final Message msg = obtainMessage(REPORT_RECORDS_IF_NECESSARY_MSG);
+ sendMessage(msg);
+ }
+
+ /**
+ * Insert network traffic event to watchlist async queue processor.
+ */
+ public void asyncNetworkEvent(String host, String[] ipAddresses, int uid) {
+ final Message msg = obtainMessage(LOG_WATCHLIST_EVENT_MSG);
+ final Bundle bundle = new Bundle();
+ bundle.putString(WatchlistEventKeys.HOST, host);
+ bundle.putStringArray(WatchlistEventKeys.IP_ADDRESSES, ipAddresses);
+ bundle.putInt(WatchlistEventKeys.UID, uid);
+ bundle.putLong(WatchlistEventKeys.TIMESTAMP, System.currentTimeMillis());
+ msg.setData(bundle);
+ sendMessage(msg);
+ }
+
+ private void handleNetworkEvent(String hostname, String[] ipAddresses,
+ int uid, long timestamp) {
+ if (DEBUG) {
+ Slog.i(TAG, "handleNetworkEvent with host: " + hostname + ", uid: " + uid);
+ }
+ final String cncDomain = searchAllSubDomainsInWatchlist(hostname);
+ if (cncDomain != null) {
+ insertRecord(getDigestFromUid(uid), cncDomain, timestamp);
+ } else {
+ final String cncIp = searchIpInWatchlist(ipAddresses);
+ if (cncIp != null) {
+ insertRecord(getDigestFromUid(uid), cncIp, timestamp);
+ }
+ }
+ }
+
+ private boolean insertRecord(byte[] digest, String cncHost, long timestamp) {
+ final boolean result = mDbHelper.insertNewRecord(digest, cncHost, timestamp);
+ tryAggregateRecords();
+ return result;
+ }
+
+ private boolean shouldReportNetworkWatchlist() {
+ final long lastReportTime = Settings.Global.getLong(mResolver,
+ Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME, 0L);
+ final long currentTimestamp = System.currentTimeMillis();
+ if (currentTimestamp < lastReportTime) {
+ Slog.i(TAG, "Last report time is larger than current time, reset report");
+ mDbHelper.cleanup();
+ return false;
+ }
+ return currentTimestamp >= lastReportTime + ONE_DAY_MS;
+ }
+
+ private void tryAggregateRecords() {
+ if (shouldReportNetworkWatchlist()) {
+ Slog.i(TAG, "Start aggregating watchlist records.");
+ final DropBoxManager dbox = mContext.getSystemService(DropBoxManager.class);
+ if (dbox != null && !dbox.isTagEnabled(DROPBOX_TAG)) {
+ final WatchlistReportDbHelper.AggregatedResult aggregatedResult =
+ mDbHelper.getAggregatedRecords();
+ final byte[] encodedResult = encodeAggregatedResult(aggregatedResult);
+ if (encodedResult != null) {
+ addEncodedReportToDropBox(encodedResult);
+ }
+ }
+ mDbHelper.cleanup();
+ Settings.Global.putLong(mResolver, Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME,
+ System.currentTimeMillis());
+ } else {
+ Slog.i(TAG, "No need to aggregate record yet.");
+ }
+ }
+
+ private byte[] encodeAggregatedResult(
+ WatchlistReportDbHelper.AggregatedResult aggregatedResult) {
+ // TODO: Encode results using differential privacy.
+ return null;
+ }
+
+ private void addEncodedReportToDropBox(byte[] encodedReport) {
+ final DropBoxManager dbox = mContext.getSystemService(DropBoxManager.class);
+ dbox.addData(DROPBOX_TAG, encodedReport, 0);
+ }
+
+ /**
+ * Get app digest from app uid.
+ */
+ private byte[] getDigestFromUid(int uid) {
+ final byte[] cachedDigest = mCachedUidDigestMap.get(uid);
+ if (cachedDigest != null) {
+ return cachedDigest;
+ }
+ final String[] packageNames = mPm.getPackagesForUid(uid);
+ final int userId = UserHandle.getUserId(uid);
+ if (!ArrayUtils.isEmpty(packageNames)) {
+ for (String packageName : packageNames) {
+ try {
+ final String apkPath = mPm.getPackageInfoAsUser(packageName,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId)
+ .applicationInfo.publicSourceDir;
+ if (TextUtils.isEmpty(apkPath)) {
+ Slog.w(TAG, "Cannot find apkPath for " + packageName);
+ continue;
+ }
+ final byte[] digest = DigestUtils.getSha256Hash(new File(apkPath));
+ mCachedUidDigestMap.put(uid, digest);
+ return digest;
+ } catch (NameNotFoundException | NoSuchAlgorithmException | IOException e) {
+ Slog.e(TAG, "Should not happen", e);
+ return null;
+ }
+ }
+ } else {
+ Slog.e(TAG, "Should not happen");
+ }
+ return null;
+ }
+
+ /**
+ * Search if any ip addresses are in watchlist.
+ *
+ * @param ipAddresses Ip address that you want to search in watchlist.
+ * @return Ip address that exists in watchlist, null if it does not match anything.
+ */
+ private String searchIpInWatchlist(String[] ipAddresses) {
+ for (String ipAddress : ipAddresses) {
+ if (isIpInWatchlist(ipAddress)) {
+ return ipAddress;
+ }
+ }
+ return null;
+ }
+
+ /** Search if the ip is in watchlist */
+ private boolean isIpInWatchlist(String ipAddr) {
+ if (ipAddr == null) {
+ return false;
+ }
+ return mSettings.containsIp(ipAddr);
+ }
+
+ /** Search if the host is in watchlist */
+ private boolean isHostInWatchlist(String host) {
+ if (host == null) {
+ return false;
+ }
+ return mSettings.containsDomain(host);
+ }
+
+ /**
+ * Search if any sub-domain in host is in watchlist.
+ *
+ * @param host Host that we want to search.
+ * @return Domain that exists in watchlist, null if it does not match anything.
+ */
+ private String searchAllSubDomainsInWatchlist(String host) {
+ if (host == null) {
+ return null;
+ }
+ final String[] subDomains = getAllSubDomains(host);
+ for (String subDomain : subDomains) {
+ if (isHostInWatchlist(subDomain)) {
+ return subDomain;
+ }
+ }
+ return null;
+ }
+
+ /** Get all sub-domains in a host */
+ @VisibleForTesting
+ static String[] getAllSubDomains(String host) {
+ if (host == null) {
+ return null;
+ }
+ final ArrayList<String> subDomainList = new ArrayList<>();
+ subDomainList.add(host);
+ int index = host.indexOf(".");
+ while (index != -1) {
+ host = host.substring(index + 1);
+ if (!TextUtils.isEmpty(host)) {
+ subDomainList.add(host);
+ }
+ index = host.indexOf(".");
+ }
+ return subDomainList.toArray(new String[0]);
+ }
+}
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
new file mode 100644
index 000000000000..f48463f5ae63
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.watchlist;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Pair;
+
+import com.android.internal.util.HexDump;
+
+import java.util.ArrayList;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Helper class to process watchlist read / save watchlist reports.
+ */
+class WatchlistReportDbHelper extends SQLiteOpenHelper {
+
+ private static final String TAG = "WatchlistReportDbHelper";
+
+ private static final String NAME = "watchlist_report.db";
+ private static final int VERSION = 2;
+
+ private static final int IDLE_CONNECTION_TIMEOUT_MS = 30000;
+
+ private static class WhiteListReportContract {
+ private static final String TABLE = "records";
+ private static final String APP_DIGEST = "app_digest";
+ private static final String CNC_DOMAIN = "cnc_domain";
+ private static final String TIMESTAMP = "timestamp";
+ }
+
+ private static final String CREATE_TABLE_MODEL = "CREATE TABLE "
+ + WhiteListReportContract.TABLE + "("
+ + WhiteListReportContract.APP_DIGEST + " BLOB,"
+ + WhiteListReportContract.CNC_DOMAIN + " TEXT,"
+ + WhiteListReportContract.TIMESTAMP + " INTEGER DEFAULT 0" + " )";
+
+ private static final int INDEX_DIGEST = 0;
+ private static final int INDEX_CNC_DOMAIN = 1;
+ private static final int INDEX_TIMESTAMP = 2;
+
+ private static final String[] DIGEST_DOMAIN_PROJECTION =
+ new String[] {
+ WhiteListReportContract.APP_DIGEST,
+ WhiteListReportContract.CNC_DOMAIN
+ };
+
+ private static WatchlistReportDbHelper sInstance;
+
+ /**
+ * Aggregated watchlist records.
+ */
+ public static class AggregatedResult {
+ // A list of digests that visited c&c domain or ip before.
+ Set<String> appDigestList;
+
+ // The c&c domain or ip visited before.
+ String cncDomainVisited;
+
+ // A list of app digests and c&c domain visited.
+ HashMap<String, String> appDigestCNCList;
+ }
+
+ private WatchlistReportDbHelper(Context context) {
+ super(context, WatchlistSettings.getSystemWatchlistFile(NAME).getAbsolutePath(),
+ null, VERSION);
+ // Memory optimization - close idle connections after 30s of inactivity
+ setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS);
+ }
+
+ public static synchronized WatchlistReportDbHelper getInstance(Context context) {
+ if (sInstance != null) {
+ return sInstance;
+ }
+ sInstance = new WatchlistReportDbHelper(context);
+ return sInstance;
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL(CREATE_TABLE_MODEL);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // TODO: For now, drop older tables and recreate new ones.
+ db.execSQL("DROP TABLE IF EXISTS " + WhiteListReportContract.TABLE);
+ onCreate(db);
+ }
+
+ /**
+ * Insert new watchlist record.
+ *
+ * @param appDigest The digest of an app.
+ * @param cncDomain C&C domain that app visited.
+ * @return True if success.
+ */
+ public boolean insertNewRecord(byte[] appDigest, String cncDomain,
+ long timestamp) {
+ final SQLiteDatabase db = getWritableDatabase();
+ final ContentValues values = new ContentValues();
+ values.put(WhiteListReportContract.APP_DIGEST, appDigest);
+ values.put(WhiteListReportContract.CNC_DOMAIN, cncDomain);
+ values.put(WhiteListReportContract.TIMESTAMP, timestamp);
+ return db.insert(WhiteListReportContract.TABLE, null, values) != -1;
+ }
+
+ /**
+ * Aggregate the records in database, and return a rappor encoded result.
+ */
+ public AggregatedResult getAggregatedRecords() {
+ final long twoDaysBefore = getTwoDaysBeforeTimestamp();
+ final long yesterday = getYesterdayTimestamp();
+ final String selectStatement = WhiteListReportContract.TIMESTAMP + " >= ? AND " +
+ WhiteListReportContract.TIMESTAMP + " <= ?";
+
+ final SQLiteDatabase db = getReadableDatabase();
+ Cursor c = null;
+ try {
+ c = db.query(true /* distinct */,
+ WhiteListReportContract.TABLE, DIGEST_DOMAIN_PROJECTION, selectStatement,
+ new String[]{"" + twoDaysBefore, "" + yesterday}, null, null,
+ null, null);
+ if (c == null || c.getCount() == 0) {
+ return null;
+ }
+ final AggregatedResult result = new AggregatedResult();
+ result.cncDomainVisited = null;
+ // After aggregation, each digest maximum will have only 1 record.
+ result.appDigestList = new HashSet<>();
+ result.appDigestCNCList = new HashMap<>();
+ while (c.moveToNext()) {
+ // We use hex string here as byte[] cannot be a key in HashMap.
+ String digestHexStr = HexDump.toHexString(c.getBlob(INDEX_DIGEST));
+ String cncDomain = c.getString(INDEX_CNC_DOMAIN);
+
+ result.appDigestList.add(digestHexStr);
+ if (result.cncDomainVisited != null) {
+ result.cncDomainVisited = cncDomain;
+ }
+ result.appDigestCNCList.put(digestHexStr, cncDomain);
+ }
+ return result;
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ }
+
+ /**
+ * Remove all the records before yesterday.
+ *
+ * @return True if success.
+ */
+ public boolean cleanup() {
+ final SQLiteDatabase db = getWritableDatabase();
+ final long twoDaysBefore = getTwoDaysBeforeTimestamp();
+ final String clause = WhiteListReportContract.TIMESTAMP + "< " + twoDaysBefore;
+ return db.delete(WhiteListReportContract.TABLE, clause, null) != 0;
+ }
+
+ static long getTwoDaysBeforeTimestamp() {
+ return getMidnightTimestamp(2);
+ }
+
+ static long getYesterdayTimestamp() {
+ return getMidnightTimestamp(1);
+ }
+
+ static long getMidnightTimestamp(int daysBefore) {
+ java.util.Calendar date = new GregorianCalendar();
+ // reset hour, minutes, seconds and millis
+ date.set(java.util.Calendar.HOUR_OF_DAY, 0);
+ date.set(java.util.Calendar.MINUTE, 0);
+ date.set(java.util.Calendar.SECOND, 0);
+ date.set(java.util.Calendar.MILLISECOND, 0);
+ date.add(java.util.Calendar.DAY_OF_MONTH, -daysBefore);
+ return date.getTimeInMillis();
+ }
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
new file mode 100644
index 000000000000..c50f0d56c992
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.watchlist;
+
+import android.os.Environment;
+import android.util.AtomicFile;
+import android.util.Log;
+import android.util.Xml;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.HexDump;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+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.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.CRC32;
+
+/**
+ * A util class to do watchlist settings operations, like setting watchlist, query if a domain
+ * exists in watchlist.
+ */
+class WatchlistSettings {
+ private static final String TAG = "WatchlistSettings";
+
+ // Settings xml will be stored in /data/system/network_watchlist/watchlist_settings.xml
+ static final String SYSTEM_WATCHLIST_DIR = "network_watchlist";
+
+ private static final String WATCHLIST_XML_FILE = "watchlist_settings.xml";
+
+ private static class XmlTags {
+ private static final String WATCHLIST_SETTINGS = "watchlist-settings";
+ private static final String SHA256_DOMAIN = "sha256-domain";
+ private static final String CRC32_DOMAIN = "crc32-domain";
+ private static final String SHA256_IP = "sha256-ip";
+ private static final String CRC32_IP = "crc32-ip";
+ private static final String HASH = "hash";
+ }
+
+ private static WatchlistSettings sInstance = new WatchlistSettings();
+ private final AtomicFile mXmlFile;
+ private final Object mLock = new Object();
+ private HarmfulDigests mCrc32DomainDigests = new HarmfulDigests(new ArrayList<>());
+ private HarmfulDigests mSha256DomainDigests = new HarmfulDigests(new ArrayList<>());
+ private HarmfulDigests mCrc32IpDigests = new HarmfulDigests(new ArrayList<>());
+ private HarmfulDigests mSha256IpDigests = new HarmfulDigests(new ArrayList<>());
+
+ public static synchronized WatchlistSettings getInstance() {
+ return sInstance;
+ }
+
+ private WatchlistSettings() {
+ this(getSystemWatchlistFile(WATCHLIST_XML_FILE));
+ }
+
+ @VisibleForTesting
+ protected WatchlistSettings(File xmlFile) {
+ mXmlFile = new AtomicFile(xmlFile);
+ readSettingsLocked();
+ }
+
+ static File getSystemWatchlistFile(String filename) {
+ final File dataSystemDir = Environment.getDataSystemDirectory();
+ final File systemWatchlistDir = new File(dataSystemDir, SYSTEM_WATCHLIST_DIR);
+ systemWatchlistDir.mkdirs();
+ return new File(systemWatchlistDir, filename);
+ }
+
+ private void readSettingsLocked() {
+ synchronized (mLock) {
+ FileInputStream stream;
+ try {
+ stream = mXmlFile.openRead();
+ } catch (FileNotFoundException e) {
+ Log.i(TAG, "No watchlist settings: " + mXmlFile.getBaseFile().getAbsolutePath());
+ return;
+ }
+
+ final List<byte[]> crc32DomainList = new ArrayList<>();
+ final List<byte[]> sha256DomainList = new ArrayList<>();
+ final List<byte[]> crc32IpList = new ArrayList<>();
+ final List<byte[]> sha256IpList = new ArrayList<>();
+
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, StandardCharsets.UTF_8.name());
+ parser.nextTag();
+ parser.require(XmlPullParser.START_TAG, null, XmlTags.WATCHLIST_SETTINGS);
+ while (parser.nextTag() == XmlPullParser.START_TAG) {
+ String tagName = parser.getName();
+ switch (tagName) {
+ case XmlTags.CRC32_DOMAIN:
+ parseHash(parser, tagName, crc32DomainList);
+ break;
+ case XmlTags.CRC32_IP:
+ parseHash(parser, tagName, crc32IpList);
+ break;
+ case XmlTags.SHA256_DOMAIN:
+ parseHash(parser, tagName, sha256DomainList);
+ break;
+ case XmlTags.SHA256_IP:
+ parseHash(parser, tagName, sha256IpList);
+ break;
+ default:
+ Log.w(TAG, "Unknown element: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ parser.require(XmlPullParser.END_TAG, null, XmlTags.WATCHLIST_SETTINGS);
+ writeSettingsToMemory(crc32DomainList, sha256DomainList, crc32IpList, sha256IpList);
+ } catch (IllegalStateException | NullPointerException | NumberFormatException |
+ XmlPullParserException | IOException | IndexOutOfBoundsException e) {
+ Log.w(TAG, "Failed parsing " + e);
+ } finally {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ private void parseHash(XmlPullParser parser, String tagName, List<byte[]> hashSet)
+ throws IOException, XmlPullParserException {
+ parser.require(XmlPullParser.START_TAG, null, tagName);
+ while (parser.nextTag() == XmlPullParser.START_TAG) {
+ parser.require(XmlPullParser.START_TAG, null, XmlTags.HASH);
+ byte[] hash = HexDump.hexStringToByteArray(parser.nextText());
+ parser.require(XmlPullParser.END_TAG, null, XmlTags.HASH);
+ hashSet.add(hash);
+ }
+ parser.require(XmlPullParser.END_TAG, null, tagName);
+ }
+
+ /**
+ * Write network watchlist settings to disk.
+ * Adb should not use it, should use writeSettingsToMemory directly instead.
+ */
+ public void writeSettingsToDisk(List<byte[]> newCrc32DomainList,
+ List<byte[]> newSha256DomainList,
+ List<byte[]> newCrc32IpList,
+ List<byte[]> newSha256IpList) {
+ synchronized (mLock) {
+ FileOutputStream stream;
+ try {
+ stream = mXmlFile.startWrite();
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to write display settings: " + e);
+ return;
+ }
+
+ try {
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, StandardCharsets.UTF_8.name());
+ out.startDocument(null, true);
+ out.startTag(null, XmlTags.WATCHLIST_SETTINGS);
+
+ writeHashSetToXml(out, XmlTags.SHA256_DOMAIN, newSha256DomainList);
+ writeHashSetToXml(out, XmlTags.SHA256_IP, newSha256IpList);
+ writeHashSetToXml(out, XmlTags.CRC32_DOMAIN, newCrc32DomainList);
+ writeHashSetToXml(out, XmlTags.CRC32_IP, newCrc32IpList);
+
+ out.endTag(null, XmlTags.WATCHLIST_SETTINGS);
+ out.endDocument();
+ mXmlFile.finishWrite(stream);
+ writeSettingsToMemory(newCrc32DomainList, newSha256DomainList, newCrc32IpList,
+ newSha256IpList);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to write display settings, restoring backup.", e);
+ mXmlFile.failWrite(stream);
+ }
+ }
+ }
+
+ /**
+ * Write network watchlist settings to memory.
+ */
+ public void writeSettingsToMemory(List<byte[]> newCrc32DomainList,
+ List<byte[]> newSha256DomainList,
+ List<byte[]> newCrc32IpList,
+ List<byte[]> newSha256IpList) {
+ synchronized (mLock) {
+ mCrc32DomainDigests = new HarmfulDigests(newCrc32DomainList);
+ mCrc32IpDigests = new HarmfulDigests(newCrc32IpList);
+ mSha256DomainDigests = new HarmfulDigests(newSha256DomainList);
+ mSha256IpDigests = new HarmfulDigests(newSha256IpList);
+ }
+ }
+
+ private static void writeHashSetToXml(XmlSerializer out, String tagName, List<byte[]> hashSet)
+ throws IOException {
+ out.startTag(null, tagName);
+ for (byte[] hash : hashSet) {
+ out.startTag(null, XmlTags.HASH);
+ out.text(HexDump.toHexString(hash));
+ out.endTag(null, XmlTags.HASH);
+ }
+ out.endTag(null, tagName);
+ }
+
+ public boolean containsDomain(String domain) {
+ // First it does a quick CRC32 check.
+ final byte[] crc32 = getCrc32(domain);
+ if (!mCrc32DomainDigests.contains(crc32)) {
+ return false;
+ }
+ // Now we do a slow SHA256 check.
+ final byte[] sha256 = getSha256(domain);
+ return mSha256DomainDigests.contains(sha256);
+ }
+
+ public boolean containsIp(String ip) {
+ // First it does a quick CRC32 check.
+ final byte[] crc32 = getCrc32(ip);
+ if (!mCrc32IpDigests.contains(crc32)) {
+ return false;
+ }
+ // Now we do a slow SHA256 check.
+ final byte[] sha256 = getSha256(ip);
+ return mSha256IpDigests.contains(sha256);
+ }
+
+
+ /** Get CRC32 of a string */
+ private byte[] getCrc32(String str) {
+ final CRC32 crc = new CRC32();
+ crc.update(str.getBytes());
+ final long tmp = crc.getValue();
+ return new byte[]{(byte)(tmp >> 24 & 255), (byte)(tmp >> 16 & 255),
+ (byte)(tmp >> 8 & 255), (byte)(tmp & 255)};
+ }
+
+ /** Get SHA256 of a string */
+ private byte[] getSha256(String str) {
+ MessageDigest messageDigest;
+ try {
+ messageDigest = MessageDigest.getInstance("SHA256");
+ } catch (NoSuchAlgorithmException e) {
+ /* can't happen */
+ return null;
+ }
+ messageDigest.update(str.getBytes());
+ return messageDigest.digest();
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Domain CRC32 digest list:");
+ mCrc32DomainDigests.dump(fd, pw, args);
+ pw.println("Domain SHA256 digest list:");
+ mSha256DomainDigests.dump(fd, pw, args);
+ pw.println("Ip CRC32 digest list:");
+ mCrc32IpDigests.dump(fd, pw, args);
+ pw.println("Ip SHA256 digest list:");
+ mSha256IpDigests.dump(fd, pw, args);
+ }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6cebdd64d8f9..557ba427e0f6 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2720,9 +2720,9 @@ public class NotificationManagerService extends SystemService {
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
final DumpFilter filter = DumpFilter.parseFromArguments(args);
- if (filter != null && filter.stats) {
+ if (filter.stats) {
dumpJson(pw, filter);
- } else if (filter != null && filter.proto) {
+ } else if (filter.proto) {
dumpProto(fd, filter);
} else {
dumpImpl(pw, filter);
@@ -2839,7 +2839,6 @@ public class NotificationManagerService extends SystemService {
@Override
public Policy getNotificationPolicy(String pkg) {
- enforcePolicyAccess(pkg, "getNotificationPolicy");
final long identity = Binder.clearCallingIdentity();
try {
return mZenModeHelper.getNotificationPolicy();
@@ -3236,7 +3235,7 @@ public class NotificationManagerService extends SystemService {
return null;
};
- private void dumpJson(PrintWriter pw, DumpFilter filter) {
+ private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
JSONObject dump = new JSONObject();
try {
dump.put("service", "Notification Manager");
@@ -3250,7 +3249,7 @@ public class NotificationManagerService extends SystemService {
pw.println(dump);
}
- private void dumpProto(FileDescriptor fd, DumpFilter filter) {
+ private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
synchronized (mNotificationLock) {
long records = proto.start(NotificationServiceDumpProto.RECORDS);
@@ -3332,7 +3331,7 @@ public class NotificationManagerService extends SystemService {
proto.flush();
}
- void dumpImpl(PrintWriter pw, DumpFilter filter) {
+ void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
pw.print("Current Notification Manager state");
if (filter.filtered) {
pw.print(" (filtered to "); pw.print(filter); pw.print(")");
@@ -5901,6 +5900,7 @@ public class NotificationManagerService extends SystemService {
public boolean redact = true;
public boolean proto = false;
+ @NonNull
public static DumpFilter parseFromArguments(String[] args) {
final DumpFilter filter = new DumpFilter();
for (int ai = 0; ai < args.length; ai++) {
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index d7e9cf377532..d566a45011d7 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -22,6 +22,7 @@ import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
+import android.annotation.NonNull;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -915,21 +916,21 @@ public class RankingHelper implements RankingConfig {
}
}
- public void dump(PrintWriter pw, String prefix, NotificationManagerService.DumpFilter filter) {
- if (filter == null) {
- final int N = mSignalExtractors.length;
- pw.print(prefix);
- pw.print("mSignalExtractors.length = ");
- pw.println(N);
- for (int i = 0; i < N; i++) {
- pw.print(prefix);
- pw.print(" ");
- pw.println(mSignalExtractors[i]);
- }
-
+ public void dump(PrintWriter pw, String prefix,
+ @NonNull NotificationManagerService.DumpFilter filter) {
+ final int N = mSignalExtractors.length;
+ pw.print(prefix);
+ pw.print("mSignalExtractors.length = ");
+ pw.println(N);
+ for (int i = 0; i < N; i++) {
pw.print(prefix);
- pw.println("per-package config:");
+ pw.print(" ");
+ pw.println(mSignalExtractors[i].getClass().getSimpleName());
}
+
+ pw.print(prefix);
+ pw.println("per-package config:");
+
pw.println("Records:");
synchronized (mRecords) {
dumpRecords(pw, prefix, filter, mRecords);
@@ -938,7 +939,8 @@ public class RankingHelper implements RankingConfig {
dumpRecords(pw, prefix, filter, mRestoredWithoutUids);
}
- public void dump(ProtoOutputStream proto, NotificationManagerService.DumpFilter filter) {
+ public void dump(ProtoOutputStream proto,
+ @NonNull NotificationManagerService.DumpFilter filter) {
final int N = mSignalExtractors.length;
for (int i = 0; i < N; i++) {
proto.write(RankingHelperProto.NOTIFICATION_SIGNAL_EXTRACTORS,
@@ -952,12 +954,13 @@ public class RankingHelper implements RankingConfig {
}
private static void dumpRecords(ProtoOutputStream proto, long fieldId,
- NotificationManagerService.DumpFilter filter, ArrayMap<String, Record> records) {
+ @NonNull NotificationManagerService.DumpFilter filter,
+ ArrayMap<String, Record> records) {
final int N = records.size();
long fToken;
for (int i = 0; i < N; i++) {
final Record r = records.valueAt(i);
- if (filter == null || filter.matches(r.pkg)) {
+ if (filter.matches(r.pkg)) {
fToken = proto.start(fieldId);
proto.write(RecordProto.PACKAGE, r.pkg);
@@ -985,11 +988,12 @@ public class RankingHelper implements RankingConfig {
}
private static void dumpRecords(PrintWriter pw, String prefix,
- NotificationManagerService.DumpFilter filter, ArrayMap<String, Record> records) {
+ @NonNull NotificationManagerService.DumpFilter filter,
+ ArrayMap<String, Record> records) {
final int N = records.size();
for (int i = 0; i < N; i++) {
final Record r = records.valueAt(i);
- if (filter == null || filter.matches(r.pkg)) {
+ if (filter.matches(r.pkg)) {
pw.print(prefix);
pw.print(" AppSettings: ");
pw.print(r.pkg);
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index f61cec9713c0..1e9fab5ce574 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -835,7 +835,8 @@ public class ZenModeHelper {
// alarm restrictions
final boolean muteMediaAndSystemSounds = zen && !mConfig.allowMediaSystemOther;
// total silence restrictions
- final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
+ final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS
+ || areAllBehaviorSoundsMuted();
for (int usage : AudioAttributes.SDK_USAGES) {
final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage);
@@ -855,9 +856,11 @@ public class ZenModeHelper {
}
}
+
@VisibleForTesting
protected void applyRestrictions(boolean mute, int usage) {
final String[] exceptionPackages = null; // none (for now)
+
mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, usage,
mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
exceptionPackages);
@@ -866,6 +869,12 @@ public class ZenModeHelper {
exceptionPackages);
}
+ private boolean areAllBehaviorSoundsMuted() {
+ return !mConfig.allowAlarms && !mConfig.allowMediaSystemOther && !mConfig.allowReminders
+ && !mConfig.allowCalls && !mConfig.allowMessages && !mConfig.allowEvents
+ && !mConfig.allowRepeatCallers;
+ }
+
private void applyZenToRingerMode() {
if (mAudioManager == null) return;
// force the ringer mode into compliance
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 357446623a08..fca95857c7e0 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -18,6 +18,8 @@ package com.android.server.pm;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
+import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
+
import com.android.internal.util.Preconditions;
import android.content.pm.PackageParser;
import android.util.ArrayMap;
@@ -341,6 +343,41 @@ public class KeySetManagerService {
return mKeySets.get(id) != null;
}
+ public boolean shouldCheckUpgradeKeySetLocked(PackageSettingBase oldPs, int scanFlags) {
+ // Can't rotate keys during boot or if sharedUser.
+ if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.isSharedUser()
+ || !oldPs.keySetData.isUsingUpgradeKeySets()) {
+ return false;
+ }
+ // app is using upgradeKeySets; make sure all are valid
+ long[] upgradeKeySets = oldPs.keySetData.getUpgradeKeySets();
+ for (int i = 0; i < upgradeKeySets.length; i++) {
+ if (!isIdValidKeySetId(upgradeKeySets[i])) {
+ Slog.wtf(TAG, "Package "
+ + (oldPs.name != null ? oldPs.name : "<null>")
+ + " contains upgrade-key-set reference to unknown key-set: "
+ + upgradeKeySets[i]
+ + " reverting to signatures check.");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS,
+ PackageParser.Package newPkg) {
+ // Upgrade keysets are being used. Determine if new package has a superset of the
+ // required keys.
+ long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
+ for (int i = 0; i < upgradeKeySets.length; i++) {
+ Set<PublicKey> upgradeSet = getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
+ if (upgradeSet != null && newPkg.mSigningKeys.containsAll(upgradeSet)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Fetches the {@link PublicKey public keys} which belong to the specified
* KeySet id.
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 50ac409f31c9..00cfa3104b0a 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -110,9 +110,9 @@ public class PackageDexOptimizer {
return false;
}
- // We do not dexopt a priv-app package when pm.dexopt.priv-apps is false.
+ // We do not dexopt a priv-app package when pm.dexopt.priv-apps-oob is true.
if (pkg.isPrivileged()) {
- return SystemProperties.getBoolean("pm.dexopt.priv-apps", true);
+ return !SystemProperties.getBoolean("pm.dexopt.priv-apps-oob", false);
}
return true;
@@ -154,7 +154,13 @@ public class PackageDexOptimizer {
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
final List<String> paths = pkg.getAllCodePaths();
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+
+ int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ if (sharedGid == -1) {
+ Slog.wtf(TAG, "Well this is awkward; package " + pkg.applicationInfo.name + " had UID "
+ + pkg.applicationInfo.uid, new Throwable());
+ sharedGid = android.os.Process.NOBODY_UID;
+ }
// Get the class loader context dependencies.
// For each code path in the package, this array contains the class loader context that
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 09f9cb8c1a31..be9b2f366a1f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -32,6 +32,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
+import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageInstallerCallback;
import android.content.pm.IPackageInstallerSession;
@@ -45,6 +46,7 @@ import android.content.pm.VersionedPackage;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
@@ -724,6 +726,12 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
Binder.restoreCallingIdentity(ident);
}
} else {
+ ApplicationInfo appInfo = mPm.getApplicationInfo(callerPackageName, 0, userId);
+ if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.REQUEST_DELETE_PACKAGES,
+ null);
+ }
+
// Take a short detour to confirm with user
final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
intent.setData(Uri.fromParts("package", versionedPackage.getPackageName(), null));
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7837b029830f..83cffe57580e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -102,6 +102,15 @@ import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
+import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
+import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
+import static com.android.server.pm.PackageManagerServiceUtils.decompressFile;
+import static com.android.server.pm.PackageManagerServiceUtils.deriveAbiOverride;
+import static com.android.server.pm.PackageManagerServiceUtils.dumpCriticalInfo;
+import static com.android.server.pm.PackageManagerServiceUtils.getCompressedFiles;
+import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime;
+import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
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;
@@ -408,7 +417,7 @@ public class PackageManagerService extends IPackageManager.Stub
private static final boolean DEBUG_FILTERS = false;
public static final boolean DEBUG_PERMISSIONS = false;
private static final boolean DEBUG_SHARED_LIBRARIES = false;
- private static final boolean DEBUG_COMPRESSION = Build.IS_DEBUGGABLE;
+ public static final boolean DEBUG_COMPRESSION = Build.IS_DEBUGGABLE;
// Debug output for dexopting. This is shared between PackageManagerService, OtaDexoptService
// and PackageDexOptimizer. All these classes have their own flag to allow switching a single
@@ -462,9 +471,9 @@ public class PackageManagerService extends IPackageManager.Stub
private static final String STATIC_SHARED_LIB_DELIMITER = "_";
/** Extension of the compressed packages */
- private final static String COMPRESSED_EXTENSION = ".gz";
+ public final static String COMPRESSED_EXTENSION = ".gz";
/** Suffix of stub packages on the system partition */
- private final static String STUB_SUFFIX = "-Stub";
+ public final static String STUB_SUFFIX = "-Stub";
private static final int[] EMPTY_INT_ARRAY = new int[0];
@@ -542,6 +551,8 @@ public class PackageManagerService extends IPackageManager.Stub
private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
+ private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB = "pm.dexopt.priv-apps-oob";
+
/** Canonical intent used to identify what counts as a "web browser" app */
private static final Intent sBrowserIntent;
static {
@@ -574,37 +585,6 @@ public class PackageManagerService extends IPackageManager.Stub
public static final int REASON_LAST = REASON_SHARED;
- /** All dangerous permission names in the same order as the events in MetricsEvent */
- private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
- Manifest.permission.READ_CALENDAR,
- Manifest.permission.WRITE_CALENDAR,
- Manifest.permission.CAMERA,
- Manifest.permission.READ_CONTACTS,
- Manifest.permission.WRITE_CONTACTS,
- Manifest.permission.GET_ACCOUNTS,
- Manifest.permission.ACCESS_FINE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.RECORD_AUDIO,
- Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.CALL_PHONE,
- Manifest.permission.READ_CALL_LOG,
- Manifest.permission.WRITE_CALL_LOG,
- Manifest.permission.ADD_VOICEMAIL,
- Manifest.permission.USE_SIP,
- Manifest.permission.PROCESS_OUTGOING_CALLS,
- Manifest.permission.READ_CELL_BROADCASTS,
- Manifest.permission.BODY_SENSORS,
- Manifest.permission.SEND_SMS,
- Manifest.permission.RECEIVE_SMS,
- Manifest.permission.READ_SMS,
- Manifest.permission.RECEIVE_WAP_PUSH,
- Manifest.permission.RECEIVE_MMS,
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.READ_PHONE_NUMBERS,
- Manifest.permission.ANSWER_PHONE_CALLS);
-
-
/**
* Version number for the package parser cache. Increment this whenever the format or
* extent of cached data changes. See {@code PackageParser#setCacheDir}.
@@ -3107,75 +3087,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private int decompressFile(File srcFile, File dstFile) throws ErrnoException {
- if (DEBUG_COMPRESSION) {
- Slog.i(TAG, "Decompress file"
- + "; src: " + srcFile.getAbsolutePath()
- + ", dst: " + dstFile.getAbsolutePath());
- }
- try (
- InputStream fileIn = new GZIPInputStream(new FileInputStream(srcFile));
- OutputStream fileOut = new FileOutputStream(dstFile, false /*append*/);
- ) {
- Streams.copy(fileIn, fileOut);
- Os.chmod(dstFile.getAbsolutePath(), 0644);
- return PackageManager.INSTALL_SUCCEEDED;
- } catch (IOException e) {
- logCriticalInfo(Log.ERROR, "Failed to decompress file"
- + "; src: " + srcFile.getAbsolutePath()
- + ", dst: " + dstFile.getAbsolutePath());
- }
- return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- }
-
- private File[] getCompressedFiles(String codePath) {
- final File stubCodePath = new File(codePath);
- final String stubName = stubCodePath.getName();
-
- // The layout of a compressed package on a given partition is as follows :
- //
- // Compressed artifacts:
- //
- // /partition/ModuleName/foo.gz
- // /partation/ModuleName/bar.gz
- //
- // Stub artifact:
- //
- // /partition/ModuleName-Stub/ModuleName-Stub.apk
- //
- // In other words, stub is on the same partition as the compressed artifacts
- // and in a directory that's suffixed with "-Stub".
- int idx = stubName.lastIndexOf(STUB_SUFFIX);
- if (idx < 0 || (stubName.length() != (idx + STUB_SUFFIX.length()))) {
- return null;
- }
-
- final File stubParentDir = stubCodePath.getParentFile();
- if (stubParentDir == null) {
- Slog.e(TAG, "Unable to determine stub parent dir for codePath: " + codePath);
- return null;
- }
-
- final File compressedPath = new File(stubParentDir, stubName.substring(0, idx));
- final File[] files = compressedPath.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- return name.toLowerCase().endsWith(COMPRESSED_EXTENSION);
- }
- });
-
- if (DEBUG_COMPRESSION && files != null && files.length > 0) {
- Slog.i(TAG, "getCompressedFiles[" + codePath + "]: " + Arrays.toString(files));
- }
-
- return files;
- }
-
- private boolean compressedFileExists(String codePath) {
- final File[] compressedFiles = getCompressedFiles(codePath);
- return compressedFiles != null && compressedFiles.length > 0;
- }
-
/**
* Decompresses the given package on the system image onto
* the /data partition.
@@ -5176,66 +5087,6 @@ public class PackageManagerService extends IPackageManager.Stub
getCallingUid(), userId, mPermissionCallback);
}
- /**
- * Get the first event id for the permission.
- *
- * <p>There are four events for each permission: <ul>
- * <li>Request permission: first id + 0</li>
- * <li>Grant permission: first id + 1</li>
- * <li>Request for permission denied: first id + 2</li>
- * <li>Revoke permission: first id + 3</li>
- * </ul></p>
- *
- * @param name name of the permission
- *
- * @return The first event id for the permission
- */
- private static int getBaseEventId(@NonNull String name) {
- int eventIdIndex = ALL_DANGEROUS_PERMISSIONS.indexOf(name);
-
- if (eventIdIndex == -1) {
- if (AppOpsManager.permissionToOpCode(name) == AppOpsManager.OP_NONE
- || Build.IS_USER) {
- Log.i(TAG, "Unknown permission " + name);
-
- return MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN;
- } else {
- // Most likely #ALL_DANGEROUS_PERMISSIONS needs to be updated.
- //
- // Also update
- // - EventLogger#ALL_DANGEROUS_PERMISSIONS
- // - metrics_constants.proto
- throw new IllegalStateException("Unknown permission " + name);
- }
- }
-
- return MetricsEvent.ACTION_PERMISSION_REQUEST_READ_CALENDAR + eventIdIndex * 4;
- }
-
- /**
- * Log that a permission was revoked.
- *
- * @param context Context of the caller
- * @param name name of the permission
- * @param packageName package permission if for
- */
- private static void logPermissionRevoked(@NonNull Context context, @NonNull String name,
- @NonNull String packageName) {
- MetricsLogger.action(context, getBaseEventId(name) + 3, packageName);
- }
-
- /**
- * Log that a permission request was granted.
- *
- * @param context Context of the caller
- * @param name name of the permission
- * @param packageName package permission if for
- */
- private static void logPermissionGranted(@NonNull Context context, @NonNull String name,
- @NonNull String packageName) {
- MetricsLogger.action(context, getBaseEventId(name) + 1, packageName);
- }
-
@Override
public void resetRuntimePermissions() {
mContext.enforceCallingOrSelfPermission(
@@ -5476,56 +5327,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
/**
- * Compares two sets of signatures. Returns:
- * <br />
- * {@link PackageManager#SIGNATURE_NEITHER_SIGNED}: if both signature sets are null,
- * <br />
- * {@link PackageManager#SIGNATURE_FIRST_NOT_SIGNED}: if the first signature set is null,
- * <br />
- * {@link PackageManager#SIGNATURE_SECOND_NOT_SIGNED}: if the second signature set is null,
- * <br />
- * {@link PackageManager#SIGNATURE_MATCH}: if the two signature sets are identical,
- * <br />
- * {@link PackageManager#SIGNATURE_NO_MATCH}: if the two signature sets differ.
- */
- public static int compareSignatures(Signature[] s1, Signature[] s2) {
- if (s1 == null) {
- return s2 == null
- ? PackageManager.SIGNATURE_NEITHER_SIGNED
- : PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
- }
-
- if (s2 == null) {
- return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
- }
-
- if (s1.length != s2.length) {
- return PackageManager.SIGNATURE_NO_MATCH;
- }
-
- // Since both signature sets are of size 1, we can compare without HashSets.
- if (s1.length == 1) {
- return s1[0].equals(s2[0]) ?
- PackageManager.SIGNATURE_MATCH :
- PackageManager.SIGNATURE_NO_MATCH;
- }
-
- ArraySet<Signature> set1 = new ArraySet<Signature>();
- for (Signature sig : s1) {
- set1.add(sig);
- }
- ArraySet<Signature> set2 = new ArraySet<Signature>();
- for (Signature sig : s2) {
- set2.add(sig);
- }
- // Make sure s2 contains all signatures in s1.
- if (set1.equals(set2)) {
- return PackageManager.SIGNATURE_MATCH;
- }
- return PackageManager.SIGNATURE_NO_MATCH;
- }
-
- /**
* If the database version for this type of package (internal storage or
* external storage) is less than the version where package signatures
* were updated, return true.
@@ -5535,76 +5336,11 @@ public class PackageManagerService extends IPackageManager.Stub
return ver.databaseVersion < DatabaseVersion.SIGNATURE_END_ENTITY;
}
- /**
- * Used for backward compatibility to make sure any packages with
- * certificate chains get upgraded to the new style. {@code existingSigs}
- * will be in the old format (since they were stored on disk from before the
- * system upgrade) and {@code scannedSigs} will be in the newer format.
- */
- private int compareSignaturesCompat(PackageSignatures existingSigs,
- PackageParser.Package scannedPkg) {
- if (!isCompatSignatureUpdateNeeded(scannedPkg)) {
- return PackageManager.SIGNATURE_NO_MATCH;
- }
-
- ArraySet<Signature> existingSet = new ArraySet<Signature>();
- for (Signature sig : existingSigs.mSignatures) {
- existingSet.add(sig);
- }
- ArraySet<Signature> scannedCompatSet = new ArraySet<Signature>();
- for (Signature sig : scannedPkg.mSignatures) {
- try {
- Signature[] chainSignatures = sig.getChainSignatures();
- for (Signature chainSig : chainSignatures) {
- scannedCompatSet.add(chainSig);
- }
- } catch (CertificateEncodingException e) {
- scannedCompatSet.add(sig);
- }
- }
- /*
- * Make sure the expanded scanned set contains all signatures in the
- * existing one.
- */
- if (scannedCompatSet.equals(existingSet)) {
- // Migrate the old signatures to the new scheme.
- existingSigs.assignSignatures(scannedPkg.mSignatures);
- // The new KeySets will be re-added later in the scanning process.
- synchronized (mPackages) {
- mSettings.mKeySetManagerService.removeAppKeySetDataLPw(scannedPkg.packageName);
- }
- return PackageManager.SIGNATURE_MATCH;
- }
- return PackageManager.SIGNATURE_NO_MATCH;
- }
-
private boolean isRecoverSignatureUpdateNeeded(PackageParser.Package scannedPkg) {
final VersionInfo ver = getSettingsVersionForPackage(scannedPkg);
return ver.databaseVersion < DatabaseVersion.SIGNATURE_MALFORMED_RECOVER;
}
- private int compareSignaturesRecover(PackageSignatures existingSigs,
- PackageParser.Package scannedPkg) {
- if (!isRecoverSignatureUpdateNeeded(scannedPkg)) {
- return PackageManager.SIGNATURE_NO_MATCH;
- }
-
- String msg = null;
- try {
- if (Signature.areEffectiveMatch(existingSigs.mSignatures, scannedPkg.mSignatures)) {
- logCriticalInfo(Log.INFO, "Recovered effectively matching certificates for "
- + scannedPkg.packageName);
- return PackageManager.SIGNATURE_MATCH;
- }
- } catch (CertificateException e) {
- msg = e.getMessage();
- }
-
- logCriticalInfo(Log.INFO,
- "Failed to recover certificates for " + scannedPkg.packageName + ": " + msg);
- return PackageManager.SIGNATURE_NO_MATCH;
- }
-
@Override
public List<String> getAllPackages() {
final int callingUid = Binder.getCallingUid();
@@ -8328,51 +8064,10 @@ public class PackageManagerService extends IPackageManager.Stub
parallelPackageParser.close();
}
- private static File getSettingsProblemFile() {
- File dataDir = Environment.getDataDirectory();
- File systemDir = new File(dataDir, "system");
- File fname = new File(systemDir, "uiderrors.txt");
- return fname;
- }
-
public static void reportSettingsProblem(int priority, String msg) {
logCriticalInfo(priority, msg);
}
- public static void logCriticalInfo(int priority, String msg) {
- Slog.println(priority, TAG, msg);
- EventLogTags.writePmCriticalInfo(msg);
- try {
- File fname = getSettingsProblemFile();
- FileOutputStream out = new FileOutputStream(fname, true);
- PrintWriter pw = new FastPrintWriter(out);
- SimpleDateFormat formatter = new SimpleDateFormat();
- String dateString = formatter.format(new Date(System.currentTimeMillis()));
- pw.println(dateString + ": " + msg);
- pw.close();
- FileUtils.setPermissions(
- fname.toString(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IROTH,
- -1, -1);
- } catch (java.io.IOException e) {
- }
- }
-
- private long getLastModifiedTime(PackageParser.Package pkg, File srcFile) {
- if (srcFile.isDirectory()) {
- final File baseFile = new File(pkg.baseCodePath);
- long maxModifiedTime = baseFile.lastModified();
- if (pkg.splitCodePaths != null) {
- for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) {
- final File splitFile = new File(pkg.splitCodePaths[i]);
- maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified());
- }
- }
- return maxModifiedTime;
- }
- return srcFile.lastModified();
- }
-
private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, File srcFile,
final int policyFlags) throws PackageManagerException {
// When upgrading from pre-N MR1, verify the package time stamp using the package
@@ -8385,7 +8080,7 @@ public class PackageManagerService extends IPackageManager.Stub
&& !isCompatSignatureUpdateNeeded(pkg)
&& !isRecoverSignatureUpdateNeeded(pkg)) {
long mSigningKeySetId = ps.keySetData.getProperSigningKeySet();
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
ArraySet<PublicKey> signingKs;
synchronized (mPackages) {
signingKs = ksms.getPublicKeysFromKeySetLPr(mSigningKeySetId);
@@ -8801,7 +8496,7 @@ public class PackageManagerService extends IPackageManager.Stub
return scannedPkg;
}
- private void renameStaticSharedLibraryPackage(PackageParser.Package pkg) {
+ private static void renameStaticSharedLibraryPackage(PackageParser.Package pkg) {
// Derive the new package synthetic package name
pkg.setPackageName(pkg.packageName + STATIC_SHARED_LIB_DELIMITER
+ pkg.staticSharedLibVersion);
@@ -8815,49 +8510,6 @@ public class PackageManagerService extends IPackageManager.Stub
return processName;
}
- private void verifySignaturesLP(PackageSetting pkgSetting, PackageParser.Package pkg)
- throws PackageManagerException {
- if (pkgSetting.signatures.mSignatures != null) {
- // Already existing package. Make sure signatures match
- boolean match = compareSignatures(pkgSetting.signatures.mSignatures, pkg.mSignatures)
- == PackageManager.SIGNATURE_MATCH;
- if (!match) {
- match = compareSignaturesCompat(pkgSetting.signatures, pkg)
- == PackageManager.SIGNATURE_MATCH;
- }
- if (!match) {
- match = compareSignaturesRecover(pkgSetting.signatures, pkg)
- == PackageManager.SIGNATURE_MATCH;
- }
- if (!match) {
- throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
- + pkg.packageName + " signatures do not match the "
- + "previously installed version; ignoring!");
- }
- }
-
- // Check for shared user signatures
- if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) {
- // Already existing package. Make sure signatures match
- boolean match = compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
- pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
- if (!match) {
- match = compareSignaturesCompat(pkgSetting.sharedUser.signatures, pkg)
- == PackageManager.SIGNATURE_MATCH;
- }
- if (!match) {
- match = compareSignaturesRecover(pkgSetting.sharedUser.signatures, pkg)
- == PackageManager.SIGNATURE_MATCH;
- }
- if (!match) {
- throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
- "Package " + pkg.packageName
- + " has no signatures that match those in shared user "
- + pkgSetting.sharedUser.name + "; ignoring!");
- }
- }
- }
-
/**
* Enforces that only the system UID or root's UID can call a method exposed
* via Binder.
@@ -9828,24 +9480,6 @@ public class PackageManagerService extends IPackageManager.Stub
return res;
}
- /**
- * Derive the value of the {@code cpuAbiOverride} based on the provided
- * value and an optional stored value from the package settings.
- */
- private static String deriveAbiOverride(String abiOverride, PackageSetting settings) {
- String cpuAbiOverride = null;
-
- if (NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
- cpuAbiOverride = null;
- } else if (abiOverride != null) {
- cpuAbiOverride = abiOverride;
- } else if (settings != null) {
- cpuAbiOverride = settings.cpuAbiOverrideString;
- }
-
- return cpuAbiOverride;
- }
-
private PackageParser.Package scanPackageTracedLI(PackageParser.Package pkg,
final int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user)
throws PackageManagerException {
@@ -9966,7 +9600,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (Build.IS_DEBUGGABLE &&
pkg.isPrivileged() &&
- !SystemProperties.getBoolean("pm.dexopt.priv-apps", true)) {
+ SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, false)) {
PackageManagerServiceUtils.logPackageHasUncompressedCode(pkg);
}
@@ -10193,8 +9827,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
- if (checkUpgradeKeySetLP(signatureCheckPs, pkg)) {
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
+ if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
pkgSetting.signatures.mSignatures = pkg.mSignatures;
@@ -10212,8 +9847,16 @@ public class PackageManagerService extends IPackageManager.Stub
}
} else {
try {
- // SIDE EFFECTS; compareSignaturesCompat() changes KeysetManagerService
- verifySignaturesLP(signatureCheckPs, pkg);
+ final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
+ final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
+ final boolean compatMatch = verifySignatures(signatureCheckPs, pkg.mSignatures,
+ compareCompat, compareRecover);
+ // The new KeySets will be re-added later in the scanning process.
+ if (compatMatch) {
+ synchronized (mPackages) {
+ ksms.removeAppKeySetDataLPw(pkg.packageName);
+ }
+ }
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
pkgSetting.signatures.mSignatures = pkg.mSignatures;
@@ -10501,7 +10144,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
// Make sure we're not adding any bogus keyset info
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
ksms.assertScannedPackageValid(pkg);
synchronized (mPackages) {
@@ -15657,42 +15300,6 @@ public class PackageManagerService extends IPackageManager.Stub
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- private boolean shouldCheckUpgradeKeySetLP(PackageSettingBase oldPs, int scanFlags) {
- // Can't rotate keys during boot or if sharedUser.
- if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.isSharedUser()
- || !oldPs.keySetData.isUsingUpgradeKeySets()) {
- return false;
- }
- // app is using upgradeKeySets; make sure all are valid
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
- long[] upgradeKeySets = oldPs.keySetData.getUpgradeKeySets();
- for (int i = 0; i < upgradeKeySets.length; i++) {
- if (!ksms.isIdValidKeySetId(upgradeKeySets[i])) {
- Slog.wtf(TAG, "Package "
- + (oldPs.name != null ? oldPs.name : "<null>")
- + " contains upgrade-key-set reference to unknown key-set: "
- + upgradeKeySets[i]
- + " reverting to signatures check.");
- return false;
- }
- }
- return true;
- }
-
- private boolean checkUpgradeKeySetLP(PackageSettingBase oldPS, PackageParser.Package newPkg) {
- // Upgrade keysets are being used. Determine if new package has a superset of the
- // required keys.
- long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
- for (int i = 0; i < upgradeKeySets.length; i++) {
- Set<PublicKey> upgradeSet = ksms.getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
- if (upgradeSet != null && newPkg.mSigningKeys.containsAll(upgradeSet)) {
- return true;
- }
- }
- return false;
- }
-
private static void updateDigest(MessageDigest digest, File file) throws IOException {
try (DigestInputStream digestStream =
new DigestInputStream(new FileInputStream(file), digest)) {
@@ -15731,8 +15338,9 @@ public class PackageManagerService extends IPackageManager.Stub
ps = mSettings.mPackages.get(pkgName);
// verify signatures are valid
- if (shouldCheckUpgradeKeySetLP(ps, scanFlags)) {
- if (!checkUpgradeKeySetLP(ps, pkg)) {
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
+ if (!ksms.checkUpgradeKeySetLocked(ps, pkg)) {
res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"New package not signed by keys specified by upgrade-keysets: "
+ pkgName);
@@ -16633,8 +16241,9 @@ public class PackageManagerService extends IPackageManager.Stub
// Quick sanity check that we're signed correctly if updating;
// we'll check this again later when scanning, but we want to
// bail early here before tripping over redefined permissions.
- if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
- if (!checkUpgradeKeySetLP(signatureCheckPs, pkg)) {
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
+ if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ pkg.packageName + " upgrade keys do not match the "
+ "previously installed version");
@@ -16642,7 +16251,16 @@ public class PackageManagerService extends IPackageManager.Stub
}
} else {
try {
- verifySignaturesLP(signatureCheckPs, pkg);
+ final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
+ final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
+ final boolean compatMatch = verifySignatures(
+ signatureCheckPs, pkg.mSignatures, compareCompat, compareRecover);
+ // The new KeySets will be re-added later in the scanning process.
+ if (compatMatch) {
+ synchronized (mPackages) {
+ ksms.removeAppKeySetDataLPw(pkg.packageName);
+ }
+ }
} catch (PackageManagerException e) {
res.setError(e.error, e.getMessage());
return;
@@ -16680,10 +16298,11 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean sigsOk;
final String sourcePackageName = bp.getSourcePackageName();
final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (sourcePackageName.equals(pkg.packageName)
- && (shouldCheckUpgradeKeySetLP(sourcePackageSetting,
- scanFlags))) {
- sigsOk = checkUpgradeKeySetLP(sourcePackageSetting, pkg);
+ && (ksms.shouldCheckUpgradeKeySetLocked(
+ sourcePackageSetting, scanFlags))) {
+ sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
} else {
sigsOk = compareSignatures(sourcePackageSetting.signatures.mSignatures,
pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
@@ -20283,6 +19902,23 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
.getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_SYSTEM);
co.onChange(true);
+ // This observer provides an one directional mapping from Global.PRIV_APP_OOB_ENABLED to
+ // pm.dexopt.priv-apps-oob property. This is only for experiment and should be removed once
+ // it is done.
+ ContentObserver privAppOobObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ int oobEnabled = Global.getInt(resolver, Global.PRIV_APP_OOB_ENABLED, 0);
+ SystemProperties.set(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB,
+ oobEnabled == 1 ? "true" : "false");
+ }
+ };
+ mContext.getContentResolver().registerContentObserver(
+ Global.getUriFor(Global.PRIV_APP_OOB_ENABLED), false, privAppOobObserver,
+ UserHandle.USER_SYSTEM);
+ // At boot, restore the value from the setting, which persists across reboot.
+ privAppOobObserver.onChange(true);
+
// Disable any carrier apps. We do this very early in boot to prevent the apps from being
// disabled after already being started.
CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this,
@@ -21029,34 +20665,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
pw.println();
pw.println("Package warning messages:");
- BufferedReader in = null;
- String line = null;
- try {
- in = new BufferedReader(new FileReader(getSettingsProblemFile()));
- while ((line = in.readLine()) != null) {
- if (line.contains("ignored: updated version")) continue;
- pw.println(line);
- }
- } catch (IOException ignored) {
- } finally {
- IoUtils.closeQuietly(in);
- }
+ dumpCriticalInfo(pw, null);
}
if (checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES)) {
- BufferedReader in = null;
- String line = null;
- try {
- in = new BufferedReader(new FileReader(getSettingsProblemFile()));
- while ((line = in.readLine()) != null) {
- if (line.contains("ignored: updated version")) continue;
- pw.print("msg,");
- pw.println(line);
- }
- } catch (IOException ignored) {
- } finally {
- IoUtils.closeQuietly(in);
- }
+ dumpCriticalInfo(pw, "msg,");
}
}
@@ -21102,26 +20715,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
dumpFeaturesProto(proto);
mSettings.dumpPackagesProto(proto);
mSettings.dumpSharedUsersProto(proto);
- dumpMessagesProto(proto);
+ dumpCriticalInfo(proto);
}
proto.flush();
}
- private void dumpMessagesProto(ProtoOutputStream proto) {
- BufferedReader in = null;
- String line = null;
- try {
- in = new BufferedReader(new FileReader(getSettingsProblemFile()));
- while ((line = in.readLine()) != null) {
- if (line.contains("ignored: updated version")) continue;
- proto.write(PackageServiceDumpProto.MESSAGES, line);
- }
- } catch (IOException ignored) {
- } finally {
- IoUtils.closeQuietly(in);
- }
- }
-
private void dumpFeaturesProto(ProtoOutputStream proto) {
synchronized (mAvailableFeatures) {
final int count = mAvailableFeatures.size();
@@ -22530,7 +22128,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
Slog.w(TAG, "KeySet requested for filtered package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
return new KeySet(ksms.getKeySetByAliasAndPackageNameLPr(packageName, alias));
}
}
@@ -22559,7 +22157,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
&& Process.SYSTEM_UID != callingUid) {
throw new SecurityException("May not access signing KeySet of other apps.");
}
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
return new KeySet(ksms.getSigningKeySetByPackageNameLPr(packageName));
}
}
@@ -22583,7 +22181,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
IBinder ksh = ks.getToken();
if (ksh instanceof KeySetHandle) {
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
return ksms.packageIsSignedByLPr(packageName, (KeySetHandle) ksh);
}
return false;
@@ -22609,7 +22207,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
IBinder ksh = ks.getToken();
if (ksh instanceof KeySetHandle) {
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
return ksms.packageIsSignedByExactlyLPr(packageName, (KeySetHandle) ksh);
}
return false;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 781216c3c43f..19b0d9bc4b90 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -52,18 +52,7 @@ public class PackageManagerServiceCompilerMapping {
// Load the property for the given reason and check for validity. This will throw an
// exception in case the reason or value are invalid.
private static String getAndCheckValidity(int reason) {
- String sysPropName = getSystemPropertyName(reason);
- String sysPropValue;
- // TODO: This is a temporary hack to keep marlin booting on aosp/master while we
- // figure out how to deal with these system properties that currently appear on
- // vendor.
- if ("pm.dexopt.inactive".equals(sysPropName)) {
- sysPropValue = "verify";
- } else if ("pm.dexopt.shared".equals(sysPropName)) {
- sysPropValue = "speed";
- } else {
- sysPropValue = SystemProperties.get(sysPropName);
- }
+ String sysPropValue = SystemProperties.get(getSystemPropertyName(reason));
if (sysPropValue == null || sysPropValue.isEmpty() ||
!DexFile.isValidCompilerFilter(sysPropValue)) {
throw new IllegalStateException("Value \"" + sysPropValue +"\" not valid "
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 67e06dda044f..758abd76950b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -16,42 +16,74 @@
package com.android.server.pm;
-import com.android.server.pm.dex.DexManager;
-import com.android.server.pm.dex.PackageDexUsage;
-
+import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
+import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
+import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION;
+import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
+import static com.android.server.pm.PackageManagerService.STUB_SUFFIX;
import static com.android.server.pm.PackageManagerService.TAG;
+import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastPrintWriter;
+import com.android.server.EventLogTags;
+import com.android.server.pm.dex.DexManager;
+import com.android.server.pm.dex.PackageDexUsage;
import android.annotation.NonNull;
import android.app.AppGlobals;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
import android.os.Build;
import android.os.Debug;
+import android.os.Environment;
+import android.os.FileUtils;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.service.pm.PackageServiceDumpProto;
import android.system.ErrnoException;
import android.system.Os;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.util.jar.StrictJarFile;
+import android.util.proto.ProtoOutputStream;
+
import dalvik.system.VMRuntime;
+
+import libcore.io.IoUtils;
import libcore.io.Libcore;
+import libcore.io.Streams;
+import java.io.BufferedReader;
import java.io.File;
+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.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.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
+import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
/**
@@ -200,7 +232,7 @@ public class PackageManagerServiceUtils {
*
* If it doesn't have sufficient information about the package, it return <code>false</code>.
*/
- static boolean isUnusedSinceTimeInMillis(long firstInstallTime, long currentTimeInMillis,
+ public static boolean isUnusedSinceTimeInMillis(long firstInstallTime, long currentTimeInMillis,
long thresholdTimeinMillis, PackageDexUsage.PackageUseInfo packageUseInfo,
long latestPackageUseTimeInMillis, long latestForegroundPackageUseTimeInMillis) {
@@ -263,6 +295,21 @@ public class PackageManagerServiceUtils {
return false;
}
+ public static long getLastModifiedTime(PackageParser.Package pkg, File srcFile) {
+ if (srcFile.isDirectory()) {
+ final File baseFile = new File(pkg.baseCodePath);
+ long maxModifiedTime = baseFile.lastModified();
+ if (pkg.splitCodePaths != null) {
+ for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) {
+ final File splitFile = new File(pkg.splitCodePaths[i]);
+ maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified());
+ }
+ }
+ return maxModifiedTime;
+ }
+ return srcFile.lastModified();
+ }
+
/**
* Checks that the archive located at {@code fileName} has uncompressed dex file and so
* files that can be direclty mapped.
@@ -318,6 +365,57 @@ public class PackageManagerServiceUtils {
}
}
+ private static File getSettingsProblemFile() {
+ File dataDir = Environment.getDataDirectory();
+ File systemDir = new File(dataDir, "system");
+ File fname = new File(systemDir, "uiderrors.txt");
+ return fname;
+ }
+
+ public static void dumpCriticalInfo(ProtoOutputStream proto) {
+ try (BufferedReader in = new BufferedReader(new FileReader(getSettingsProblemFile()))) {
+ String line = null;
+ while ((line = in.readLine()) != null) {
+ if (line.contains("ignored: updated version")) continue;
+ proto.write(PackageServiceDumpProto.MESSAGES, line);
+ }
+ } catch (IOException ignored) {
+ }
+ }
+
+ public static void dumpCriticalInfo(PrintWriter pw, String msg) {
+ try (BufferedReader in = new BufferedReader(new FileReader(getSettingsProblemFile()))) {
+ String line = null;
+ while ((line = in.readLine()) != null) {
+ if (line.contains("ignored: updated version")) continue;
+ if (msg != null) {
+ pw.print(msg);
+ }
+ pw.println(line);
+ }
+ } catch (IOException ignored) {
+ }
+ }
+
+ public static void logCriticalInfo(int priority, String msg) {
+ Slog.println(priority, TAG, msg);
+ EventLogTags.writePmCriticalInfo(msg);
+ try {
+ File fname = getSettingsProblemFile();
+ FileOutputStream out = new FileOutputStream(fname, true);
+ PrintWriter pw = new FastPrintWriter(out);
+ SimpleDateFormat formatter = new SimpleDateFormat();
+ String dateString = formatter.format(new Date(System.currentTimeMillis()));
+ pw.println(dateString + ": " + msg);
+ pw.close();
+ FileUtils.setPermissions(
+ fname.toString(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IROTH,
+ -1, -1);
+ } catch (java.io.IOException e) {
+ }
+ }
+
public static void enforceShellRestriction(String restriction, int callingUid, int userHandle) {
if (callingUid == Process.SHELL_UID) {
if (userHandle >= 0
@@ -331,4 +429,240 @@ public class PackageManagerServiceUtils {
}
}
}
+
+ /**
+ * Derive the value of the {@code cpuAbiOverride} based on the provided
+ * value and an optional stored value from the package settings.
+ */
+ public static String deriveAbiOverride(String abiOverride, PackageSetting settings) {
+ String cpuAbiOverride = null;
+ if (NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
+ cpuAbiOverride = null;
+ } else if (abiOverride != null) {
+ cpuAbiOverride = abiOverride;
+ } else if (settings != null) {
+ cpuAbiOverride = settings.cpuAbiOverrideString;
+ }
+ return cpuAbiOverride;
+ }
+
+ /**
+ * Compares two sets of signatures. Returns:
+ * <br />
+ * {@link PackageManager#SIGNATURE_NEITHER_SIGNED}: if both signature sets are null,
+ * <br />
+ * {@link PackageManager#SIGNATURE_FIRST_NOT_SIGNED}: if the first signature set is null,
+ * <br />
+ * {@link PackageManager#SIGNATURE_SECOND_NOT_SIGNED}: if the second signature set is null,
+ * <br />
+ * {@link PackageManager#SIGNATURE_MATCH}: if the two signature sets are identical,
+ * <br />
+ * {@link PackageManager#SIGNATURE_NO_MATCH}: if the two signature sets differ.
+ */
+ public static int compareSignatures(Signature[] s1, Signature[] s2) {
+ if (s1 == null) {
+ return s2 == null
+ ? PackageManager.SIGNATURE_NEITHER_SIGNED
+ : PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
+ }
+
+ if (s2 == null) {
+ return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
+ }
+
+ if (s1.length != s2.length) {
+ return PackageManager.SIGNATURE_NO_MATCH;
+ }
+
+ // Since both signature sets are of size 1, we can compare without HashSets.
+ if (s1.length == 1) {
+ return s1[0].equals(s2[0]) ?
+ PackageManager.SIGNATURE_MATCH :
+ PackageManager.SIGNATURE_NO_MATCH;
+ }
+
+ ArraySet<Signature> set1 = new ArraySet<Signature>();
+ for (Signature sig : s1) {
+ set1.add(sig);
+ }
+ ArraySet<Signature> set2 = new ArraySet<Signature>();
+ for (Signature sig : s2) {
+ set2.add(sig);
+ }
+ // Make sure s2 contains all signatures in s1.
+ if (set1.equals(set2)) {
+ return PackageManager.SIGNATURE_MATCH;
+ }
+ return PackageManager.SIGNATURE_NO_MATCH;
+ }
+
+ /**
+ * Used for backward compatibility to make sure any packages with
+ * certificate chains get upgraded to the new style. {@code existingSigs}
+ * will be in the old format (since they were stored on disk from before the
+ * system upgrade) and {@code scannedSigs} will be in the newer format.
+ */
+ private static boolean matchSignaturesCompat(String packageName,
+ PackageSignatures packageSignatures, Signature[] parsedSignatures) {
+ ArraySet<Signature> existingSet = new ArraySet<Signature>();
+ for (Signature sig : packageSignatures.mSignatures) {
+ existingSet.add(sig);
+ }
+ ArraySet<Signature> scannedCompatSet = new ArraySet<Signature>();
+ for (Signature sig : parsedSignatures) {
+ try {
+ Signature[] chainSignatures = sig.getChainSignatures();
+ for (Signature chainSig : chainSignatures) {
+ scannedCompatSet.add(chainSig);
+ }
+ } catch (CertificateEncodingException e) {
+ scannedCompatSet.add(sig);
+ }
+ }
+ // make sure the expanded scanned set contains all signatures in the existing one
+ if (scannedCompatSet.equals(existingSet)) {
+ // migrate the old signatures to the new scheme
+ packageSignatures.assignSignatures(parsedSignatures);
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean matchSignaturesRecover(String packageName,
+ Signature[] existingSignatures, Signature[] parsedSignatures) {
+ String msg = null;
+ try {
+ if (Signature.areEffectiveMatch(existingSignatures, parsedSignatures)) {
+ logCriticalInfo(Log.INFO,
+ "Recovered effectively matching certificates for " + packageName);
+ return true;
+ }
+ } catch (CertificateException e) {
+ msg = e.getMessage();
+ }
+ logCriticalInfo(Log.INFO,
+ "Failed to recover certificates for " + packageName + ": " + msg);
+ return false;
+ }
+
+ /**
+ * Verifies that signatures match.
+ * @returns {@code true} if the compat signatures were matched; otherwise, {@code false}.
+ * @throws PackageManagerException if the signatures did not match.
+ */
+ public static boolean verifySignatures(PackageSetting pkgSetting,
+ Signature[] parsedSignatures, boolean compareCompat, boolean compareRecover)
+ throws PackageManagerException {
+ final String packageName = pkgSetting.name;
+ boolean compatMatch = false;
+ if (pkgSetting.signatures.mSignatures != null) {
+ // Already existing package. Make sure signatures match
+ boolean match = compareSignatures(pkgSetting.signatures.mSignatures, parsedSignatures)
+ == PackageManager.SIGNATURE_MATCH;
+ if (!match && compareCompat) {
+ match = matchSignaturesCompat(packageName, pkgSetting.signatures, parsedSignatures);
+ compatMatch = match;
+ }
+ if (!match && compareRecover) {
+ match = matchSignaturesRecover(
+ packageName, pkgSetting.signatures.mSignatures, parsedSignatures);
+ }
+ if (!match) {
+ throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+ "Package " + packageName +
+ " signatures don't match previously installed version; ignoring!");
+ }
+ }
+ // Check for shared user signatures
+ if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) {
+ // Already existing package. Make sure signatures match
+ boolean match = compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
+ parsedSignatures) == PackageManager.SIGNATURE_MATCH;
+ if (!match) {
+ match = matchSignaturesCompat(
+ packageName, pkgSetting.sharedUser.signatures, parsedSignatures);
+ }
+ if (!match && compareCompat) {
+ match = matchSignaturesRecover(
+ packageName, pkgSetting.sharedUser.signatures.mSignatures, parsedSignatures);
+ compatMatch |= match;
+ }
+ if (!match && compareRecover) {
+ throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
+ "Package " + packageName
+ + " has no signatures that match those in shared user "
+ + pkgSetting.sharedUser.name + "; ignoring!");
+ }
+ }
+ return compatMatch;
+ }
+
+ public static int decompressFile(File srcFile, File dstFile) throws ErrnoException {
+ if (DEBUG_COMPRESSION) {
+ Slog.i(TAG, "Decompress file"
+ + "; src: " + srcFile.getAbsolutePath()
+ + ", dst: " + dstFile.getAbsolutePath());
+ }
+ try (
+ InputStream fileIn = new GZIPInputStream(new FileInputStream(srcFile));
+ OutputStream fileOut = new FileOutputStream(dstFile, false /*append*/);
+ ) {
+ Streams.copy(fileIn, fileOut);
+ Os.chmod(dstFile.getAbsolutePath(), 0644);
+ return PackageManager.INSTALL_SUCCEEDED;
+ } catch (IOException e) {
+ logCriticalInfo(Log.ERROR, "Failed to decompress file"
+ + "; src: " + srcFile.getAbsolutePath()
+ + ", dst: " + dstFile.getAbsolutePath());
+ }
+ return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ }
+
+ public static File[] getCompressedFiles(String codePath) {
+ final File stubCodePath = new File(codePath);
+ final String stubName = stubCodePath.getName();
+
+ // The layout of a compressed package on a given partition is as follows :
+ //
+ // Compressed artifacts:
+ //
+ // /partition/ModuleName/foo.gz
+ // /partation/ModuleName/bar.gz
+ //
+ // Stub artifact:
+ //
+ // /partition/ModuleName-Stub/ModuleName-Stub.apk
+ //
+ // In other words, stub is on the same partition as the compressed artifacts
+ // and in a directory that's suffixed with "-Stub".
+ int idx = stubName.lastIndexOf(STUB_SUFFIX);
+ if (idx < 0 || (stubName.length() != (idx + STUB_SUFFIX.length()))) {
+ return null;
+ }
+
+ final File stubParentDir = stubCodePath.getParentFile();
+ if (stubParentDir == null) {
+ Slog.e(TAG, "Unable to determine stub parent dir for codePath: " + codePath);
+ return null;
+ }
+
+ final File compressedPath = new File(stubParentDir, stubName.substring(0, idx));
+ final File[] files = compressedPath.listFiles(new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.toLowerCase().endsWith(COMPRESSED_EXTENSION);
+ }
+ });
+
+ if (DEBUG_COMPRESSION && files != null && files.length > 0) {
+ Slog.i(TAG, "getCompressedFiles[" + codePath + "]: " + Arrays.toString(files));
+ }
+
+ return files;
+ }
+
+ public static boolean compressedFileExists(String codePath) {
+ final File[] compressedFiles = getCompressedFiles(codePath);
+ return compressedFiles != null && compressedFiles.length > 0;
+ }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index a3585bc1f97d..ba97c428bb44 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -615,10 +615,16 @@ class ShortcutPackage extends ShortcutPackageItem {
// Fix up isPinned for the caller. Note we need to do it before the "test" callback,
// since it may check isPinned.
- if (!isPinnedByCaller) {
- clone.clearFlags(ShortcutInfo.FLAG_PINNED);
+ // However, if getPinnedByAnyLauncher is set, we do it after the test.
+ if (!getPinnedByAnyLauncher) {
+ if (!isPinnedByCaller) {
+ clone.clearFlags(ShortcutInfo.FLAG_PINNED);
+ }
}
if (query == null || query.test(clone)) {
+ if (!isPinnedByCaller) {
+ clone.clearFlags(ShortcutInfo.FLAG_PINNED);
+ }
result.add(clone);
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 25e923994789..0907dd7c5a9e 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2234,7 +2234,7 @@ public class ShortcutService extends IShortcutService.Stub {
// We override this method in unit tests to do a simpler check.
boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId,
int callingPid, int callingUid) {
- if (injectCheckAccessShortcutsPermission(callingPid, callingUid)) {
+ if (canSeeAnyPinnedShortcut(callingPackage, userId, callingPid, callingUid)) {
return true;
}
final long start = injectElapsedRealtime();
@@ -2245,10 +2245,21 @@ public class ShortcutService extends IShortcutService.Stub {
}
}
+ boolean canSeeAnyPinnedShortcut(@NonNull String callingPackage, int userId,
+ int callingPid, int callingUid) {
+ if (injectHasAccessShortcutsPermission(callingPid, callingUid)) {
+ return true;
+ }
+ synchronized (mLock) {
+ return getUserShortcutsLocked(userId).hasHostPackage(callingPackage);
+ }
+ }
+
/**
* Returns true if the caller has the "ACCESS_SHORTCUTS" permission.
*/
- boolean injectCheckAccessShortcutsPermission(int callingPid, int callingUid) {
+ @VisibleForTesting
+ boolean injectHasAccessShortcutsPermission(int callingPid, int callingUid) {
return mContext.checkPermission(android.Manifest.permission.ACCESS_SHORTCUTS,
callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
}
@@ -2262,10 +2273,6 @@ public class ShortcutService extends IShortcutService.Stub {
final ShortcutUser user = getUserShortcutsLocked(userId);
- if (user.hasHostPackage(packageName)) {
- return true;
- }
-
// Always trust the cached component.
final ComponentName cached = user.getCachedLauncher();
if (cached != null) {
@@ -2491,8 +2498,8 @@ public class ShortcutService extends IShortcutService.Stub {
final ArraySet<String> ids = shortcutIds == null ? null
: new ArraySet<>(shortcutIds);
- final ShortcutPackage p = getUserShortcutsLocked(userId)
- .getPackageShortcutsIfExists(packageName);
+ final ShortcutUser user = getUserShortcutsLocked(userId);
+ final ShortcutPackage p = user.getPackageShortcutsIfExists(packageName);
if (p == null) {
return; // No need to instantiate ShortcutPackage.
}
@@ -2500,9 +2507,12 @@ public class ShortcutService extends IShortcutService.Stub {
final boolean matchPinned = (queryFlags & ShortcutQuery.FLAG_MATCH_PINNED) != 0;
final boolean matchManifest = (queryFlags & ShortcutQuery.FLAG_MATCH_MANIFEST) != 0;
+ final boolean canAccessAllShortcuts =
+ canSeeAnyPinnedShortcut(callingPackage, launcherUserId, callingPid, callingUid);
+
final boolean getPinnedByAnyLauncher =
- ((queryFlags & ShortcutQuery.FLAG_MATCH_ALL_PINNED) != 0)
- && injectCheckAccessShortcutsPermission(callingPid, callingUid);
+ canAccessAllShortcuts &&
+ ((queryFlags & ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER) != 0);
p.findAll(ret,
(ShortcutInfo si) -> {
@@ -2521,7 +2531,7 @@ public class ShortcutService extends IShortcutService.Stub {
if (matchDynamic && si.isDynamic()) {
return true;
}
- if ((matchPinned && si.isPinned()) || getPinnedByAnyLauncher) {
+ if ((matchPinned || getPinnedByAnyLauncher) && si.isPinned()) {
return true;
}
if (matchManifest && si.isDeclaredInManifest()) {
@@ -2614,14 +2624,15 @@ public class ShortcutService extends IShortcutService.Stub {
.attemptToRestoreIfNeededAndSave();
final boolean getPinnedByAnyLauncher =
- injectCheckAccessShortcutsPermission(callingPid, callingUid);
+ canSeeAnyPinnedShortcut(callingPackage, launcherUserId,
+ callingPid, callingUid);
// Make sure the shortcut is actually visible to the launcher.
final ShortcutInfo si = getShortcutInfoLocked(
launcherUserId, callingPackage, packageName, shortcutId, userId,
getPinnedByAnyLauncher);
// "si == null" should suffice here, but check the flags too just to make sure.
- if (si == null || !si.isEnabled() || !si.isAlive()) {
+ if (si == null || !si.isEnabled() || !(si.isAlive() || getPinnedByAnyLauncher)) {
Log.e(TAG, "Shortcut " + shortcutId + " does not exist or disabled");
return null;
}
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
index bfe09b8ecbce..96c102b50a12 100644
--- a/services/core/java/com/android/server/pm/UserDataPreparer.java
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -16,6 +16,8 @@
package com.android.server.pm;
+import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.Environment;
@@ -40,8 +42,6 @@ import java.util.List;
import java.util.Objects;
import java.util.Set;
-import static com.android.server.pm.PackageManagerService.logCriticalInfo;
-
/**
* Helper class for preparing and destroying user storage
*/
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 1e5245cfd81c..1152310116a0 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1010,6 +1010,23 @@ public class UserManagerService extends IUserManager.Stub {
}
}
+ @Override
+ public boolean hasRestrictedProfiles() {
+ checkManageUsersPermission("hasRestrictedProfiles");
+ final int callingUserId = UserHandle.getCallingUserId();
+ synchronized (mUsersLock) {
+ final int userSize = mUsers.size();
+ for (int i = 0; i < userSize; i++) {
+ UserInfo profile = mUsers.valueAt(i).info;
+ if (callingUserId != profile.id
+ && profile.restrictedProfileParentId == callingUserId) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
/*
* Should be locked on mUsers before calling this.
*/
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index c86122f2507a..4b1340437795 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -66,6 +66,7 @@ public class UserRestrictionsUtils {
public static final Set<String> USER_RESTRICTIONS = newSetWithUniqueCheck(new String[] {
UserManager.DISALLOW_CONFIG_WIFI,
+ UserManager.DISALLOW_CONFIG_LOCALE,
UserManager.DISALLOW_MODIFY_ACCOUNTS,
UserManager.DISALLOW_INSTALL_APPS,
UserManager.DISALLOW_UNINSTALL_APPS,
@@ -112,6 +113,7 @@ public class UserRestrictionsUtils {
UserManager.DISALLOW_OEM_UNLOCK,
UserManager.DISALLOW_UNMUTE_DEVICE,
UserManager.DISALLOW_AUTOFILL,
+ UserManager.DISALLOW_USER_SWITCH
});
/**
@@ -143,6 +145,13 @@ public class UserRestrictionsUtils {
);
/**
+ * User restrictions that cannot be set by profile owners. Applied to all users.
+ */
+ private static final Set<String> DEVICE_OWNER_ONLY_RESTRICTIONS = Sets.newArraySet(
+ UserManager.DISALLOW_USER_SWITCH
+ );
+
+ /**
* User restrictions that can't be changed by device owner or profile owner.
*/
private static final Set<String> IMMUTABLE_BY_OWNERS = Sets.newArraySet(
@@ -311,6 +320,7 @@ public class UserRestrictionsUtils {
*/
public static boolean canProfileOwnerChange(String restriction, int userId) {
return !IMMUTABLE_BY_OWNERS.contains(restriction)
+ && !DEVICE_OWNER_ONLY_RESTRICTIONS.contains(restriction)
&& !(userId != UserHandle.USER_SYSTEM
&& PRIMARY_USER_ONLY_RESTRICTIONS.contains(restriction));
}
@@ -363,8 +373,9 @@ public class UserRestrictionsUtils {
*/
private static boolean isGlobal(boolean isDeviceOwner, String key) {
return (isDeviceOwner &&
- (PRIMARY_USER_ONLY_RESTRICTIONS.contains(key)|| GLOBAL_RESTRICTIONS.contains(key)))
- || PROFILE_GLOBAL_RESTRICTIONS.contains(key);
+ (PRIMARY_USER_ONLY_RESTRICTIONS.contains(key) || GLOBAL_RESTRICTIONS.contains(key)))
+ || PROFILE_GLOBAL_RESTRICTIONS.contains(key)
+ || DEVICE_OWNER_ONLY_RESTRICTIONS.contains(key);
}
/**
diff --git a/services/core/java/com/android/server/pm/crossprofile/CrossProfileAppsService.java b/services/core/java/com/android/server/pm/crossprofile/CrossProfileAppsService.java
new file mode 100644
index 000000000000..0913269f35e1
--- /dev/null
+++ b/services/core/java/com/android/server/pm/crossprofile/CrossProfileAppsService.java
@@ -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.
+ */
+package com.android.server.pm.crossprofile;
+
+import android.content.Context;
+
+import com.android.server.SystemService;
+
+public class CrossProfileAppsService extends SystemService {
+ private CrossProfileAppsServiceImpl mServiceImpl;
+
+ public CrossProfileAppsService(Context context) {
+ super(context);
+ mServiceImpl = new CrossProfileAppsServiceImpl(context);
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.CROSS_PROFILE_APPS_SERVICE, mServiceImpl);
+ }
+}
diff --git a/services/core/java/com/android/server/pm/crossprofile/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/crossprofile/CrossProfileAppsServiceImpl.java
new file mode 100644
index 000000000000..854b70439d56
--- /dev/null
+++ b/services/core/java/com/android/server/pm/crossprofile/CrossProfileAppsServiceImpl.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.crossprofile;
+
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+
+import android.annotation.UserIdInt;
+import android.app.AppOpsManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
+import android.content.pm.crossprofile.ICrossProfileApps;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.text.TextUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+import com.android.server.LocalServices;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
+ private static final String TAG = "CrossProfileAppsService";
+
+ private Context mContext;
+ private Injector mInjector;
+
+ public CrossProfileAppsServiceImpl(Context context) {
+ this(context, new InjectorImpl(context));
+ }
+
+ @VisibleForTesting
+ CrossProfileAppsServiceImpl(Context context, Injector injector) {
+ mContext = context;
+ mInjector = injector;
+ }
+
+ @Override
+ public List<UserHandle> getTargetUserProfiles(String callingPackage) {
+ Preconditions.checkNotNull(callingPackage);
+
+ verifyCallingPackage(callingPackage);
+
+ return getTargetUserProfilesUnchecked(
+ callingPackage, mInjector.getCallingUserId());
+ }
+
+ @Override
+ public void startActivityAsUser(
+ String callingPackage,
+ ComponentName component,
+ Rect sourceBounds,
+ Bundle startActivityOptions,
+ UserHandle user) throws RemoteException {
+ Preconditions.checkNotNull(callingPackage);
+ Preconditions.checkNotNull(component);
+ Preconditions.checkNotNull(user);
+
+ verifyCallingPackage(callingPackage);
+
+ List<UserHandle> allowedTargetUsers = getTargetUserProfilesUnchecked(
+ callingPackage, mInjector.getCallingUserId());
+ if (!allowedTargetUsers.contains(user)) {
+ throw new SecurityException(
+ callingPackage + " cannot access unrelated user " + user.getIdentifier());
+ }
+
+ // Verify that caller package is starting activity in its own package.
+ if (!callingPackage.equals(component.getPackageName())) {
+ throw new SecurityException(
+ callingPackage + " attempts to start an activity in other package - "
+ + component.getPackageName());
+ }
+
+ final int callingUid = mInjector.getCallingUid();
+
+ // Verify that target activity does handle the intent with ACTION_MAIN and
+ // CATEGORY_LAUNCHER as calling startActivityAsUser ignore them if component is present.
+ final Intent launchIntent = new Intent(Intent.ACTION_MAIN);
+ launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ launchIntent.setSourceBounds(sourceBounds);
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ // Only package name is set here, as opposed to component name, because intent action and
+ // category are ignored if component name is present while we are resolving intent.
+ launchIntent.setPackage(component.getPackageName());
+ verifyActivityCanHandleIntentAndExported(launchIntent, component, callingUid, user);
+
+ final long ident = mInjector.clearCallingIdentity();
+ try {
+ launchIntent.setComponent(component);
+ mContext.startActivityAsUser(launchIntent, startActivityOptions, user);
+ } finally {
+ mInjector.restoreCallingIdentity(ident);
+ }
+ }
+
+ private List<UserHandle> getTargetUserProfilesUnchecked(
+ String callingPackage, @UserIdInt int callingUserId) {
+ final long ident = mInjector.clearCallingIdentity();
+ try {
+ final int[] enabledProfileIds =
+ mInjector.getUserManager().getEnabledProfileIds(callingUserId);
+
+ List<UserHandle> targetProfiles = new ArrayList<>();
+ for (final int userId : enabledProfileIds) {
+ if (userId == callingUserId) {
+ continue;
+ }
+ if (!isPackageEnabled(callingPackage, userId)) {
+ continue;
+ }
+ targetProfiles.add(UserHandle.of(userId));
+ }
+ return targetProfiles;
+ } finally {
+ mInjector.restoreCallingIdentity(ident);
+ }
+ }
+
+ private boolean isPackageEnabled(String packageName, @UserIdInt int userId) {
+ final int callingUid = mInjector.getCallingUid();
+ final long ident = mInjector.clearCallingIdentity();
+ try {
+ final PackageInfo info = mInjector.getPackageManagerInternal()
+ .getPackageInfo(
+ packageName,
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+ callingUid,
+ userId);
+ return info != null && info.applicationInfo.enabled;
+ } finally {
+ mInjector.restoreCallingIdentity(ident);
+ }
+ }
+
+ /**
+ * Verify that the specified intent does resolved to the specified component and the resolved
+ * activity is exported.
+ */
+ private void verifyActivityCanHandleIntentAndExported(
+ Intent launchIntent, ComponentName component, int callingUid, UserHandle user) {
+ final long ident = mInjector.clearCallingIdentity();
+ try {
+ final List<ResolveInfo> apps =
+ mInjector.getPackageManagerInternal().queryIntentActivities(
+ launchIntent,
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+ callingUid,
+ user.getIdentifier());
+ final int size = apps.size();
+ for (int i = 0; i < size; ++i) {
+ final ActivityInfo activityInfo = apps.get(i).activityInfo;
+ if (TextUtils.equals(activityInfo.packageName, component.getPackageName())
+ && TextUtils.equals(activityInfo.name, component.getClassName())
+ && activityInfo.exported) {
+ return;
+ }
+ }
+ throw new SecurityException("Attempt to launch activity without "
+ + " category Intent.CATEGORY_LAUNCHER or activity is not exported" + component);
+ } finally {
+ mInjector.restoreCallingIdentity(ident);
+ }
+ }
+
+ /**
+ * Verify that the given calling package is belong to the calling UID.
+ */
+ private void verifyCallingPackage(String callingPackage) {
+ mInjector.getAppOpsManager().checkPackage(mInjector.getCallingUid(), callingPackage);
+ }
+
+ private static class InjectorImpl implements Injector {
+ private Context mContext;
+
+ public InjectorImpl(Context context) {
+ mContext = context;
+ }
+
+ public int getCallingUid() {
+ return Binder.getCallingUid();
+ }
+
+ public int getCallingUserId() {
+ return UserHandle.getCallingUserId();
+ }
+
+ public UserHandle getCallingUserHandle() {
+ return Binder.getCallingUserHandle();
+ }
+
+ public long clearCallingIdentity() {
+ return Binder.clearCallingIdentity();
+ }
+
+ public void restoreCallingIdentity(long token) {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ public UserManager getUserManager() {
+ return mContext.getSystemService(UserManager.class);
+ }
+
+ public PackageManagerInternal getPackageManagerInternal() {
+ return LocalServices.getService(PackageManagerInternal.class);
+ }
+
+ public PackageManager getPackageManager() {
+ return mContext.getPackageManager();
+ }
+
+ public AppOpsManager getAppOpsManager() {
+ return mContext.getSystemService(AppOpsManager.class);
+ }
+ }
+
+ @VisibleForTesting
+ public interface Injector {
+ int getCallingUid();
+
+ int getCallingUserId();
+
+ UserHandle getCallingUserHandle();
+
+ long clearCallingIdentity();
+
+ void restoreCallingIdentity(long token);
+
+ UserManager getUserManager();
+
+ PackageManagerInternal getPackageManagerInternal();
+
+ PackageManager getPackageManager();
+
+ AppOpsManager getAppOpsManager();
+
+ }
+}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 8014acf653ee..c40d1fad9931 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -16,6 +16,8 @@
package com.android.server.pm.permission;
+import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1110,8 +1112,8 @@ public final class DefaultPermissionGrantPolicy {
final String systemPackageName = mServiceInternal.getKnownPackageName(
PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM);
final PackageParser.Package systemPackage = getPackage(systemPackageName);
- return PackageManagerService.compareSignatures(systemPackage.mSignatures,
- pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
+ return compareSignatures(systemPackage.mSignatures, pkg.mSignatures)
+ == PackageManager.SIGNATURE_MATCH;
}
private void grantDefaultPermissionExceptions(int userId) {
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 76805ce3a9ff..7d8e20696aff 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -37,6 +37,7 @@ import android.content.pm.PackageParser;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.PackageParser.Package;
+import android.metrics.LogMaker;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -92,36 +93,6 @@ import java.util.Set;
public class PermissionManagerService {
private static final String TAG = "PackageManager";
- /** All dangerous permission names in the same order as the events in MetricsEvent */
- private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
- Manifest.permission.READ_CALENDAR,
- Manifest.permission.WRITE_CALENDAR,
- Manifest.permission.CAMERA,
- Manifest.permission.READ_CONTACTS,
- Manifest.permission.WRITE_CONTACTS,
- Manifest.permission.GET_ACCOUNTS,
- Manifest.permission.ACCESS_FINE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.RECORD_AUDIO,
- Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.CALL_PHONE,
- Manifest.permission.READ_CALL_LOG,
- Manifest.permission.WRITE_CALL_LOG,
- Manifest.permission.ADD_VOICEMAIL,
- Manifest.permission.USE_SIP,
- Manifest.permission.PROCESS_OUTGOING_CALLS,
- Manifest.permission.READ_CELL_BROADCASTS,
- Manifest.permission.BODY_SENSORS,
- Manifest.permission.SEND_SMS,
- Manifest.permission.RECEIVE_SMS,
- Manifest.permission.READ_SMS,
- Manifest.permission.RECEIVE_WAP_PUSH,
- Manifest.permission.RECEIVE_MMS,
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.READ_PHONE_NUMBERS,
- Manifest.permission.ANSWER_PHONE_CALLS);
-
/** Permission grant: not grant the permission. */
private static final int GRANT_DENIED = 1;
/** Permission grant: grant the permission as an install permission. */
@@ -160,6 +131,7 @@ public class PermissionManagerService {
private final HandlerThread mHandlerThread;
private final Handler mHandler;
private final Context mContext;
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
/** Internal storage for permissions and related settings */
@GuardedBy("mLock")
@@ -1037,10 +1009,10 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages));
PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM);
final PackageParser.Package systemPackage =
mPackageManagerInt.getPackage(systemPackageName);
- boolean allowed = (PackageManagerService.compareSignatures(
+ boolean allowed = (PackageManagerServiceUtils.compareSignatures(
bp.getSourceSignatures(), pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH)
- || (PackageManagerService.compareSignatures(
+ || (PackageManagerServiceUtils.compareSignatures(
systemPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH);
if (!allowed && (privilegedPermission || oemPermission)) {
@@ -1386,7 +1358,7 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages));
}
if (bp.isRuntime()) {
- logPermissionGranted(mContext, permName, packageName);
+ logPermission(MetricsEvent.ACTION_PERMISSION_GRANTED, permName, packageName);
}
if (callback != null) {
@@ -1484,7 +1456,7 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages));
}
if (bp.isRuntime()) {
- logPermissionRevoked(mContext, permName, packageName);
+ logPermission(MetricsEvent.ACTION_PERMISSION_REVOKED, permName, packageName);
}
if (callback != null) {
@@ -1938,63 +1910,18 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages));
}
/**
- * Get the first event id for the permission.
- *
- * <p>There are four events for each permission: <ul>
- * <li>Request permission: first id + 0</li>
- * <li>Grant permission: first id + 1</li>
- * <li>Request for permission denied: first id + 2</li>
- * <li>Revoke permission: first id + 3</li>
- * </ul></p>
- *
- * @param name name of the permission
- *
- * @return The first event id for the permission
- */
- private static int getBaseEventId(@NonNull String name) {
- int eventIdIndex = ALL_DANGEROUS_PERMISSIONS.indexOf(name);
-
- if (eventIdIndex == -1) {
- if (AppOpsManager.permissionToOpCode(name) == AppOpsManager.OP_NONE
- || Build.IS_USER) {
- Log.i(TAG, "Unknown permission " + name);
-
- return MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN;
- } else {
- // Most likely #ALL_DANGEROUS_PERMISSIONS needs to be updated.
- //
- // Also update
- // - EventLogger#ALL_DANGEROUS_PERMISSIONS
- // - metrics_constants.proto
- throw new IllegalStateException("Unknown permission " + name);
- }
- }
-
- return MetricsEvent.ACTION_PERMISSION_REQUEST_READ_CALENDAR + eventIdIndex * 4;
- }
-
- /**
- * Log that a permission was revoked.
+ * Log that a permission request was granted/revoked.
*
- * @param context Context of the caller
+ * @param action the action performed
* @param name name of the permission
- * @param packageName package permission if for
+ * @param packageName package permission is for
*/
- private static void logPermissionRevoked(@NonNull Context context, @NonNull String name,
- @NonNull String packageName) {
- MetricsLogger.action(context, getBaseEventId(name) + 3, packageName);
- }
+ private void logPermission(int action, @NonNull String name, @NonNull String packageName) {
+ final LogMaker log = new LogMaker(action);
+ log.setPackageName(packageName);
+ log.addTaggedData(MetricsEvent.FIELD_PERMISSION, name);
- /**
- * Log that a permission request was granted.
- *
- * @param context Context of the caller
- * @param name name of the permission
- * @param packageName package permission if for
- */
- private static void logPermissionGranted(@NonNull Context context, @NonNull String name,
- @NonNull String packageName) {
- MetricsLogger.action(context, getBaseEventId(name) + 1, packageName);
+ mMetricsLogger.write(log);
}
private class PermissionManagerInternalImpl extends PermissionManagerInternal {
diff --git a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
index 92729dc08b63..6886985eec50 100644
--- a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
+++ b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
@@ -253,7 +253,8 @@ public class BurnInProtectionHelper implements DisplayManager.DisplayListener,
public void onDisplayChanged(int displayId) {
if (displayId == mDisplay.getDisplayId()) {
if (mDisplay.getState() == Display.STATE_DOZE
- || mDisplay.getState() == Display.STATE_DOZE_SUSPEND) {
+ || mDisplay.getState() == Display.STATE_DOZE_SUSPEND
+ || mDisplay.getState() == Display.STATE_ON_SUSPEND) {
startBurnInProtection();
} else {
cancelBurnInProtection();
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index 7a2e630cfdac..3707a5edb3c1 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -58,7 +58,7 @@ class GlobalActions implements GlobalActionsListener {
public void showDialog(boolean keyguardShowing, boolean deviceProvisioned) {
if (DEBUG) Slog.d(TAG, "showDialog " + keyguardShowing + " " + deviceProvisioned);
- if (mStatusBarInternal.isGlobalActionsDisabled()) {
+ if (mStatusBarInternal != null && mStatusBarInternal.isGlobalActionsDisabled()) {
return;
}
mKeyguardShowing = keyguardShowing;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 6520dc94072f..9162a97ad5f7 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -59,6 +59,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SYSTEM_WINDOW;
@@ -66,6 +68,8 @@ import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
@@ -122,11 +126,8 @@ import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
-import static com.android.server.wm.proto.WindowManagerPolicyProto.STABLE_BOUNDS;
-
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.ActivityManager.StackId;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.SleepToken;
import android.app.ActivityThread;
@@ -183,6 +184,7 @@ import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UEventObserver;
@@ -197,6 +199,7 @@ import android.service.dreams.IDreamManager;
import android.service.vr.IPersistentVrStateCallbacks;
import android.speech.RecognizerIntent;
import android.telecom.TelecomManager;
+import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -207,6 +210,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
+import android.view.DisplayFrames;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.IApplicationToken;
@@ -455,6 +459,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private AccessibilityShortcutController mAccessibilityShortcutController;
boolean mSafeMode;
+ private final ArraySet<WindowState> mScreenDecorWindows = new ArraySet<>();
WindowState mStatusBar = null;
int mStatusBarHeight;
WindowState mNavigationBar = null;
@@ -592,47 +597,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
PointerLocationView mPointerLocationView;
- // The current size of the screen; really; extends into the overscan area of
- // the screen and doesn't account for any system elements like the status bar.
- int mOverscanScreenLeft, mOverscanScreenTop;
- int mOverscanScreenWidth, mOverscanScreenHeight;
- // The current visible size of the screen; really; (ir)regardless of whether the status
- // bar can be hidden but not extending into the overscan area.
- int mUnrestrictedScreenLeft, mUnrestrictedScreenTop;
- int mUnrestrictedScreenWidth, mUnrestrictedScreenHeight;
- // Like mOverscanScreen*, but allowed to move into the overscan region where appropriate.
- int mRestrictedOverscanScreenLeft, mRestrictedOverscanScreenTop;
- int mRestrictedOverscanScreenWidth, mRestrictedOverscanScreenHeight;
- // The current size of the screen; these may be different than (0,0)-(dw,dh)
- // if the status bar can't be hidden; in that case it effectively carves out
- // that area of the display from all other windows.
- int mRestrictedScreenLeft, mRestrictedScreenTop;
- int mRestrictedScreenWidth, mRestrictedScreenHeight;
- // During layout, the current screen borders accounting for any currently
- // visible system UI elements.
- int mSystemLeft, mSystemTop, mSystemRight, mSystemBottom;
- // For applications requesting stable content insets, these are them.
- int mStableLeft, mStableTop, mStableRight, mStableBottom;
- // For applications requesting stable content insets but have also set the
- // fullscreen window flag, these are the stable dimensions without the status bar.
- int mStableFullscreenLeft, mStableFullscreenTop;
- int mStableFullscreenRight, mStableFullscreenBottom;
- // During layout, the current screen borders with all outer decoration
- // (status bar, input method dock) accounted for.
- int mCurLeft, mCurTop, mCurRight, mCurBottom;
- // During layout, the frame in which content should be displayed
- // to the user, accounting for all screen decoration except for any
- // space they deem as available for other content. This is usually
- // the same as mCur*, but may be larger if the screen decor has supplied
- // content insets.
- int mContentLeft, mContentTop, mContentRight, mContentBottom;
- // During layout, the frame in which voice content should be displayed
- // to the user, accounting for all screen decoration except for any
- // space they deem as available for other content.
- int mVoiceContentLeft, mVoiceContentTop, mVoiceContentRight, mVoiceContentBottom;
- // During layout, the current screen borders along which input method
- // windows are placed.
- int mDockLeft, mDockTop, mDockRight, mDockBottom;
// During layout, the layer at which the doc window is placed.
int mDockLayer;
// During layout, this is the layer of the status bar.
@@ -730,18 +694,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Display mDisplay;
- private int mDisplayRotation;
-
int mLandscapeRotation = 0; // default landscape rotation
int mSeascapeRotation = 0; // "other" landscape rotation, 180 degrees from mLandscapeRotation
int mPortraitRotation = 0; // default portrait rotation
int mUpsideDownRotation = 0; // "other" portrait rotation
- int mOverscanLeft = 0;
- int mOverscanTop = 0;
- int mOverscanRight = 0;
- int mOverscanBottom = 0;
-
// What we do when the user long presses on home
private int mLongPressOnHomeBehavior;
@@ -1057,7 +1014,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
View.NAVIGATION_BAR_UNHIDE,
View.NAVIGATION_BAR_TRANSLUCENT,
StatusBarManager.WINDOW_NAVIGATION_BAR,
- WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,
+ FLAG_TRANSLUCENT_NAVIGATION,
View.NAVIGATION_BAR_TRANSPARENT);
private final BarController.OnBarVisibilityChangedListener mNavBarVisibilityListener =
@@ -1168,14 +1125,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
+ ", mOrientationSensorEnabled=" + mOrientationSensorEnabled
+ ", mKeyguardDrawComplete=" + mKeyguardDrawComplete
+ ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
- final boolean keyguardGoingAway = mWindowManagerInternal.isKeyguardGoingAway();
boolean disable = true;
// Note: We postpone the rotating of the screen until the keyguard as well as the
// window manager have reported a draw complete or the keyguard is going away in dismiss
// mode.
- if (mScreenOnEarly && mAwake && ((mKeyguardDrawComplete && mWindowManagerDrawComplete)
- || keyguardGoingAway)) {
+ if (mScreenOnEarly && mAwake && ((mKeyguardDrawComplete && mWindowManagerDrawComplete))) {
if (needSensorRunningLp()) {
disable = false;
//enable listener if not already enabled
@@ -1186,7 +1141,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// the sensor reading was cleared which can cause it to relaunch the app that
// will show in the wrong orientation first before correcting leading to app
// launch delays.
- mOrientationListener.enable(!keyguardGoingAway /* clearCurrentRotation */);
+ mOrientationListener.enable(true /* clearCurrentRotation */);
if(localLOGV) Slog.v(TAG, "Enabling listeners");
mOrientationSensorEnabled = true;
}
@@ -1661,14 +1616,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private long getAccessibilityShortcutTimeout() {
ViewConfiguration config = ViewConfiguration.get(mContext);
- try {
- return Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, mCurrentUserId) == 0
- ? config.getAccessibilityShortcutKeyTimeout()
- : config.getAccessibilityShortcutKeyTimeoutAfterConfirmation();
- } catch (Settings.SettingNotFoundException e) {
- throw new RuntimeException(e);
- }
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, mCurrentUserId) == 0
+ ? config.getAccessibilityShortcutKeyTimeout()
+ : config.getAccessibilityShortcutKeyTimeoutAfterConfirmation();
}
private long getScreenshotChordLongPressDelay() {
@@ -2070,6 +2021,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
context.registerReceiver(mMultiuserReceiver, filter);
// monitor for system gestures
+ // TODO(multi-display): Needs to be display specific.
mSystemGestures = new SystemGesturesPointerEventListener(context,
new SystemGesturesPointerEventListener.Callbacks() {
@Override
@@ -2316,17 +2268,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return mForceDefaultOrientation;
}
- @Override
- public void setDisplayOverscan(Display display, int left, int top, int right, int bottom) {
- // TODO(multi-display): Define policy for secondary displays.
- if (display.getDisplayId() == DEFAULT_DISPLAY) {
- mOverscanLeft = left;
- mOverscanTop = top;
- mOverscanRight = right;
- mOverscanBottom = bottom;
- }
- }
-
public void updateSettings() {
ContentResolver resolver = mContext.getContentResolver();
boolean updateRotation = false;
@@ -2612,7 +2553,19 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
- public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
+ public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
+ boolean hasStatusBarServicePermission) {
+
+ final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
+ if (mScreenDecorWindows.contains(win)) {
+ if (!isScreenDecor) {
+ // No longer has the flag set, so remove from the set.
+ mScreenDecorWindows.remove(win);
+ }
+ } else if (isScreenDecor && hasStatusBarServicePermission) {
+ mScreenDecorWindows.add(win);
+ }
+
switch (attrs.type) {
case TYPE_SYSTEM_OVERLAY:
case TYPE_SECURE_SYSTEM_OVERLAY:
@@ -3073,6 +3026,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
*/
@Override
public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
+
+ if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.STATUS_BAR_SERVICE,
+ "PhoneWindowManager");
+ mScreenDecorWindows.add(win);
+ }
+
switch (attrs.type) {
case TYPE_STATUS_BAR:
mContext.enforceCallingOrSelfPermission(
@@ -3124,6 +3085,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mNavigationBar = null;
mNavigationBarController.setWindow(null);
}
+ mScreenDecorWindows.remove(win);
}
static final boolean PRINT_ANIM = false;
@@ -4302,12 +4264,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
+ // TODO: Should probably be moved into DisplayFrames.
public boolean getInsetHintLw(WindowManager.LayoutParams attrs, Rect taskBounds,
- int displayRotation, int displayWidth, int displayHeight, Rect outContentInsets,
- Rect outStableInsets, Rect outOutsets) {
+ DisplayFrames displayFrames, Rect outContentInsets, Rect outStableInsets,
+ Rect outOutsets) {
final int fl = PolicyControl.getWindowFlags(null, attrs);
final int sysuiVis = PolicyControl.getSystemUiVisibility(null, attrs);
final int systemUiVisibility = (sysuiVis | attrs.subtreeSystemUiVisibility);
+ final int displayRotation = displayFrames.mRotation;
+ final int displayWidth = displayFrames.mDisplayWidth;
+ final int displayHeight = displayFrames.mDisplayHeight;
final boolean useOutsets = outOutsets != null && shouldUseOutsets(attrs, fl);
if (useOutsets) {
@@ -4330,34 +4296,33 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int availRight, availBottom;
if (canHideNavigationBar() &&
(systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
- availRight = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
- availBottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+ availRight = displayFrames.mUnrestricted.right;
+ availBottom = displayFrames.mUnrestricted.bottom;
} else {
- availRight = mRestrictedScreenLeft + mRestrictedScreenWidth;
- availBottom = mRestrictedScreenTop + mRestrictedScreenHeight;
+ availRight = displayFrames.mRestricted.right;
+ availBottom = displayFrames.mRestricted.bottom;
}
+ outStableInsets.set(displayFrames.mStable.left, displayFrames.mStable.top,
+ availRight - displayFrames.mStable.right,
+ availBottom - displayFrames.mStable.bottom);
+
if ((systemUiVisibility & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
if ((fl & FLAG_FULLSCREEN) != 0) {
- outContentInsets.set(mStableFullscreenLeft, mStableFullscreenTop,
- availRight - mStableFullscreenRight,
- availBottom - mStableFullscreenBottom);
+ outContentInsets.set(displayFrames.mStableFullscreen.left,
+ displayFrames.mStableFullscreen.top,
+ availRight - displayFrames.mStableFullscreen.right,
+ availBottom - displayFrames.mStableFullscreen.bottom);
} else {
- outContentInsets.set(mStableLeft, mStableTop,
- availRight - mStableRight, availBottom - mStableBottom);
+ outContentInsets.set(outStableInsets);
}
} else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) {
outContentInsets.setEmpty();
- } else if ((systemUiVisibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)) == 0) {
- outContentInsets.set(mCurLeft, mCurTop,
- availRight - mCurRight, availBottom - mCurBottom);
} else {
- outContentInsets.set(mCurLeft, mCurTop,
- availRight - mCurRight, availBottom - mCurBottom);
+ outContentInsets.set(displayFrames.mCurrent.left, displayFrames.mCurrent.top,
+ availRight - displayFrames.mCurrent.right,
+ availBottom - displayFrames.mCurrent.bottom);
}
- outStableInsets.set(mStableLeft, mStableTop,
- availRight - mStableRight, availBottom - mStableBottom);
if (taskBounds != null) {
calculateRelevantTaskInsets(taskBounds, outContentInsets,
displayWidth, displayHeight);
@@ -4394,67 +4359,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
@Override
- public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
- int displayRotation, int uiMode) {
- mDisplayRotation = displayRotation;
- final int overscanLeft, overscanTop, overscanRight, overscanBottom;
- if (isDefaultDisplay) {
- switch (displayRotation) {
- case Surface.ROTATION_90:
- overscanLeft = mOverscanTop;
- overscanTop = mOverscanRight;
- overscanRight = mOverscanBottom;
- overscanBottom = mOverscanLeft;
- break;
- case Surface.ROTATION_180:
- overscanLeft = mOverscanRight;
- overscanTop = mOverscanBottom;
- overscanRight = mOverscanLeft;
- overscanBottom = mOverscanTop;
- break;
- case Surface.ROTATION_270:
- overscanLeft = mOverscanBottom;
- overscanTop = mOverscanLeft;
- overscanRight = mOverscanTop;
- overscanBottom = mOverscanRight;
- break;
- default:
- overscanLeft = mOverscanLeft;
- overscanTop = mOverscanTop;
- overscanRight = mOverscanRight;
- overscanBottom = mOverscanBottom;
- break;
- }
- } else {
- overscanLeft = 0;
- overscanTop = 0;
- overscanRight = 0;
- overscanBottom = 0;
- }
- mOverscanScreenLeft = mRestrictedOverscanScreenLeft = 0;
- mOverscanScreenTop = mRestrictedOverscanScreenTop = 0;
- mOverscanScreenWidth = mRestrictedOverscanScreenWidth = displayWidth;
- mOverscanScreenHeight = mRestrictedOverscanScreenHeight = displayHeight;
- mSystemLeft = 0;
- mSystemTop = 0;
- mSystemRight = displayWidth;
- mSystemBottom = displayHeight;
- mUnrestrictedScreenLeft = overscanLeft;
- mUnrestrictedScreenTop = overscanTop;
- mUnrestrictedScreenWidth = displayWidth - overscanLeft - overscanRight;
- mUnrestrictedScreenHeight = displayHeight - overscanTop - overscanBottom;
- mRestrictedScreenLeft = mUnrestrictedScreenLeft;
- mRestrictedScreenTop = mUnrestrictedScreenTop;
- mRestrictedScreenWidth = mSystemGestures.screenWidth = mUnrestrictedScreenWidth;
- mRestrictedScreenHeight = mSystemGestures.screenHeight = mUnrestrictedScreenHeight;
- mDockLeft = mContentLeft = mVoiceContentLeft = mStableLeft = mStableFullscreenLeft
- = mCurLeft = mUnrestrictedScreenLeft;
- mDockTop = mContentTop = mVoiceContentTop = mStableTop = mStableFullscreenTop
- = mCurTop = mUnrestrictedScreenTop;
- mDockRight = mContentRight = mVoiceContentRight = mStableRight = mStableFullscreenRight
- = mCurRight = displayWidth - overscanRight;
- mDockBottom = mContentBottom = mVoiceContentBottom = mStableBottom = mStableFullscreenBottom
- = mCurBottom = displayHeight - overscanBottom;
+ public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
+ displayFrames.onBeginLayout();
+ // TODO(multi-display): This doesn't seem right...Maybe only apply to default display?
+ mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
+ mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
mDockLayer = 0x10000000;
mStatusBarLayer = -1;
@@ -4464,13 +4373,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final Rect of = mTmpOverscanFrame;
final Rect vf = mTmpVisibleFrame;
final Rect dcf = mTmpDecorFrame;
- pf.left = df.left = of.left = vf.left = mDockLeft;
- pf.top = df.top = of.top = vf.top = mDockTop;
- pf.right = df.right = of.right = vf.right = mDockRight;
- pf.bottom = df.bottom = of.bottom = vf.bottom = mDockBottom;
+ vf.set(displayFrames.mDock);
+ of.set(displayFrames.mDock);
+ df.set(displayFrames.mDock);
+ pf.set(displayFrames.mDock);
dcf.setEmpty(); // Decor frame N/A for system bars.
- if (isDefaultDisplay) {
+ if (displayFrames.mDisplayId == DEFAULT_DISPLAY) {
// For purposes of putting out fake window up to steal focus, we will
// drive nav being hidden only by whether it is requested.
final int sysui = mLastSystemUiFlags;
@@ -4489,10 +4398,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
&& mStatusBar.getAttrs().height == MATCH_PARENT
&& mStatusBar.getAttrs().width == MATCH_PARENT;
- // When the navigation bar isn't visible, we put up a fake
- // input window to catch all touch events. This way we can
- // detect when the user presses anywhere to bring back the nav
- // bar and ensure the application doesn't see the event.
+ // When the navigation bar isn't visible, we put up a fake input window to catch all
+ // touch events. This way we can detect when the user presses anywhere to bring back the
+ // nav bar and ensure the application doesn't see the event.
if (navVisible || navAllowedHidden) {
if (mInputConsumer != null) {
mHandler.sendMessage(
@@ -4508,199 +4416,237 @@ public class PhoneWindowManager implements WindowManagerPolicy {
InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
}
- // For purposes of positioning and showing the nav bar, if we have
- // decided that it can't be hidden (because of the screen aspect ratio),
- // then take that into account.
+ // For purposes of positioning and showing the nav bar, if we have decided that it can't
+ // be hidden (because of the screen aspect ratio), then take that into account.
navVisible |= !canHideNavigationBar();
- boolean updateSysUiVisibility = layoutNavigationBar(displayWidth, displayHeight,
- displayRotation, uiMode, overscanLeft, overscanRight, overscanBottom, dcf, navVisible, navTranslucent,
- navAllowedHidden, statusBarExpandedNotKeyguard);
- if (DEBUG_LAYOUT) Slog.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
- mDockLeft, mDockTop, mDockRight, mDockBottom));
- updateSysUiVisibility |= layoutStatusBar(pf, df, of, vf, dcf, sysui, isKeyguardShowing);
+ boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, dcf,
+ navVisible, navTranslucent, navAllowedHidden, statusBarExpandedNotKeyguard);
+ if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
+ updateSysUiVisibility |= layoutStatusBar(
+ displayFrames, pf, df, of, vf, dcf, sysui, isKeyguardShowing);
if (updateSysUiVisibility) {
updateSystemUiVisibilityLw();
}
}
+ layoutScreenDecorWindows(displayFrames, pf, df, dcf);
}
- private boolean layoutStatusBar(Rect pf, Rect df, Rect of, Rect vf, Rect dcf, int sysui,
- boolean isKeyguardShowing) {
+ private void layoutScreenDecorWindows(DisplayFrames displayFrames, Rect pf, Rect df, Rect dcf) {
+ if (mScreenDecorWindows.isEmpty()) {
+ return;
+ }
+
+ final int displayId = displayFrames.mDisplayId;
+ final Rect dockFrame = displayFrames.mDock;
+ final int displayHeight = displayFrames.mDisplayHeight;
+ final int displayWidth = displayFrames.mDisplayWidth;
+
+ for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
+ final WindowState w = mScreenDecorWindows.valueAt(i);
+ if (w.getDisplayId() != displayId || !w.isVisibleLw()) {
+ // Skip if not on the same display or not visible.
+ continue;
+ }
+
+ w.computeFrameLw(pf /* parentFrame */, df /* displayFrame */, df /* overlayFrame */,
+ df /* contentFrame */, df /* visibleFrame */, dcf /* decorFrame */,
+ df /* stableFrame */, df /* outsetFrame */);
+ final Rect frame = w.getFrameLw();
+
+ if (frame.left <= 0 && frame.top <= 0) {
+ // Docked at left or top.
+ if (frame.bottom >= displayHeight) {
+ // Docked left.
+ dockFrame.left = Math.max(frame.right, dockFrame.left);
+ } else if (frame.right >= displayWidth ) {
+ // Docked top.
+ dockFrame.top = Math.max(frame.bottom, dockFrame.top);
+ } else {
+ Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
+ + " not docked on left or top of display. frame=" + frame
+ + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
+ }
+ } else if (frame.right >= displayWidth && frame.bottom >= displayHeight) {
+ // Docked at right or bottom.
+ if (frame.top <= 0) {
+ // Docked right.
+ dockFrame.right = Math.min(frame.left, dockFrame.right);
+ } else if (frame.left <= 0) {
+ // Docked bottom.
+ dockFrame.bottom = Math.min(frame.top, dockFrame.bottom);
+ } else {
+ Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
+ + " not docked on right or bottom" + " of display. frame=" + frame
+ + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
+ }
+ } else {
+ // Screen decor windows are required to be docked on one of the sides of the screen.
+ Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
+ + " not docked on one of the sides of the display. frame=" + frame
+ + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
+ }
+ }
+
+ displayFrames.mRestricted.set(dockFrame);
+ displayFrames.mCurrent.set(dockFrame);
+ displayFrames.mVoiceContent.set(dockFrame);
+ displayFrames.mSystem.set(dockFrame);
+ displayFrames.mContent.set(dockFrame);
+ displayFrames.mRestrictedOverscan.set(dockFrame);
+ }
+
+ private boolean layoutStatusBar(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect vf,
+ Rect dcf, int sysui, boolean isKeyguardShowing) {
// decide where the status bar goes ahead of time
- if (mStatusBar != null) {
- // apply any navigation bar insets
- pf.left = df.left = of.left = mUnrestrictedScreenLeft;
- pf.top = df.top = of.top = mUnrestrictedScreenTop;
- pf.right = df.right = of.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft;
- pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenHeight
- + mUnrestrictedScreenTop;
- vf.left = mStableLeft;
- vf.top = mStableTop;
- vf.right = mStableRight;
- vf.bottom = mStableBottom;
-
- mStatusBarLayer = mStatusBar.getSurfaceLayer();
-
- // 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 */);
-
- // For layout, the status bar is always at the top with our fixed height.
- mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;
-
- boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
- boolean statusBarTranslucent = (sysui
- & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;
- if (!isKeyguardShowing) {
- statusBarTranslucent &= areTranslucentBarsAllowed();
- }
-
- // If the status bar is hidden, we don't want to cause
- // windows behind it to scroll.
- if (mStatusBar.isVisibleLw() && !statusBarTransient) {
- // Status bar may go away, so the screen area it occupies
- // is available to apps but just covering them when the
- // status bar is visible.
- mDockTop = mUnrestrictedScreenTop + mStatusBarHeight;
-
- mContentTop = mVoiceContentTop = mCurTop = mDockTop;
- mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom;
- mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft;
- mContentRight = mVoiceContentRight = mCurRight = mDockRight;
-
- if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " +
- String.format(
- "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]",
- mDockLeft, mDockTop, mDockRight, mDockBottom,
- mContentLeft, mContentTop, mContentRight, mContentBottom,
- mCurLeft, mCurTop, mCurRight, mCurBottom));
- }
- if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw()
- && !statusBarTransient && !statusBarTranslucent
+ if (mStatusBar == null) {
+ return false;
+ }
+ // apply any navigation bar insets
+ of.set(displayFrames.mUnrestricted);
+ df.set(displayFrames.mUnrestricted);
+ pf.set(displayFrames.mUnrestricted);
+ vf.set(displayFrames.mStable);
+
+ mStatusBarLayer = mStatusBar.getSurfaceLayer();
+
+ // 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 */);
+
+ // For layout, the status bar is always at the top with our fixed height.
+ displayFrames.mStable.top = displayFrames.mUnrestricted.top + mStatusBarHeight;
+
+ boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
+ boolean statusBarTranslucent = (sysui
+ & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;
+ if (!isKeyguardShowing) {
+ statusBarTranslucent &= areTranslucentBarsAllowed();
+ }
+
+ // If the status bar is hidden, we don't want to cause windows behind it to scroll.
+ if (mStatusBar.isVisibleLw() && !statusBarTransient) {
+ // Status bar may go away, so the screen area it occupies is available to apps but just
+ // covering them when the status bar is visible.
+ final Rect dockFrame = displayFrames.mDock;
+ dockFrame.top = displayFrames.mStable.top;
+ displayFrames.mContent.set(dockFrame);
+ displayFrames.mVoiceContent.set(dockFrame);
+
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format(
+ "dock=%s content=%s cur=%s", dockFrame.toString(),
+ displayFrames.mContent.toString(), displayFrames.mCurrent.toString()));
+
+ if (!mStatusBar.isAnimatingLw() && !statusBarTranslucent
&& !mStatusBarController.wasRecentlyTranslucent()) {
- // If the opaque status bar is currently requested to be visible,
- // and not in the process of animating on or off, then
- // we can tell the app that it is covered by it.
- mSystemTop = mUnrestrictedScreenTop + mStatusBarHeight;
- }
- if (mStatusBarController.checkHiddenLw()) {
- return true;
+ // If the opaque status bar is currently requested to be visible, and not in the
+ // process of animating on or off, then we can tell the app that it is covered by it.
+ displayFrames.mSystem.top = displayFrames.mStable.top;
}
}
- return false;
+ return mStatusBarController.checkHiddenLw();
}
- private boolean layoutNavigationBar(int displayWidth, int displayHeight, int displayRotation,
- int uiMode, int overscanLeft, int overscanRight, int overscanBottom, Rect dcf,
+ private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, Rect dcf,
boolean navVisible, boolean navTranslucent, boolean navAllowedHidden,
boolean statusBarExpandedNotKeyguard) {
- if (mNavigationBar != null) {
- boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
- // Force the navigation bar to its appropriate place and
- // size. We need to do this directly, instead of relying on
- // it to bubble up from the nav bar, because this needs to
- // change atomically with screen rotations.
- mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight,
- displayRotation);
- if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
- // It's a system nav bar or a portrait screen; nav bar goes on bottom.
- int top = displayHeight - overscanBottom
- - getNavigationBarHeight(displayRotation, uiMode);
- mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom);
- mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
- if (transientNavBarShowing) {
- mNavigationBarController.setBarShowingLw(true);
- } else if (navVisible) {
- mNavigationBarController.setBarShowingLw(true);
- mDockBottom = mTmpNavigationFrame.top;
- mRestrictedScreenHeight = mDockBottom - mRestrictedScreenTop;
- mRestrictedOverscanScreenHeight = mDockBottom - mRestrictedOverscanScreenTop;
- } else {
- // We currently want to hide the navigation UI - unless we expanded the status
- // bar.
- mNavigationBarController.setBarShowingLw(statusBarExpandedNotKeyguard);
- }
- if (navVisible && !navTranslucent && !navAllowedHidden
- && !mNavigationBar.isAnimatingLw()
- && !mNavigationBarController.wasRecentlyTranslucent()) {
- // If the opaque nav bar is currently requested to be visible,
- // and not in the process of animating on or off, then
- // we can tell the app that it is covered by it.
- mSystemBottom = mTmpNavigationFrame.top;
- }
- } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
- // Landscape screen; nav bar goes to the right.
- int left = displayWidth - overscanRight
- - getNavigationBarWidth(displayRotation, uiMode);
- mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight);
- mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
- if (transientNavBarShowing) {
- mNavigationBarController.setBarShowingLw(true);
- } else if (navVisible) {
- mNavigationBarController.setBarShowingLw(true);
- mDockRight = mTmpNavigationFrame.left;
- mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft;
- mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft;
- } else {
- // We currently want to hide the navigation UI - unless we expanded the status
- // bar.
- mNavigationBarController.setBarShowingLw(statusBarExpandedNotKeyguard);
- }
- if (navVisible && !navTranslucent && !navAllowedHidden
- && !mNavigationBar.isAnimatingLw()
- && !mNavigationBarController.wasRecentlyTranslucent()) {
- // If the nav bar is currently requested to be visible,
- // and not in the process of animating on or off, then
- // we can tell the app that it is covered by it.
- mSystemRight = mTmpNavigationFrame.left;
- }
- } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
- // Seascape screen; nav bar goes to the left.
- int right = overscanLeft + getNavigationBarWidth(displayRotation, uiMode);
- mTmpNavigationFrame.set(overscanLeft, 0, right, displayHeight);
- mStableLeft = mStableFullscreenLeft = mTmpNavigationFrame.right;
- if (transientNavBarShowing) {
- mNavigationBarController.setBarShowingLw(true);
- } else if (navVisible) {
- mNavigationBarController.setBarShowingLw(true);
- mDockLeft = mTmpNavigationFrame.right;
- // TODO: not so sure about those:
- mRestrictedScreenLeft = mRestrictedOverscanScreenLeft = mDockLeft;
- mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft;
- mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft;
- } else {
- // We currently want to hide the navigation UI - unless we expanded the status
- // bar.
- mNavigationBarController.setBarShowingLw(statusBarExpandedNotKeyguard);
- }
- if (navVisible && !navTranslucent && !navAllowedHidden
- && !mNavigationBar.isAnimatingLw()
- && !mNavigationBarController.wasRecentlyTranslucent()) {
- // If the nav bar is currently requested to be visible,
- // and not in the process of animating on or off, then
- // we can tell the app that it is covered by it.
- mSystemLeft = mTmpNavigationFrame.right;
- }
+ if (mNavigationBar == null) {
+ return false;
+ }
+ boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
+ // Force the navigation bar to its appropriate place and size. We need to do this directly,
+ // instead of relying on it to bubble up from the nav bar, because this needs to change
+ // atomically with screen rotations.
+ final int rotation = displayFrames.mRotation;
+ final int displayHeight = displayFrames.mDisplayHeight;
+ final int displayWidth = displayFrames.mDisplayWidth;
+ final Rect dockFrame = displayFrames.mDock;
+ mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
+
+ 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
+ - getNavigationBarHeight(rotation, uiMode);
+ mTmpNavigationFrame.set(0, top, displayWidth, displayFrames.mUnrestricted.bottom);
+ displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
+ if (transientNavBarShowing) {
+ mNavigationBarController.setBarShowingLw(true);
+ } else if (navVisible) {
+ mNavigationBarController.setBarShowingLw(true);
+ dockFrame.bottom = displayFrames.mRestricted.bottom
+ = displayFrames.mRestrictedOverscan.bottom = top;
+ } else {
+ // We currently want to hide the navigation UI - unless we expanded the status bar.
+ mNavigationBarController.setBarShowingLw(statusBarExpandedNotKeyguard);
+ }
+ if (navVisible && !navTranslucent && !navAllowedHidden
+ && !mNavigationBar.isAnimatingLw()
+ && !mNavigationBarController.wasRecentlyTranslucent()) {
+ // If the opaque nav bar is currently requested to be visible and not in the process
+ // of animating on or off, then we can tell the app that it is covered by it.
+ displayFrames.mSystem.bottom = top;
+ }
+ } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
+ // Landscape screen; nav bar goes to the right.
+ final int left = displayFrames.mUnrestricted.right
+ - getNavigationBarWidth(rotation, uiMode);
+ mTmpNavigationFrame.set(left, 0, displayFrames.mUnrestricted.right, displayHeight);
+ displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
+ if (transientNavBarShowing) {
+ mNavigationBarController.setBarShowingLw(true);
+ } else if (navVisible) {
+ mNavigationBarController.setBarShowingLw(true);
+ dockFrame.right = displayFrames.mRestricted.right
+ = displayFrames.mRestrictedOverscan.right = left;
+ } else {
+ // We currently want to hide the navigation UI - unless we expanded the status bar.
+ mNavigationBarController.setBarShowingLw(statusBarExpandedNotKeyguard);
+ }
+ if (navVisible && !navTranslucent && !navAllowedHidden
+ && !mNavigationBar.isAnimatingLw()
+ && !mNavigationBarController.wasRecentlyTranslucent()) {
+ // If the nav bar is currently requested to be visible, and not in the process of
+ // animating on or off, then we can tell the app that it is covered by it.
+ displayFrames.mSystem.right = left;
+ }
+ } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
+ // Seascape screen; nav bar goes to the left.
+ final int right = displayFrames.mUnrestricted.left
+ + getNavigationBarWidth(rotation, uiMode);
+ mTmpNavigationFrame.set(displayFrames.mUnrestricted.left, 0, right, displayHeight);
+ displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
+ if (transientNavBarShowing) {
+ mNavigationBarController.setBarShowingLw(true);
+ } else if (navVisible) {
+ mNavigationBarController.setBarShowingLw(true);
+ dockFrame.left = displayFrames.mRestricted.left =
+ displayFrames.mRestrictedOverscan.left = right;
+ } else {
+ // We currently want to hide the navigation UI - unless we expanded the status bar.
+ mNavigationBarController.setBarShowingLw(statusBarExpandedNotKeyguard);
}
- // Make sure the content and current rectangles are updated to
- // account for the restrictions from the navigation bar.
- mContentTop = mVoiceContentTop = mCurTop = mDockTop;
- mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom;
- mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft;
- mContentRight = mVoiceContentRight = mCurRight = mDockRight;
- mStatusBarLayer = mNavigationBar.getSurfaceLayer();
- // And compute the final frame.
- mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
- mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf,
- mTmpNavigationFrame, mTmpNavigationFrame);
- if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
- if (mNavigationBarController.checkHiddenLw()) {
- return true;
+ if (navVisible && !navTranslucent && !navAllowedHidden
+ && !mNavigationBar.isAnimatingLw()
+ && !mNavigationBarController.wasRecentlyTranslucent()) {
+ // If the nav bar is currently requested to be visible, and not in the process of
+ // animating on or off, then we can tell the app that it is covered by it.
+ displayFrames.mSystem.left = right;
}
}
- return false;
+
+ // Make sure the content and current rectangles are updated to account for the restrictions
+ // from the navigation bar.
+ displayFrames.mCurrent.set(dockFrame);
+ displayFrames.mVoiceContent.set(dockFrame);
+ displayFrames.mContent.set(dockFrame);
+ mStatusBarLayer = mNavigationBar.getSurfaceLayer();
+ // And compute the final frame.
+ mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
+ mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf,
+ mTmpNavigationFrame, mTmpNavigationFrame);
+ if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
+ return mNavigationBarController.checkHiddenLw();
}
private int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
@@ -4728,32 +4674,26 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return 0;
}
- @Override
- public void getContentRectLw(Rect r) {
- r.set(mContentLeft, mContentTop, mContentRight, mContentBottom);
- }
-
- void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
- boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf) {
+ private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
+ boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf,
+ DisplayFrames displayFrames) {
if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) {
- // Here's a special case: if this attached window is a panel that is
- // above the dock window, and the window it is attached to is below
- // the dock window, then the frames we computed for the window it is
- // attached to can not be used because the dock is effectively part
- // of the underlying window and the attached window is floating on top
- // of the whole thing. So, we ignore the attached window and explicitly
- // compute the frames that would be appropriate without the dock.
- df.left = of.left = cf.left = vf.left = mDockLeft;
- df.top = of.top = cf.top = vf.top = mDockTop;
- df.right = of.right = cf.right = vf.right = mDockRight;
- df.bottom = of.bottom = cf.bottom = vf.bottom = mDockBottom;
+ // Here's a special case: if this attached window is a panel that is above the dock
+ // window, and the window it is attached to is below the dock window, then the frames we
+ // computed for the window it is attached to can not be used because the dock is
+ // effectively part of the underlying window and the attached window is floating on top
+ // of the whole thing. So, we ignore the attached window and explicitly compute the
+ // frames that would be appropriate without the dock.
+ vf.set(displayFrames.mDock);
+ cf.set(displayFrames.mDock);
+ of.set(displayFrames.mDock);
+ df.set(displayFrames.mDock);
} else {
- // The effective display frame of the attached window depends on
- // whether it is taking care of insetting its content. If not,
- // we need to use the parent's content frame so that the entire
- // window is positioned within that content. Otherwise we can use
- // the overscan frame and let the attached window take care of
- // positioning its content appropriately.
+ // The effective display frame of the attached window depends on whether it is taking
+ // care of insetting its content. If not, we need to use the parent's content frame so
+ // that the entire window is positioned within that content. Otherwise we can use the
+ // overscan frame and let the attached window take care of positioning its content
+ // appropriately.
if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
// Set the content frame of the attached window to the parent's decor frame
// (same as content frame when IME isn't present) if specifically requested by
@@ -4762,51 +4702,37 @@ public class PhoneWindowManager implements WindowManagerPolicy {
cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
? attached.getContentFrameLw() : attached.getOverscanFrameLw());
} else {
- // If the window is resizing, then we want to base the content
- // frame on our attached content frame to resize... however,
- // things can be tricky if the attached window is NOT in resize
- // mode, in which case its content frame will be larger.
- // Ungh. So to deal with that, make sure the content frame
- // we end up using is not covering the IM dock.
+ // If the window is resizing, then we want to base the content frame on our attached
+ // content frame to resize...however, things can be tricky if the attached window is
+ // NOT in resize mode, in which case its content frame will be larger.
+ // Ungh. So to deal with that, make sure the content frame we end up using is not
+ // covering the IM dock.
cf.set(attached.getContentFrameLw());
if (attached.isVoiceInteraction()) {
- if (cf.left < mVoiceContentLeft) cf.left = mVoiceContentLeft;
- if (cf.top < mVoiceContentTop) cf.top = mVoiceContentTop;
- if (cf.right > mVoiceContentRight) cf.right = mVoiceContentRight;
- if (cf.bottom > mVoiceContentBottom) cf.bottom = mVoiceContentBottom;
+ cf.intersectUnchecked(displayFrames.mVoiceContent);
} else if (attached.getSurfaceLayer() < mDockLayer) {
- if (cf.left < mContentLeft) cf.left = mContentLeft;
- if (cf.top < mContentTop) cf.top = mContentTop;
- if (cf.right > mContentRight) cf.right = mContentRight;
- if (cf.bottom > mContentBottom) cf.bottom = mContentBottom;
+ cf.intersectUnchecked(displayFrames.mContent);
}
}
df.set(insetDecors ? attached.getDisplayFrameLw() : cf);
of.set(insetDecors ? attached.getOverscanFrameLw() : cf);
vf.set(attached.getVisibleFrameLw());
}
- // The LAYOUT_IN_SCREEN flag is used to determine whether the attached
- // window should be positioned relative to its parent or the entire
- // screen.
- pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0
- ? attached.getFrameLw() : df);
- }
-
- private void applyStableConstraints(int sysui, int fl, Rect r) {
- if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
- // If app is requesting a stable layout, don't let the
- // content insets go below the stable values.
- if ((fl & FLAG_FULLSCREEN) != 0) {
- if (r.left < mStableFullscreenLeft) r.left = mStableFullscreenLeft;
- if (r.top < mStableFullscreenTop) r.top = mStableFullscreenTop;
- if (r.right > mStableFullscreenRight) r.right = mStableFullscreenRight;
- if (r.bottom > mStableFullscreenBottom) r.bottom = mStableFullscreenBottom;
- } else {
- if (r.left < mStableLeft) r.left = mStableLeft;
- if (r.top < mStableTop) r.top = mStableTop;
- if (r.right > mStableRight) r.right = mStableRight;
- if (r.bottom > mStableBottom) r.bottom = mStableBottom;
- }
+ // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
+ // positioned relative to its parent or the entire screen.
+ pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
+ }
+
+ private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
+ if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) {
+ return;
+ }
+ // If app is requesting a stable layout, don't let the content insets go below the stable
+ // values.
+ if ((fl & FLAG_FULLSCREEN) != 0) {
+ r.intersectUnchecked(displayFrames.mStableFullscreen);
+ } else {
+ r.intersectUnchecked(displayFrames.mStable);
}
}
@@ -4821,10 +4747,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
@Override
- public void layoutWindowLw(WindowState win, WindowState attached) {
- // We've already done the navigation bar and status bar. If the status bar can receive
- // input, we need to layout it again to accomodate for the IME window.
- if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar) {
+ public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
+ // We've already done the navigation bar, status bar, and all screen decor windows. If the
+ // status bar can receive input, we need to layout it again to accommodate for the IME
+ // window.
+ if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
+ || mScreenDecorWindows.contains(win)) {
return;
}
final WindowManager.LayoutParams attrs = win.getAttrs();
@@ -4833,9 +4761,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
(win == mLastInputMethodTargetWindow && mLastInputMethodWindow != null);
if (needsToOffsetInputMethodTarget) {
if (DEBUG_LAYOUT) Slog.i(TAG, "Offset ime target window by the last ime window state");
- offsetInputMethodWindowLw(mLastInputMethodWindow);
+ offsetInputMethodWindowLw(mLastInputMethodWindow, displayFrames);
}
+ final int type = attrs.type;
final int fl = PolicyControl.getWindowFlags(win, attrs);
final int pfl = attrs.privateFlags;
final int sim = attrs.softInputMode;
@@ -4856,119 +4785,83 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
- if (isDefaultDisplay) {
- sf.set(mStableLeft, mStableTop, mStableRight, mStableBottom);
- } else {
- sf.set(mOverscanLeft, mOverscanTop, mOverscanRight, mOverscanBottom);
- }
+ sf.set(displayFrames.mStable);
- if (!isDefaultDisplay) {
- if (attached != null) {
- // If this window is attached to another, our display
- // frame is the same as the one we are attached to.
- setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf);
- } else {
- // Give the window full screen.
- pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
- pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
- pf.right = df.right = of.right = cf.right
- = mOverscanScreenLeft + mOverscanScreenWidth;
- pf.bottom = df.bottom = of.bottom = cf.bottom
- = mOverscanScreenTop + mOverscanScreenHeight;
- }
- } else if (attrs.type == TYPE_INPUT_METHOD) {
- pf.left = df.left = of.left = cf.left = vf.left = mDockLeft;
- pf.top = df.top = of.top = cf.top = vf.top = mDockTop;
- pf.right = df.right = of.right = cf.right = vf.right = mDockRight;
+ if (type == TYPE_INPUT_METHOD) {
+ vf.set(displayFrames.mDock);
+ cf.set(displayFrames.mDock);
+ of.set(displayFrames.mDock);
+ df.set(displayFrames.mDock);
+ pf.set(displayFrames.mDock);
// IM dock windows layout below the nav bar...
- pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+ pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom;
// ...with content insets above the nav bar
- cf.bottom = vf.bottom = mStableBottom;
+ cf.bottom = vf.bottom = displayFrames.mStable.bottom;
if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
// The status bar forces the navigation bar while it's visible. Make sure the IME
// avoids the navigation bar in that case.
if (mNavigationBarPosition == NAV_BAR_RIGHT) {
- pf.right = df.right = of.right = cf.right = vf.right = mStableRight;
+ pf.right = df.right = of.right = cf.right = vf.right =
+ displayFrames.mStable.right;
} else if (mNavigationBarPosition == NAV_BAR_LEFT) {
- pf.left = df.left = of.left = cf.left = vf.left = mStableLeft;
+ pf.left = df.left = of.left = cf.left = vf.left = displayFrames.mStable.left;
}
}
// IM dock windows always go to the bottom of the screen.
attrs.gravity = Gravity.BOTTOM;
mDockLayer = win.getSurfaceLayer();
- } else if (attrs.type == TYPE_VOICE_INTERACTION) {
- pf.left = df.left = of.left = mUnrestrictedScreenLeft;
- pf.top = df.top = of.top = mUnrestrictedScreenTop;
- pf.right = df.right = of.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
- pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+ } else if (type == TYPE_VOICE_INTERACTION) {
+ of.set(displayFrames.mUnrestricted);
+ df.set(displayFrames.mUnrestricted);
+ pf.set(displayFrames.mUnrestricted);
if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.left = mDockLeft;
- cf.top = mDockTop;
- cf.right = mDockRight;
- cf.bottom = mDockBottom;
+ cf.set(displayFrames.mDock);
} else {
- cf.left = mContentLeft;
- cf.top = mContentTop;
- cf.right = mContentRight;
- cf.bottom = mContentBottom;
+ cf.set(displayFrames.mContent);
}
if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.left = mCurLeft;
- vf.top = mCurTop;
- vf.right = mCurRight;
- vf.bottom = mCurBottom;
+ vf.set(displayFrames.mCurrent);
} else {
vf.set(cf);
}
- } else if (attrs.type == TYPE_WALLPAPER) {
- layoutWallpaper(win, pf, df, of, cf);
+ } else if (type == TYPE_WALLPAPER) {
+ layoutWallpaper(displayFrames, pf, df, of, cf);
} else if (win == mStatusBar) {
- pf.left = df.left = of.left = mUnrestrictedScreenLeft;
- pf.top = df.top = of.top = mUnrestrictedScreenTop;
- pf.right = df.right = of.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft;
- pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenHeight + mUnrestrictedScreenTop;
- cf.left = vf.left = mStableLeft;
- cf.top = vf.top = mStableTop;
- cf.right = vf.right = mStableRight;
- vf.bottom = mStableBottom;
+ of.set(displayFrames.mUnrestricted);
+ df.set(displayFrames.mUnrestricted);
+ pf.set(displayFrames.mUnrestricted);
+ cf.set(displayFrames.mStable);
+ vf.set(displayFrames.mStable);
if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
- cf.bottom = mContentBottom;
+ cf.bottom = displayFrames.mContent.bottom;
} else {
- cf.bottom = mDockBottom;
- vf.bottom = mContentBottom;
+ cf.bottom = displayFrames.mDock.bottom;
+ vf.bottom = displayFrames.mContent.bottom;
}
} else {
-
- // Default policy decor for the default display
- dcf.left = mSystemLeft;
- dcf.top = mSystemTop;
- dcf.right = mSystemRight;
- dcf.bottom = mSystemBottom;
- final boolean inheritTranslucentDecor = (attrs.privateFlags
- & WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) != 0;
+ dcf.set(displayFrames.mSystem);
+ final boolean inheritTranslucentDecor =
+ (attrs.privateFlags & PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) != 0;
final boolean isAppWindow =
- attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW &&
- attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+ type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
final boolean topAtRest =
win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
if (isAppWindow && !inheritTranslucentDecor && !topAtRest) {
if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
- && (fl & WindowManager.LayoutParams.FLAG_FULLSCREEN) == 0
- && (fl & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) == 0
- && (fl & WindowManager.LayoutParams.
- FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
+ && (fl & FLAG_FULLSCREEN) == 0
+ && (fl & FLAG_TRANSLUCENT_STATUS) == 0
+ && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
&& (pfl & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) == 0) {
// Ensure policy decor includes status bar
- dcf.top = mStableTop;
+ dcf.top = displayFrames.mStable.top;
}
- if ((fl & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) == 0
+ if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0
&& (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
- && (fl & WindowManager.LayoutParams.
- FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
+ && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
// Ensure policy decor includes navigation bar
- dcf.bottom = mStableBottom;
- dcf.right = mStableRight;
+ dcf.bottom = displayFrames.mStable.bottom;
+ dcf.right = displayFrames.mStable.right;
}
}
@@ -4976,117 +4869,83 @@ public class PhoneWindowManager implements WindowManagerPolicy {
== (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
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 screen space, and it can take care of
- // moving its contents to account for screen decorations that
- // intrude into that space.
+ // This is the case for a normal activity window: we want it to cover all of the
+ // screen space, and it can take care of moving its contents to account for screen
+ // decorations that intrude into that space.
if (attached != null) {
// If this window is attached to another, our display
// frame is the same as the one we are attached to.
- setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf);
+ setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf,
+ displayFrames);
} else {
- if (attrs.type == TYPE_STATUS_BAR_PANEL
- || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
- // Status bar panels are the only windows who can go on top of
- // the status bar. They are protected by the STATUS_BAR_SERVICE
- // permission, so they have the same privileges as the status
- // bar itself.
+ if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
+ // Status bar panels are the only windows who can go on top of the status
+ // bar. They are protected by the STATUS_BAR_SERVICE permission, so they
+ // have the same privileges as the status bar itself.
//
// However, they should still dodge the navigation bar if it exists.
pf.left = df.left = of.left = hasNavBar
- ? mDockLeft : mUnrestrictedScreenLeft;
- pf.top = df.top = of.top = mUnrestrictedScreenTop;
+ ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
+ pf.top = df.top = of.top = displayFrames.mUnrestricted.top;
pf.right = df.right = of.right = hasNavBar
- ? mRestrictedScreenLeft+mRestrictedScreenWidth
- : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+ ? displayFrames.mRestricted.right
+ : displayFrames.mUnrestricted.right;
pf.bottom = df.bottom = of.bottom = hasNavBar
- ? mRestrictedScreenTop+mRestrictedScreenHeight
- : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+ ? displayFrames.mRestricted.bottom
+ : displayFrames.mUnrestricted.bottom;
if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
"Laying out status bar window: (%d,%d - %d,%d)",
pf.left, pf.top, pf.right, pf.bottom));
} else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
- && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
- && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+ && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
// Asking to layout into the overscan region, so give it that pure
// unrestricted area.
- pf.left = df.left = of.left = mOverscanScreenLeft;
- pf.top = df.top = of.top = mOverscanScreenTop;
- pf.right = df.right = of.right = mOverscanScreenLeft + mOverscanScreenWidth;
- pf.bottom = df.bottom = of.bottom = mOverscanScreenTop
- + mOverscanScreenHeight;
+ of.set(displayFrames.mOverscan);
+ df.set(displayFrames.mOverscan);
+ pf.set(displayFrames.mOverscan);
} else if (canHideNavigationBar()
&& (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
- && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
- && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
- // Asking for layout as if the nav bar is hidden, lets the
- // application extend into the unrestricted overscan screen area. We
- // only do this for application windows to ensure no window that
- // can be above the nav bar can do this.
- pf.left = df.left = mOverscanScreenLeft;
- pf.top = df.top = mOverscanScreenTop;
- pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
- pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
- // We need to tell the app about where the frame inside the overscan
- // is, so it can inset its content by that amount -- it didn't ask
- // to actually extend itself into the overscan region.
- of.left = mUnrestrictedScreenLeft;
- of.top = mUnrestrictedScreenTop;
- of.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
- of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+ && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
+ // Asking for layout as if the nav bar is hidden, lets the application
+ // extend into the unrestricted overscan screen area. We only do this for
+ // application windows to ensure no window that can be above the nav bar can
+ // do this.
+ df.set(displayFrames.mOverscan);
+ pf.set(displayFrames.mOverscan);
+ // We need to tell the app about where the frame inside the overscan is, so
+ // it can inset its content by that amount -- it didn't ask to actually
+ // extend itself into the overscan region.
+ of.set(displayFrames.mUnrestricted);
} else {
- pf.left = df.left = mRestrictedOverscanScreenLeft;
- pf.top = df.top = mRestrictedOverscanScreenTop;
- pf.right = df.right = mRestrictedOverscanScreenLeft
- + mRestrictedOverscanScreenWidth;
- pf.bottom = df.bottom = mRestrictedOverscanScreenTop
- + mRestrictedOverscanScreenHeight;
+ df.set(displayFrames.mRestrictedOverscan);
+ pf.set(displayFrames.mRestrictedOverscan);
// We need to tell the app about where the frame inside the overscan
// is, so it can inset its content by that amount -- it didn't ask
// to actually extend itself into the overscan region.
- of.left = mUnrestrictedScreenLeft;
- of.top = mUnrestrictedScreenTop;
- of.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
- of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+ of.set(displayFrames.mUnrestricted);
}
if ((fl & FLAG_FULLSCREEN) == 0) {
if (win.isVoiceInteraction()) {
- cf.left = mVoiceContentLeft;
- cf.top = mVoiceContentTop;
- cf.right = mVoiceContentRight;
- cf.bottom = mVoiceContentBottom;
+ cf.set(displayFrames.mVoiceContent);
} else {
if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.left = mDockLeft;
- cf.top = mDockTop;
- cf.right = mDockRight;
- cf.bottom = mDockBottom;
+ cf.set(displayFrames.mDock);
} else {
- cf.left = mContentLeft;
- cf.top = mContentTop;
- cf.right = mContentRight;
- cf.bottom = mContentBottom;
+ cf.set(displayFrames.mContent);
}
}
} else {
- // Full screen windows are always given a layout that is as if the
- // status bar and other transient decors are gone. This is to avoid
- // bad states when moving from a window that is not hding the
- // status bar to one that is.
- cf.left = mRestrictedScreenLeft;
- cf.top = mRestrictedScreenTop;
- cf.right = mRestrictedScreenLeft + mRestrictedScreenWidth;
- cf.bottom = mRestrictedScreenTop + mRestrictedScreenHeight;
+ // Full screen windows are always given a layout that is as if the status
+ // bar and other transient decors are gone. This is to avoid bad states when
+ // moving from a window that is not hiding the status bar to one that is.
+ cf.set(displayFrames.mRestricted);
}
- applyStableConstraints(sysUiFl, fl, cf);
+ applyStableConstraints(sysUiFl, fl, cf, displayFrames);
if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.left = mCurLeft;
- vf.top = mCurTop;
- vf.right = mCurRight;
- vf.bottom = mCurBottom;
+ vf.set(displayFrames.mCurrent);
} else {
vf.set(cf);
}
@@ -5094,86 +4953,70 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0 || (sysUiFl
& (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() +
- "): IN_SCREEN");
+ if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
+ + "): IN_SCREEN");
// A window that has requested to fill the entire screen just
// gets everything, period.
- if (attrs.type == TYPE_STATUS_BAR_PANEL
- || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
- pf.left = df.left = of.left = cf.left = hasNavBar
- ? mDockLeft : mUnrestrictedScreenLeft;
- pf.top = df.top = of.top = cf.top = mUnrestrictedScreenTop;
- pf.right = df.right = of.right = cf.right = hasNavBar
- ? mRestrictedScreenLeft + mRestrictedScreenWidth
- : mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
- pf.bottom = df.bottom = of.bottom = cf.bottom = hasNavBar
- ? mRestrictedScreenTop + mRestrictedScreenHeight
- : mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+ if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
+ cf.set(displayFrames.mUnrestricted);
+ of.set(displayFrames.mUnrestricted);
+ df.set(displayFrames.mUnrestricted);
+ pf.set(displayFrames.mUnrestricted);
+ if (hasNavBar) {
+ pf.left = df.left = of.left = cf.left = displayFrames.mDock.left;
+ pf.right = df.right = of.right = cf.right = displayFrames.mRestricted.right;
+ pf.bottom = df.bottom = of.bottom = cf.bottom =
+ displayFrames.mRestricted.bottom;
+ }
if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
"Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
pf.left, pf.top, pf.right, pf.bottom));
- } else if (attrs.type == TYPE_VOLUME_OVERLAY) {
+ } else if (type == TYPE_VOLUME_OVERLAY) {
// Volume overlay covers everything, including the status and navbar
- pf.left = df.left = of.left = cf.left = mUnrestrictedScreenLeft;
- pf.top = df.top = of.top = cf.top = mUnrestrictedScreenTop;
- pf.right = df.right = of.right = cf.right =
- mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
- pf.bottom = df.bottom = of.bottom = cf.bottom =
- mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+ cf.set(displayFrames.mUnrestricted);
+ of.set(displayFrames.mUnrestricted);
+ df.set(displayFrames.mUnrestricted);
+ pf.set(displayFrames.mUnrestricted);
if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
"Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
pf.left, pf.top, pf.right, pf.bottom));
- } else if (attrs.type == TYPE_NAVIGATION_BAR
- || attrs.type == TYPE_NAVIGATION_BAR_PANEL) {
+ } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
// The navigation bar has Real Ultimate Power.
- pf.left = df.left = of.left = mUnrestrictedScreenLeft;
- pf.top = df.top = of.top = mUnrestrictedScreenTop;
- pf.right = df.right = of.right = mUnrestrictedScreenLeft
- + mUnrestrictedScreenWidth;
- pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenTop
- + mUnrestrictedScreenHeight;
+ of.set(displayFrames.mUnrestricted);
+ df.set(displayFrames.mUnrestricted);
+ pf.set(displayFrames.mUnrestricted);
if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
"Laying out navigation bar window: (%d,%d - %d,%d)",
pf.left, pf.top, pf.right, pf.bottom));
- } else if ((attrs.type == TYPE_SECURE_SYSTEM_OVERLAY
- || attrs.type == TYPE_BOOT_PROGRESS
- || attrs.type == TYPE_SCREENSHOT)
+ } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
&& ((fl & FLAG_FULLSCREEN) != 0)) {
// Fullscreen secure system overlays get what they ask for. Screenshot region
// selection overlay should also expand to full screen.
- pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
- pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
- pf.right = df.right = of.right = cf.right = mOverscanScreenLeft
- + mOverscanScreenWidth;
- pf.bottom = df.bottom = of.bottom = cf.bottom = mOverscanScreenTop
- + mOverscanScreenHeight;
- } else if (attrs.type == TYPE_BOOT_PROGRESS) {
+ cf.set(displayFrames.mOverscan);
+ of.set(displayFrames.mOverscan);
+ df.set(displayFrames.mOverscan);
+ pf.set(displayFrames.mOverscan);
+ } else if (type == TYPE_BOOT_PROGRESS) {
// Boot progress screen always covers entire display.
- pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
- pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
- pf.right = df.right = of.right = cf.right = mOverscanScreenLeft
- + mOverscanScreenWidth;
- pf.bottom = df.bottom = of.bottom = cf.bottom = mOverscanScreenTop
- + mOverscanScreenHeight;
+ cf.set(displayFrames.mOverscan);
+ of.set(displayFrames.mOverscan);
+ df.set(displayFrames.mOverscan);
+ pf.set(displayFrames.mOverscan);
} else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
- && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
- && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
- // Asking to layout into the overscan region, so give it that pure
- // unrestricted area.
- pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
- pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
- pf.right = df.right = of.right = cf.right
- = mOverscanScreenLeft + mOverscanScreenWidth;
- pf.bottom = df.bottom = of.bottom = cf.bottom
- = mOverscanScreenTop + mOverscanScreenHeight;
+ && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
+ // Asking to layout into the overscan region, so give it that pure unrestricted
+ // area.
+ cf.set(displayFrames.mOverscan);
+ of.set(displayFrames.mOverscan);
+ df.set(displayFrames.mOverscan);
+ pf.set(displayFrames.mOverscan);
} else if (canHideNavigationBar()
&& (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
- && (attrs.type == TYPE_STATUS_BAR
- || attrs.type == TYPE_TOAST
- || attrs.type == TYPE_DOCK_DIVIDER
- || attrs.type == TYPE_VOICE_INTERACTION_STARTING
- || (attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
- && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW))) {
+ && (type == TYPE_STATUS_BAR
+ || type == TYPE_TOAST
+ || type == TYPE_DOCK_DIVIDER
+ || type == TYPE_VOICE_INTERACTION_STARTING
+ || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) {
// Asking for layout as if the nav bar is hidden, lets the
// application extend into the unrestricted screen area. We
// only do this for application windows (or toasts) to ensure no window that
@@ -5181,102 +5024,76 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// XXX This assumes that an app asking for this will also
// ask for layout in only content. We can't currently figure out
// what the screen would be if only laying out to hide the nav bar.
- pf.left = df.left = of.left = cf.left = mUnrestrictedScreenLeft;
- pf.top = df.top = of.top = cf.top = mUnrestrictedScreenTop;
- pf.right = df.right = of.right = cf.right = mUnrestrictedScreenLeft
- + mUnrestrictedScreenWidth;
- pf.bottom = df.bottom = of.bottom = cf.bottom = mUnrestrictedScreenTop
- + mUnrestrictedScreenHeight;
+ cf.set(displayFrames.mUnrestricted);
+ of.set(displayFrames.mUnrestricted);
+ df.set(displayFrames.mUnrestricted);
+ pf.set(displayFrames.mUnrestricted);
} else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
- pf.left = df.left = of.left = mRestrictedScreenLeft;
- pf.top = df.top = of.top = mRestrictedScreenTop;
- pf.right = df.right = of.right = mRestrictedScreenLeft + mRestrictedScreenWidth;
- pf.bottom = df.bottom = of.bottom = mRestrictedScreenTop
- + mRestrictedScreenHeight;
+ of.set(displayFrames.mRestricted);
+ df.set(displayFrames.mRestricted);
+ pf.set(displayFrames.mRestricted);
if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.left = mDockLeft;
- cf.top = mDockTop;
- cf.right = mDockRight;
- cf.bottom = mDockBottom;
+ cf.set(displayFrames.mDock);
} else {
- cf.left = mContentLeft;
- cf.top = mContentTop;
- cf.right = mContentRight;
- cf.bottom = mContentBottom;
+ cf.set(displayFrames.mContent);
}
} else {
- pf.left = df.left = of.left = cf.left = mRestrictedScreenLeft;
- pf.top = df.top = of.top = cf.top = mRestrictedScreenTop;
- pf.right = df.right = of.right = cf.right = mRestrictedScreenLeft
- + mRestrictedScreenWidth;
- pf.bottom = df.bottom = of.bottom = cf.bottom = mRestrictedScreenTop
- + mRestrictedScreenHeight;
+ cf.set(displayFrames.mRestricted);
+ of.set(displayFrames.mRestricted);
+ df.set(displayFrames.mRestricted);
+ pf.set(displayFrames.mRestricted);
}
- applyStableConstraints(sysUiFl, fl, cf);
+ applyStableConstraints(sysUiFl, fl, cf,displayFrames);
if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.left = mCurLeft;
- vf.top = mCurTop;
- vf.right = mCurRight;
- vf.bottom = mCurBottom;
+ vf.set(displayFrames.mCurrent);
} else {
vf.set(cf);
}
} else if (attached != null) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() +
- "): attached to " + attached);
+ if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
+ + "): attached to " + attached);
// A child window should be placed inside of the same visible
// frame that its parent had.
- setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf);
+ setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf,
+ displayFrames);
} else {
if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() +
"): normal window");
// Otherwise, a normal window must be placed inside the content
// of all screen decorations.
- if (attrs.type == TYPE_STATUS_BAR_PANEL || attrs.type == TYPE_VOLUME_OVERLAY) {
+ if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_VOLUME_OVERLAY) {
// Status bar panels and the volume dialog are the only windows who can go on
- // top of the status bar. They are protected by the STATUS_BAR_SERVICE
- // permission, so they have the same privileges as the status
- // bar itself.
- pf.left = df.left = of.left = cf.left = mRestrictedScreenLeft;
- pf.top = df.top = of.top = cf.top = mRestrictedScreenTop;
- pf.right = df.right = of.right = cf.right = mRestrictedScreenLeft
- + mRestrictedScreenWidth;
- pf.bottom = df.bottom = of.bottom = cf.bottom = mRestrictedScreenTop
- + mRestrictedScreenHeight;
- } else if (attrs.type == TYPE_TOAST || attrs.type == TYPE_SYSTEM_ALERT) {
+ // top of the status bar. They are protected by the STATUS_BAR_SERVICE
+ // permission, so they have the same privileges as the status bar itself.
+ cf.set(displayFrames.mRestricted);
+ of.set(displayFrames.mRestricted);
+ df.set(displayFrames.mRestricted);
+ pf.set(displayFrames.mRestricted);
+ } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
// These dialogs are stable to interim decor changes.
- pf.left = df.left = of.left = cf.left = mStableLeft;
- pf.top = df.top = of.top = cf.top = mStableTop;
- pf.right = df.right = of.right = cf.right = mStableRight;
- pf.bottom = df.bottom = of.bottom = cf.bottom = mStableBottom;
+ cf.set(displayFrames.mStable);
+ of.set(displayFrames.mStable);
+ df.set(displayFrames.mStable);
+ pf.set(displayFrames.mStable);
} else {
- pf.left = mContentLeft;
- pf.top = mContentTop;
- pf.right = mContentRight;
- pf.bottom = mContentBottom;
+ pf.set(displayFrames.mContent);
if (win.isVoiceInteraction()) {
- df.left = of.left = cf.left = mVoiceContentLeft;
- df.top = of.top = cf.top = mVoiceContentTop;
- df.right = of.right = cf.right = mVoiceContentRight;
- df.bottom = of.bottom = cf.bottom = mVoiceContentBottom;
+ cf.set(displayFrames.mVoiceContent);
+ of.set(displayFrames.mVoiceContent);
+ df.set(displayFrames.mVoiceContent);
} else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- df.left = of.left = cf.left = mDockLeft;
- df.top = of.top = cf.top = mDockTop;
- df.right = of.right = cf.right = mDockRight;
- df.bottom = of.bottom = cf.bottom = mDockBottom;
+ cf.set(displayFrames.mDock);
+ of.set(displayFrames.mDock);
+ df.set(displayFrames.mDock);
} else {
- df.left = of.left = cf.left = mContentLeft;
- df.top = of.top = cf.top = mContentTop;
- df.right = of.right = cf.right = mContentRight;
- df.bottom = of.bottom = cf.bottom = mContentBottom;
+ cf.set(displayFrames.mContent);
+ of.set(displayFrames.mContent);
+ df.set(displayFrames.mContent);
}
if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.left = mCurLeft;
- vf.top = mCurTop;
- vf.right = mCurRight;
- vf.bottom = mCurBottom;
+ vf.set(displayFrames.mCurrent);
} else {
vf.set(cf);
}
@@ -5286,11 +5103,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// 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 && attrs.type != TYPE_SYSTEM_ERROR
+ if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
&& !win.isInMultiWindowMode()) {
df.left = df.top = -10000;
df.right = df.bottom = 10000;
- if (attrs.type != TYPE_WALLPAPER) {
+ if (type != TYPE_WALLPAPER) {
of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
}
@@ -5306,7 +5123,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
osf.set(cf.left, cf.top, cf.right, cf.bottom);
int outset = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
if (outset > 0) {
- int rotation = mDisplayRotation;
+ int rotation = displayFrames.mRotation;
if (rotation == Surface.ROTATION_0) {
osf.bottom += outset;
} else if (rotation == Surface.ROTATION_90) {
@@ -5323,7 +5140,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
+ ": sim=#" + Integer.toHexString(sim)
- + " attach=" + attached + " type=" + attrs.type
+ + " attach=" + attached + " type=" + type
+ String.format(" flags=0x%08x", fl)
+ " pf=" + pf.toShortString() + " df=" + df.toShortString()
+ " of=" + of.toShortString()
@@ -5336,62 +5153,42 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Dock windows carve out the bottom of the screen, so normal windows
// can't appear underneath them.
- if (attrs.type == TYPE_INPUT_METHOD && win.isVisibleLw()
+ if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
&& !win.getGivenInsetsPendingLw()) {
setLastInputMethodWindowLw(null, null);
- offsetInputMethodWindowLw(win);
+ offsetInputMethodWindowLw(win, displayFrames);
}
- if (attrs.type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
+ if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
&& !win.getGivenInsetsPendingLw()) {
- offsetVoiceInputWindowLw(win);
+ offsetVoiceInputWindowLw(win, displayFrames);
}
}
- private void layoutWallpaper(WindowState win, Rect pf, Rect df, Rect of, Rect cf) {
-
- // The wallpaper also has Real Ultimate Power, but we want to tell
- // it about the overscan area.
- pf.left = df.left = mOverscanScreenLeft;
- pf.top = df.top = mOverscanScreenTop;
- pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
- pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
- of.left = cf.left = mUnrestrictedScreenLeft;
- of.top = cf.top = mUnrestrictedScreenTop;
- of.right = cf.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
- of.bottom = cf.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+ private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect cf) {
+ // The wallpaper has Real Ultimate Power, but we want to tell it about the overscan area.
+ df.set(displayFrames.mOverscan);
+ pf.set(displayFrames.mOverscan);
+ cf.set(displayFrames.mUnrestricted);
+ of.set(displayFrames.mUnrestricted);
}
- private void offsetInputMethodWindowLw(WindowState win) {
+ private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
top += win.getGivenContentInsetsLw().top;
- if (mContentBottom > top) {
- mContentBottom = top;
- }
- if (mVoiceContentBottom > top) {
- mVoiceContentBottom = top;
- }
+ displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
+ displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
top = win.getVisibleFrameLw().top;
top += win.getGivenVisibleInsetsLw().top;
- if (mCurBottom > top) {
- mCurBottom = top;
- }
+ displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top);
if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
- + mDockBottom + " mContentBottom="
- + mContentBottom + " mCurBottom=" + mCurBottom);
+ + displayFrames.mDock.bottom + " mContentBottom="
+ + displayFrames.mContent.bottom + " mCurBottom=" + displayFrames.mCurrent.bottom);
}
- private void offsetVoiceInputWindowLw(WindowState win) {
+ private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) {
int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
top += win.getGivenContentInsetsLw().top;
- if (mVoiceContentBottom > top) {
- mVoiceContentBottom = top;
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public void finishLayoutLw() {
- return;
+ displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
}
/** {@inheritDoc} */
@@ -5798,6 +5595,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
void initializeHdmiState() {
+ final int oldMask = StrictMode.allowThreadDiskReadsMask();
+ try {
+ initializeHdmiStateInternal();
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
+ }
+ }
+
+ void initializeHdmiStateInternal() {
boolean plugged = false;
// watch for HDMI plug messages if the hdmi switch exists
if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) {
@@ -8235,11 +8041,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
- public int getInputMethodWindowVisibleHeightLw() {
- return mDockBottom - mCurBottom;
- }
-
- @Override
public void setCurrentUserLw(int newUserId) {
mCurrentUserId = newUserId;
if (mKeyguardDelegate != null) {
@@ -8328,8 +8129,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
- new Rect(mStableLeft, mStableTop, mStableRight, mStableBottom).writeToProto(proto,
- STABLE_BOUNDS);
proto.end(token);
}
@@ -8435,58 +8234,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
- pw.print(prefix); pw.print("mOverscanScreen=("); pw.print(mOverscanScreenLeft);
- pw.print(","); pw.print(mOverscanScreenTop);
- pw.print(") "); pw.print(mOverscanScreenWidth);
- pw.print("x"); pw.println(mOverscanScreenHeight);
- if (mOverscanLeft != 0 || mOverscanTop != 0
- || mOverscanRight != 0 || mOverscanBottom != 0) {
- pw.print(prefix); pw.print("mOverscan left="); pw.print(mOverscanLeft);
- pw.print(" top="); pw.print(mOverscanTop);
- pw.print(" right="); pw.print(mOverscanRight);
- pw.print(" bottom="); pw.println(mOverscanBottom);
- }
- pw.print(prefix); pw.print("mRestrictedOverscanScreen=(");
- pw.print(mRestrictedOverscanScreenLeft);
- pw.print(","); pw.print(mRestrictedOverscanScreenTop);
- pw.print(") "); pw.print(mRestrictedOverscanScreenWidth);
- pw.print("x"); pw.println(mRestrictedOverscanScreenHeight);
- pw.print(prefix); pw.print("mUnrestrictedScreen=("); pw.print(mUnrestrictedScreenLeft);
- pw.print(","); pw.print(mUnrestrictedScreenTop);
- pw.print(") "); pw.print(mUnrestrictedScreenWidth);
- pw.print("x"); pw.println(mUnrestrictedScreenHeight);
- pw.print(prefix); pw.print("mRestrictedScreen=("); pw.print(mRestrictedScreenLeft);
- pw.print(","); pw.print(mRestrictedScreenTop);
- pw.print(") "); pw.print(mRestrictedScreenWidth);
- pw.print("x"); pw.println(mRestrictedScreenHeight);
- pw.print(prefix); pw.print("mStableFullscreen=("); pw.print(mStableFullscreenLeft);
- pw.print(","); pw.print(mStableFullscreenTop);
- pw.print(")-("); pw.print(mStableFullscreenRight);
- pw.print(","); pw.print(mStableFullscreenBottom); pw.println(")");
- pw.print(prefix); pw.print("mStable=("); pw.print(mStableLeft);
- pw.print(","); pw.print(mStableTop);
- pw.print(")-("); pw.print(mStableRight);
- pw.print(","); pw.print(mStableBottom); pw.println(")");
- pw.print(prefix); pw.print("mSystem=("); pw.print(mSystemLeft);
- pw.print(","); pw.print(mSystemTop);
- pw.print(")-("); pw.print(mSystemRight);
- pw.print(","); pw.print(mSystemBottom); pw.println(")");
- pw.print(prefix); pw.print("mCur=("); pw.print(mCurLeft);
- pw.print(","); pw.print(mCurTop);
- pw.print(")-("); pw.print(mCurRight);
- pw.print(","); pw.print(mCurBottom); pw.println(")");
- pw.print(prefix); pw.print("mContent=("); pw.print(mContentLeft);
- pw.print(","); pw.print(mContentTop);
- pw.print(")-("); pw.print(mContentRight);
- pw.print(","); pw.print(mContentBottom); pw.println(")");
- pw.print(prefix); pw.print("mVoiceContent=("); pw.print(mVoiceContentLeft);
- pw.print(","); pw.print(mVoiceContentTop);
- pw.print(")-("); pw.print(mVoiceContentRight);
- pw.print(","); pw.print(mVoiceContentBottom); pw.println(")");
- pw.print(prefix); pw.print("mDock=("); pw.print(mDockLeft);
- pw.print(","); pw.print(mDockTop);
- pw.print(")-("); pw.print(mDockRight);
- pw.print(","); pw.print(mDockBottom); pw.println(")");
pw.print(prefix); pw.print("mDockLayer="); pw.print(mDockLayer);
pw.print(" mStatusBarLayer="); pw.println(mStatusBarLayer);
pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 1781d8c657c3..2fceae4ff458 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -15,50 +15,33 @@
*/
package com.android.server.power;
-import android.annotation.IntDef;
import android.content.ContentResolver;
+import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
+import android.os.PowerManager.ServiceType;
+import android.os.PowerSaveState;
import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.KeyValueListParser;
import android.util.Slog;
-import android.os.PowerSaveState;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
/**
* Class to decide whether to turn on battery saver mode for specific service
+ *
+ * Test: atest BatterySaverPolicyTest
*/
public class BatterySaverPolicy extends ContentObserver {
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({ServiceType.GPS,
- ServiceType.VIBRATION,
- ServiceType.ANIMATION,
- ServiceType.FULL_BACKUP,
- ServiceType.KEYVALUE_BACKUP,
- ServiceType.NETWORK_FIREWALL,
- ServiceType.SCREEN_BRIGHTNESS,
- ServiceType.SOUND,
- ServiceType.BATTERY_STATS,
- ServiceType.DATA_SAVER})
- public @interface ServiceType {
- int NULL = 0;
- int GPS = 1;
- int VIBRATION = 2;
- int ANIMATION = 3;
- int FULL_BACKUP = 4;
- int KEYVALUE_BACKUP = 5;
- int NETWORK_FIREWALL = 6;
- int SCREEN_BRIGHTNESS = 7;
- int SOUND = 8;
- int BATTERY_STATS = 9;
- int DATA_SAVER = 10;
- }
-
private static final String TAG = "BatterySaverPolicy";
// Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode.
@@ -79,8 +62,15 @@ public class BatterySaverPolicy extends ContentObserver {
private static final String KEY_ADJUST_BRIGHTNESS_FACTOR = "adjust_brightness_factor";
private static final String KEY_FULLBACKUP_DEFERRED = "fullbackup_deferred";
private static final String KEY_KEYVALUE_DEFERRED = "keyvaluebackup_deferred";
+ private static final String KEY_FORCE_ALL_APPS_STANDBY = "force_all_apps_standby";
+ private static final String KEY_OPTIONAL_SENSORS_DISABLED = "optional_sensors_disabled";
+
+ private static final String KEY_SCREEN_ON_FILE_PREFIX = "file-on:";
+ private static final String KEY_SCREEN_OFF_FILE_PREFIX = "file-off:";
- private final KeyValueListParser mParser = new KeyValueListParser(',');
+ private static String mSettings;
+ private static String mDeviceSpecificSettings;
+ private static String mDeviceSpecificSettingsSource; // For dump() only.
/**
* {@code true} if vibration is disabled in battery saver mode.
@@ -164,51 +154,182 @@ public class BatterySaverPolicy extends ContentObserver {
*/
private float mAdjustBrightnessFactor;
+ /**
+ * Whether to put all apps in the stand-by mode.
+ */
+ private boolean mForceAllAppsStandby;
+
+ /**
+ * Weather to show non-essential sensors (e.g. edge sensors) or not.
+ */
+ private boolean mOptionalSensorsDisabled;
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private Context mContext;
+
+ @GuardedBy("mLock")
private ContentResolver mContentResolver;
+ @GuardedBy("mLock")
+ private final ArrayList<BatterySaverPolicyListener> mListeners = new ArrayList<>();
+
+ /**
+ * List of [Filename -> content] that should be written when battery saver is activated
+ * and the screen is on.
+ *
+ * We use this to change the max CPU frequencies.
+ */
+ @GuardedBy("mLock")
+ private ArrayMap<String, String> mScreenOnFiles;
+
+ /**
+ * List of [Filename -> content] that should be written when battery saver is activated
+ * and the screen is off.
+ *
+ * We use this to change the max CPU frequencies.
+ */
+ @GuardedBy("mLock")
+ private ArrayMap<String, String> mScreenOffFiles;
+
+ public interface BatterySaverPolicyListener {
+ void onBatterySaverPolicyChanged(BatterySaverPolicy policy);
+ }
+
public BatterySaverPolicy(Handler handler) {
super(handler);
}
- public void start(ContentResolver contentResolver) {
- mContentResolver = contentResolver;
+ public void systemReady(Context context) {
+ synchronized (mLock) {
+ mContext = context;
+ mContentResolver = context.getContentResolver();
+
+ mContentResolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.BATTERY_SAVER_CONSTANTS), false, this);
+ mContentResolver.registerContentObserver(Settings.Global.getUriFor(
+ Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS), false, this);
+ }
+ onChange(true, null);
+ }
+
+ public void addListener(BatterySaverPolicyListener listener) {
+ synchronized (mLock) {
+ mListeners.add(listener);
+ }
+ }
+
+ @VisibleForTesting
+ String getGlobalSetting(String key) {
+ return Settings.Global.getString(mContentResolver, key);
+ }
+
+ @VisibleForTesting
+ int getDeviceSpecificConfigResId() {
+ return R.string.config_batterySaverDeviceSpecificConfig;
+ }
- mContentResolver.registerContentObserver(Settings.Global.getUriFor(
- Settings.Global.BATTERY_SAVER_CONSTANTS), false, this);
+ @VisibleForTesting
+ void onChangeForTest() {
onChange(true, null);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
- final String value = Settings.Global.getString(mContentResolver,
- Settings.Global.BATTERY_SAVER_CONSTANTS);
- updateConstants(value);
+ final BatterySaverPolicyListener[] listeners;
+ synchronized (mLock) {
+ // Load the non-device-specific setting.
+ final String setting = getGlobalSetting(Settings.Global.BATTERY_SAVER_CONSTANTS);
+
+ // Load the device specific setting.
+ // We first check the global setting, and if it's empty or the string "null" is set,
+ // use the default value from config.xml.
+ String deviceSpecificSetting = getGlobalSetting(
+ Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS);
+ mDeviceSpecificSettingsSource =
+ Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS;
+
+ if (TextUtils.isEmpty(deviceSpecificSetting) || "null".equals(deviceSpecificSetting)) {
+ deviceSpecificSetting =
+ mContext.getString(getDeviceSpecificConfigResId());
+ mDeviceSpecificSettingsSource = "(overlay)";
+ }
+
+ // Update.
+ updateConstantsLocked(setting, deviceSpecificSetting);
+
+ listeners = mListeners.toArray(new BatterySaverPolicyListener[mListeners.size()]);
+ }
+
+ // Notify the listeners.
+ for (BatterySaverPolicyListener listener : listeners) {
+ listener.onBatterySaverPolicyChanged(this);
+ }
}
@VisibleForTesting
- void updateConstants(final String value) {
- synchronized (BatterySaverPolicy.this) {
- try {
- mParser.setString(value);
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Bad battery saver constants");
+ void updateConstantsLocked(final String setting, final String deviceSpecificSetting) {
+ mSettings = setting;
+ mDeviceSpecificSettings = deviceSpecificSetting;
+
+ final KeyValueListParser parser = new KeyValueListParser(',');
+
+ // Non-device-specific parameters.
+ try {
+ parser.setString(setting);
+ } catch (IllegalArgumentException e) {
+ Slog.wtf(TAG, "Bad battery saver constants: " + setting);
+ }
+
+ mVibrationDisabled = parser.getBoolean(KEY_VIBRATION_DISABLED, true);
+ mAnimationDisabled = parser.getBoolean(KEY_ANIMATION_DISABLED, true);
+ 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);
+ mAdjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR, 0.5f);
+ mDataSaverDisabled = parser.getBoolean(KEY_DATASAVER_DISABLED, true);
+ mForceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY, true);
+ mOptionalSensorsDisabled = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED, true);
+
+ // Get default value from Settings.Secure
+ final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE,
+ GPS_MODE_NO_CHANGE);
+ mGpsMode = parser.getInt(KEY_GPS_MODE, defaultGpsMode);
+
+ // Non-device-specific parameters.
+ try {
+ parser.setString(deviceSpecificSetting);
+ } catch (IllegalArgumentException e) {
+ Slog.wtf(TAG, "Bad device specific battery saver constants: "
+ + deviceSpecificSetting);
+ }
+
+ mScreenOnFiles = collectParams(parser, KEY_SCREEN_ON_FILE_PREFIX);
+ mScreenOffFiles = collectParams(parser, KEY_SCREEN_OFF_FILE_PREFIX);
+ }
+
+ private static ArrayMap<String, String> collectParams(
+ KeyValueListParser parser, String prefix) {
+ final ArrayMap<String, String> ret = new ArrayMap<>();
+
+ for (int i = parser.size() - 1; i >= 0; i--) {
+ final String key = parser.keyAt(i);
+ if (!key.startsWith(prefix)) {
+ continue;
}
+ final String path = key.substring(prefix.length());
- mVibrationDisabled = mParser.getBoolean(KEY_VIBRATION_DISABLED, true);
- mAnimationDisabled = mParser.getBoolean(KEY_ANIMATION_DISABLED, true);
- mSoundTriggerDisabled = mParser.getBoolean(KEY_SOUNDTRIGGER_DISABLED, true);
- mFullBackupDeferred = mParser.getBoolean(KEY_FULLBACKUP_DEFERRED, true);
- mKeyValueBackupDeferred = mParser.getBoolean(KEY_KEYVALUE_DEFERRED, true);
- mFireWallDisabled = mParser.getBoolean(KEY_FIREWALL_DISABLED, false);
- mAdjustBrightnessDisabled = mParser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, false);
- mAdjustBrightnessFactor = mParser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR, 0.5f);
- mDataSaverDisabled = mParser.getBoolean(KEY_DATASAVER_DISABLED, true);
-
- // Get default value from Settings.Secure
- final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE,
- GPS_MODE_DISABLED_WHEN_SCREEN_OFF);
- mGpsMode = mParser.getInt(KEY_GPS_MODE, defaultGpsMode);
+ if (!(path.startsWith("/sys/") || path.startsWith("/proc"))) {
+ Slog.wtf(TAG, "Invalid path: " + path);
+ continue;
+ }
+
+ ret.put(path, parser.getString(key, ""));
}
+ return ret;
}
/**
@@ -221,7 +342,7 @@ public class BatterySaverPolicy extends ContentObserver {
* @return State data that contains battery saver data
*/
public PowerSaveState getBatterySaverPolicy(@ServiceType int type, boolean realMode) {
- synchronized (BatterySaverPolicy.this) {
+ synchronized (mLock) {
final PowerSaveState.Builder builder = new PowerSaveState.Builder()
.setGlobalBatterySaverEnabled(realMode);
if (!realMode) {
@@ -258,6 +379,9 @@ public class BatterySaverPolicy extends ContentObserver {
case ServiceType.VIBRATION:
return builder.setBatterySaverEnabled(mVibrationDisabled)
.build();
+ case ServiceType.OPTIONAL_SENSORS:
+ return builder.setBatterySaverEnabled(mOptionalSensorsDisabled)
+ .build();
default:
return builder.setBatterySaverEnabled(realMode)
.build();
@@ -265,23 +389,56 @@ public class BatterySaverPolicy extends ContentObserver {
}
}
+ public ArrayMap<String, String> getFileValues(boolean screenOn) {
+ synchronized (mLock) {
+ return screenOn ? mScreenOnFiles : mScreenOffFiles;
+ }
+ }
+
public void dump(PrintWriter pw) {
- pw.println();
- pw.println("Battery saver policy");
- pw.println(" Settings " + Settings.Global.BATTERY_SAVER_CONSTANTS);
- pw.println(" value: " + Settings.Global.getString(mContentResolver,
- Settings.Global.BATTERY_SAVER_CONSTANTS));
-
- pw.println();
- pw.println(" " + KEY_VIBRATION_DISABLED + "=" + mVibrationDisabled);
- pw.println(" " + KEY_ANIMATION_DISABLED + "=" + mAnimationDisabled);
- pw.println(" " + KEY_FULLBACKUP_DEFERRED + "=" + mFullBackupDeferred);
- pw.println(" " + KEY_KEYVALUE_DEFERRED + "=" + mKeyValueBackupDeferred);
- pw.println(" " + KEY_FIREWALL_DISABLED + "=" + mFireWallDisabled);
- pw.println(" " + KEY_DATASAVER_DISABLED + "=" + mDataSaverDisabled);
- pw.println(" " + KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + mAdjustBrightnessDisabled);
- pw.println(" " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mAdjustBrightnessFactor);
- pw.println(" " + KEY_GPS_MODE + "=" + mGpsMode);
+ synchronized (mLock) {
+ pw.println();
+ pw.println("Battery saver policy");
+ pw.println(" Settings " + Settings.Global.BATTERY_SAVER_CONSTANTS);
+ pw.println(" value: " + mSettings);
+ pw.println(" Settings " + mDeviceSpecificSettingsSource);
+ pw.println(" value: " + mDeviceSpecificSettings);
+
+ pw.println();
+ pw.println(" " + KEY_VIBRATION_DISABLED + "=" + mVibrationDisabled);
+ pw.println(" " + KEY_ANIMATION_DISABLED + "=" + mAnimationDisabled);
+ pw.println(" " + KEY_FULLBACKUP_DEFERRED + "=" + mFullBackupDeferred);
+ pw.println(" " + KEY_KEYVALUE_DEFERRED + "=" + mKeyValueBackupDeferred);
+ pw.println(" " + KEY_FIREWALL_DISABLED + "=" + mFireWallDisabled);
+ pw.println(" " + KEY_DATASAVER_DISABLED + "=" + mDataSaverDisabled);
+ pw.println(" " + KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + mAdjustBrightnessDisabled);
+ pw.println(" " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mAdjustBrightnessFactor);
+ pw.println(" " + KEY_GPS_MODE + "=" + mGpsMode);
+ pw.println(" " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mForceAllAppsStandby);
+ pw.println(" " + KEY_OPTIONAL_SENSORS_DISABLED + "=" + mOptionalSensorsDisabled);
+ pw.println();
+ pw.print(" Screen On Files:\n");
+ dumpMap(pw, " ", mScreenOnFiles);
+ pw.println();
+
+ pw.print(" Screen Off Files:\n");
+ dumpMap(pw, " ", mScreenOffFiles);
+ pw.println();
+ }
+ }
+
+ private void dumpMap(PrintWriter pw, String prefix, ArrayMap<String, String> map) {
+ if (map == null) {
+ return;
+ }
+ final int size = map.size();
+ for (int i = 0; i < size; i++) {
+ pw.print(prefix);
+ pw.print(map.keyAt(i));
+ pw.print(": '");
+ pw.print(map.valueAt(i));
+ pw.println("'");
+ }
}
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 2494bded1b86..a47b8095dae7 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -43,6 +43,7 @@ import android.os.IPowerManager;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.Process;
@@ -62,7 +63,6 @@ import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
import android.util.EventLog;
import android.util.KeyValueListParser;
-import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
@@ -70,6 +70,7 @@ import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.WindowManagerPolicy;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
@@ -89,11 +90,8 @@ import com.android.server.Watchdog;
import com.android.server.am.BatteryStatsService;
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
+import com.android.server.power.batterysaver.BatterySaverController;
+
import libcore.util.Objects;
import java.io.FileDescriptor;
@@ -226,6 +224,7 @@ public final class PowerManagerService extends SystemService
private final PowerManagerHandler mHandler;
private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
private final BatterySaverPolicy mBatterySaverPolicy;
+ private final BatterySaverController mBatterySaverController;
private LightsManager mLightsManager;
private BatteryManagerInternal mBatteryManagerInternal;
@@ -553,9 +552,6 @@ public final class PowerManagerService extends SystemService
// True if double tap to wake is enabled
private boolean mDoubleTapWakeEnabled;
- private final ArrayList<PowerManagerInternal.LowPowerModeListener> mLowPowerModeListeners
- = new ArrayList<PowerManagerInternal.LowPowerModeListener>();
-
// True if we are currently in VR Mode.
private boolean mIsVrModeEnabled;
@@ -643,7 +639,10 @@ public final class PowerManagerService extends SystemService
mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
mConstants = new Constants(mHandler);
mAmbientDisplayConfiguration = new AmbientDisplayConfiguration(mContext);
+
mBatterySaverPolicy = new BatterySaverPolicy(mHandler);
+ mBatterySaverController = new BatterySaverController(mContext,
+ BackgroundThread.get().getLooper(), mBatterySaverPolicy);
synchronized (mLock) {
mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
@@ -668,7 +667,6 @@ public final class PowerManagerService extends SystemService
PowerManagerService(Context context, BatterySaverPolicy batterySaverPolicy) {
super(context);
- mBatterySaverPolicy = batterySaverPolicy;
mContext = context;
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
@@ -678,6 +676,10 @@ public final class PowerManagerService extends SystemService
mAmbientDisplayConfiguration = new AmbientDisplayConfiguration(mContext);
mDisplaySuspendBlocker = null;
mWakeLockSuspendBlocker = null;
+
+ mBatterySaverPolicy = batterySaverPolicy;
+ mBatterySaverController = new BatterySaverController(context,
+ BackgroundThread.getHandler().getLooper(), batterySaverPolicy);
}
@Override
@@ -750,6 +752,7 @@ public final class PowerManagerService extends SystemService
mDisplayManagerInternal.initPowerManagement(
mDisplayPowerCallbacks, mHandler, sensorManager);
+
// Go.
readConfigurationLocked();
updateSettingsLocked();
@@ -759,7 +762,9 @@ public final class PowerManagerService extends SystemService
final ContentResolver resolver = mContext.getContentResolver();
mConstants.start(resolver);
- mBatterySaverPolicy.start(resolver);
+
+ mBatterySaverController.systemReady();
+ mBatterySaverPolicy.systemReady(mContext);
// Register for settings changes.
resolver.registerContentObserver(Settings.Secure.getUriFor(
@@ -994,36 +999,9 @@ public final class PowerManagerService extends SystemService
if (mLowPowerModeEnabled != lowPowerModeEnabled) {
mLowPowerModeEnabled = lowPowerModeEnabled;
- powerHintInternal(PowerHint.LOW_POWER, lowPowerModeEnabled ? 1 : 0);
- postAfterBootCompleted(new Runnable() {
- @Override
- public void run() {
- Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)
- .putExtra(PowerManager.EXTRA_POWER_SAVE_MODE, mLowPowerModeEnabled)
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mContext.sendBroadcast(intent);
- ArrayList<PowerManagerInternal.LowPowerModeListener> listeners;
- synchronized (mLock) {
- listeners = new ArrayList<PowerManagerInternal.LowPowerModeListener>(
- mLowPowerModeListeners);
- }
- for (int i = 0; i < listeners.size(); i++) {
- final PowerManagerInternal.LowPowerModeListener listener = listeners.get(i);
- final PowerSaveState result =
- mBatterySaverPolicy.getBatterySaverPolicy(
- listener.getServiceType(), lowPowerModeEnabled);
- listener.onLowPowerModeChanged(result);
- }
- intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
- // Send internal version that requires signature permission.
- intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
- Manifest.permission.DEVICE_POWER);
- }
- });
+
+ postAfterBootCompleted(() ->
+ mBatterySaverController.enableBatterySaver(mLowPowerModeEnabled));
}
}
@@ -2364,9 +2342,13 @@ public final class PowerManagerService extends SystemService
if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
- if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND
- && (mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
- mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;
+ if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
+ if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) {
+ mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;
+ }
+ if (mDisplayPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND) {
+ mDisplayPowerRequest.dozeScreenState = Display.STATE_ON;
+ }
}
mDisplayPowerRequest.dozeScreenBrightness =
mDozeScreenBrightnessOverrideFromDreamManager;
@@ -3123,7 +3105,7 @@ public final class PowerManagerService extends SystemService
mIsVrModeEnabled = enabled;
}
- private void powerHintInternal(int hintId, int data) {
+ public static void powerHintInternal(int hintId, int data) {
nativeSendPowerHint(hintId, data);
}
@@ -4392,7 +4374,7 @@ public final class PowerManagerService extends SystemService
* Gets the reason for the last time the phone had to reboot.
*
* @return The reason the phone last shut down as an int or
- * {@link PowerManager.SHUTDOWN_REASON_UNKNOWN} if the file could not be opened.
+ * {@link PowerManager#SHUTDOWN_REASON_UNKNOWN} if the file could not be opened.
*/
@Override // Binder call
public int getLastShutdownReason() {
@@ -4676,6 +4658,7 @@ public final class PowerManagerService extends SystemService
case Display.STATE_OFF:
case Display.STATE_DOZE:
case Display.STATE_DOZE_SUSPEND:
+ case Display.STATE_ON_SUSPEND:
case Display.STATE_ON:
case Display.STATE_VR:
break;
@@ -4714,9 +4697,7 @@ public final class PowerManagerService extends SystemService
@Override
public void registerLowPowerModeObserver(LowPowerModeListener listener) {
- synchronized (mLock) {
- mLowPowerModeListeners.add(listener);
- }
+ mBatterySaverController.addListener(listener);
}
@Override
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 755c5f09599c..6bf725e1a09f 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -68,7 +68,8 @@ import java.nio.charset.StandardCharsets;
public final class ShutdownThread extends Thread {
// constants
private static final String TAG = "ShutdownThread";
- private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500;
+ private static final int ACTION_DONE_POLL_WAIT_MS = 500;
+ private static final int RADIOS_STATE_POLL_SLEEP_MS = 100;
// maximum time we wait for the shutdown broadcast before going on.
private static final int MAX_BROADCAST_TIME = 10*1000;
private static final int MAX_SHUTDOWN_WAIT_TIME = 20*1000;
@@ -471,7 +472,7 @@ public final class ShutdownThread extends Thread {
sInstance.setRebootProgress(status, null);
}
try {
- mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC));
+ mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
} catch (InterruptedException e) {
}
}
@@ -565,7 +566,7 @@ public final class ShutdownThread extends Thread {
sInstance.setRebootProgress(status, null);
}
try {
- mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC));
+ mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
} catch (InterruptedException e) {
}
}
@@ -710,8 +711,7 @@ public final class ShutdownThread extends Thread {
done[0] = true;
break;
}
- SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC);
-
+ SystemClock.sleep(RADIOS_STATE_POLL_SLEEP_MS);
delay = endTime - SystemClock.elapsedRealtime();
}
}
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
new file mode 100644
index 000000000000..b3e853838069
--- /dev/null
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.Manifest;
+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.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.PowerManagerInternal.LowPowerModeListener;
+import android.os.PowerSaveState;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.widget.Toast;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+import com.android.server.power.BatterySaverPolicy;
+import com.android.server.power.BatterySaverPolicy.BatterySaverPolicyListener;
+import com.android.server.power.PowerManagerService;
+
+import java.util.ArrayList;
+
+/**
+ * Responsible for battery saver mode transition logic.
+ */
+public class BatterySaverController implements BatterySaverPolicyListener {
+ static final String TAG = "BatterySaverController";
+
+ static final boolean DEBUG = false; // DO NOT MERGE WITH TRUE
+
+ private final Object mLock = new Object();
+ private final Context mContext;
+ private final MyHandler mHandler;
+ private final FileUpdater mFileUpdater;
+
+ private PowerManager mPowerManager;
+
+ private final BatterySaverPolicy mBatterySaverPolicy;
+
+ @GuardedBy("mLock")
+ private final ArrayList<LowPowerModeListener> mListeners = new ArrayList<>();
+
+ @GuardedBy("mLock")
+ private boolean mEnabled;
+
+ /**
+ * Keep track of the previous enabled state, which we use to decide when to send broadcasts,
+ * which we don't want to send only when the screen state changes.
+ */
+ @GuardedBy("mLock")
+ private boolean mWasEnabled;
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ switch (intent.getAction()) {
+ case Intent.ACTION_SCREEN_ON:
+ case Intent.ACTION_SCREEN_OFF:
+ mHandler.postStateChanged();
+ break;
+ }
+ }
+ };
+
+ /**
+ * Constructor.
+ */
+ public BatterySaverController(Context context, Looper looper, BatterySaverPolicy policy) {
+ mContext = context;
+ mHandler = new MyHandler(looper);
+ mBatterySaverPolicy = policy;
+ mBatterySaverPolicy.addListener(this);
+ mFileUpdater = new FileUpdater(context);
+ }
+
+ /**
+ * Add a listener.
+ */
+ public void addListener(LowPowerModeListener listener) {
+ synchronized (mLock) {
+ mListeners.add(listener);
+ }
+ }
+
+ /**
+ * Called by {@link PowerManagerService} on system ready..
+ */
+ public void systemReady() {
+ final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ mContext.registerReceiver(mReceiver, filter);
+ }
+
+ private PowerManager getPowerManager() {
+ if (mPowerManager == null) {
+ mPowerManager =
+ Preconditions.checkNotNull(mContext.getSystemService(PowerManager.class));
+ }
+ return mPowerManager;
+ }
+
+ @Override
+ public void onBatterySaverPolicyChanged(BatterySaverPolicy policy) {
+ mHandler.postStateChanged();
+ }
+
+ private class MyHandler extends Handler {
+ private final int MSG_STATE_CHANGED = 1;
+
+ public MyHandler(Looper looper) {
+ super(looper);
+ }
+
+ public void postStateChanged() {
+ obtainMessage(MSG_STATE_CHANGED).sendToTarget();
+ }
+
+ @Override
+ public void dispatchMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_STATE_CHANGED:
+ handleBatterySaverStateChanged();
+ break;
+ }
+ }
+ }
+
+ /**
+ * Called by {@link PowerManagerService} to update the battery saver stete.
+ */
+ public void enableBatterySaver(boolean enable) {
+ synchronized (mLock) {
+ if (mEnabled == enable) {
+ return;
+ }
+ mEnabled = enable;
+
+ mHandler.postStateChanged();
+ }
+ }
+
+ /**
+ * Dispatch power save events to the listeners.
+ *
+ * This is always called on the handler thread.
+ */
+ void handleBatterySaverStateChanged() {
+ final LowPowerModeListener[] listeners;
+
+ final boolean wasEnabled;
+ final boolean enabled;
+ final boolean isScreenOn = getPowerManager().isInteractive();
+ final ArrayMap<String, String> fileValues;
+
+ synchronized (mLock) {
+ Slog.i(TAG, "Battery saver enabled: screen on=" + isScreenOn);
+
+ listeners = mListeners.toArray(new LowPowerModeListener[mListeners.size()]);
+ wasEnabled = mWasEnabled;
+ enabled = mEnabled;
+
+ if (enabled) {
+ fileValues = mBatterySaverPolicy.getFileValues(isScreenOn);
+ } else {
+ fileValues = null;
+ }
+ }
+
+ PowerManagerService.powerHintInternal(PowerHint.LOW_POWER, enabled ? 1 : 0);
+
+ if (enabled) {
+ // STOPSHIP Remove the toast.
+ Toast.makeText(mContext,
+ com.android.internal.R.string.battery_saver_warning,
+ Toast.LENGTH_LONG).show();
+ }
+
+ if (fileValues == null || fileValues.size() == 0) {
+ mFileUpdater.restoreDefault();
+ } else {
+ mFileUpdater.writeFiles(fileValues);
+ }
+
+ if (enabled != wasEnabled) {
+ if (DEBUG) {
+ Slog.i(TAG, "Sending broadcasts for mode: " + enabled);
+ }
+
+ // Send the broadcasts and notify the listeners. We only do this when the battery saver
+ // mode changes, but not when only the screen state changes.
+ Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)
+ .putExtra(PowerManager.EXTRA_POWER_SAVE_MODE, enabled)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcast(intent);
+
+ intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+
+ // Send internal version that requires signature permission.
+ intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+ Manifest.permission.DEVICE_POWER);
+
+
+ for (LowPowerModeListener listener : listeners) {
+ final PowerSaveState result =
+ mBatterySaverPolicy.getBatterySaverPolicy(
+ listener.getServiceType(), enabled);
+ listener.onLowPowerModeChanged(result);
+ }
+ }
+
+ synchronized (mLock) {
+ mWasEnabled = enabled;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/power/batterysaver/FileUpdater.java b/services/core/java/com/android/server/power/batterysaver/FileUpdater.java
new file mode 100644
index 000000000000..cfe8fc490e0a
--- /dev/null
+++ b/services/core/java/com/android/server/power/batterysaver/FileUpdater.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.util.ArrayMap;
+import android.util.Slog;
+
+/**
+ * Used by {@link BatterySaverController} to write values to /sys/ (and possibly /proc/ too) files
+ * with retry and to restore the original values.
+ *
+ * TODO Implement it
+ */
+public class FileUpdater {
+ private static final String TAG = BatterySaverController.TAG;
+
+ private static final boolean DEBUG = BatterySaverController.DEBUG;
+
+ private final Object mLock = new Object();
+ private final Context mContext;
+
+ public FileUpdater(Context context) {
+ mContext = context;
+ }
+
+ public void writeFiles(ArrayMap<String, String> fileValues) {
+ if (DEBUG) {
+ final int size = fileValues.size();
+ for (int i = 0; i < size; i++) {
+ Slog.d(TAG, "Writing '" + fileValues.valueAt(i)
+ + "' to '" + fileValues.keyAt(i) + "'");
+ }
+ }
+ }
+
+ public void restoreDefault() {
+ if (DEBUG) {
+ Slog.d(TAG, "Resetting file default values");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 41534cbb641f..dafab770cb41 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -44,6 +44,8 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.os.KernelWakelockReader;
import com.android.internal.os.KernelWakelockStats;
+import com.android.internal.os.KernelCpuSpeedReader;
+import com.android.internal.os.PowerProfile;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -60,6 +62,8 @@ import java.util.Map;
public class StatsCompanionService extends IStatsCompanionService.Stub {
static final String TAG = "StatsCompanionService";
static final boolean DEBUG = true;
+ public static final String ACTION_TRIGGER_COLLECTION =
+ "com.android.server.stats.action.TRIGGER_COLLECTION";
private final Context mContext;
private final AlarmManager mAlarmManager;
@@ -71,6 +75,9 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
private final PendingIntent mPullingAlarmIntent;
private final BroadcastReceiver mAppUpdateReceiver;
private final BroadcastReceiver mUserUpdateReceiver;
+ private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
+ private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
+ private final KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
public StatsCompanionService(Context context) {
super();
@@ -103,6 +110,22 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
};
Slog.w(TAG, "Registered receiver for ACTION_PACKAGE_REPLACE AND ADDED.");
+ PowerProfile powerProfile = new PowerProfile(context);
+ final int numClusters = powerProfile.getNumCpuClusters();
+ mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters];
+ int firstCpuOfCluster = 0;
+ for (int i = 0; i < numClusters; i++) {
+ final int numSpeedSteps = powerProfile.getNumSpeedStepsInCpuCluster(i);
+ mKernelCpuSpeedReaders[i] = new KernelCpuSpeedReader(firstCpuOfCluster,
+ numSpeedSteps);
+ firstCpuOfCluster += powerProfile.getNumCoresInCpuCluster(i);
+ }
+ }
+
+ @Override
+ public void sendBroadcast(String pkg, String cls) {
+ mContext.sendBroadcastAsUser(new Intent(ACTION_TRIGGER_COLLECTION).setClassName(pkg, cls),
+ UserHandle.SYSTEM);
}
private final static int[] toIntArray(List<Integer> list) {
@@ -159,7 +182,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
Slog.i(TAG, "StatsCompanionService noticed an app was updated.");
synchronized (sStatsdLock) {
if (sStatsd == null) {
- Slog.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
+ Slog.w(TAG, "Could not access statsd to inform it of an app update");
return;
}
try {
@@ -286,13 +309,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
}
- // These values must be kept in sync with cmd/statsd/StatsPullerManager.h.
- // TODO: pull the constant from stats_events.proto instead
- private static final int PULL_CODE_KERNEL_WAKELOCKS = 20;
-
- private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
- private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
-
private StatsLogEventWrapper[] addNetworkStats(int tag, NetworkStats stats, boolean withFGBG) {
List<StatsLogEventWrapper> ret = new ArrayList<>();
int size = stats.size();
@@ -347,12 +363,12 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
@Override // Binder call
- public StatsLogEventWrapper[] pullData(int pullCode) {
+ public StatsLogEventWrapper[] pullData(int tagId) {
enforceCallingPermission();
if (DEBUG)
- Slog.d(TAG, "Pulling " + pullCode);
+ Slog.d(TAG, "Pulling " + tagId);
- switch (pullCode) {
+ switch (tagId) {
case StatsLog.WIFI_BYTES_TRANSFERRED: {
long token = Binder.clearCallingIdentity();
try {
@@ -366,7 +382,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
// Combine all the metrics per Uid into one record.
NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
NetworkStats.TAG_NONE, null).groupedByUid();
- return addNetworkStats(pullCode, stats, false);
+ return addNetworkStats(tagId, stats, false);
} catch (java.io.IOException e) {
Slog.e(TAG, "Pulling netstats for wifi bytes has error", e);
} finally {
@@ -386,7 +402,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
// Combine all the metrics per Uid into one record.
NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
NetworkStats.TAG_NONE, null).groupedByUid();
- return addNetworkStats(pullCode, stats, false);
+ return addNetworkStats(tagId, stats, false);
} catch (java.io.IOException e) {
Slog.e(TAG, "Pulling netstats for mobile bytes has error", e);
} finally {
@@ -406,7 +422,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
NetworkStats stats = rollupNetworkStatsByFGBG(
nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
NetworkStats.TAG_NONE, null));
- return addNetworkStats(pullCode, stats, true);
+ return addNetworkStats(tagId, stats, true);
} catch (java.io.IOException e) {
Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e);
} finally {
@@ -426,7 +442,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
NetworkStats stats = rollupNetworkStatsByFGBG(
nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
NetworkStats.TAG_NONE, null));
- return addNetworkStats(pullCode, stats, true);
+ return addNetworkStats(tagId, stats, true);
} catch (java.io.IOException e) {
Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e);
} finally {
@@ -434,14 +450,14 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
break;
}
- case StatsLog.KERNEL_WAKELOCKS_REPORTED: {
+ case StatsLog.KERNEL_WAKELOCK_PULLED: {
final KernelWakelockStats wakelockStats =
mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
List<StatsLogEventWrapper> ret = new ArrayList();
for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
String name = ent.getKey();
KernelWakelockStats.Entry kws = ent.getValue();
- StatsLogEventWrapper e = new StatsLogEventWrapper(pullCode, 4);
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 4);
e.writeString(name);
e.writeInt(kws.mCount);
e.writeInt(kws.mVersion);
@@ -450,8 +466,24 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
return ret.toArray(new StatsLogEventWrapper[ret.size()]);
}
+ case StatsLog.CPU_TIME_PER_FREQ_PULLED: {
+ List<StatsLogEventWrapper> ret = new ArrayList();
+ for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) {
+ long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readDelta();
+ if (clusterTimeMs != null) {
+ for (int speed = clusterTimeMs.length - 1; speed >= 0; --speed) {
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 3);
+ e.writeInt(tagId);
+ e.writeInt(speed);
+ e.writeLong(clusterTimeMs[speed]);
+ ret.add(e);
+ }
+ }
+ }
+ return ret.toArray(new StatsLogEventWrapper[ret.size()]);
+ }
default:
- Slog.w(TAG, "No such pollable data as " + pullCode);
+ Slog.w(TAG, "No such tagId data as " + tagId);
return null;
}
return null;
diff --git a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
deleted file mode 100644
index cabce183a1a4..000000000000
--- a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.server.updates;
-
-import com.android.timezone.distro.TimeZoneDistro;
-import com.android.timezone.distro.installer.TimeZoneDistroInstaller;
-
-import android.util.Slog;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * An install receiver responsible for installing timezone data updates.
- */
-public class TzDataInstallReceiver extends ConfigUpdateInstallReceiver {
-
- private static final String TAG = "TZDataInstallReceiver";
-
- private static final File SYSTEM_TZ_DATA_FILE = new File("/system/usr/share/zoneinfo/tzdata");
- private static final File TZ_DATA_DIR = new File("/data/misc/zoneinfo");
- private static final String UPDATE_DIR_NAME = TZ_DATA_DIR.getPath() + "/updates/";
- private static final String UPDATE_METADATA_DIR_NAME = "metadata/";
- private static final String UPDATE_VERSION_FILE_NAME = "version";
- private static final String UPDATE_CONTENT_FILE_NAME = "tzdata_distro.zip";
-
- private final TimeZoneDistroInstaller installer;
-
- public TzDataInstallReceiver() {
- super(UPDATE_DIR_NAME, UPDATE_CONTENT_FILE_NAME, UPDATE_METADATA_DIR_NAME,
- UPDATE_VERSION_FILE_NAME);
- installer = new TimeZoneDistroInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR);
- }
-
- @Override
- protected void install(byte[] content, int version) throws IOException {
- TimeZoneDistro distro = new TimeZoneDistro(content);
- boolean valid = installer.install(distro);
- Slog.i(TAG, "Timezone data install valid for this device: " + valid);
- // Even if !valid, we call super.install(). Only in the event of an exception should we
- // not. If we didn't do this we could attempt to install repeatedly.
- super.install(content, version);
- }
-}
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index e8ebbe4dd805..5493207d0f8a 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -756,7 +756,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC
mBootsToVr = SystemProperties.getBoolean("ro.boot.vr", false);
mUseStandbyToExitVrMode = mBootsToVr
- && SystemProperties.getBoolean("persist.vr.use_standby_to_exit_vr_mode", false);
+ && SystemProperties.getBoolean("persist.vr.use_standby_to_exit_vr_mode", true);
publishLocalService(VrManagerInternal.class, new LocalService());
publishBinderService(Context.VR_SERVICE, mVrManager.asBinder());
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2f54e0e18b8b..4d839d009c56 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
@@ -104,6 +105,7 @@ import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
import static com.android.server.wm.proto.DisplayProto.ABOVE_APP_WINDOWS;
import static com.android.server.wm.proto.DisplayProto.BELOW_APP_WINDOWS;
+import static com.android.server.wm.proto.DisplayProto.DISPLAY_FRAMES;
import static com.android.server.wm.proto.DisplayProto.DISPLAY_INFO;
import static com.android.server.wm.proto.DisplayProto.DOCKED_STACK_DIVIDER_CONTROLLER;
import static com.android.server.wm.proto.DisplayProto.DPI;
@@ -147,6 +149,7 @@ import android.view.WindowManagerPolicy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ToBooleanFunction;
import com.android.internal.view.IInputMethodClient;
+import android.view.DisplayFrames;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -222,6 +225,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
private final DisplayInfo mDisplayInfo = new DisplayInfo();
private final Display mDisplay;
private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+ DisplayFrames mDisplayFrames;
+
/**
* For default display it contains real metrics, empty for others.
* @see WindowManagerService#createWatermarkInTransaction()
@@ -285,7 +290,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
private boolean mLastWallpaperVisible = false;
private Rect mBaseDisplayRect = new Rect();
- private Rect mContentRect = new Rect();
// Accessed directly by all users.
private boolean mLayoutNeeded;
@@ -545,7 +549,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
w.mLayoutNeeded = false;
w.prelayout();
final boolean firstLayout = !w.isLaidOut();
- mService.mPolicy.layoutWindowLw(w, null);
+ mService.mPolicy.layoutWindowLw(w, null, mDisplayFrames);
w.mLayoutSeq = mService.mLayoutSeq;
// If this is the first layout, we need to initialize the last inset values as
@@ -586,7 +590,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
w.mLayoutNeeded = false;
w.prelayout();
- mService.mPolicy.layoutWindowLw(w, w.getParentWindow());
+ mService.mPolicy.layoutWindowLw(w, w.getParentWindow(), mDisplayFrames);
w.mLayoutSeq = mService.mLayoutSeq;
if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.mFrame
+ " mContainingFrame=" + w.mContainingFrame
@@ -758,6 +762,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
display.getMetrics(mDisplayMetrics);
isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
mService = service;
+ mDisplayFrames = new DisplayFrames(mDisplayId, mDisplayInfo);
initializeDisplayBaseInfo();
mDividerControllerLocked = new DockedStackDividerController(service, this);
mPinnedStackControllerLocked = new PinnedStackController(service, this);
@@ -1129,6 +1134,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return true;
}
+ void configureDisplayPolicy() {
+ mService.mPolicy.setInitialDisplaySize(getDisplay(),
+ mBaseDisplayWidth, mBaseDisplayHeight, mBaseDisplayDensity);
+
+ mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo);
+ }
+
/**
* Update {@link #mDisplayInfo} and other internal variables when display is rotated or config
* changed.
@@ -1477,7 +1489,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
* Returns the topmost stack on the display that is compatible with the input windowing mode.
* Null is no compatible stack on the display.
*/
- TaskStack getStack(int windowingMode) {
+ TaskStack getTopStackInWindowingMode(int windowingMode) {
return getStack(windowingMode, ACTIVITY_TYPE_UNDEFINED);
}
@@ -1744,7 +1756,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
void getContentRect(Rect out) {
- out.set(mContentRect);
+ out.set(mDisplayFrames.mContent);
}
TaskStack createStack(int stackId, boolean onTop, StackWindowController controller) {
@@ -1753,10 +1765,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
final TaskStack stack = new TaskStack(mService, stackId, controller);
mTaskStackContainers.addStackToDisplay(stack, onTop);
-
- if (stack.inSplitScreenPrimaryWindowingMode()) {
- mDividerControllerLocked.notifyDockedStackExistsChanged(true);
- }
return stack;
}
@@ -1847,8 +1855,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mTmpRect2.setEmpty();
for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
- stack.setTouchExcludeRegion(
- focusedTask, delta, mTouchExcludeRegion, mContentRect, mTmpRect2);
+ stack.setTouchExcludeRegion(focusedTask, delta, mTouchExcludeRegion,
+ mDisplayFrames.mContent, mTmpRect2);
}
// If we removed the focused task above, add it back and only leave its
// outside touch area in the exclusion. TapDectector is not interested in
@@ -2025,7 +2033,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
final boolean imeOnTop = (imeDockSide == DOCKED_TOP);
final boolean imeOnBottom = (imeDockSide == DOCKED_BOTTOM);
final boolean dockMinimized = mDividerControllerLocked.isMinimizedDock();
- final int imeHeight = mService.mPolicy.getInputMethodWindowVisibleHeightLw();
+ final int imeHeight = mDisplayFrames.getInputMethodWindowVisibleHeight();
final boolean imeHeightChanged = imeVisible &&
imeHeight != mDividerControllerLocked.getImeHeightAdjustedFor();
@@ -2167,6 +2175,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (screenRotationAnimation != null) {
screenRotationAnimation.writeToProto(proto, SCREEN_ROTATION_ANIMATION);
}
+ mDisplayFrames.writeToProto(proto, DISPLAY_FRAMES);
proto.end(token);
}
@@ -2246,6 +2255,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
pw.println(subPrefix
+ "mInputMethodAnimLayerAdjustment=" + mInputMethodAnimLayerAdjustment);
}
+
+ pw.println();
+ mDisplayFrames.dump(prefix, pw);
}
@Override
@@ -2259,7 +2271,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
/** Returns true if the stack in the windowing mode is visible. */
boolean isStackVisible(int windowingMode) {
- final TaskStack stack = getStack(windowingMode);
+ final TaskStack stack = getTopStackInWindowingMode(windowingMode);
return stack != null && stack.isVisible();
}
@@ -2871,22 +2883,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
final int dw = mDisplayInfo.logicalWidth;
final int dh = mDisplayInfo.logicalHeight;
-
if (DEBUG_LAYOUT) {
Slog.v(TAG, "-------------------------------------");
Slog.v(TAG, "performLayout: needed=" + isLayoutNeeded() + " dw=" + dw + " dh=" + dh);
}
- mService.mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mRotation,
- getConfiguration().uiMode);
+ mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo);
+ // TODO: Not sure if we really need to set the rotation here since we are updating from the
+ // display info above...
+ mDisplayFrames.mRotation = mRotation;
+ mService.mPolicy.beginLayoutLw(mDisplayFrames, getConfiguration().uiMode);
if (isDefaultDisplay) {
// Not needed on non-default displays.
mService.mSystemDecorLayer = mService.mPolicy.getSystemDecorLayerLw();
mService.mScreenRect.set(0, 0, dw, dh);
}
- mService.mPolicy.getContentRectLw(mContentRect);
-
int seq = mService.mLayoutSeq + 1;
if (seq < 0) seq = 0;
mService.mLayoutSeq = seq;
@@ -2916,7 +2928,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
}
- mService.mPolicy.finishLayoutLw();
mService.mH.sendEmptyMessage(UPDATE_DOCKED_STACK_DIVIDER);
}
@@ -3377,6 +3388,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
final TaskStack stack = mTaskStackContainers.getChildAt(i);
+ if (activityType == ACTIVITY_TYPE_UNDEFINED
+ && windowingMode == stack.getWindowingMode()) {
+ // Passing in undefined type means we want to match the topmost stack with the
+ // windowing mode.
+ return stack;
+ }
if (stack.isCompatible(windowingMode, activityType)) {
return stack;
}
@@ -3447,6 +3464,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
+ " already exist on display=" + this + " stack=" + stack);
}
mSplitScreenPrimaryStack = stack;
+ mDividerControllerLocked.notifyDockedStackExistsChanged(true);
}
}
@@ -3457,6 +3475,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mPinnedStack = null;
} else if (stack == mSplitScreenPrimaryStack) {
mSplitScreenPrimaryStack = null;
+ // Re-set the split-screen create mode whenever the split-screen stack is removed.
+ mService.setDockedStackCreateStateLocked(
+ SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
+ mDividerControllerLocked.notifyDockedStackExistsChanged(false);
}
}
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 5ea0e1d041ba..d79ba897150b 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -23,6 +23,7 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.DOCKED_TOP;
@@ -116,6 +117,7 @@ public class DockedStackDividerController implements DimLayerUser {
private final DimLayer mDimLayer;
private boolean mMinimizedDock;
+ private int mOriginalDockedSide = DOCKED_INVALID;
private boolean mAnimatingForMinimizedDockedStack;
private boolean mAnimationStarted;
private long mAnimationStartTime;
@@ -408,6 +410,31 @@ public class DockedStackDividerController implements DimLayerUser {
mDockedStackListeners.finishBroadcast();
}
+ /**
+ * Checks if the primary stack is allowed to dock to a specific side based on its original dock
+ * side.
+ *
+ * @param dockSide the side to see if it is valid
+ * @return true if the side provided is valid
+ */
+ boolean canPrimaryStackDockTo(int dockSide) {
+ if (mService.mPolicy.isDockSideAllowed(dockSide)) {
+ // Side is the same as original side
+ if (dockSide == mOriginalDockedSide) {
+ return true;
+ }
+ // Special rule that the top in portrait is always valid
+ if (dockSide == DOCKED_TOP) {
+ return true;
+ }
+ // Only if original docked side was top in portrait will allow left side for landscape
+ if (dockSide == DOCKED_LEFT && mOriginalDockedSide == DOCKED_TOP) {
+ return true;
+ }
+ }
+ return false;
+ }
+
void notifyDockedStackExistsChanged(boolean exists) {
// TODO(multi-display): Perform all actions only for current display.
final int size = mDockedStackListeners.beginBroadcast();
@@ -430,8 +457,11 @@ public class DockedStackDividerController implements DimLayerUser {
inputMethodManagerInternal.hideCurrentInputMethod();
mImeHideRequested = true;
}
+ final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
+ mOriginalDockedSide = stack.getDockSide();
return;
}
+ mOriginalDockedSide = DOCKED_INVALID;
setMinimizedDockedStack(false /* minimizedDock */, false /* animate */);
}
@@ -529,7 +559,7 @@ public class DockedStackDividerController implements DimLayerUser {
void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha) {
// TODO: Maybe only allow split-screen windowing modes?
final TaskStack stack = targetWindowingMode != WINDOWING_MODE_UNDEFINED
- ? mDisplayContent.getStack(targetWindowingMode)
+ ? mDisplayContent.getTopStackInWindowingMode(targetWindowingMode)
: null;
final TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStack();
boolean visibleAndValid = visible && stack != null && dockedStack != null;
@@ -633,11 +663,15 @@ public class DockedStackDividerController implements DimLayerUser {
if (mMinimizedDock && mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
return;
}
- final TaskStack fullscreenStack = mDisplayContent.getStack(
+ final TaskStack topSecondaryStack = mDisplayContent.getTopStackInWindowingMode(
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
- final boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
- final boolean homeBehind = fullscreenStack != null && fullscreenStack.isVisible();
- setMinimizedDockedStack(homeVisible && !homeBehind, animate);
+ boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
+ if (homeVisible && topSecondaryStack != null) {
+ // Home should only be considered visible if it is greater or equal to the top secondary
+ // stack in terms of z-order.
+ homeVisible = homeStack.compareTo(topSecondaryStack) >= 0;
+ }
+ setMinimizedDockedStack(homeVisible, animate);
}
private boolean isWithinDisplay(Task task) {
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 79d46ce51326..4567e101157d 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -21,6 +21,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACT
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.annotation.NonNull;
import android.content.ClipData;
import android.graphics.PixelFormat;
import android.os.Binder;
@@ -35,6 +36,9 @@ import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.View;
+import android.view.WindowManagerInternal.IDragDropCallback;
+import com.android.internal.util.Preconditions;
+import com.android.server.input.InputWindowHandle;
/**
* Managing drag and drop operations initiated by View#startDragAndDrop.
@@ -49,20 +53,80 @@ class DragDropController {
static final int MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT = 2;
static final int MSG_ANIMATION_END = 3;
- DragState mDragState;
+ /**
+ * Drag state per operation.
+ * Needs a lock of {@code WindowManagerService#mWindowMap} to read this. Needs both locks of
+ * {@code mWriteLock} and {@code WindowManagerService#mWindowMap} to update this.
+ * The variable is cleared by {@code #onDragStateClosedLocked} which is invoked by DragState
+ * itself, thus the variable can be null after calling DragState's methods.
+ */
+ private DragState mDragState;
private WindowManagerService mService;
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() {};
+
boolean dragDropActiveLocked() {
return mDragState != null;
}
+ InputWindowHandle getInputWindowHandleLocked() {
+ return mDragState.getInputWindowHandle();
+ }
+
+ void registerCallback(IDragDropCallback callback) {
+ Preconditions.checkNotNull(callback);
+ synchronized (mWriteLock) {
+ mCallback = callback;
+ }
+ }
+
DragDropController(WindowManagerService service, Looper looper) {
mService = service;
mHandler = new DragHandler(service, looper);
}
+ void sendDragStartedIfNeededLocked(WindowState window) {
+ mDragState.sendDragStartedIfNeededLocked(window);
+ }
+
IBinder prepareDrag(SurfaceSession session, int callerPid,
int callerUid, IWindow window, int flags, int width, int height, Surface outSurface) {
if (DEBUG_DRAG) {
@@ -71,46 +135,46 @@ class DragDropController {
+ " asbinder=" + window.asBinder());
}
- IBinder token = null;
-
- synchronized (mService.mWindowMap) {
- if (dragDropActiveLocked()) {
- Slog.w(TAG_WM, "Drag already in progress");
- return null;
- }
+ synchronized (mWriteLock) {
+ 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;
+ // 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;
}
- surface.setAlpha(alpha);
-
- if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, " DRAG " + surface + ": CREATE");
- outSurface.copyFrom(surface);
- final IBinder winBinder = window.asBinder();
- 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;
}
boolean performDrag(IWindow window, IBinder dragToken,
@@ -120,77 +184,81 @@ class DragDropController {
Slog.d(TAG_WM, "perform drag: win=" + window + " data=" + data);
}
- synchronized (mService.mWindowMap) {
- if (mDragState == null) {
- Slog.w(TAG_WM, "No drag prepared");
- throw new IllegalStateException("performDrag() without prepareDrag()");
+ synchronized (mWriteLock) {
+ if (!mCallback.performDrag(window, dragToken, touchSource, touchX, touchY, thumbCenterX,
+ thumbCenterY, data)) {
+ return false;
}
+ 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()");
- }
+ 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?
- }
+ 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: 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());
+ 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.
+ // !!! 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
+ // !!! 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.unregister();
- mDragState.reset();
- mDragState = null;
- return false;
- }
+ 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();
- } finally {
- mService.closeSurfaceTransaction("performDrag");
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
- TAG_WM, "<<< CLOSE TRANSACTION performDrag");
- }
+ 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);
+ mDragState.notifyLocationLocked(touchX, touchY);
+ }
}
return true; // success!
@@ -202,32 +270,36 @@ class DragDropController {
Slog.d(TAG_WM, "Drop result=" + consumed + " reported by " + token);
}
- synchronized (mService.mWindowMap) {
- if (mDragState == null) {
- // Most likely the drop recipient ANRed and we ended the drag
- // out from under it. Log the issue and move on.
- Slog.w(TAG_WM, "Drop result given but no drag in progress");
- return;
- }
+ synchronized (mWriteLock) {
+ mCallback.reportDropResult(window, consumed);
+ synchronized (mService.mWindowMap) {
+ if (mDragState == null) {
+ // Most likely the drop recipient ANRed and we ended the drag
+ // out from under it. Log the issue and move on.
+ Slog.w(TAG_WM, "Drop result given but no drag in progress");
+ return;
+ }
- if (mDragState.mToken != token) {
- // We're in a drag, but the wrong window has responded.
- Slog.w(TAG_WM, "Invalid drop-result claim by " + window);
- throw new IllegalStateException("reportDropResult() by non-recipient");
- }
+ if (mDragState.mToken != token) {
+ // We're in a drag, but the wrong window has responded.
+ Slog.w(TAG_WM, "Invalid drop-result claim by " + window);
+ throw new IllegalStateException("reportDropResult() by non-recipient");
+ }
+
+ // The right window has responded, even if it's no longer around,
+ // so be sure to halt the timeout even if the later WindowState
+ // lookup fails.
+ mHandler.removeMessages(MSG_DRAG_END_TIMEOUT, window.asBinder());
+ WindowState callingWin = mService.windowForClientLocked(null, window, false);
+ if (callingWin == null) {
+ Slog.w(TAG_WM, "Bad result-reporting window " + window);
+ return; // !!! TODO: throw here?
+ }
- // The right window has responded, even if it's no longer around,
- // so be sure to halt the timeout even if the later WindowState
- // lookup fails.
- mHandler.removeMessages(MSG_DRAG_END_TIMEOUT, window.asBinder());
- WindowState callingWin = mService.windowForClientLocked(null, window, false);
- if (callingWin == null) {
- Slog.w(TAG_WM, "Bad result-reporting window " + window);
- return; // !!! TODO: throw here?
- }
- mDragState.mDragResult = consumed;
- mDragState.endDragLocked();
+ mDragState.mDragResult = consumed;
+ mDragState.endDragLocked();
+ }
}
}
@@ -236,21 +308,50 @@ class DragDropController {
Slog.d(TAG_WM, "cancelDragAndDrop");
}
- synchronized (mService.mWindowMap) {
- if (mDragState == null) {
- Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()");
- throw new IllegalStateException("cancelDragAndDrop() without prepareDrag()");
- }
+ synchronized (mWriteLock) {
+ mCallback.cancelDragAndDrop(dragToken);
+ synchronized (mService.mWindowMap) {
+ if (mDragState == null) {
+ Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()");
+ throw new IllegalStateException("cancelDragAndDrop() without prepareDrag()");
+ }
+
+ if (mDragState.mToken != dragToken) {
+ Slog.w(TAG_WM,
+ "cancelDragAndDrop() does not match prepareDrag()");
+ throw new IllegalStateException(
+ "cancelDragAndDrop() does not match prepareDrag()");
+ }
- if (mDragState.mToken != dragToken) {
- Slog.w(TAG_WM,
- "cancelDragAndDrop() does not match prepareDrag()");
- throw new IllegalStateException(
- "cancelDragAndDrop() does not match prepareDrag()");
+ mDragState.mDragResult = false;
+ mDragState.cancelDragLocked();
}
+ }
+ }
+
+ /**
+ * Handles motion events.
+ * @param keepHandling Whether if the drag operation is continuing or this is the last motion
+ * event.
+ * @param newX X coordinate value in dp in the screen coordinate
+ * @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;
+ }
- mDragState.mDragResult = false;
- mDragState.cancelDragLocked();
+ if (keepHandling) {
+ mDragState.notifyMoveLocked(newX, newY);
+ } else {
+ mDragState.notifyDropLocked(newX, newY);
+ }
+ }
}
}
@@ -282,6 +383,17 @@ class DragDropController {
mHandler.sendMessageDelayed(msg, DRAG_TIMEOUT_MS);
}
+ /**
+ * Notifies the current drag state is closed.
+ */
+ void onDragStateClosedLocked(DragState dragState) {
+ if (mDragState != dragState) {
+ Slog.wtf(TAG_WM, "Unknown drag state is closed");
+ return;
+ }
+ mDragState = null;
+ }
+
private class DragHandler extends Handler {
/**
* Lock for window manager.
@@ -301,27 +413,29 @@ class DragDropController {
if (DEBUG_DRAG) {
Slog.w(TAG_WM, "Timeout starting drag by win " + win);
}
- synchronized (mService.mWindowMap) {
- // !!! TODO: ANR the app that has failed to start the drag in time
- if (mDragState != null) {
- mDragState.unregister();
- mDragState.reset();
- mDragState = null;
+ synchronized (mWriteLock) {
+ synchronized (mService.mWindowMap) {
+ // !!! TODO: ANR the app that has failed to start the drag in time
+ if (mDragState != null) {
+ mDragState.closeLocked();
+ }
}
}
break;
}
case MSG_DRAG_END_TIMEOUT: {
- IBinder win = (IBinder) msg.obj;
+ final IBinder win = (IBinder) msg.obj;
if (DEBUG_DRAG) {
Slog.w(TAG_WM, "Timeout ending drag to win " + win);
}
- synchronized (mService.mWindowMap) {
- // !!! TODO: ANR the drag-receiving app
- if (mDragState != null) {
- mDragState.mDragResult = false;
- mDragState.endDragLocked();
+ synchronized (mWriteLock) {
+ synchronized (mService.mWindowMap) {
+ // !!! TODO: ANR the drag-receiving app
+ if (mDragState != null) {
+ mDragState.mDragResult = false;
+ mDragState.endDragLocked();
+ }
}
}
break;
@@ -330,23 +444,25 @@ class DragDropController {
case MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT: {
if (DEBUG_DRAG)
Slog.d(TAG_WM, "Drag ending; tearing down input channel");
- DragState.InputInterceptor interceptor = (DragState.InputInterceptor) msg.obj;
- if (interceptor != null) {
- synchronized (mService.mWindowMap) {
- interceptor.tearDown();
- }
+ final DragState.InputInterceptor interceptor =
+ (DragState.InputInterceptor) msg.obj;
+ if (interceptor == null) return;
+ synchronized (mService.mWindowMap) {
+ interceptor.tearDown();
}
break;
}
case MSG_ANIMATION_END: {
- synchronized (mService.mWindowMap) {
- if (mDragState == null) {
- Slog.wtf(TAG_WM, "mDragState unexpectedly became null while " +
- "plyaing animation");
- return;
+ synchronized (mWriteLock) {
+ synchronized (mService.mWindowMap) {
+ if (mDragState == null) {
+ Slog.wtf(TAG_WM, "mDragState unexpectedly became null while " +
+ "plyaing animation");
+ return;
+ }
+ mDragState.closeLocked();
}
- mDragState.onAnimationEndLocked();
}
break;
}
diff --git a/services/core/java/com/android/server/wm/DragInputEventReceiver.java b/services/core/java/com/android/server/wm/DragInputEventReceiver.java
index b4bbc9055631..bee2bacf83d2 100644
--- a/services/core/java/com/android/server/wm/DragInputEventReceiver.java
+++ b/services/core/java/com/android/server/wm/DragInputEventReceiver.java
@@ -37,7 +37,6 @@ import android.view.MotionEvent;
* Input receiver for drag and drop
*/
class DragInputEventReceiver extends InputEventReceiver {
- private final WindowManagerService mService;
private final DragDropController mDragDropController;
// Set, if stylus button was down at the start of the drag.
@@ -48,100 +47,63 @@ class DragInputEventReceiver extends InputEventReceiver {
// are still being dispatched.
private boolean mMuteInput = false;
- public DragInputEventReceiver(InputChannel inputChannel, Looper looper,
- DragDropController controller, WindowManagerService service) {
+ DragInputEventReceiver(InputChannel inputChannel, Looper looper,
+ DragDropController controller) {
super(inputChannel, looper);
mDragDropController = controller;
- mService = service;
}
@Override
public void onInputEvent(InputEvent event, int displayId) {
boolean handled = false;
try {
- synchronized (mService.mWindowMap) {
- if (!mDragDropController.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.
- handled = true;
- return;
- }
- if (!(event instanceof MotionEvent)
- || (event.getSource() & SOURCE_CLASS_POINTER) == 0
- || mMuteInput) {
- return;
- }
- final MotionEvent motionEvent = (MotionEvent) event;
- boolean endDrag = false;
- final float newX = motionEvent.getRawX();
- final float newY = motionEvent.getRawY();
- final boolean isStylusButtonDown =
- (motionEvent.getButtonState() & BUTTON_STYLUS_PRIMARY) != 0;
-
- if (mIsStartEvent) {
- if (isStylusButtonDown) {
- // First event and the button was down, check for the button being
- // lifted in the future, if that happens we'll drop the item.
- mStylusButtonDownAtStart = true;
- }
- mIsStartEvent = false;
- }
-
- switch (motionEvent.getAction()) {
- case ACTION_DOWN: {
- if (DEBUG_DRAG) Slog.w(TAG_WM, "Unexpected ACTION_DOWN in drag layer");
- }
- break;
+ if (!(event instanceof MotionEvent)
+ || (event.getSource() & SOURCE_CLASS_POINTER) == 0
+ || mMuteInput) {
+ return;
+ }
+ final MotionEvent motionEvent = (MotionEvent) event;
+ final float newX = motionEvent.getRawX();
+ final float newY = motionEvent.getRawY();
+ final boolean isStylusButtonDown =
+ (motionEvent.getButtonState() & BUTTON_STYLUS_PRIMARY) != 0;
- case ACTION_MOVE: {
- if (mStylusButtonDownAtStart && !isStylusButtonDown) {
- if (DEBUG_DRAG) {
- Slog.d(TAG_WM, "Button no longer pressed; dropping at "
- + newX + "," + newY);
- }
- mMuteInput = true;
- endDrag = mDragDropController.mDragState
- .notifyDropLocked(newX, newY);
- } else {
- // move the surface and tell the involved window(s) where we are
- mDragDropController.mDragState.notifyMoveLocked(newX, newY);
- }
- }
- break;
+ if (mIsStartEvent) {
+ // First event and the button was down, check for the button being
+ // lifted in the future, if that happens we'll drop the item.
+ mStylusButtonDownAtStart = isStylusButtonDown;
+ mIsStartEvent = false;
+ }
- case ACTION_UP: {
+ switch (motionEvent.getAction()) {
+ case ACTION_DOWN:
+ if (DEBUG_DRAG) Slog.w(TAG_WM, "Unexpected ACTION_DOWN in drag layer");
+ return;
+ case ACTION_MOVE:
+ if (mStylusButtonDownAtStart && !isStylusButtonDown) {
if (DEBUG_DRAG) {
- Slog.d(TAG_WM, "Got UP on move channel; dropping at "
- + newX + "," + newY);
+ Slog.d(TAG_WM, "Button no longer pressed; dropping at " + newX + ","
+ + newY);
}
mMuteInput = true;
- endDrag = mDragDropController.mDragState
- .notifyDropLocked(newX, newY);
}
break;
-
- case ACTION_CANCEL: {
- if (DEBUG_DRAG) Slog.d(TAG_WM, "Drag cancelled!");
- mMuteInput = true;
- endDrag = true;
+ case ACTION_UP:
+ if (DEBUG_DRAG) {
+ Slog.d(TAG_WM, "Got UP on move channel; dropping at " + newX + "," + newY);
}
+ mMuteInput = true;
break;
- }
-
- if (endDrag) {
- if (DEBUG_DRAG)
- Slog.d(TAG_WM, "Drag ended; tearing down state");
- // tell all the windows that the drag has ended
- // endDragLocked will post back to looper to dispose the receiver
- // since we still need the receiver for the last finishInputEvent.
- mDragDropController.mDragState.endDragLocked();
- mStylusButtonDownAtStart = false;
- mIsStartEvent = true;
- }
-
- handled = true;
+ case ACTION_CANCEL:
+ if (DEBUG_DRAG) Slog.d(TAG_WM, "Drag cancelled!");
+ mMuteInput = true;
+ break;
+ default:
+ return;
}
+
+ mDragDropController.handleMotionEvent(!mMuteInput /* keepHandling */, newX, newY);
+ handled = true;
} catch (Exception e) {
Slog.e(TAG_WM, "Exception caught by drag handleMotion", e);
} finally {
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 861fb443b6d0..e81d366bd85a 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -105,6 +105,11 @@ class DragState {
WindowState mTargetWindow;
ArrayList<WindowState> mNotifiedWindows;
boolean mDragInProgress;
+ /**
+ * Whether if animation is completed. Needs to be volatile to update from the animation thread
+ * without having a WM lock.
+ */
+ volatile boolean mAnimationCompleted = false;
DisplayContent mDisplayContent;
@Nullable private ValueAnimator mAnimator;
@@ -122,21 +127,79 @@ class DragState {
mNotifiedWindows = new ArrayList<WindowState>();
}
- void reset() {
- if (mAnimator != null) {
- Slog.wtf(TAG_WM,
- "Unexpectedly destroying mSurfaceControl while animation is running");
+ /**
+ * After calling this, DragDropController#onDragStateClosedLocked is invoked, which causes
+ * DragDropController#mDragState becomes null.
+ */
+ void closeLocked() {
+ // Unregister the input interceptor.
+ if (mInputInterceptor != null) {
+ if (DEBUG_DRAG)
+ Slog.d(TAG_WM, "unregistering drag input channel");
+
+ // Input channel should be disposed on the thread where the input is being handled.
+ mDragDropController.sendHandlerMessage(
+ MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT, mInputInterceptor);
+ mInputInterceptor = null;
+ mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
+ }
+
+ // Send drag end broadcast if drag start has been sent.
+ if (mDragInProgress) {
+ final int myPid = Process.myPid();
+
+ if (DEBUG_DRAG) {
+ Slog.d(TAG_WM, "broadcasting DRAG_ENDED");
+ }
+ for (WindowState ws : mNotifiedWindows) {
+ float x = 0;
+ float y = 0;
+ if (!mDragResult && (ws.mSession.mPid == mPid)) {
+ // Report unconsumed drop location back to the app that started the drag.
+ x = mCurrentX;
+ y = mCurrentY;
+ }
+ DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
+ x, y, null, null, null, null, mDragResult);
+ try {
+ ws.mClient.dispatchDragEvent(evt);
+ } catch (RemoteException e) {
+ Slog.w(TAG_WM, "Unable to drag-end window " + ws);
+ }
+ // if the current window is in the same process,
+ // the dispatch has already recycled the event
+ if (myPid != ws.mSession.mPid) {
+ evt.recycle();
+ }
+ }
+ mNotifiedWindows.clear();
+ mDragInProgress = false;
+ }
+
+ // Take the cursor back if it has been changed.
+ if (isFromSource(InputDevice.SOURCE_MOUSE)) {
+ mService.restorePointerIconLocked(mDisplayContent, mCurrentX, mCurrentY);
+ mTouchSource = 0;
}
+
+ // Clear the internal variables.
if (mSurfaceControl != null) {
mSurfaceControl.destroy();
+ mSurfaceControl = null;
+ }
+ if (mAnimator != null && !mAnimationCompleted) {
+ Slog.wtf(TAG_WM,
+ "Unexpectedly destroying mSurfaceControl while animation is running");
}
- mSurfaceControl = null;
mFlags = 0;
mLocalWin = null;
mToken = null;
mData = null;
mThumbOffsetX = mThumbOffsetY = 0;
mNotifiedWindows = null;
+
+ // Notifies the controller that the drag state is closed.
+ mDragDropController.onDragStateClosedLocked(this);
}
class InputInterceptor {
@@ -151,7 +214,7 @@ class DragState {
mClientChannel = channels[1];
mService.mInputManager.registerInputChannel(mServerChannel, null);
mInputEventReceiver = new DragInputEventReceiver(mClientChannel,
- mService.mH.getLooper(), mDragDropController, mService);
+ mService.mH.getLooper(), mDragDropController);
mDragApplicationHandle = new InputApplicationHandle(null);
mDragApplicationHandle.name = "drag";
@@ -235,19 +298,6 @@ class DragState {
}
}
- void unregister() {
- if (DEBUG_DRAG) Slog.d(TAG_WM, "unregistering drag input channel");
- if (mInputInterceptor == null) {
- Slog.e(TAG_WM, "Unregister of nonexistent drag input channel");
- } else {
- // Input channel should be disposed on the thread where the input is being handled.
- mDragDropController.sendHandlerMessage(
- MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT, mInputInterceptor);
- mInputInterceptor = null;
- mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
- }
- }
-
int getDragLayerLocked() {
return mService.mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_DRAG)
* WindowManagerService.TYPE_LAYER_MULTIPLIER
@@ -366,46 +416,15 @@ class DragState {
return false;
}
- private void broadcastDragEndedLocked() {
- final int myPid = Process.myPid();
-
- if (DEBUG_DRAG) {
- Slog.d(TAG_WM, "broadcasting DRAG_ENDED");
- }
- for (WindowState ws : mNotifiedWindows) {
- float x = 0;
- float y = 0;
- if (!mDragResult && (ws.mSession.mPid == mPid)) {
- // Report unconsumed drop location back to the app that started the drag.
- x = mCurrentX;
- y = mCurrentY;
- }
- DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
- x, y, null, null, null, null, mDragResult);
- try {
- ws.mClient.dispatchDragEvent(evt);
- } catch (RemoteException e) {
- Slog.w(TAG_WM, "Unable to drag-end window " + ws);
- }
- // if the current window is in the same process,
- // the dispatch has already recycled the event
- if (myPid != ws.mSession.mPid) {
- evt.recycle();
- }
- }
- mNotifiedWindows.clear();
- mDragInProgress = false;
- }
-
void endDragLocked() {
if (mAnimator != null) {
return;
}
if (!mDragResult) {
mAnimator = createReturnAnimationLocked();
- return; // Will call cleanUpDragLw when the animation is done.
+ return; // Will call closeLocked() when the animation is done.
}
- cleanUpDragLocked();
+ closeLocked();
}
void cancelDragLocked() {
@@ -414,33 +433,15 @@ class DragState {
}
if (!mDragInProgress) {
// This can happen if an app invokes Session#cancelDragAndDrop before
- // Session#performDrag. Reset the drag state:
- // 1. without sending the end broadcast because the start broadcast has not been sent,
- // and
- // 2. without playing the cancel animation because H.DRAG_START_TIMEOUT may be sent to
- // WindowManagerService, which will cause DragState#reset() while playing the
- // cancel animation.
- reset();
- mDragDropController.mDragState = null;
+ // Session#performDrag. Reset the drag state without playing the cancel animation
+ // because H.DRAG_START_TIMEOUT may be sent to WindowManagerService, which will cause
+ // DragState#reset() while playing the cancel animation.
+ closeLocked();
return;
}
mAnimator = createCancelAnimationLocked();
}
- private void cleanUpDragLocked() {
- broadcastDragEndedLocked();
- if (isFromSource(InputDevice.SOURCE_MOUSE)) {
- mService.restorePointerIconLocked(mDisplayContent, mCurrentX, mCurrentY);
- }
-
- // stop intercepting input
- unregister();
-
- // free our resources and drop all the object references
- reset();
- mDragDropController.mDragState = null;
- }
-
void notifyMoveLocked(float x, float y) {
if (mAnimator != null) {
return;
@@ -507,34 +508,33 @@ class DragState {
mTargetWindow = touchedWin;
}
- // Find the drop target and tell it about the data. Returns 'true' if we can immediately
- // dispatch the global drag-ended message, 'false' if we need to wait for a
- // result from the recipient.
- boolean notifyDropLocked(float x, float y) {
+ /**
+ * Finds the drop target and tells it about the data. If the drop event is not sent to the
+ * target, invokes {@code endDragLocked} immediately.
+ */
+ void notifyDropLocked(float x, float y) {
if (mAnimator != null) {
- return false;
+ return;
}
mCurrentX = x;
mCurrentY = y;
- WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
+ final WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
if (!isWindowNotified(touchedWin)) {
// "drop" outside a valid window -- no recipient to apply a
// timeout to, and we can send the drag-ended message immediately.
mDragResult = false;
- return true;
+ endDragLocked();
+ return;
}
- if (DEBUG_DRAG) {
- Slog.d(TAG_WM, "sending DROP to " + touchedWin);
- }
+ if (DEBUG_DRAG) Slog.d(TAG_WM, "sending DROP to " + touchedWin);
final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid());
- DragAndDropPermissionsHandler dragAndDropPermissions = null;
- if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 &&
- (mFlags & DRAG_FLAGS_URI_ACCESS) != 0) {
+ final DragAndDropPermissionsHandler dragAndDropPermissions;
+ if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0) {
dragAndDropPermissions = new DragAndDropPermissionsHandler(
mData,
mUid,
@@ -542,13 +542,15 @@ class DragState {
mFlags & DRAG_FLAGS_URI_PERMISSIONS,
mSourceUserId,
targetUserId);
+ } else {
+ dragAndDropPermissions = null;
}
if (mSourceUserId != targetUserId){
mData.fixUris(mSourceUserId);
}
final int myPid = Process.myPid();
final IBinder token = touchedWin.mClient.asBinder();
- DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
+ final DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
null, null, mData, dragAndDropPermissions, false);
try {
touchedWin.mClient.dispatchDragEvent(evt);
@@ -557,23 +559,13 @@ class DragState {
mDragDropController.sendTimeoutMessage(MSG_DRAG_END_TIMEOUT, token);
} catch (RemoteException e) {
Slog.w(TAG_WM, "can't send drop notification to win " + touchedWin);
- return true;
+ endDragLocked();
} finally {
if (myPid != touchedWin.mSession.mPid) {
evt.recycle();
}
}
mToken = token;
- return false;
- }
-
- void onAnimationEndLocked() {
- if (mAnimator == null) {
- Slog.wtf(TAG_WM, "Unexpected null mAnimator");
- return;
- }
- mAnimator = null;
- cleanUpDragLocked();
}
private static DragEvent obtainDragEvent(WindowState win, int action,
@@ -677,6 +669,7 @@ class DragState {
@Override
public void onAnimationEnd(Animator animator) {
+ mAnimationCompleted = true;
// Updating mDragState requires the WM lock so continues it on the out of
// AnimationThread.
mDragDropController.sendHandlerMessage(MSG_ANIMATION_END, null);
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 40eab45a26d9..a766097c7078 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -381,7 +381,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
Log.d(TAG_WM, "Inserting drag window");
}
final InputWindowHandle dragWindowHandle =
- mService.mDragDropController.mDragState.getInputWindowHandle();
+ mService.mDragDropController.getInputWindowHandleLocked();
if (dragWindowHandle != null) {
addInputWindowHandle(dragWindowHandle);
} else {
@@ -698,7 +698,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
// If there's a drag in progress and 'child' is a potential drop target,
// make sure it's been told about the drag
if (inDrag && isVisible && w.getDisplayContent().isDefaultDisplay) {
- mService.mDragDropController.mDragState.sendDragStartedIfNeededLocked(w);
+ mService.mDragDropController.sendDragStartedIfNeededLocked(w);
}
addInputWindowHandle(
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 365366ada504..d8726bfc2c20 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -149,6 +149,9 @@ class PinnedStackController {
@Override
public void binderDied() {
// Clean up the state if the listener dies
+ if (mPinnedStackListener != null) {
+ mPinnedStackListener.asBinder().unlinkToDeath(mPinnedStackListenerDeathHandler, 0);
+ }
mPinnedStackListener = null;
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index bcb6e6736d04..f541926ea304 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -247,7 +247,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
if (mService.mDisplayManagerInternal != null) {
mService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
displayId, displayInfo);
- mService.configureDisplayPolicyLocked(dc);
+ dc.configureDisplayPolicy();
// Tap Listeners are supported for:
// 1. All physical displays (multi-display).
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
index aff1bc62563f..95c1d536123f 100644
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ b/services/core/java/com/android/server/wm/StackWindowController.java
@@ -225,11 +225,13 @@ public class StackWindowController
}
}
- private void getRawBounds(Rect outBounds) {
- if (mContainer.getRawFullscreen()) {
- outBounds.setEmpty();
- } else {
- mContainer.getRawBounds(outBounds);
+ public void getRawBounds(Rect outBounds) {
+ synchronized (mWindowMap) {
+ if (mContainer.getRawFullscreen()) {
+ outBounds.setEmpty();
+ } else {
+ mContainer.getRawBounds(outBounds);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 6e89e3ea37bb..053fb47023e1 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -442,7 +442,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
mTmpRect2.set(mBounds);
mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
if (inSplitScreenPrimaryWindowingMode()) {
- repositionDockedStackAfterRotation(mTmpRect2);
+ repositionPrimarySplitScreenStackAfterRotation(mTmpRect2);
snapDockedStackAfterRotation(mTmpRect2);
final int newDockSide = getDockSide(mTmpRect2);
@@ -466,14 +466,14 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
}
/**
- * Some dock sides are not allowed by the policy. This method queries the policy and moves
- * the docked stack around if needed.
+ * Some primary split screen sides are not allowed by the policy. This method queries the policy
+ * and moves the primary stack around if needed.
*
- * @param inOutBounds the bounds of the docked stack to adjust
+ * @param inOutBounds the bounds of the primary stack to adjust
*/
- private void repositionDockedStackAfterRotation(Rect inOutBounds) {
+ private void repositionPrimarySplitScreenStackAfterRotation(Rect inOutBounds) {
int dockSide = getDockSide(inOutBounds);
- if (mService.mPolicy.isDockSideAllowed(dockSide)) {
+ if (mDisplayContent.getDockedDividerController().canPrimaryStackDockTo(dockSide)) {
return;
}
mDisplayContent.getLogicalDisplayRect(mTmpRect);
@@ -603,6 +603,14 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
} else {
maxPosition = computeMaxPosition(maxPosition);
}
+
+ // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid.
+ if (targetPosition == POSITION_BOTTOM && minPosition == 0) {
+ return POSITION_BOTTOM;
+ } else if (targetPosition == POSITION_TOP
+ && maxPosition == (addingNew ? stackSize : stackSize - 1)) {
+ return POSITION_TOP;
+ }
// Reset position based on minimum/maximum possible positions.
return Math.min(Math.max(targetPosition, minPosition), maxPosition);
}
@@ -677,9 +685,12 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
public void onConfigurationChanged(Configuration newParentConfig) {
final int prevWindowingMode = getWindowingMode();
super.onConfigurationChanged(newParentConfig);
- if (mDisplayContent != null && prevWindowingMode != getWindowingMode()) {
- mDisplayContent.onStackWindowingModeChanged(this);
+ final int windowingMode = getWindowingMode();
+ if (mDisplayContent == null || prevWindowingMode == windowingMode) {
+ return;
}
+ mDisplayContent.onStackWindowingModeChanged(this);
+ updateBoundsForWindowModeChange();
}
@Override
@@ -691,39 +702,41 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
mDisplayContent = dc;
mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId(),
"animation background stackId=" + mStackId);
+ updateBoundsForWindowModeChange();
+ super.onDisplayChanged(dc);
+ }
+ private void updateBoundsForWindowModeChange() {
Rect bounds = null;
- final TaskStack dockedStack = dc.getSplitScreenPrimaryStackIgnoringVisibility();
- if (inSplitScreenPrimaryWindowingMode()
- || (dockedStack != null && inSplitScreenSecondaryWindowingMode()
- && !dockedStack.fillsParent())) {
+ final boolean inSplitScreenPrimary = inSplitScreenPrimaryWindowingMode();
+ final TaskStack splitScreenStack =
+ mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
+ if (inSplitScreenPrimary || (splitScreenStack != null
+ && inSplitScreenSecondaryWindowingMode() && !splitScreenStack.fillsParent())) {
// The existence of a docked stack affects the size of other static stack created since
// the docked stack occupies a dedicated region on screen, but only if the dock stack is
// not fullscreen. If it's fullscreen, it means that we are in the transition of
// dismissing it, so we must not resize this stack.
bounds = new Rect();
- dc.getLogicalDisplayRect(mTmpRect);
+ mDisplayContent.getLogicalDisplayRect(mTmpRect);
mTmpRect2.setEmpty();
- if (dockedStack != null) {
- dockedStack.getRawBounds(mTmpRect2);
+ if (splitScreenStack != null) {
+ splitScreenStack.getRawBounds(mTmpRect2);
}
final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode
== SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
getStackDockedModeBounds(mTmpRect, bounds, mTmpRect2,
- mDisplayContent.mDividerControllerLocked.getContentWidth(),
- dockedOnTopOrLeft);
+ mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
} else if (inPinnedWindowingMode()) {
// Update the bounds based on any changes to the display info
getAnimationOrCurrentBounds(mTmpRect2);
- boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged(
- mTmpRect2, mTmpRect3);
- if (updated) {
+ if (mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged(
+ mTmpRect2, mTmpRect3)) {
bounds = new Rect(mTmpRect3);
}
}
updateDisplayInfo(bounds);
- super.onDisplayChanged(dc);
}
/**
@@ -914,10 +927,6 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
mAnimationBackgroundSurface = null;
}
- if (inSplitScreenPrimaryWindowingMode()) {
- mDisplayContent.mDividerControllerLocked.notifyDockedStackExistsChanged(false);
- }
-
mDisplayContent = null;
mService.mWindowPlacerLocked.requestTraversal();
}
diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
index 65f8cdf3acc0..b3bb0b7e001d 100644
--- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
@@ -103,6 +103,10 @@ public class TaskWindowContainerController
}
}
+ public void positionChildAtTop(AppWindowContainerController childController) {
+ positionChildAt(childController, POSITION_TOP);
+ }
+
public void positionChildAt(AppWindowContainerController childController, int position) {
synchronized(mService.mWindowMap) {
final AppWindowToken aToken = childController.mContainer;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index bf5f4bc83e6c..ce3430615df6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -124,7 +124,9 @@ import android.app.ActivityManagerInternal;
import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.app.IActivityManager;
+import android.app.IAssistDataReceiver;
import android.content.BroadcastReceiver;
+import android.content.ClipData;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -158,6 +160,7 @@ import android.os.Message;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.RemoteException;
@@ -224,7 +227,6 @@ import android.view.animation.Animation;
import android.view.inputmethod.InputMethodManagerInternal;
import com.android.internal.R;
-import com.android.internal.app.IAssistDataReceiver;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -243,7 +245,7 @@ import com.android.server.LocalServices;
import com.android.server.UiThread;
import com.android.server.Watchdog;
import com.android.server.input.InputManagerService;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
+import android.view.DisplayFrames;
import com.android.server.power.ShutdownThread;
import com.android.server.utils.PriorityDump;
@@ -568,6 +570,8 @@ public class WindowManagerService extends IWindowManager.Stub
boolean mForceResizableTasks = false;
boolean mSupportsPictureInPicture = false;
+ private boolean mDisableTransitionAnimation = false;
+
int getDragLayerLocked() {
return mPolicy.getWindowLayerFromTypeLw(TYPE_DRAG) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
}
@@ -965,6 +969,8 @@ public class WindowManagerService extends IWindowManager.Stub
com.android.internal.R.bool.config_allowAnimationsInLowPowerMode);
mMaxUiWidth = context.getResources().getInteger(
com.android.internal.R.integer.config_maxUiWidth);
+ mDisableTransitionAnimation = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_disableTransitionAnimation);
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mDisplaySettings = new DisplaySettings();
@@ -1320,7 +1326,10 @@ public class WindowManagerService extends IWindowManager.Stub
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
- mPolicy.adjustWindowParamsLw(win.mAttrs);
+ final boolean hasStatusBarServicePermission =
+ mContext.checkCallingOrSelfPermission(permission.STATUS_BAR_SERVICE)
+ == PackageManager.PERMISSION_GRANTED;
+ mPolicy.adjustWindowParamsLw(win, win.mAttrs, hasStatusBarServicePermission);
win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
res = mPolicy.prepareAddWindowLw(win, attrs);
@@ -1444,23 +1453,19 @@ public class WindowManagerService extends IWindowManager.Stub
prepareNoneTransitionForRelaunching(atoken);
}
- if (displayContent.isDefaultDisplay) {
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final Rect taskBounds;
- if (atoken != null && atoken.getTask() != null) {
- taskBounds = mTmpRect;
- atoken.getTask().getBounds(mTmpRect);
- } else {
- taskBounds = null;
- }
- if (mPolicy.getInsetHintLw(win.mAttrs, taskBounds, displayInfo.rotation,
- displayInfo.logicalWidth, displayInfo.logicalHeight, outContentInsets,
- outStableInsets, outOutsets)) {
- res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR;
- }
+ final DisplayFrames displayFrames = displayContent.mDisplayFrames;
+ // TODO: Not sure if onDisplayInfoUpdated() call is needed.
+ displayFrames.onDisplayInfoUpdated(displayContent.getDisplayInfo());
+ final Rect taskBounds;
+ if (atoken != null && atoken.getTask() != null) {
+ taskBounds = mTmpRect;
+ atoken.getTask().getBounds(mTmpRect);
} else {
- outContentInsets.setEmpty();
- outStableInsets.setEmpty();
+ taskBounds = null;
+ }
+ if (mPolicy.getInsetHintLw(win.mAttrs, taskBounds, displayFrames, outContentInsets,
+ outStableInsets, outOutsets)) {
+ res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR;
}
if (mInTouchMode) {
@@ -1846,8 +1851,11 @@ public class WindowManagerService extends IWindowManager.Stub
MergedConfiguration mergedConfiguration, Surface outSurface) {
int result = 0;
boolean configChanged;
- boolean hasStatusBarPermission =
- mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+ final boolean hasStatusBarPermission =
+ mContext.checkCallingOrSelfPermission(permission.STATUS_BAR)
+ == PackageManager.PERMISSION_GRANTED;
+ final boolean hasStatusBarServicePermission =
+ mContext.checkCallingOrSelfPermission(permission.STATUS_BAR_SERVICE)
== PackageManager.PERMISSION_GRANTED;
long origId = Binder.clearCallingIdentity();
@@ -1867,7 +1875,7 @@ public class WindowManagerService extends IWindowManager.Stub
int attrChanges = 0;
int flagChanges = 0;
if (attrs != null) {
- mPolicy.adjustWindowParamsLw(attrs);
+ mPolicy.adjustWindowParamsLw(win, attrs, hasStatusBarServicePermission);
// if they don't have the permission, mask out the status bar bits
if (seq == win.mSeq) {
int systemUiVisibility = attrs.systemUiVisibility
@@ -2272,6 +2280,14 @@ public class WindowManagerService extends IWindowManager.Stub
boolean applyAnimationLocked(AppWindowToken atoken, WindowManager.LayoutParams lp,
int transit, boolean enter, boolean isVoiceInteraction) {
+ if (mDisableTransitionAnimation) {
+ if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
+ Slog.v(TAG_WM,
+ "applyAnimation: transition animation is disabled. atoken=" + atoken);
+ }
+ atoken.mAppAnimator.clearAnimation();
+ return false;
+ }
// 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
@@ -2910,10 +2926,9 @@ public class WindowManagerService extends IWindowManager.Stub
}
public void setKeyguardGoingAway(boolean keyguardGoingAway) {
-// TODO: Use of this can be removed. Revert ag/I8369723d6a77f2c602f1ef080371fa7cd9ee094e
-// synchronized (mWindowMap) {
-// mKeyguardGoingAway = keyguardGoingAway;
-// }
+ synchronized (mWindowMap) {
+ mKeyguardGoingAway = keyguardGoingAway;
+ }
}
// -------------------------------------------------------------
@@ -4650,7 +4665,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TOUCHSCREEN);
- configureDisplayPolicyLocked(getDefaultDisplayContentLocked());
+ getDefaultDisplayContentLocked().configureDisplayPolicy();
}
try {
@@ -5507,7 +5522,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (!mDisplayReady) {
return;
}
- configureDisplayPolicyLocked(displayContent);
+ displayContent.configureDisplayPolicy();
displayContent.setLayoutNeeded();
final int displayId = displayContent.getDisplayId();
@@ -5528,18 +5543,6 @@ public class WindowManagerService extends IWindowManager.Stub
mWindowPlacerLocked.performSurfacePlacement();
}
- void configureDisplayPolicyLocked(DisplayContent displayContent) {
- mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
- displayContent.mBaseDisplayWidth,
- displayContent.mBaseDisplayHeight,
- displayContent.mBaseDisplayDensity);
-
- DisplayInfo displayInfo = displayContent.getDisplayInfo();
- mPolicy.setDisplayOverscan(displayContent.getDisplay(),
- displayInfo.overscanLeft, displayInfo.overscanTop,
- displayInfo.overscanRight, displayInfo.overscanBottom);
- }
-
/**
* Get an array with display ids ordered by focus priority - last items should be given
* focus first. Sparse array just maps position to displayId.
@@ -6857,11 +6860,16 @@ public class WindowManagerService extends IWindowManager.Stub
public void setWillReplaceWindow(IBinder token, boolean animate) {
synchronized (mWindowMap) {
final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token);
- if (appWindowToken == null || !appWindowToken.hasContentToDisplay()) {
+ if (appWindowToken == null) {
Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
+ token);
return;
}
+ if (!appWindowToken.hasContentToDisplay()) {
+ Slog.w(TAG_WM, "Attempted to set replacing window on app token with no content"
+ + token);
+ return;
+ }
appWindowToken.setWillReplaceWindows(animate);
}
}
@@ -6881,11 +6889,16 @@ public class WindowManagerService extends IWindowManager.Stub
void setWillReplaceWindows(IBinder token, boolean childrenOnly) {
synchronized (mWindowMap) {
final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token);
- if (appWindowToken == null || !appWindowToken.hasContentToDisplay()) {
+ if (appWindowToken == null) {
Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
+ token);
return;
}
+ if (!appWindowToken.hasContentToDisplay()) {
+ Slog.w(TAG_WM, "Attempted to set replacing window on app token with no content"
+ + token);
+ return;
+ }
if (childrenOnly) {
appWindowToken.setWillReplaceChildWindows();
@@ -7081,7 +7094,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
synchronized (mWindowMap) {
- if (mDragDropController.mDragState != null) {
+ if (mDragDropController.dragDropActiveLocked()) {
// Drag cursor overrides the app cursor.
return;
}
@@ -7272,11 +7285,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public boolean isKeyguardGoingAway() {
- return WindowManagerService.this.mKeyguardGoingAway;
- }
-
- @Override
public boolean isKeyguardShowingAndNotOccluded() {
return WindowManagerService.this.isKeyguardShowingAndNotOccluded();
}
@@ -7357,7 +7365,9 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public int getInputMethodWindowVisibleHeight() {
synchronized (mWindowMap) {
- return mPolicy.getInputMethodWindowVisibleHeightLw();
+ // TODO(multi-display): Have caller pass in the display they are interested in.
+ final DisplayContent dc = getDefaultDisplayContentLocked();
+ return dc.mDisplayFrames.getInputMethodWindowVisibleHeight();
}
}
@@ -7441,6 +7451,11 @@ public class WindowManagerService extends IWindowManager.Stub
mVr2dDisplayId = vr2dDisplayId;
}
}
+
+ @Override
+ public void registerDragDropControllerCallback(IDragDropCallback callback) {
+ mDragDropController.registerCallback(callback);
+ }
}
void registerAppFreezeListener(AppFreezeListener listener) {
diff --git a/services/core/jni/BroadcastRadio/Tuner.cpp b/services/core/jni/BroadcastRadio/Tuner.cpp
index 6403a5a0f35a..df53feeaf8fa 100644
--- a/services/core/jni/BroadcastRadio/Tuner.cpp
+++ b/services/core/jni/BroadcastRadio/Tuner.cpp
@@ -51,8 +51,9 @@ using V1_0::Band;
using V1_0::BandConfig;
using V1_0::MetaData;
using V1_0::Result;
-using V1_2::ITunerCallback;
using V1_1::ProgramListResult;
+using V1_1::VendorKeyValue;
+using V1_2::ITunerCallback;
using utils::HalRevision;
static mutex gContextMutex;
@@ -93,6 +94,7 @@ struct TunerContext {
wp<V1_1::IBroadcastRadio> mHalModule11;
sp<V1_0::ITuner> mHalTuner;
sp<V1_1::ITuner> mHalTuner11;
+ sp<V1_2::ITuner> mHalTuner12;
sp<HalDeathRecipient> mHalDeathRecipient;
private:
@@ -179,8 +181,11 @@ void assignHalInterfaces(JNIEnv *env, JavaRef<jobject> const &jTuner,
ctx.mHalTuner = halTuner;
ctx.mHalTuner11 = V1_1::ITuner::castFrom(halTuner).withDefault(nullptr);
+ ctx.mHalTuner12 = V1_2::ITuner::castFrom(halTuner).withDefault(nullptr);
ALOGW_IF(ctx.mHalRev >= HalRevision::V1_1 && ctx.mHalTuner11 == nullptr,
"Provided tuner does not implement 1.1 HAL");
+ ALOGW_IF(ctx.mHalRev >= HalRevision::V1_2 && ctx.mHalTuner12 == nullptr,
+ "Provided tuner does not implement 1.2 HAL");
ctx.mHalDeathRecipient = new HalDeathRecipient(getNativeCallback(env, jTuner));
halTuner->linkToDeath(ctx.mHalDeathRecipient, 0);
@@ -194,16 +199,21 @@ static sp<V1_0::ITuner> getHalTuner(const TunerContext& ctx) {
return tuner;
}
-sp<V1_0::ITuner> getHalTuner(jlong nativeContext) {
+static sp<V1_0::ITuner> getHalTuner(jlong nativeContext) {
lock_guard<mutex> lk(gContextMutex);
return getHalTuner(getNativeContext(nativeContext));
}
-sp<V1_1::ITuner> getHalTuner11(jlong nativeContext) {
+static sp<V1_1::ITuner> getHalTuner11(jlong nativeContext) {
lock_guard<mutex> lk(gContextMutex);
return getNativeContext(nativeContext).mHalTuner11;
}
+static sp<V1_2::ITuner> getHalTuner12(jlong nativeContext) {
+ lock_guard<mutex> lk(gContextMutex);
+ return getNativeContext(nativeContext).mHalTuner12;
+}
+
sp<ITunerCallback> getNativeCallback(JNIEnv *env, JavaRef<jobject> const &tuner) {
return TunerCallback::getNativeCallback(env,
env->GetObjectField(tuner.get(), gjni.Tuner.tunerCallback));
@@ -233,6 +243,7 @@ static void nativeClose(JNIEnv *env, jobject obj, jlong nativeContext) {
ctx.mHalDeathRecipient = nullptr;
ctx.mHalTuner11 = nullptr;
+ ctx.mHalTuner12 = nullptr;
ctx.mHalTuner = nullptr;
}
@@ -488,6 +499,48 @@ static void nativeSetAnalogForced(JNIEnv *env, jobject obj, jlong nativeContext,
convert::ThrowIfFailed(env, halResult);
}
+static jobject nativeSetParameters(JNIEnv *env, jobject obj, jlong nativeContext, jobject jParameters) {
+ ALOGV("%s", __func__);
+
+ auto halTuner = getHalTuner12(nativeContext);
+ if (halTuner == nullptr) {
+ ALOGI("Parameters are not supported with HAL < 1.2");
+ return nullptr;
+ }
+
+ JavaRef<jobject> jResults = nullptr;
+ auto parameters = convert::VendorInfoToHal(env, jParameters);
+ auto hidlResult = halTuner->setParameters(parameters,
+ [&](const hidl_vec<VendorKeyValue> results) {
+ jResults = convert::VendorInfoFromHal(env, results);
+ });
+
+ if (convert::ThrowIfFailed(env, hidlResult)) return nullptr;
+
+ return jResults.release();
+}
+
+static jobject nativeGetParameters(JNIEnv *env, jobject obj, jlong nativeContext, jobject jKeys) {
+ ALOGV("%s", __func__);
+
+ auto halTuner = getHalTuner12(nativeContext);
+ if (halTuner == nullptr) {
+ ALOGI("Parameters are not supported with HAL < 1.2");
+ return nullptr;
+ }
+
+ JavaRef<jobject> jResults = nullptr;
+ auto keys = convert::StringListToHal(env, jKeys);
+ auto hidlResult = halTuner->getParameters(keys,
+ [&](const hidl_vec<VendorKeyValue> parameters) {
+ jResults = convert::VendorInfoFromHal(env, parameters);
+ });
+
+ if (convert::ThrowIfFailed(env, hidlResult)) return nullptr;
+
+ return jResults.release();
+}
+
static bool nativeIsAntennaConnected(JNIEnv *env, jobject obj, jlong nativeContext) {
ALOGV("%s", __func__);
auto halTuner = getHalTuner(nativeContext);
@@ -525,6 +578,8 @@ static const JNINativeMethod gTunerMethods[] = {
{ "nativeGetImage", "(JI)[B", (void*)nativeGetImage},
{ "nativeIsAnalogForced", "(J)Z", (void*)nativeIsAnalogForced },
{ "nativeSetAnalogForced", "(JZ)V", (void*)nativeSetAnalogForced },
+ { "nativeSetParameters", "(JLjava/util/Map;)Ljava/util/Map;", (void*)nativeSetParameters },
+ { "nativeGetParameters", "(JLjava/util/List;)Ljava/util/Map;", (void*)nativeGetParameters },
{ "nativeIsAntennaConnected", "(J)Z", (void*)nativeIsAntennaConnected },
};
diff --git a/services/core/jni/BroadcastRadio/TunerCallback.cpp b/services/core/jni/BroadcastRadio/TunerCallback.cpp
index ed7c9c4749c8..d624df69a7ff 100644
--- a/services/core/jni/BroadcastRadio/TunerCallback.cpp
+++ b/services/core/jni/BroadcastRadio/TunerCallback.cpp
@@ -70,6 +70,7 @@ static struct {
jmethodID onBackgroundScanAvailabilityChange;
jmethodID onBackgroundScanComplete;
jmethodID onProgramListChanged;
+ jmethodID onParametersUpdated;
} TunerCallback;
} gjni;
@@ -346,7 +347,10 @@ Return<void> NativeCallback::currentProgramInfoChanged(const ProgramInfo& info)
Return<void> NativeCallback::parametersUpdated(const hidl_vec<VendorKeyValue>& parameters) {
ALOGV("%s", __func__);
- // TODO(b/65862441): pass this callback to the front-end
+ mCallbackThread.enqueue([this, parameters](JNIEnv *env) {
+ auto jParameters = convert::VendorInfoFromHal(env, parameters);
+ env->CallVoidMethod(mJCallback, gjni.TunerCallback.onParametersUpdated, jParameters.get());
+ });
return {};
}
@@ -437,6 +441,8 @@ void register_android_server_broadcastradio_TunerCallback(JavaVM *vm, JNIEnv *en
"onBackgroundScanComplete", "()V");
gjni.TunerCallback.onProgramListChanged = GetMethodIDOrDie(env, tunerCbClass,
"onProgramListChanged", "()V");
+ gjni.TunerCallback.onParametersUpdated = GetMethodIDOrDie(env, tunerCbClass,
+ "onParametersUpdated", "(Ljava/util/Map;)V");
auto res = jniRegisterNativeMethods(env, "com/android/server/broadcastradio/TunerCallback",
gTunerCallbackMethods, NELEM(gTunerCallbackMethods));
diff --git a/services/core/jni/BroadcastRadio/convert.cpp b/services/core/jni/BroadcastRadio/convert.cpp
index 8dfa14f126f7..734ce793e833 100644
--- a/services/core/jni/BroadcastRadio/convert.cpp
+++ b/services/core/jni/BroadcastRadio/convert.cpp
@@ -34,6 +34,7 @@ namespace convert {
namespace utils = hardware::broadcastradio::utils;
using hardware::Return;
+using hardware::hidl_string;
using hardware::hidl_vec;
using regions::RegionalBandConfig;
@@ -98,6 +99,11 @@ static struct {
} HashMap;
struct {
+ jmethodID get;
+ jmethodID size;
+ } List;
+
+ struct {
jmethodID put;
} Map;
@@ -145,8 +151,21 @@ static struct {
jclass clazz;
jmethodID cstor;
} ParcelableException;
+
+ struct {
+ jclass clazz;
+ } String;
} gjni;
+static jstring CastToString(JNIEnv *env, jobject obj) {
+ if (env->IsInstanceOf(obj, gjni.String.clazz)) {
+ return static_cast<jstring>(obj);
+ } else {
+ ALOGE("Cast failed, object is not a string");
+ return nullptr;
+ }
+}
+
template <>
bool ThrowIfFailed(JNIEnv *env, const hardware::Return<void> &hidlResult) {
return __ThrowIfFailedHidl(env, hidlResult);
@@ -250,12 +269,26 @@ static JavaRef<jobjectArray> ArrayFromHal(JNIEnv *env, const hidl_vec<T>& vec,
}
static std::string StringFromJava(JNIEnv *env, JavaRef<jstring> &jStr) {
- auto cstr = (jStr == nullptr) ? nullptr : env->GetStringUTFChars(jStr.get(), nullptr);
+ if (jStr == nullptr) return {};
+ auto cstr = env->GetStringUTFChars(jStr.get(), nullptr);
std::string str(cstr);
env->ReleaseStringUTFChars(jStr.get(), cstr);
return str;
}
+hidl_vec<hidl_string> StringListToHal(JNIEnv *env, jobject jList) {
+ auto len = (jList == nullptr) ? 0 : env->CallIntMethod(jList, gjni.List.size);
+ hidl_vec<hidl_string> list(len);
+
+ for (decltype(len) i = 0; i < len; i++) {
+ auto jString = make_javaref(env, CastToString(env, env->CallObjectMethod(
+ jList, gjni.List.get, i)));
+ list[i] = StringFromJava(env, jString);
+ }
+
+ return list;
+}
+
JavaRef<jobject> VendorInfoFromHal(JNIEnv *env, const hidl_vec<VendorKeyValue> &info) {
ALOGV("%s(%s)", __func__, toString(info).substr(0, 100).c_str());
@@ -275,7 +308,10 @@ hidl_vec<VendorKeyValue> VendorInfoToHal(JNIEnv *env, jobject jInfo) {
auto jInfoArr = make_javaref(env, static_cast<jobjectArray>(env->CallStaticObjectMethod(
gjni.Convert.clazz, gjni.Convert.stringMapToNative, jInfo)));
- LOG_FATAL_IF(jInfoArr == nullptr, "Converted array is null");
+ if (jInfoArr == nullptr) {
+ ALOGE("Converted array is null");
+ return {};
+ }
auto len = env->GetArrayLength(jInfoArr.get());
hidl_vec<VendorKeyValue> vec;
@@ -651,6 +687,10 @@ void register_android_server_broadcastradio_convert(JNIEnv *env) {
gjni.HashMap.clazz = MakeGlobalRefOrDie(env, hashMapClass);
gjni.HashMap.cstor = GetMethodIDOrDie(env, hashMapClass, "<init>", "()V");
+ auto listClass = FindClassOrDie(env, "java/util/List");
+ gjni.List.get = GetMethodIDOrDie(env, listClass, "get", "(I)Ljava/lang/Object;");
+ gjni.List.size = GetMethodIDOrDie(env, listClass, "size", "()I");
+
auto mapClass = FindClassOrDie(env, "java/util/Map");
gjni.Map.put = GetMethodIDOrDie(env, mapClass, "put",
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
@@ -713,6 +753,9 @@ void register_android_server_broadcastradio_convert(JNIEnv *env) {
gjni.ParcelableException.clazz = MakeGlobalRefOrDie(env, parcelableExcClass);
gjni.ParcelableException.cstor = GetMethodIDOrDie(env, parcelableExcClass, "<init>",
"(Ljava/lang/Throwable;)V");
+
+ auto stringClass = FindClassOrDie(env, "java/lang/String");
+ gjni.String.clazz = MakeGlobalRefOrDie(env, stringClass);
}
} // namespace android
diff --git a/services/core/jni/BroadcastRadio/convert.h b/services/core/jni/BroadcastRadio/convert.h
index 1fc75f06f38d..b8c55c1f0c62 100644
--- a/services/core/jni/BroadcastRadio/convert.h
+++ b/services/core/jni/BroadcastRadio/convert.h
@@ -35,6 +35,8 @@ namespace convert {
namespace V1_0 = hardware::broadcastradio::V1_0;
namespace V1_1 = hardware::broadcastradio::V1_1;
+hardware::hidl_vec<hardware::hidl_string> StringListToHal(JNIEnv *env, jobject jList);
+
JavaRef<jobject> VendorInfoFromHal(JNIEnv *env, const hardware::hidl_vec<V1_1::VendorKeyValue> &info);
hardware::hidl_vec<V1_1::VendorKeyValue> VendorInfoToHal(JNIEnv *env, jobject jInfo);
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index d4ffa70417e1..3901cebcc787 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -48,6 +48,8 @@ static void android_server_SystemServer_startHidlServices(JNIEnv* env, jobject /
status_t err;
+ configureRpcThreadpool(5, false /* callerWillJoin */);
+
JavaVM *vm;
LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Cannot get Java VM");
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 1f1324acc463..daf3f2fc7486 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1207,6 +1207,13 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject
ALOGE("Unable to initialize GNSS NI interface\n");
}
+ sp<IAGnssRilCallback> aGnssRilCbIface = new AGnssRilCallback();
+ if (agnssRilIface != nullptr) {
+ agnssRilIface->setCallback(aGnssRilCbIface);
+ } else {
+ ALOGI("Unable to Initialize AGnss Ril interface\n");
+ }
+
return JNI_TRUE;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
index 00859311af84..0aaf32cbe275 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
@@ -107,7 +107,8 @@ final class NetworkLogger {
return false;
}
try {
- if (mIpConnectivityMetrics.registerNetdEventCallback(mNetdEventCallback)) {
+ if (mIpConnectivityMetrics.addNetdEventCallback(
+ INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY, mNetdEventCallback)) {
mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
/* allowIo */ false);
mHandlerThread.start();
@@ -138,7 +139,8 @@ final class NetworkLogger {
// logging is forcefully disabled even if unregistering fails
return true;
}
- return mIpConnectivityMetrics.unregisterNetdEventCallback();
+ return mIpConnectivityMetrics.removeNetdEventCallback(
+ INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY);
} catch (RemoteException re) {
Slog.wtf(TAG, "Failed to make remote calls to unregister the callback", re);
return true;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a2c2aeb0fa78..74a7bd4a8c0b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -37,7 +37,6 @@ import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
-import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
import android.os.SystemClock;
@@ -52,7 +51,7 @@ import android.util.Slog;
import android.view.WindowManager;
import com.android.internal.R;
-import com.android.internal.app.NightDisplayController;
+import com.android.internal.app.ColorDisplayController;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BinderInternal;
@@ -69,7 +68,7 @@ import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.coverage.CoverageService;
import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.display.DisplayManagerService;
-import com.android.server.display.NightDisplayService;
+import com.android.server.display.ColorDisplayService;
import com.android.server.dreams.DreamManagerService;
import com.android.server.emergency.EmergencyAffordanceService;
import com.android.server.fingerprint.FingerprintService;
@@ -83,6 +82,7 @@ import com.android.server.media.MediaSessionService;
import com.android.server.media.projection.MediaProjectionManagerService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
+import com.android.server.net.watchlist.NetworkWatchlistService;
import com.android.server.notification.NotificationManagerService;
import com.android.server.oemlock.OemLockService;
import com.android.server.om.OverlayManagerService;
@@ -95,6 +95,7 @@ import com.android.server.pm.OtaDexoptService;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.ShortcutService;
import com.android.server.pm.UserManagerService;
+import com.android.server.pm.crossprofile.CrossProfileAppsService;
import com.android.server.policy.PhoneWindowManager;
import com.android.server.power.PowerManagerService;
import com.android.server.power.ShutdownThread;
@@ -193,6 +194,8 @@ public final class SystemServer {
"com.google.android.clockwork.ThermalObserver";
private static final String WEAR_CONNECTIVITY_SERVICE_CLASS =
"com.google.android.clockwork.connectivity.WearConnectivityService";
+ private static final String WEAR_SIDEKICK_SERVICE_CLASS =
+ "com.google.android.clockwork.sidekick.SidekickService";
private static final String WEAR_DISPLAY_SERVICE_CLASS =
"com.google.android.clockwork.display.WearDisplayService";
private static final String WEAR_LEFTY_SERVICE_CLASS =
@@ -404,10 +407,8 @@ public final class SystemServer {
traceEnd();
}
- // For debug builds, log event loop stalls to dropbox for analysis.
- if (StrictMode.conditionallyEnableDebugLogging()) {
- Slog.i(TAG, "Enabled StrictMode for system server main thread.");
- }
+ StrictMode.initVmDefaults(null);
+
if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
int uptimeMillis = (int) SystemClock.elapsedRealtime();
MetricsLogger.histogram(null, "boot_system_server_ready", uptimeMillis);
@@ -559,6 +560,13 @@ public final class SystemServer {
mSystemServiceManager.startService(LightsService.class);
traceEnd();
+ traceBeginAndSlog("StartSidekickService");
+ // Package manager isn't started yet; need to use SysProp not hardware feature
+ if (SystemProperties.getBoolean("config.enable_sidekick_graphics", false)) {
+ mSystemServiceManager.startService(WEAR_SIDEKICK_SERVICE_CLASS);
+ }
+ traceEnd();
+
// Display manager is needed to provide display metrics before package manager
// starts up.
traceBeginAndSlog("StartDisplayManager");
@@ -658,9 +666,6 @@ public final class SystemServer {
mSystemServiceManager.startService(DropBoxManagerService.class);
traceEnd();
- // First hwbinder call is in BatteryService.
- android.os.HwBinder.startRpcThreadPool(5, false /* callerWillJoin */);
-
traceBeginAndSlog("StartBatteryService");
// Tracks the battery level. Requires LightService.
mSystemServiceManager.startService(BatteryService.class);
@@ -880,6 +885,10 @@ public final class SystemServer {
mSystemServiceManager.startService(IpConnectivityMetrics.class);
traceEnd();
+ traceBeginAndSlog("NetworkWatchlistService");
+ mSystemServiceManager.startService(NetworkWatchlistService.Lifecycle.class);
+ traceEnd();
+
traceBeginAndSlog("PinnerService");
mSystemServiceManager.startService(PinnerService.class);
traceEnd();
@@ -1273,9 +1282,9 @@ public final class SystemServer {
mSystemServiceManager.startService(TwilightService.class);
traceEnd();
- if (NightDisplayController.isAvailable(context)) {
+ if (ColorDisplayController.isAvailable(context)) {
traceBeginAndSlog("StartNightDisplay");
- mSystemServiceManager.startService(NightDisplayService.class);
+ mSystemServiceManager.startService(ColorDisplayService.class);
traceEnd();
}
@@ -1481,6 +1490,10 @@ public final class SystemServer {
traceBeginAndSlog("StartLauncherAppsService");
mSystemServiceManager.startService(LauncherAppsService.class);
traceEnd();
+
+ traceBeginAndSlog("StartCrossProfileAppsService");
+ mSystemServiceManager.startService(CrossProfileAppsService.class);
+ traceEnd();
}
if (!disableMediaProjection) {
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 5c2b66f6b24f..31a1abb39461 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -86,6 +86,14 @@ import libcore.io.IoBridge;
*/
public class ApfFilter {
+ // Helper class for specifying functional filter parameters.
+ public static class ApfConfiguration {
+ public ApfCapabilities apfCapabilities;
+ public boolean multicastFilter;
+ public boolean ieee802_3Filter;
+ public int[] ethTypeBlackList;
+ }
+
// Enums describing the outcome of receiving an RA packet.
private static enum ProcessRaResult {
MATCH, // Received RA matched a known RA
@@ -261,17 +269,16 @@ public class ApfFilter {
private int mIPv4PrefixLength;
@VisibleForTesting
- ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
- IpClient.Callback ipClientCallback, boolean multicastFilter,
- boolean ieee802_3Filter, int[] ethTypeBlackList, IpConnectivityLog log) {
- mApfCapabilities = apfCapabilities;
+ ApfFilter(ApfConfiguration config, NetworkInterface networkInterface,
+ IpClient.Callback ipClientCallback, IpConnectivityLog log) {
+ mApfCapabilities = config.apfCapabilities;
mIpClientCallback = ipClientCallback;
mNetworkInterface = networkInterface;
- mMulticastFilter = multicastFilter;
- mDrop802_3Frames = ieee802_3Filter;
+ mMulticastFilter = config.multicastFilter;
+ mDrop802_3Frames = config.ieee802_3Filter;
// Now fill the black list from the passed array
- mEthTypeBlackList = filterEthTypeBlackList(ethTypeBlackList);
+ mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
mMetricsLog = log;
@@ -1160,9 +1167,10 @@ public class ApfFilter {
* Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
* filtering using APF programs.
*/
- public static ApfFilter maybeCreate(ApfCapabilities apfCapabilities,
- NetworkInterface networkInterface, IpClient.Callback ipClientCallback,
- boolean multicastFilter, boolean ieee802_3Filter, int[] ethTypeBlackList) {
+ public static ApfFilter maybeCreate(ApfConfiguration config,
+ NetworkInterface networkInterface, IpClient.Callback ipClientCallback) {
+ if (config == null) return null;
+ ApfCapabilities apfCapabilities = config.apfCapabilities;
if (apfCapabilities == null || networkInterface == null) return null;
if (apfCapabilities.apfVersionSupported == 0) return null;
if (apfCapabilities.maximumApfProgramSize < 512) {
@@ -1178,8 +1186,7 @@ public class ApfFilter {
Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
return null;
}
- return new ApfFilter(apfCapabilities, networkInterface, ipClientCallback,
- multicastFilter, ieee802_3Filter, ethTypeBlackList, new IpConnectivityLog());
+ return new ApfFilter(config, networkInterface, ipClientCallback, new IpConnectivityLog());
}
public synchronized void shutdown() {
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index 2359fab41260..70983c864ffc 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -310,12 +310,12 @@ public class IpClient extends StateMachine {
return this;
}
- public Builder withIPv6AddrGenModeEUI64() {
+ public Builder withRandomMacAddress() {
mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_EUI64;
return this;
}
- public Builder withIPv6AddrGenModeStablePrivacy() {
+ public Builder withStableMacAddress() {
mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
return this;
}
@@ -1429,15 +1429,15 @@ public class IpClient extends StateMachine {
@Override
public void enter() {
+ ApfFilter.ApfConfiguration apfConfig = new ApfFilter.ApfConfiguration();
+ apfConfig.apfCapabilities = mConfiguration.mApfCapabilities;
+ apfConfig.multicastFilter = mMulticastFiltering;
// Get the Configuration for ApfFilter from Context
- final boolean filter802_3Frames =
+ apfConfig.ieee802_3Filter =
mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
-
- final int[] ethTypeBlackList = mContext.getResources().getIntArray(
- R.array.config_apfEthTypeBlackList);
-
- mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
- mCallback, mMulticastFiltering, filter802_3Frames, ethTypeBlackList);
+ apfConfig.ethTypeBlackList =
+ mContext.getResources().getIntArray(R.array.config_apfEthTypeBlackList);
+ mApfFilter = ApfFilter.maybeCreate(apfConfig, mNetworkInterface, mCallback);
// TODO: investigate the effects of any multicast filtering racing/interfering with the
// rest of this IP configuration startup.
if (mApfFilter == null) {
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index b12cb32cd5f1..38981453e2e1 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -88,16 +88,6 @@ public class IpManager extends IpClient {
return this;
}
@Override
- public Builder withIPv6AddrGenModeEUI64() {
- super.withIPv6AddrGenModeEUI64();
- return this;
- }
- @Override
- public Builder withIPv6AddrGenModeStablePrivacy() {
- super.withIPv6AddrGenModeStablePrivacy();
- return this;
- }
- @Override
public Builder withNetwork(Network network) {
super.withNetwork(network);
return this;
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 58833bee1b98..e8ae020c2728 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -597,6 +597,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
PrintJobStateChangeListenerRecord record =
mPrintJobStateChangeListenerRecords.get(i);
if (record.listener.asBinder().equals(listener.asBinder())) {
+ record.destroy();
mPrintJobStateChangeListenerRecords.remove(i);
break;
}
@@ -639,6 +640,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
ListenerRecord<IPrintServicesChangeListener> record =
mPrintServicesChangeListenerRecords.get(i);
if (record.listener.asBinder().equals(listener.asBinder())) {
+ record.destroy();
mPrintServicesChangeListenerRecords.remove(i);
break;
}
@@ -686,6 +688,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
ListenerRecord<IRecommendationsChangeListener> record =
mPrintServiceRecommendationsChangeListenerRecords.get(i);
if (record.listener.asBinder().equals(listener.asBinder())) {
+ record.destroy();
mPrintServiceRecommendationsChangeListenerRecords.remove(i);
break;
}
@@ -1285,6 +1288,10 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
listener.asBinder().linkToDeath(this, 0);
}
+ public void destroy() {
+ listener.asBinder().unlinkToDeath(this, 0);
+ }
+
@Override
public void binderDied() {
listener.asBinder().unlinkToDeath(this, 0);
@@ -1302,6 +1309,10 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks,
listener.asBinder().linkToDeath(this, 0);
}
+ public void destroy() {
+ listener.asBinder().unlinkToDeath(this, 0);
+ }
+
@Override
public void binderDied() {
listener.asBinder().unlinkToDeath(this, 0);
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
index 322b891116d9..114929ccecfd 100644
--- a/services/robotests/Android.mk
+++ b/services/robotests/Android.mk
@@ -26,13 +26,8 @@ LOCAL_MODULE_TAGS := optional
LOCAL_PRIVILEGED_MODULE := true
LOCAL_STATIC_JAVA_LIBRARIES := \
- frameworks-base-testutils \
services.backup \
- services.core \
- android-support-test \
- mockito-target-minus-junit4 \
- platform-test-annotations \
- truth-prebuilt
+ services.core
include $(BUILD_PACKAGE)
@@ -45,11 +40,15 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src)
# Include the testing libraries (JUnit4 + Robolectric libs).
LOCAL_STATIC_JAVA_LIBRARIES := \
+ 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-prebuilt
+ platform-robolectric-3.1.1-prebuilt
LOCAL_INSTRUMENTATION_FOR := FrameworksServicesLib
LOCAL_MODULE := FrameworksServicesRoboTests
@@ -74,4 +73,5 @@ LOCAL_TEST_PACKAGE := FrameworksServicesLib
LOCAL_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))backup/java
-include prebuilts/misc/common/robolectric/run_robotests.mk
+# TODO(b/69254249): Migrate to Robolectric 3.4.2
+include prebuilts/misc/common/robolectric/3.1.1/run_robotests.mk
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index df989f7d6be5..3c02e23eed2a 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -25,6 +25,20 @@ import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -74,20 +88,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class RankingHelperTest extends NotificationTestCase {
diff --git a/services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java
index cbe9650edc43..8ac6481e69d9 100644
--- a/services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/ZenModeHelperTest.java
@@ -17,7 +17,7 @@
package com.android.server.notification;
import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
+import static junit.framework.TestCase.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -100,5 +100,34 @@ public class ZenModeHelperTest extends NotificationTestCase {
AudioAttributes.USAGE_GAME);
verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
AudioAttributes.USAGE_ASSISTANCE_SONIFICATION);
+ verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+ AudioAttributes.USAGE_UNKNOWN);
+ }
+
+ @Test
+ public void testZenAllCannotBypass() {
+ // Only audio attributes with SUPPRESIBLE_NEVER can bypass
+ mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ mZenModeHelperSpy.mConfig.allowAlarms = false;
+ mZenModeHelperSpy.mConfig.allowMediaSystemOther = false;
+ mZenModeHelperSpy.mConfig.allowReminders = false;
+ mZenModeHelperSpy.mConfig.allowCalls = false;
+ mZenModeHelperSpy.mConfig.allowMessages = false;
+ mZenModeHelperSpy.mConfig.allowEvents = false;
+ mZenModeHelperSpy.mConfig.allowRepeatCallers= false;
+ assertFalse(mZenModeHelperSpy.mConfig.allowAlarms);
+ assertFalse(mZenModeHelperSpy.mConfig.allowMediaSystemOther);
+ assertFalse(mZenModeHelperSpy.mConfig.allowReminders);
+ assertFalse(mZenModeHelperSpy.mConfig.allowCalls);
+ assertFalse(mZenModeHelperSpy.mConfig.allowMessages);
+ assertFalse(mZenModeHelperSpy.mConfig.allowEvents);
+ assertFalse(mZenModeHelperSpy.mConfig.allowRepeatCallers);
+ mZenModeHelperSpy.applyRestrictions();
+
+ for (int usage : AudioAttributes.SDK_USAGES) {
+ boolean shouldMute = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage)
+ != AudioAttributes.SUPPRESSIBLE_NEVER;
+ verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(shouldMute, usage);
+ }
}
}
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 8e41a554b9e3..a2ec23496a03 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -25,7 +25,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
mockito-target-minus-junit4 \
platform-test-annotations \
ShortcutManagerTestUtils \
- truth-prebuilt
+ truth-prebuilt \
+ testng
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 4729d06c61f9..f1e76abf2200 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -55,6 +55,8 @@
<uses-permission android:name="android.permission.DEVICE_POWER" />
<uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" />
<uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
@@ -132,6 +134,8 @@
<activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity2" />
<activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity3" />
+ <activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity" />
+
<activity android:name="com.android.server.pm.ShortcutTestActivity"
android:enabled="true" android:exported="true" />
diff --git a/services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_settings_test1.xml b/services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_settings_test1.xml
new file mode 100644
index 000000000000..bb97e9431f72
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_settings_test1.xml
@@ -0,0 +1,27 @@
+<?xml version='1.0'?>
+<watchlist-settings>
+ <sha256-domain>
+ <!-- test-cc-domain.com -->
+ <hash>8E7DCD2AEB4F364358242BB3F403263E61E3B4AECE4E2500FF28BF32E52FF0F1</hash>
+ <!-- test-cc-match-sha256-only.com -->
+ <hash>F0905DA7549614957B449034C281EF7BDEFDBC2B6E050AD1E78D6DE18FBD0D5F</hash>
+ </sha256-domain>
+ <sha256-ip>
+ <!-- 127.0.0.2 -->
+ <hash>1EDD62868F2767A1FFF68DF0A4CB3C23448E45100715768DB9310B5E719536A1</hash>
+ <!-- 127.0.0.3, match in sha256 only -->
+ <hash>18DD41C9F2E8E4879A1575FB780514EF33CF6E1F66578C4AE7CCA31F49B9F2ED</hash>
+ </sha256-ip>
+ <crc32-domain>
+ <!-- test-cc-domain.com -->
+ <hash>6C67059D</hash>
+ <!-- test-cc-match-crc32-only.com -->
+ <hash>3DC775F8</hash>
+ </crc32-domain>
+ <crc32-ip>
+ <!-- 127.0.0.2 -->
+ <hash>4EBEB612</hash>
+ <!-- 127.0.0.4, match in crc32 only -->
+ <hash>A7DD1327</hash>
+ </crc32-ip>
+</watchlist-settings>
diff --git a/services/tests/servicestests/res/values/strings.xml b/services/tests/servicestests/res/values/strings.xml
index 1253d448f3c9..3ac56bb5d8bc 100644
--- a/services/tests/servicestests/res/values/strings.xml
+++ b/services/tests/servicestests/res/values/strings.xml
@@ -28,4 +28,8 @@
<string name="test_account_type2_authenticator_label">AccountManagerService Test Account Type2</string>
<string name="test_account_type1">com.android.server.accounts.account_manager_service_test.account.type1</string>
<string name="test_account_type2">com.android.server.accounts.account_manager_service_test.account.type2</string>
+
+ <string name="config_batterySaverDeviceSpecificConfig_1"></string>
+ <string name="config_batterySaverDeviceSpecificConfig_2">file-off:/sys/a=1,file-off:/sys/b=2</string>
+ <string name="config_batterySaverDeviceSpecificConfig_3">file-off:/sys/a=3,file-on:/proc/c=4,/abc=3</string>
</resources>
diff --git a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java b/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
index daaad7a8c0b6..106f9e8c2705 100644
--- a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
@@ -36,12 +36,14 @@ import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
+import org.mockito.invocation.InvocationOnMock;
public class BatteryServiceTest extends AndroidTestCase {
@Mock IServiceManager mMockedManager;
@Mock IHealth mMockedHal;
+ @Mock IHealth mMockedHal2;
@Mock BatteryService.HealthServiceWrapper.Callback mCallback;
@Mock BatteryService.HealthServiceWrapper.IServiceManagerSupplier mManagerSupplier;
@@ -56,6 +58,12 @@ public class BatteryServiceTest extends AndroidTestCase {
MockitoAnnotations.initMocks(this);
}
+ @Override
+ public void tearDown() {
+ if (mWrapper != null)
+ mWrapper.getHandlerThread().quitSafely();
+ }
+
public static <T> ArgumentMatcher<T> isOneOf(Collection<T> collection) {
return new ArgumentMatcher<T>() {
@Override public boolean matches(T e) {
@@ -70,42 +78,64 @@ public class BatteryServiceTest extends AndroidTestCase {
private void initForInstances(String... instanceNamesArr) throws Exception {
final Collection<String> instanceNames = Arrays.asList(instanceNamesArr);
doAnswer((invocation) -> {
- Slog.e("BatteryServiceTest", "health: onRegistration " + invocation.getArguments()[2]);
- ((IServiceNotification)invocation.getArguments()[2]).onRegistration(
- IHealth.kInterfaceName,
- (String)invocation.getArguments()[1],
- true /* preexisting */);
+ // technically, preexisting is ignored by
+ // BatteryService.HealthServiceWrapper.Notification, but still call it correctly.
+ sendNotification(invocation, true);
+ sendNotification(invocation, true);
+ sendNotification(invocation, false);
return null;
}).when(mMockedManager).registerForNotifications(
eq(IHealth.kInterfaceName),
argThat(isOneOf(instanceNames)),
any(IServiceNotification.class));
- doReturn(mMockedHal).when(mMockedManager)
- .get(eq(IHealth.kInterfaceName), argThat(isOneOf(instanceNames)));
-
- doReturn(IServiceManager.Transport.HWBINDER).when(mMockedManager)
- .getTransport(eq(IHealth.kInterfaceName), argThat(isOneOf(instanceNames)));
-
doReturn(mMockedManager).when(mManagerSupplier).get();
- doReturn(mMockedHal).when(mHealthServiceSupplier)
- .get(argThat(isOneOf(instanceNames)));
+ doReturn(mMockedHal) // init calls this
+ .doReturn(mMockedHal) // notification 1
+ .doReturn(mMockedHal) // notification 2
+ .doReturn(mMockedHal2) // notification 3
+ .doThrow(new RuntimeException("Should not call getService for more than 4 times"))
+ .when(mHealthServiceSupplier).get(argThat(isOneOf(instanceNames)));
mWrapper = new BatteryService.HealthServiceWrapper();
}
+ private void waitHandlerThreadFinish() throws Exception {
+ for (int i = 0; i < 5; i++) {
+ if (!mWrapper.getHandlerThread().getThreadHandler().hasMessagesOrCallbacks()) {
+ return;
+ }
+ Thread.sleep(300);
+ }
+ assertFalse(mWrapper.getHandlerThread().getThreadHandler().hasMessagesOrCallbacks());
+ }
+
+ private static void sendNotification(InvocationOnMock invocation, boolean preexisting)
+ throws Exception {
+ ((IServiceNotification)invocation.getArguments()[2]).onRegistration(
+ IHealth.kInterfaceName,
+ (String)invocation.getArguments()[1],
+ preexisting);
+ }
+
@SmallTest
public void testWrapPreferVendor() throws Exception {
initForInstances(VENDOR, HEALTHD);
mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier);
- verify(mCallback).onRegistration(same(null), same(mMockedHal), eq(VENDOR));
+ waitHandlerThreadFinish();
+ verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(VENDOR));
+ verify(mCallback, never()).onRegistration(same(mMockedHal), same(mMockedHal), anyString());
+ verify(mCallback, times(1)).onRegistration(same(mMockedHal), same(mMockedHal2), eq(VENDOR));
}
@SmallTest
public void testUseHealthd() throws Exception {
initForInstances(HEALTHD);
mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier);
- verify(mCallback).onRegistration(same(null), same(mMockedHal), eq(HEALTHD));
+ waitHandlerThreadFinish();
+ verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(HEALTHD));
+ verify(mCallback, never()).onRegistration(same(mMockedHal), same(mMockedHal), anyString());
+ verify(mCallback, times(1)).onRegistration(same(mMockedHal), same(mMockedHal2), eq(HEALTHD));
}
@SmallTest
diff --git a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/ColorDisplayServiceTest.java
index 3a92d638fb02..46b364c21559 100644
--- a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ColorDisplayServiceTest.java
@@ -29,10 +29,10 @@ import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.mock.MockContentResolver;
-import com.android.internal.app.NightDisplayController;
+import com.android.internal.app.ColorDisplayController;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.display.DisplayTransformManager;
-import com.android.server.display.NightDisplayService;
+import com.android.server.display.ColorDisplayService;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
@@ -55,15 +55,15 @@ import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.Mockito.doReturn;
@RunWith(AndroidJUnit4.class)
-public class NightDisplayServiceTest {
+public class ColorDisplayServiceTest {
private Context mContext;
private int mUserId;
private MockTwilightManager mTwilightManager;
- private NightDisplayController mNightDisplayController;
- private NightDisplayService mNightDisplayService;
+ private ColorDisplayController mColorDisplayController;
+ private ColorDisplayService mColorDisplayService;
@Before
public void setUp() {
@@ -85,8 +85,8 @@ public class NightDisplayServiceTest {
mTwilightManager = new MockTwilightManager();
LocalServices.addService(TwilightManager.class, mTwilightManager);
- mNightDisplayController = new NightDisplayController(mContext, mUserId);
- mNightDisplayService = new NightDisplayService(mContext);
+ mColorDisplayController = new ColorDisplayController(mContext, mUserId);
+ mColorDisplayService = new ColorDisplayService(mContext);
}
@After
@@ -94,8 +94,8 @@ public class NightDisplayServiceTest {
LocalServices.removeServiceForTest(DisplayTransformManager.class);
LocalServices.removeServiceForTest(TwilightManager.class);
- mNightDisplayService = null;
- mNightDisplayController = null;
+ mColorDisplayService = null;
+ mColorDisplayController = null;
mTwilightManager = null;
@@ -902,9 +902,9 @@ public class NightDisplayServiceTest {
* @param endTimeOffset the offset relative to now to deactivate Night display (in minutes)
*/
private void setAutoModeCustom(int startTimeOffset, int endTimeOffset) {
- mNightDisplayController.setAutoMode(NightDisplayController.AUTO_MODE_CUSTOM);
- mNightDisplayController.setCustomStartTime(getLocalTimeRelativeToNow(startTimeOffset));
- mNightDisplayController.setCustomEndTime(getLocalTimeRelativeToNow(endTimeOffset));
+ mColorDisplayController.setAutoMode(ColorDisplayController.AUTO_MODE_CUSTOM);
+ mColorDisplayController.setCustomStartTime(getLocalTimeRelativeToNow(startTimeOffset));
+ mColorDisplayController.setCustomEndTime(getLocalTimeRelativeToNow(endTimeOffset));
}
/**
@@ -914,7 +914,7 @@ public class NightDisplayServiceTest {
* @param sunriseOffset the offset relative to now for sunrise (in minutes)
*/
private void setAutoModeTwilight(int sunsetOffset, int sunriseOffset) {
- mNightDisplayController.setAutoMode(NightDisplayController.AUTO_MODE_TWILIGHT);
+ mColorDisplayController.setAutoMode(ColorDisplayController.AUTO_MODE_TWILIGHT);
mTwilightManager.setTwilightState(
getTwilightStateRelativeToNow(sunsetOffset, sunriseOffset));
}
@@ -927,7 +927,7 @@ public class NightDisplayServiceTest {
* activated (in minutes)
*/
private void setActivated(boolean activated, int lastActivatedTimeOffset) {
- mNightDisplayController.setActivated(activated);
+ mColorDisplayController.setActivated(activated);
Secure.putStringForUser(mContext.getContentResolver(),
Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
LocalDateTime.now().plusMinutes(lastActivatedTimeOffset).toString(),
@@ -935,7 +935,7 @@ public class NightDisplayServiceTest {
}
/**
- * Convenience method to start {@link #mNightDisplayService}.
+ * Convenience method to start {@link #mColorDisplayService}.
*/
private void startService() {
Secure.putIntForUser(mContext.getContentResolver(), Secure.USER_SETUP_COMPLETE, 1, mUserId);
@@ -943,9 +943,9 @@ public class NightDisplayServiceTest {
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
- mNightDisplayService.onStart();
- mNightDisplayService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
- mNightDisplayService.onStartUser(mUserId);
+ mColorDisplayService.onStart();
+ mColorDisplayService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+ mColorDisplayService.onStartUser(mUserId);
}
});
}
@@ -957,7 +957,7 @@ public class NightDisplayServiceTest {
*/
private void assertActivated(boolean activated) {
assertWithMessage("Invalid Night display activated state")
- .that(mNightDisplayController.isActivated())
+ .that(mColorDisplayController.isActivated())
.isEqualTo(activated);
}
@@ -988,21 +988,21 @@ public class NightDisplayServiceTest {
final LocalDateTime now = LocalDateTime.now();
final ZoneId zoneId = ZoneId.systemDefault();
- long sunsetMillis = NightDisplayService.getDateTimeBefore(sunset, now)
+ long sunsetMillis = ColorDisplayService.getDateTimeBefore(sunset, now)
.atZone(zoneId)
.toInstant()
.toEpochMilli();
- long sunriseMillis = NightDisplayService.getDateTimeBefore(sunrise, now)
+ long sunriseMillis = ColorDisplayService.getDateTimeBefore(sunrise, now)
.atZone(zoneId)
.toInstant()
.toEpochMilli();
if (sunsetMillis < sunriseMillis) {
- sunsetMillis = NightDisplayService.getDateTimeAfter(sunset, now)
+ sunsetMillis = ColorDisplayService.getDateTimeAfter(sunset, now)
.atZone(zoneId)
.toInstant()
.toEpochMilli();
} else {
- sunriseMillis = NightDisplayService.getDateTimeAfter(sunrise, now)
+ sunriseMillis = ColorDisplayService.getDateTimeAfter(sunrise, now)
.atZone(zoneId)
.toInstant()
.toEpochMilli();
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index cb13e85157aa..2b770acf59cc 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -29,6 +29,11 @@ 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.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+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.content.ComponentName;
@@ -156,7 +161,8 @@ public class ActivityRecordTests extends ActivityTestsBase {
record.canBeLaunchedOnDisplay(DEFAULT_DISPLAY);
- assertEquals(((TestActivityStackSupervisor) mService.mStackSupervisor)
- .getLastResizeableFromCanPlaceEntityOnDisplay(), expected);
+
+ verify(mService.mStackSupervisor, times(1)).canPlaceEntityOnDisplay(anyInt(), eq(expected), anyInt(), anyInt(),
+ eq(record.info));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index 480b210c17b8..6b09363cff0b 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -166,6 +166,8 @@ public class ActivityStackTests extends ActivityTestsBase {
final ActivityDisplay display = mService.mStackSupervisor.getDefaultDisplay();
final TestActivityStack homeStack = createStackForShouldBeVisibleTest(display,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
+ // Home stack should always be fullscreen for this test.
+ homeStack.setSupportsSplitScreen(false);
final TestActivityStack splitScreenPrimary = createStackForShouldBeVisibleTest(display,
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final TestActivityStack splitScreenSecondary = createStackForShouldBeVisibleTest(display,
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 5b1e4b731d38..f9933fb63f12 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -16,13 +16,28 @@
package com.android.server.am;
+import static android.app.ActivityManager.START_ABORTED;
+import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
+import static android.app.ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
+import static android.app.ActivityManager.START_NOT_VOICE_COMPATIBLE;
+import static android.app.ActivityManager.START_SUCCESS;
+import static android.app.ActivityManager.START_SWITCHES_CANCELED;
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 android.app.ActivityOptions;
+import android.app.IApplicationThread;
import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
import android.graphics.Rect;
+import android.os.IBinder;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.service.voice.IVoiceInteractionSession;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -36,10 +51,20 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyObject;
+import static org.mockito.Mockito.doAnswer;
+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 static android.app.ActivityManager.START_PERMISSION_DENIED;
+import static android.app.ActivityManager.START_INTENT_NOT_RESOLVED;
+
+import com.android.internal.os.BatteryStatsImpl;
+
/**
* Tests for the {@link ActivityStack} class.
*
@@ -52,12 +77,26 @@ import static org.mockito.Mockito.times;
public class ActivityStarterTests extends ActivityTestsBase {
private ActivityManagerService mService;
private ActivityStarter mStarter;
+ private IPackageManager mPackageManager;
+
+ private static final int PRECONDITION_NO_CALLER_APP = 1;
+ private static final int PRECONDITION_NO_INTENT_COMPONENT = 1 << 1;
+ private static final int PRECONDITION_NO_ACTIVITY_INFO = 1 << 2;
+ private static final int PRECONDITION_SOURCE_PRESENT = 1 << 3;
+ private static final int PRECONDITION_REQUEST_CODE = 1 << 4;
+ private static final int PRECONDITION_SOURCE_VOICE_SESSION = 1 << 5;
+ private static final int PRECONDITION_NO_VOICE_SESSION_SUPPORT = 1 << 6;
+ private static final int PRECONDITION_DIFFERENT_UID = 1 << 7;
+ private static final int PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION = 1 << 8;
+ private static final int PRECONDITION_CANNOT_START_ANY_ACTIVITY = 1 << 9;
+ private static final int PRECONDITION_DISALLOW_APP_SWITCHING = 1 << 10;
@Override
public void setUp() throws Exception {
super.setUp();
mService = createActivityManagerService();
- mStarter = new ActivityStarter(mService);
+ mPackageManager = mock(IPackageManager.class);
+ mStarter = new ActivityStarter(mService, mPackageManager);
}
@Test
@@ -92,4 +131,152 @@ public class ActivityStarterTests extends ActivityTestsBase {
assertEquals(task2.mBounds, null);
}
}
+
+ @Test
+ public void testStartActivityPreconditions() throws Exception {
+ verifyStartActivityPreconditions(PRECONDITION_NO_CALLER_APP, START_PERMISSION_DENIED);
+ verifyStartActivityPreconditions(PRECONDITION_NO_INTENT_COMPONENT,
+ START_INTENT_NOT_RESOLVED);
+ verifyStartActivityPreconditions(PRECONDITION_NO_ACTIVITY_INFO, START_CLASS_NOT_FOUND);
+ verifyStartActivityPreconditions(PRECONDITION_SOURCE_PRESENT | PRECONDITION_REQUEST_CODE,
+ Intent.FLAG_ACTIVITY_FORWARD_RESULT, START_FORWARD_AND_REQUEST_CONFLICT);
+ verifyStartActivityPreconditions(
+ PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
+ | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID,
+ START_NOT_VOICE_COMPATIBLE);
+ verifyStartActivityPreconditions(
+ PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
+ | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID
+ | PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION,
+ START_NOT_VOICE_COMPATIBLE);
+ verifyStartActivityPreconditions(PRECONDITION_CANNOT_START_ANY_ACTIVITY, START_ABORTED);
+ verifyStartActivityPreconditions(PRECONDITION_DISALLOW_APP_SWITCHING,
+ START_SWITCHES_CANCELED);
+ }
+
+ private static boolean containsConditions(int preconditions, int mask) {
+ return (preconditions & mask) == mask;
+ }
+
+ private void verifyStartActivityPreconditions(int preconditions, int expectedResult) {
+ verifyStartActivityPreconditions(preconditions, 0 /*launchFlags*/, expectedResult);
+ }
+
+ /**
+ * Excercises how the {@link ActivityStarter} reacts to various preconditions. The caller
+ * provides a bitmask of all the set conditions (such as {@link #PRECONDITION_NO_CALLER_APP})
+ * 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.
+ * @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.
+ */
+ private void verifyStartActivityPreconditions(int preconditions, int launchFlags,
+ int expectedResult) {
+ final ActivityManagerService service = createActivityManagerService();
+ final IPackageManager packageManager = mock(IPackageManager.class);
+ final ActivityStarter starter = new ActivityStarter(service, packageManager);
+
+ final IApplicationThread caller = mock(IApplicationThread.class);
+
+ // If no caller app, return {@code null} {@link ProcessRecord}.
+ final ProcessRecord record = containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
+ ? null : new ProcessRecord(mock(BatteryStatsImpl.class),
+ mock(ApplicationInfo.class), null, 0);
+
+ doReturn(record).when(service).getRecordForAppLocked(anyObject());
+
+ final Intent intent = new Intent();
+ intent.setFlags(launchFlags);
+
+ final ActivityInfo aInfo = containsConditions(preconditions, PRECONDITION_NO_ACTIVITY_INFO)
+ ? null : new ActivityInfo();
+
+ if (aInfo != null) {
+ aInfo.applicationInfo = new ApplicationInfo();
+ aInfo.applicationInfo.packageName = ActivityBuilder.DEFAULT_PACKAGE;
+ }
+
+ IVoiceInteractionSession voiceSession =
+ containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
+ ? mock(IVoiceInteractionSession.class) : null;
+
+ // Create source token
+ final ActivityBuilder builder = new ActivityBuilder(service).setTask(
+ new TaskBuilder(service.mStackSupervisor).setVoiceSession(voiceSession).build());
+
+ // Offset uid by one from {@link ActivityInfo} to simulate different uids.
+ if (containsConditions(preconditions, PRECONDITION_DIFFERENT_UID)) {
+ builder.setUid(aInfo.applicationInfo.uid + 1);
+ }
+
+ final ActivityRecord source = builder.build();
+
+ if (!containsConditions(preconditions, PRECONDITION_NO_INTENT_COMPONENT)) {
+ intent.setComponent(source.realActivity);
+ }
+
+ if (containsConditions(preconditions, PRECONDITION_DISALLOW_APP_SWITCHING)) {
+ doReturn(false).when(service).checkAppSwitchAllowedLocked(anyInt(), anyInt(), anyInt(),
+ anyInt(), any());
+ }
+
+ if (containsConditions(preconditions,PRECONDITION_CANNOT_START_ANY_ACTIVITY)) {
+ doReturn(false).when(service.mStackSupervisor).checkStartAnyActivityPermission(
+ any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), anyBoolean(),
+ any(), any(), any(), any());
+ }
+
+ try {
+ if (containsConditions(preconditions,
+ PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION)) {
+ doAnswer((inv) -> {
+ throw new RemoteException();
+ }).when(packageManager).activitySupportsIntent(eq(source.realActivity), eq(intent),
+ any());
+ } else {
+ doReturn(!containsConditions(preconditions, PRECONDITION_NO_VOICE_SESSION_SUPPORT))
+ .when(packageManager).activitySupportsIntent(eq(source.realActivity),
+ eq(intent), any());
+ }
+ } catch (RemoteException e) {
+ }
+
+ final IBinder resultTo = containsConditions(preconditions, PRECONDITION_SOURCE_PRESENT)
+ || containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
+ ? source.appToken : null;
+
+ 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");
+
+ // In some cases the expected result internally is different than the published result. We
+ // must use ActivityStarter#getExternalResult to translate.
+ assertEquals(ActivityStarter.getExternalResult(expectedResult), result);
+
+ // Ensure that {@link ActivityOptions} are aborted with unsuccessful result.
+ if (expectedResult != START_SUCCESS) {
+ 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");
+ verify(options, times(1)).abort();
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 198cc6ded558..9c949ad34844 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -21,8 +21,11 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.Display.DEFAULT_DISPLAY;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.spy;
@@ -38,6 +41,7 @@ import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.HandlerThread;
import android.os.Looper;
+import android.service.voice.IVoiceInteractionSession;
import android.support.test.InstrumentationRegistry;
import com.android.server.AttributeCache;
import com.android.server.wm.AppWindowContainerController;
@@ -78,7 +82,10 @@ public class ActivityTestsBase {
}
protected ActivityManagerService createActivityManagerService() {
- return setupActivityManagerService(new TestActivityManagerService(mContext));
+ final ActivityManagerService service =
+ setupActivityManagerService(new TestActivityManagerService(mContext));
+ AttributeCache.init(mContext);
+ return service;
}
protected ActivityManagerService setupActivityManagerService(ActivityManagerService service) {
@@ -95,7 +102,7 @@ public class ActivityTestsBase {
private static int sCurrentActivityId = 0;
// Default package name
- private static final String DEFAULT_PACKAGE = "com.foo";
+ static final String DEFAULT_PACKAGE = "com.foo";
// Default base activity name
private static final String DEFAULT_BASE_ACTIVITY_NAME = ".BarActivity";
@@ -156,7 +163,6 @@ public class ActivityTestsBase {
aInfo.applicationInfo = new ApplicationInfo();
aInfo.applicationInfo.packageName = mComponent.getPackageName();
aInfo.applicationInfo.uid = mUid;
- AttributeCache.init(mService.mContext);
final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
0 /* launchedFromPid */, 0, null, intent, null,
aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */,
@@ -182,6 +188,7 @@ public class ActivityTestsBase {
private String mPackage;
private int mFlags = 0;
private int mTaskId = 0;
+ private IVoiceInteractionSession mVoiceSession;
private ActivityStack mStack;
@@ -199,6 +206,11 @@ public class ActivityTestsBase {
return this;
}
+ TaskBuilder setVoiceSession(IVoiceInteractionSession session) {
+ mVoiceSession = session;
+ return this;
+ }
+
TaskBuilder setFlags(int flags) {
mFlags = flags;
return this;
@@ -229,7 +241,7 @@ public class ActivityTestsBase {
intent.setFlags(mFlags);
final TaskRecord task = new TaskRecord(mSupervisor.mService, mTaskId, aInfo,
- intent /*intent*/, null /*_taskDescription*/);
+ intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/);
mSupervisor.setFocusStackUnchecked("test", mStack);
mStack.addTask(task, true, "creating test task");
task.setStack(mStack);
@@ -255,7 +267,27 @@ public class ActivityTestsBase {
}
@Override
- protected ActivityStackSupervisor createStackSupervisor() {
+ final protected ActivityStackSupervisor createStackSupervisor() {
+ final ActivityStackSupervisor supervisor = spy(createTestSupervisor());
+
+ // No home stack is set.
+ doNothing().when(supervisor).moveHomeStackToFront(any());
+ doReturn(true).when(supervisor).moveHomeStackTaskToTop(any());
+ // Invoked during {@link ActivityStack} creation.
+ doNothing().when(supervisor).updateUIDsPresentOnDisplay();
+ // Always keep things awake.
+ doReturn(true).when(supervisor).hasAwakeDisplay();
+ // Called when moving activity to pinned stack.
+ doNothing().when(supervisor).ensureActivitiesVisibleLocked(any(), anyInt(), anyBoolean());
+ // Do not schedule idle timeouts
+ doNothing().when(supervisor).scheduleIdleTimeoutLocked(any());
+
+ supervisor.initialize();
+
+ return supervisor;
+ }
+
+ protected ActivityStackSupervisor createTestSupervisor() {
return new TestActivityStackSupervisor(this, mHandlerThread.getLooper());
}
@@ -269,14 +301,18 @@ public class ActivityTestsBase {
* setup not available in the test environment. Also specifies an injector for
*/
protected static class TestActivityStackSupervisor extends ActivityStackSupervisor {
- private final ActivityDisplay mDisplay;
- private boolean mLastResizeable;
+ private ActivityDisplay mDisplay;
public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) {
super(service, looper);
mDisplayManager =
(DisplayManager) mService.mContext.getSystemService(Context.DISPLAY_SERVICE);
mWindowManager = prepareMockWindowManager();
+ }
+
+ @Override
+ public void initialize() {
+ super.initialize();
mDisplay = new TestActivityDisplay(this, DEFAULT_DISPLAY);
attachDisplay(mDisplay);
}
@@ -286,54 +322,11 @@ public class ActivityTestsBase {
return mDisplay;
}
- // TODO: Use Mockito spy instead. Currently not possible due to TestActivityStackSupervisor
- // access to ActivityDisplay
- @Override
- boolean canPlaceEntityOnDisplay(int displayId, boolean resizeable, int callingPid,
- int callingUid, ActivityInfo activityInfo) {
- mLastResizeable = resizeable;
- return super.canPlaceEntityOnDisplay(displayId, resizeable, callingPid, callingUid,
- activityInfo);
- }
-
- // TODO: remove and use Mockito verify once {@link #canPlaceEntityOnDisplay} override is
- // removed.
- public boolean getLastResizeableFromCanPlaceEntityOnDisplay() {
- return mLastResizeable;
- }
-
- // No home stack is set.
- @Override
- void moveHomeStackToFront(String reason) {
- }
-
- @Override
- boolean moveHomeStackTaskToTop(String reason) {
- return true;
- }
-
- // Invoked during {@link ActivityStack} creation.
- @Override
- void updateUIDsPresentOnDisplay() {
- }
-
- // Just return the current front task.
+ // Just return the current front task. This is called internally so we cannot use spy to mock this out.
@Override
ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus) {
return mFocusedStack;
}
-
- // Called when moving activity to pinned stack.
- @Override
- void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
- boolean preserveWindows) {
- }
-
- // Always keep things awake
- @Override
- boolean hasAwakeDisplay() {
- return true;
- }
}
private static class TestActivityDisplay extends ActivityDisplay {
@@ -396,6 +389,11 @@ public class ActivityTestsBase {
static final int IS_TRANSLUCENT_TRUE = 2;
private int mIsTranslucent = IS_TRANSLUCENT_UNSET;
+ static final int SUPPORTS_SPLIT_SCREEN_UNSET = 0;
+ static final int SUPPORTS_SPLIT_SCREEN_FALSE = 1;
+ static final int SUPPORTS_SPLIT_SCREEN_TRUE = 2;
+ private int mSupportsSplitScreen = SUPPORTS_SPLIT_SCREEN_UNSET;
+
TestActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
int windowingMode, int activityType, boolean onTop) {
super(display, stackId, supervisor, windowingMode, activityType, onTop);
@@ -439,5 +437,23 @@ public class ActivityTestsBase {
return super.isStackTranslucent(starting);
}
}
+
+ void setSupportsSplitScreen(boolean supportsSplitScreen) {
+ mSupportsSplitScreen = supportsSplitScreen
+ ? SUPPORTS_SPLIT_SCREEN_TRUE : SUPPORTS_SPLIT_SCREEN_FALSE;
+ }
+
+ @Override
+ public boolean supportsSplitScreenWindowingMode() {
+ switch (mSupportsSplitScreen) {
+ case SUPPORTS_SPLIT_SCREEN_TRUE:
+ return true;
+ case SUPPORTS_SPLIT_SCREEN_FALSE:
+ return false;
+ case SUPPORTS_SPLIT_SCREEN_UNSET:
+ default:
+ return super.supportsSplitScreenWindowingMode();
+ }
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java b/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java
index bec46db2b7ab..ce88d849a1d4 100644
--- a/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java
@@ -22,6 +22,7 @@ import static android.app.AppOpsManager.OP_ASSIST_SCREENSHOT;
import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE;
import static android.graphics.Bitmap.Config.ARGB_8888;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -74,6 +75,8 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
private static final boolean CALLER_ASSIST_SCREENSHOT_ALLOWED = true;
private static final boolean FETCH_DATA = true;
private static final boolean FETCH_SCREENSHOTS = true;
+ private static final boolean ALLOW_FETCH_DATA = true;
+ private static final boolean ALLOW_FETCH_SCREENSHOTS = true;
private static final int TEST_UID = 0;
private static final String TEST_PACKAGE = "";
@@ -128,8 +131,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
mHandler.post(() -> {
try {
mGate.await(10, TimeUnit.SECONDS);
- mDataRequester.onHandleAssistScreenshot(Bitmap.createBitmap(1, 1,
- ARGB_8888));
+ mDataRequester.onHandleAssistScreenshot(Bitmap.createBitmap(1, 1, ARGB_8888));
} catch (InterruptedException e) {
Log.e(TAG, "Failed to wait", e);
}
@@ -153,7 +155,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
CALLER_ASSIST_SCREENSHOT_ALLOWED);
mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
assertReceivedDataCount(5, 5, 1, 1);
}
@@ -163,18 +165,18 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
CALLER_ASSIST_SCREENSHOT_ALLOWED);
mDataRequester.requestAssistData(createActivityList(0), FETCH_DATA, FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
assertReceivedDataCount(0, 0, 0, 0);
}
@Test
- public void testCurrentAppDisallow_expectNoCallbacks() throws Exception {
+ public void testCurrentAppDisallow_expectNullCallbacks() throws Exception {
setupMocks(!CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
CALLER_ASSIST_SCREENSHOT_ALLOWED);
mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
- assertReceivedDataCount(0, 0, 0, 0);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
+ assertReceivedDataCount(0, 1, 0, 1);
}
@Test
@@ -184,7 +186,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
mCallbacks.canHandleReceivedData = false;
mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
assertTrue(mDataRequester.getPendingDataCount() == 5);
assertTrue(mDataRequester.getPendingScreenshotCount() == 1);
mGate.countDown();
@@ -195,21 +197,32 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
assertTrue(mDataRequester.getPendingScreenshotCount() == 0);
assertTrue(mCallbacks.receivedData.isEmpty());
assertTrue(mCallbacks.receivedScreenshots.isEmpty());
+ assertFalse(mCallbacks.requestCompleted);
mCallbacks.canHandleReceivedData = true;
mDataRequester.processPendingAssistData();
+ // Since we are posting the callback for the request-complete, flush the handler as well
+ mGate.countDown();
+ waitForIdle(mHandler);
assertTrue(mCallbacks.receivedData.size() == 5);
assertTrue(mCallbacks.receivedScreenshots.size() == 1);
+ assertTrue(mCallbacks.requestCompleted);
+
+ // Clear the state and ensure that we only process pending data once
+ mCallbacks.reset();
+ mDataRequester.processPendingAssistData();
+ assertTrue(mCallbacks.receivedData.isEmpty());
+ assertTrue(mCallbacks.receivedScreenshots.isEmpty());
}
@Test
- public void testNoFetchData_expectNoCallbacks() throws Exception {
+ public void testNoFetchData_expectNoDataCallbacks() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
CALLER_ASSIST_SCREENSHOT_ALLOWED);
mDataRequester.requestAssistData(createActivityList(5), !FETCH_DATA, FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
- assertReceivedDataCount(0, 0, 0, 0);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
+ assertReceivedDataCount(0, 0, 0, 1);
}
@Test
@@ -218,9 +231,9 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
CALLER_ASSIST_SCREENSHOT_ALLOWED);
mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
// Expect a single null data when the appops is denied
- assertReceivedDataCount(0, 1, 0, 0);
+ assertReceivedDataCount(0, 1, 0, 1);
}
@Test
@@ -231,9 +244,9 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
anyBoolean(), anyBoolean());
mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
// Expect a single null data when requestAssistContextExtras() fails
- assertReceivedDataCount(0, 1, 0, 0);
+ assertReceivedDataCount(0, 1, 0, 1);
}
@Test
@@ -242,7 +255,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
CALLER_ASSIST_SCREENSHOT_ALLOWED);
mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, !FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
assertReceivedDataCount(5, 5, 0, 0);
}
@@ -252,11 +265,35 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
!CALLER_ASSIST_SCREENSHOT_ALLOWED);
mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
// Expect a single null screenshot when the appops is denied
assertReceivedDataCount(5, 5, 0, 1);
}
+ @Test
+ public void testCanNotHandleReceivedData_expectNoCallbacks() throws Exception {
+ setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, !CALLER_ASSIST_STRUCTURE_ALLOWED,
+ !CALLER_ASSIST_SCREENSHOT_ALLOWED);
+
+ mCallbacks.canHandleReceivedData = false;
+ mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
+ mGate.countDown();
+ waitForIdle(mHandler);
+ assertTrue(mCallbacks.receivedData.isEmpty());
+ assertTrue(mCallbacks.receivedScreenshots.isEmpty());
+ }
+
+ @Test
+ public void testRequestDataNoneAllowed_expectNullCallbacks() throws Exception {
+ setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
+ CALLER_ASSIST_SCREENSHOT_ALLOWED);
+
+ mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
+ !ALLOW_FETCH_DATA, !ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
+ assertReceivedDataCount(0, 1, 0, 1);
+ }
+
private void assertReceivedDataCount(int numPendingData, int numReceivedData,
int numPendingScreenshots, int numReceivedScreenshots) throws Exception {
assertTrue("Expected " + numPendingData + " pending data, got "
@@ -265,6 +302,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
assertTrue("Expected " + numPendingScreenshots + " pending screenshots, got "
+ mDataRequester.getPendingScreenshotCount(),
mDataRequester.getPendingScreenshotCount() == numPendingScreenshots);
+ assertFalse("Expected request NOT completed", mCallbacks.requestCompleted);
mGate.countDown();
waitForIdle(mHandler);
assertTrue("Expected " + numReceivedData + " data, received "
@@ -273,6 +311,7 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
assertTrue("Expected " + numReceivedScreenshots + " screenshots, received "
+ mCallbacks.receivedScreenshots.size(),
mCallbacks.receivedScreenshots.size() == numReceivedScreenshots);
+ assertTrue("Expected request completed", mCallbacks.requestCompleted);
}
private List<IBinder> createActivityList(int size) {
@@ -292,12 +331,19 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
latch.await(2, TimeUnit.SECONDS);
}
- private static class Callbacks implements AssistDataRequesterCallbacks {
+ private class Callbacks implements AssistDataRequesterCallbacks {
boolean canHandleReceivedData = true;
+ boolean requestCompleted = false;
ArrayList<Bundle> receivedData = new ArrayList<>();
ArrayList<Bitmap> receivedScreenshots = new ArrayList<>();
+ void reset() {
+ canHandleReceivedData = true;
+ receivedData.clear();
+ receivedScreenshots.clear();
+ }
+
@Override
public boolean canHandleReceivedAssistDataLocked() {
return canHandleReceivedData;
@@ -312,5 +358,17 @@ public class AssistDataRequesterTest extends ActivityTestsBase {
public void onAssistScreenshotReceivedLocked(Bitmap screenshot) {
receivedScreenshots.add(screenshot);
}
+
+ @Override
+ public void onAssistRequestCompleted() {
+ mHandler.post(() -> {
+ try {
+ mGate.await(10, TimeUnit.SECONDS);
+ requestCompleted = true;
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Failed to wait", e);
+ }
+ });
+ }
}
} \ No newline at end of file
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 f5ea60ff5929..afece5d21940 100644
--- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
@@ -428,7 +428,8 @@ public class RecentTasksTest extends ActivityTestsBase {
assertSecurityException(expectCallable, () -> mService.getTaskDescription(0));
assertSecurityException(expectCallable, () -> mService.cancelTaskWindowTransition(0));
assertSecurityException(expectCallable, () -> mService.cancelTaskThumbnailTransition(0));
- assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null, 0));
+ assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null,
+ null, 0));
}
private void testGetTasksApis(boolean expectCallable) {
@@ -510,7 +511,7 @@ public class RecentTasksTest extends ActivityTestsBase {
}
@Override
- protected ActivityStackSupervisor createStackSupervisor() {
+ protected ActivityStackSupervisor createTestSupervisor() {
return new MyTestActivityStackSupervisor(this, mHandlerThread.getLooper());
}
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 9d23fe9691b1..6de3395e6fdf 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3193,7 +3193,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
// feature is disabled because there are non-affiliated secondary users.
getServices().removeUser(DpmMockContext.CALLER_USER_HANDLE);
- when(getServices().iipConnectivityMetrics.registerNetdEventCallback(anyObject()))
+ when(getServices().iipConnectivityMetrics.addNetdEventCallback(anyInt(), anyObject()))
.thenReturn(true);
// No logs were retrieved so far.
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
new file mode 100644
index 000000000000..d9fac8768c6b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
@@ -0,0 +1,640 @@
+/*
+ * 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.assertArrayEquals;
+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.app.ActivityManager;
+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.database.ContentObserver;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.display.BrightnessChangeEvent;
+import android.os.BatteryManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.MessageQueue;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.AtomicFile;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BrightnessTrackerTest {
+
+ private BrightnessTracker mTracker;
+ private TestInjector mInjector;
+
+ private static Object sHandlerLock = new Object();
+ private static Handler sHandler;
+ private static HandlerThread sThread =
+ new HandlerThread("brightness.test", android.os.Process.THREAD_PRIORITY_BACKGROUND);
+
+ private static Handler ensureHandler() {
+ synchronized (sHandlerLock) {
+ if (sHandler == null) {
+ sThread.start();
+ sHandler = new Handler(sThread.getLooper());
+ }
+ return sHandler;
+ }
+ }
+
+
+ @Before
+ public void setUp() throws Exception {
+ mInjector = new TestInjector(ensureHandler());
+
+ mTracker = new BrightnessTracker(InstrumentationRegistry.getContext(), mInjector);
+ }
+
+ @Test
+ public void testStartStopTracker() {
+ startTracker(mTracker);
+ assertNotNull(mInjector.mSensorListener);
+ assertNotNull(mInjector.mSettingsObserver);
+ assertNotNull(mInjector.mBroadcastReceiver);
+ mTracker.stop();
+ assertNull(mInjector.mSensorListener);
+ assertNull(mInjector.mSettingsObserver);
+ assertNull(mInjector.mBroadcastReceiver);
+ }
+
+ @Test
+ public void testBrightnessEvent() {
+ final int brightness = 20;
+
+ mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS, brightness);
+ startTracker(mTracker);
+ mInjector.mSensorListener.onSensorChanged(createSensorEvent(1.0f));
+ mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2));
+ mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
+ Settings.System.SCREEN_BRIGHTNESS));
+ List<BrightnessChangeEvent> events = mTracker.getEvents(0).getList();
+ mTracker.stop();
+
+ assertEquals(1, events.size());
+ BrightnessChangeEvent event = events.get(0);
+ assertEquals(mInjector.currentTimeMillis(), event.timeStamp);
+ assertEquals(1, event.luxValues.length);
+ assertEquals(1.0f, event.luxValues[0], 0.1f);
+ assertEquals(mInjector.currentTimeMillis() - TimeUnit.SECONDS.toMillis(2),
+ event.luxTimestamps[0]);
+ assertEquals(brightness, event.brightness);
+
+ // System had no data so these should all be at defaults.
+ assertEquals(Float.NaN, event.batteryLevel, 0.0);
+ assertFalse(event.nightMode);
+ assertEquals(0, event.colorTemperature);
+ }
+
+ @Test
+ public void testBrightnessFullPopulatedEvent() {
+ final int lastBrightness = 230;
+ final int brightness = 130;
+
+ mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS, lastBrightness);
+ mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_ACTIVATED, 1);
+ mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, 3333);
+
+ startTracker(mTracker);
+ mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS, brightness);
+ mInjector.mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(),
+ batteryChangeEvent(30, 60));
+ mInjector.mSensorListener.onSensorChanged(createSensorEvent(1000.0f));
+ final long sensorTime = mInjector.currentTimeMillis();
+ mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
+ Settings.System.SCREEN_BRIGHTNESS));
+ List<BrightnessChangeEvent> events = mTracker.getEvents(0).getList();
+ mTracker.stop();
+
+ assertEquals(1, events.size());
+ BrightnessChangeEvent event = events.get(0);
+ assertEquals(event.timeStamp, mInjector.currentTimeMillis());
+ assertArrayEquals(new float[] {1000.0f}, event.luxValues, 0.01f);
+ assertArrayEquals(new long[] {sensorTime}, event.luxTimestamps);
+ assertEquals(brightness, event.brightness);
+ assertEquals(lastBrightness, event.lastBrightness);
+ assertEquals(0.5, event.batteryLevel, 0.01);
+ assertTrue(event.nightMode);
+ assertEquals(3333, event.colorTemperature);
+ assertEquals("a.package", event.packageName);
+ assertEquals(0, event.userId);
+ }
+
+ @Test
+ public void testIgnoreSelfChange() {
+ final int initialBrightness = 30;
+ mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS, initialBrightness);
+ startTracker(mTracker);
+ mInjector.mSensorListener.onSensorChanged(createSensorEvent(1.0f));
+ mInjector.incrementTime(TimeUnit.SECONDS.toMillis(1));
+
+ final int systemUpdatedBrightness = 20;
+ mTracker.setBrightness(systemUpdatedBrightness, 0);
+ assertEquals(systemUpdatedBrightness,
+ (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();
+ // No events because we filtered out our change.
+ assertEquals(0, events.size());
+
+ final int firstUserUpdateBrightness = 20;
+ // Then change comes from somewhere else so we shouldn't filter.
+ mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS,
+ firstUserUpdateBrightness);
+ mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
+ Settings.System.SCREEN_BRIGHTNESS));
+
+ // and with a different brightness value.
+ final int secondUserUpdateBrightness = 34;
+ mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS,
+ secondUserUpdateBrightness);
+ mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
+ Settings.System.SCREEN_BRIGHTNESS));
+ events = mTracker.getEvents(0).getList();
+
+ assertEquals(2, events.size());
+ // First event is change from system update (20) to first user update (20)
+ assertEquals(systemUpdatedBrightness, events.get(0).lastBrightness);
+ assertEquals(firstUserUpdateBrightness, events.get(0).brightness);
+ // Second event is from first to second user update.
+ assertEquals(firstUserUpdateBrightness, events.get(1).lastBrightness);
+ assertEquals(secondUserUpdateBrightness, events.get(1).brightness);
+
+ mTracker.stop();
+ }
+
+ @Test
+ public void testLimitedBufferSize() {
+ startTracker(mTracker);
+ mInjector.mSensorListener.onSensorChanged(createSensorEvent(1.0f));
+
+ for (int brightness = 0; brightness <= 255; ++brightness) {
+ mInjector.mSensorListener.onSensorChanged(createSensorEvent(1.0f));
+ mInjector.incrementTime(TimeUnit.SECONDS.toNanos(1));
+ mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS, brightness);
+ mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
+ Settings.System.SCREEN_BRIGHTNESS));
+ }
+ List<BrightnessChangeEvent> events = mTracker.getEvents(0).getList();
+ mTracker.stop();
+
+ // Should be capped at 100 events, and they should be the most recent 100.
+ assertEquals(100, events.size());
+ for (int i = 0; i < events.size(); i++) {
+ BrightnessChangeEvent event = events.get(i);
+ assertEquals(156 + i, event.brightness);
+ }
+ }
+
+ @Test
+ public void testLimitedSensorEvents() {
+ final int brightness = 20;
+ mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS, brightness);
+
+ startTracker(mTracker);
+ // 20 Sensor events 1 second apart.
+ for (int i = 0; i < 20; ++i) {
+ mInjector.incrementTime(TimeUnit.SECONDS.toMillis(1));
+ mInjector.mSensorListener.onSensorChanged(createSensorEvent(i + 1.0f));
+ }
+ mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
+ Settings.System.SCREEN_BRIGHTNESS));
+ List<BrightnessChangeEvent> events = mTracker.getEvents(0).getList();
+ mTracker.stop();
+
+ assertEquals(1, events.size());
+ BrightnessChangeEvent event = events.get(0);
+ assertEquals(mInjector.currentTimeMillis(), event.timeStamp);
+
+ // 12 sensor events, 11 for 0->10 seconds + 1 previous event.
+ assertEquals(12, event.luxValues.length);
+ for (int i = 0; i < 12; ++i) {
+ assertEquals(event.luxTimestamps[11 - i],
+ mInjector.currentTimeMillis() - i * TimeUnit.SECONDS.toMillis(1));
+ }
+ assertEquals(brightness, event.brightness);
+ }
+
+ @Test
+ public void testReadEvents() throws Exception {
+ BrightnessTracker tracker = new BrightnessTracker(InstrumentationRegistry.getContext(),
+ mInjector);
+ mInjector.mCurrentTimeMillis = System.currentTimeMillis();
+ long someTimeAgo = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(12);
+ long twoMonthsAgo = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60);
+ // 3 Events in the file but one too old to read.
+ String eventFile =
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<events>\n"
+ + "<event brightness=\"194\" timestamp=\""
+ + Long.toString(someTimeAgo) + "\" packageName=\""
+ + "com.example.app\" user=\"10\" "
+ + "lastBrightness=\"32\" "
+ + "batteryLevel=\"1.0\" nightMode=\"false\" colorTemperature=\"0\"\n"
+ + "lux=\"32.2,31.1\" luxTimestamps=\""
+ + Long.toString(someTimeAgo) + "," + Long.toString(someTimeAgo) + "\"/>"
+ + "<event brightness=\"71\" timestamp=\""
+ + Long.toString(someTimeAgo) + "\" packageName=\""
+ + "com.android.anapp\" user=\"11\" "
+ + "lastBrightness=\"32\" "
+ + "batteryLevel=\"0.5\" nightMode=\"true\" colorTemperature=\"3235\"\n"
+ + "lux=\"132.2,131.1\" luxTimestamps=\""
+ + Long.toString(someTimeAgo) + "," + Long.toString(someTimeAgo) + "\"/>"
+ // Event that is too old so shouldn't show up.
+ + "<event brightness=\"142\" timestamp=\""
+ + Long.toString(twoMonthsAgo) + "\" packageName=\""
+ + "com.example.app\" user=\"10\" "
+ + "lastBrightness=\"32\" "
+ + "batteryLevel=\"1.0\" nightMode=\"false\" colorTemperature=\"0\"\n"
+ + "lux=\"32.2,31.1\" luxTimestamps=\""
+ + Long.toString(twoMonthsAgo) + "," + Long.toString(twoMonthsAgo) + "\"/>"
+ + "</events>";
+ tracker.readEventsLocked(getInputStream(eventFile));
+ List<BrightnessChangeEvent> events = tracker.getEvents(0).getList();
+ assertEquals(1, events.size());
+ BrightnessChangeEvent event = events.get(0);
+ assertEquals(someTimeAgo, event.timeStamp);
+ assertEquals(194, event.brightness);
+ assertArrayEquals(new float[] {32.2f, 31.1f}, event.luxValues, 0.01f);
+ assertArrayEquals(new long[] {someTimeAgo, someTimeAgo}, event.luxTimestamps);
+ assertEquals(32, event.lastBrightness);
+ assertEquals(0, event.userId);
+ assertFalse(event.nightMode);
+ assertEquals(1.0f, event.batteryLevel, 0.01);
+ assertEquals("com.example.app", event.packageName);
+
+ events = tracker.getEvents(1).getList();
+ assertEquals(1, events.size());
+ event = events.get(0);
+ assertEquals(someTimeAgo, event.timeStamp);
+ assertEquals(71, event.brightness);
+ assertArrayEquals(new float[] {132.2f, 131.1f}, event.luxValues, 0.01f);
+ assertArrayEquals(new long[] {someTimeAgo, someTimeAgo}, event.luxTimestamps);
+ assertEquals(32, event.lastBrightness);
+ assertEquals(1, event.userId);
+ assertTrue(event.nightMode);
+ assertEquals(3235, event.colorTemperature);
+ assertEquals(0.5f, event.batteryLevel, 0.01);
+ assertEquals("com.android.anapp", event.packageName);
+ }
+
+ @Test
+ public void testFailedRead() {
+ String someTimeAgo =
+ Long.toString(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(12));
+ mInjector.mCurrentTimeMillis = System.currentTimeMillis();
+
+ BrightnessTracker tracker = new BrightnessTracker(InstrumentationRegistry.getContext(),
+ mInjector);
+ String eventFile = "junk in the file";
+ try {
+ tracker.readEventsLocked(getInputStream(eventFile));
+ } catch (IOException e) {
+ // Expected;
+ }
+ assertEquals(0, tracker.getEvents(0).getList().size());
+
+ // Missing lux value.
+ eventFile =
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<events>\n"
+ + "<event brightness=\"194\" timestamp=\"" + someTimeAgo + "\" packageName=\""
+ + "com.example.app\" user=\"10\" "
+ + "batteryLevel=\"0.7\" nightMode=\"false\" colorTemperature=\"0\" />\n"
+ + "</events>";
+ try {
+ tracker.readEventsLocked(getInputStream(eventFile));
+ } catch (IOException e) {
+ // Expected;
+ }
+ assertEquals(0, tracker.getEvents(0).getList().size());
+ }
+
+ @Test
+ public void testWriteThenRead() throws Exception {
+ final int brightness = 20;
+
+ mInjector.mSystemIntSettings.put(Settings.System.SCREEN_BRIGHTNESS, brightness);
+ mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_ACTIVATED, 1);
+ mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, 3339);
+
+ startTracker(mTracker);
+ mInjector.mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(),
+ batteryChangeEvent(30, 100));
+ mInjector.mSensorListener.onSensorChanged(createSensorEvent(2000.0f));
+ final long firstSensorTime = mInjector.currentTimeMillis();
+ mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2));
+ mInjector.mSensorListener.onSensorChanged(createSensorEvent(3000.0f));
+ final long secondSensorTime = mInjector.currentTimeMillis();
+ mInjector.incrementTime(TimeUnit.SECONDS.toMillis(3));
+ mInjector.mSettingsObserver.onChange(false, Settings.System.getUriFor(
+ Settings.System.SCREEN_BRIGHTNESS));
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ mTracker.writeEventsLocked(baos);
+ mTracker.stop();
+
+ baos.flush();
+ ByteArrayInputStream input = new ByteArrayInputStream(baos.toByteArray());
+ BrightnessTracker tracker = new BrightnessTracker(InstrumentationRegistry.getContext(),
+ mInjector);
+ tracker.readEventsLocked(input);
+ List<BrightnessChangeEvent> events = tracker.getEvents(0).getList();
+
+ assertEquals(1, events.size());
+ BrightnessChangeEvent event = events.get(0);
+ assertArrayEquals(new float[] {2000.0f, 3000.0f}, event.luxValues, 0.01f);
+ assertArrayEquals(new long[] {firstSensorTime, secondSensorTime}, event.luxTimestamps);
+ assertEquals(brightness, event.brightness);
+ assertEquals(0.3, event.batteryLevel, 0.01f);
+ assertTrue(event.nightMode);
+ assertEquals(3339, event.colorTemperature);
+ }
+
+ @Test
+ public void testParcelUnParcel() {
+ Parcel parcel = Parcel.obtain();
+ BrightnessChangeEvent event = new BrightnessChangeEvent();
+ event.brightness = 23;
+ event.timeStamp = 345L;
+ event.packageName = "com.example";
+ event.userId = 12;
+ event.luxValues = new float[2];
+ event.luxValues[0] = 3000.0f;
+ event.luxValues[1] = 4000.0f;
+ event.luxTimestamps = new long[2];
+ event.luxTimestamps[0] = 325L;
+ event.luxTimestamps[1] = 315L;
+ event.batteryLevel = 0.7f;
+ event.nightMode = false;
+ event.colorTemperature = 345;
+ event.lastBrightness = 50;
+
+ event.writeToParcel(parcel, 0);
+ byte[] parceled = parcel.marshall();
+ parcel.recycle();
+
+ parcel = Parcel.obtain();
+ parcel.unmarshall(parceled, 0, parceled.length);
+ parcel.setDataPosition(0);
+
+ BrightnessChangeEvent event2 = BrightnessChangeEvent.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+ assertEquals(event.brightness, event2.brightness);
+ assertEquals(event.timeStamp, event2.timeStamp);
+ assertEquals(event.packageName, event2.packageName);
+ assertEquals(event.userId, event2.userId);
+ assertArrayEquals(event.luxValues, event2.luxValues, 0.01f);
+ assertArrayEquals(event.luxTimestamps, event2.luxTimestamps);
+ assertEquals(event.batteryLevel, event2.batteryLevel, 0.01f);
+ assertEquals(event.nightMode, event2.nightMode);
+ assertEquals(event.colorTemperature, event2.colorTemperature);
+ assertEquals(event.lastBrightness, event2.lastBrightness);
+
+ parcel = Parcel.obtain();
+ event.batteryLevel = Float.NaN;
+ event.writeToParcel(parcel, 0);
+ parceled = parcel.marshall();
+ parcel.recycle();
+
+ parcel = Parcel.obtain();
+ parcel.unmarshall(parceled, 0, parceled.length);
+ parcel.setDataPosition(0);
+ event2 = BrightnessChangeEvent.CREATOR.createFromParcel(parcel);
+ assertEquals(event.batteryLevel, event2.batteryLevel, 0.01f);
+ }
+
+ private InputStream getInputStream(String data) {
+ return new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8));
+ }
+
+ private Intent batteryChangeEvent(int level, int scale) {
+ Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_BATTERY_CHANGED);
+ intent.putExtra(BatteryManager.EXTRA_LEVEL, level);
+ intent.putExtra(BatteryManager.EXTRA_SCALE, scale);
+ return intent;
+ }
+
+ private SensorEvent createSensorEvent(float lux) {
+ SensorEvent event;
+ try {
+ Constructor<SensorEvent> constr =
+ SensorEvent.class.getDeclaredConstructor(Integer.TYPE);
+ constr.setAccessible(true);
+ event = constr.newInstance(1);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ event.values[0] = lux;
+ event.timestamp = mInjector.mElapsedRealtimeNanos;
+
+ return event;
+ }
+
+ private void startTracker(BrightnessTracker tracker) {
+ tracker.start();
+ mInjector.waitForHandler();
+ }
+
+
+ private static final class Idle implements MessageQueue.IdleHandler {
+ private boolean mIdle;
+
+ @Override
+ public boolean queueIdle() {
+ synchronized (this) {
+ mIdle = true;
+ notifyAll();
+ }
+ return false;
+ }
+
+ public synchronized void waitForIdle() {
+ while (!mIdle) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }
+
+ private class TestInjector extends BrightnessTracker.Injector {
+ SensorEventListener mSensorListener;
+ ContentObserver mSettingsObserver;
+ BroadcastReceiver mBroadcastReceiver;
+ Map<String, Integer> mSystemIntSettings = new HashMap<>();
+ Map<String, Integer> mSecureIntSettings = new HashMap<>();
+ long mCurrentTimeMillis = System.currentTimeMillis();
+ long mElapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
+ Handler mHandler;
+
+ public TestInjector(Handler handler) {
+ mHandler = handler;
+ }
+
+ public void incrementTime(long timeMillis) {
+ mCurrentTimeMillis += timeMillis;
+ mElapsedRealtimeNanos += TimeUnit.MILLISECONDS.toNanos(timeMillis);
+ }
+
+ @Override
+ public void registerSensorListener(Context context,
+ SensorEventListener sensorListener) {
+ mSensorListener = sensorListener;
+ }
+
+ @Override
+ public void unregisterSensorListener(Context context,
+ SensorEventListener sensorListener) {
+ mSensorListener = null;
+ }
+
+ @Override
+ public void registerBrightnessObserver(ContentResolver resolver,
+ ContentObserver settingsObserver) {
+ mSettingsObserver = settingsObserver;
+ }
+
+ @Override
+ public void unregisterBrightnessObserver(Context context,
+ ContentObserver settingsObserver) {
+ mSettingsObserver = null;
+ }
+
+ @Override
+ public void registerReceiver(Context context,
+ BroadcastReceiver shutdownReceiver, IntentFilter shutdownFilter) {
+ mBroadcastReceiver = shutdownReceiver;
+ }
+
+ @Override
+ public void unregisterReceiver(Context context,
+ BroadcastReceiver broadcastReceiver) {
+ assertEquals(mBroadcastReceiver, broadcastReceiver);
+ mBroadcastReceiver = null;
+ }
+
+ @Override
+ public Handler getBackgroundHandler() {
+ return mHandler;
+ }
+
+ public void waitForHandler() {
+ Idle idle = new Idle();
+ mHandler.getLooper().getQueue().addIdleHandler(idle);
+ mHandler.post(() -> {});
+ idle.waitForIdle();
+ }
+
+ @Override
+ public int getSystemIntForUser(ContentResolver resolver, String setting, int defaultValue,
+ int userId) {
+ Integer value = mSystemIntSettings.get(setting);
+ if (value == null) {
+ return defaultValue;
+ } else {
+ return value;
+ }
+ }
+
+ @Override
+ public void putSystemIntForUser(ContentResolver resolver, String setting, int value,
+ int userId) {
+ mSystemIntSettings.put(setting, value);
+ }
+
+ @Override
+ public int getSecureIntForUser(ContentResolver resolver, String setting, int defaultValue,
+ int userId) {
+ Integer value = mSecureIntSettings.get(setting);
+ if (value == null) {
+ return defaultValue;
+ } else {
+ return value;
+ }
+ }
+
+ @Override
+ public AtomicFile getFile() {
+ // Don't have the test write / read from anywhere.
+ return null;
+ }
+
+ @Override
+ public long currentTimeMillis() {
+ return mCurrentTimeMillis;
+ }
+
+ @Override
+ public long elapsedRealtimeNanos() {
+ return mElapsedRealtimeNanos;
+ }
+
+ @Override
+ public int getUserSerialNumber(UserManager userManager, int userId) {
+ return userId + 10;
+ }
+
+ @Override
+ public int getUserId(UserManager userManager, int userSerialNumber) {
+ return userSerialNumber - 10;
+ }
+
+ @Override
+ public ActivityManager.StackInfo getFocusedStack() throws RemoteException {
+ ActivityManager.StackInfo focusedStack = new ActivityManager.StackInfo();
+ focusedStack.userId = 0;
+ focusedStack.topActivity = new ComponentName("a.package", "a.class");
+ return focusedStack;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
index afe432b96f85..467b47acd48a 100644
--- a/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/BackgroundRestrictionsTest.java
@@ -37,7 +37,6 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.provider.Settings;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
@@ -57,10 +56,10 @@ import org.junit.runner.RunWith;
* To run this test from root of checkout:
* <pre>
* mmm -j32 frameworks/base/services/tests/servicestests/
- * adb install out/target/product/marlin/data/app/JobTestApp/JobTestApp.apk
- * adb install out/target/product/marlin/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
+ * adb install -r $OUT/data/app/JobTestApp/JobTestApp.apk
+ * adb install -r $OUT/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
* adb shell am instrument -e class 'com.android.server.job.BackgroundRestrictionsTest' -w \
- * 'com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner'
+ com.android.frameworks.servicestests
* </pre>
*/
@RunWith(AndroidJUnit4.class)
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index 31ed8ba7dd23..bf912dd7e0e1 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -1,50 +1,93 @@
package com.android.server.job;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
-import android.content.ComponentName;
-import android.content.Context;
import android.app.job.JobInfo;
import android.app.job.JobInfo.Builder;
+import android.content.ComponentName;
+import android.content.Context;
+import android.net.NetworkRequest;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.SystemClock;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
import android.test.RenamingDelegatingContext;
import android.util.Log;
import android.util.Pair;
+import com.android.internal.util.HexDump;
+import com.android.server.IoThread;
import com.android.server.job.JobStore.JobSet;
import com.android.server.job.controllers.JobStatus;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.Clock;
+import java.time.ZoneOffset;
+import java.util.Arrays;
import java.util.Iterator;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Test reading and writing correctly from file.
*/
-public class JobStoreTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class JobStoreTest {
private static final String TAG = "TaskStoreTest";
private static final String TEST_PREFIX = "_test_";
- private static final int SOME_UID = 34234;
+ private static final int SOME_UID = android.os.Process.FIRST_APPLICATION_UID;
private ComponentName mComponent;
- private static final long IO_WAIT = 1000L;
JobStore mTaskStoreUnderTest;
Context mTestContext;
- @Override
+ private Context getContext() {
+ return InstrumentationRegistry.getContext();
+ }
+
+ @Before
public void setUp() throws Exception {
mTestContext = new RenamingDelegatingContext(getContext(), TEST_PREFIX);
Log.d(TAG, "Saving tasks to '" + mTestContext.getFilesDir() + "'");
mTaskStoreUnderTest =
JobStore.initAndGetForTesting(mTestContext, mTestContext.getFilesDir());
mComponent = new ComponentName(getContext().getPackageName(), StubClass.class.getName());
+
+ // Freeze the clocks at this moment in time
+ JobSchedulerService.sSystemClock =
+ Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
+ JobSchedulerService.sUptimeMillisClock =
+ Clock.fixed(SystemClock.uptimeMillisClock().instant(), ZoneOffset.UTC);
+ JobSchedulerService.sElapsedRealtimeClock =
+ Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC);
}
- @Override
+ @After
public void tearDown() throws Exception {
mTaskStoreUnderTest.clear();
}
+ private void waitForPendingIo() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ IoThread.getHandler().post(() -> {
+ latch.countDown();
+ });
+ latch.await(10, TimeUnit.SECONDS);
+ }
+
+ @Test
public void testMaybeWriteStatusToDisk() throws Exception {
int taskId = 5;
long runByMillis = 20000L; // 20s
@@ -61,7 +104,8 @@ public class JobStoreTest extends AndroidTestCase {
.build();
final JobStatus ts = JobStatus.createFromJobInfo(task, SOME_UID, null, -1, null);
mTaskStoreUnderTest.add(ts);
- Thread.sleep(IO_WAIT);
+ waitForPendingIo();
+
// Manually load tasks from xml file.
final JobSet jobStatusSet = new JobSet();
mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true);
@@ -75,9 +119,9 @@ public class JobStoreTest extends AndroidTestCase {
ts.getEarliestRunTime(), loadedTaskStatus.getEarliestRunTime());
compareTimestampsSubjectToIoLatency("Late run-times not the same after read.",
ts.getLatestRunTimeElapsed(), loadedTaskStatus.getLatestRunTimeElapsed());
-
}
+ @Test
public void testWritingTwoFilesToDisk() throws Exception {
final JobInfo task1 = new Builder(8, mComponent)
.setRequiresDeviceIdle(true)
@@ -96,7 +140,7 @@ public class JobStoreTest extends AndroidTestCase {
final JobStatus taskStatus2 = JobStatus.createFromJobInfo(task2, SOME_UID, null, -1, null);
mTaskStoreUnderTest.add(taskStatus1);
mTaskStoreUnderTest.add(taskStatus2);
- Thread.sleep(IO_WAIT);
+ waitForPendingIo();
final JobSet jobStatusSet = new JobSet();
mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true);
@@ -125,9 +169,9 @@ public class JobStoreTest extends AndroidTestCase {
taskStatus2.getEarliestRunTime(), loaded2.getEarliestRunTime());
compareTimestampsSubjectToIoLatency("Late run-times not the same after read.",
taskStatus2.getLatestRunTimeElapsed(), loaded2.getLatestRunTimeElapsed());
-
}
+ @Test
public void testWritingTaskWithExtras() throws Exception {
JobInfo.Builder b = new Builder(8, mComponent)
.setRequiresDeviceIdle(true)
@@ -144,7 +188,7 @@ public class JobStoreTest extends AndroidTestCase {
JobStatus taskStatus = JobStatus.createFromJobInfo(task, SOME_UID, null, -1, null);
mTaskStoreUnderTest.add(taskStatus);
- Thread.sleep(IO_WAIT);
+ waitForPendingIo();
final JobSet jobStatusSet = new JobSet();
mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true);
@@ -152,6 +196,8 @@ public class JobStoreTest extends AndroidTestCase {
JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
assertTasksEqual(task, loaded.getJob());
}
+
+ @Test
public void testWritingTaskWithSourcePackage() throws Exception {
JobInfo.Builder b = new Builder(8, mComponent)
.setRequiresDeviceIdle(true)
@@ -162,7 +208,7 @@ public class JobStoreTest extends AndroidTestCase {
"com.google.android.gms", 0, null);
mTaskStoreUnderTest.add(taskStatus);
- Thread.sleep(IO_WAIT);
+ waitForPendingIo();
final JobSet jobStatusSet = new JobSet();
mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true);
@@ -174,6 +220,7 @@ public class JobStoreTest extends AndroidTestCase {
taskStatus.getSourceUserId());
}
+ @Test
public void testWritingTaskWithFlex() throws Exception {
JobInfo.Builder b = new Builder(8, mComponent)
.setRequiresDeviceIdle(true)
@@ -183,7 +230,7 @@ public class JobStoreTest extends AndroidTestCase {
JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
mTaskStoreUnderTest.add(taskStatus);
- Thread.sleep(IO_WAIT);
+ waitForPendingIo();
final JobSet jobStatusSet = new JobSet();
mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true);
@@ -195,6 +242,7 @@ public class JobStoreTest extends AndroidTestCase {
taskStatus.getJob().getFlexMillis());
}
+ @Test
public void testMassivePeriodClampedOnRead() throws Exception {
final long ONE_HOUR = 60*60*1000L; // flex
final long TWO_HOURS = 2 * ONE_HOUR; // period
@@ -214,7 +262,7 @@ public class JobStoreTest extends AndroidTestCase {
persistedExecutionTimesUTC);
mTaskStoreUnderTest.add(js);
- Thread.sleep(IO_WAIT);
+ waitForPendingIo();
final JobSet jobStatusSet = new JobSet();
mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true);
@@ -231,6 +279,7 @@ public class JobStoreTest extends AndroidTestCase {
loaded.getEarliestRunTime() <= newNowElapsed + TWO_HOURS + ONE_HOUR);
}
+ @Test
public void testPriorityPersisted() throws Exception {
JobInfo.Builder b = new Builder(92, mComponent)
.setOverrideDeadline(5000)
@@ -238,7 +287,8 @@ public class JobStoreTest extends AndroidTestCase {
.setPersisted(true);
final JobStatus js = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
mTaskStoreUnderTest.add(js);
- Thread.sleep(IO_WAIT);
+ waitForPendingIo();
+
final JobSet jobStatusSet = new JobSet();
mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true);
JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
@@ -248,6 +298,7 @@ public class JobStoreTest extends AndroidTestCase {
/**
* Test that non persisted job is not written to disk.
*/
+ @Test
public void testNonPersistedTaskIsNotPersisted() throws Exception {
JobInfo.Builder b = new Builder(42, mComponent)
.setOverrideDeadline(10000)
@@ -259,7 +310,8 @@ public class JobStoreTest extends AndroidTestCase {
.setPersisted(true);
JobStatus jsPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1, null);
mTaskStoreUnderTest.add(jsPersisted);
- Thread.sleep(IO_WAIT);
+ waitForPendingIo();
+
final JobSet jobStatusSet = new JobSet();
mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true);
assertEquals("Job count is incorrect.", 1, jobStatusSet.size());
@@ -267,6 +319,62 @@ public class JobStoreTest extends AndroidTestCase {
assertEquals("Wrong job persisted.", 43, jobStatus.getJobId());
}
+ @Test
+ public void testRequiredNetworkType() throws Exception {
+ assertPersistedEquals(new JobInfo.Builder(0, mComponent)
+ .setPersisted(true)
+ .setRequiresDeviceIdle(true)
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE).build());
+ assertPersistedEquals(new JobInfo.Builder(0, mComponent)
+ .setPersisted(true)
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build());
+ assertPersistedEquals(new JobInfo.Builder(0, mComponent)
+ .setPersisted(true)
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED).build());
+ assertPersistedEquals(new JobInfo.Builder(0, mComponent)
+ .setPersisted(true)
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_NOT_ROAMING).build());
+ assertPersistedEquals(new JobInfo.Builder(0, mComponent)
+ .setPersisted(true)
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_CELLULAR).build());
+ }
+
+ @Test
+ public void testRequiredNetwork() throws Exception {
+ assertPersistedEquals(new JobInfo.Builder(0, mComponent)
+ .setPersisted(true)
+ .setRequiresDeviceIdle(true)
+ .setRequiredNetwork(null).build());
+ assertPersistedEquals(new JobInfo.Builder(0, mComponent)
+ .setPersisted(true)
+ .setRequiredNetwork(new NetworkRequest.Builder().build()).build());
+ assertPersistedEquals(new JobInfo.Builder(0, mComponent)
+ .setPersisted(true)
+ .setRequiredNetwork(new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build())
+ .build());
+ assertPersistedEquals(new JobInfo.Builder(0, mComponent)
+ .setPersisted(true)
+ .setRequiredNetwork(new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_IMS).build())
+ .build());
+ }
+
+ /**
+ * Helper function to kick a {@link JobInfo} through a persistence cycle and
+ * assert that it's unchanged.
+ */
+ private void assertPersistedEquals(JobInfo first) throws Exception {
+ mTaskStoreUnderTest.clear();
+ mTaskStoreUnderTest.add(JobStatus.createFromJobInfo(first, SOME_UID, null, -1, null));
+ waitForPendingIo();
+
+ final JobSet jobStatusSet = new JobSet();
+ mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true);
+ final JobStatus second = jobStatusSet.getAllJobs().iterator().next();
+ assertTasksEqual(first, second.getJob());
+ }
+
/**
* Helper function to throw an error if the provided task and TaskStatus objects are not equal.
*/
@@ -286,12 +394,10 @@ public class JobStoreTest extends AndroidTestCase {
second.isRequireBatteryNotLow());
assertEquals("Invalid idle constraint.", first.isRequireDeviceIdle(),
second.isRequireDeviceIdle());
- assertEquals("Invalid unmetered constraint.",
- first.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED,
- second.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED);
- assertEquals("Invalid connectivity constraint.",
- first.getNetworkType() == JobInfo.NETWORK_TYPE_ANY,
- second.getNetworkType() == JobInfo.NETWORK_TYPE_ANY);
+ assertEquals("Invalid network type.",
+ first.getNetworkType(), second.getNetworkType());
+ assertEquals("Invalid network.",
+ first.getRequiredNetwork(), second.getRequiredNetwork());
assertEquals("Invalid deadline constraint.",
first.hasLateConstraint(),
second.hasLateConstraint());
@@ -302,6 +408,26 @@ public class JobStoreTest extends AndroidTestCase {
first.getExtras().toString(), second.getExtras().toString());
assertEquals("Transient xtras don't match",
first.getTransientExtras().toString(), second.getTransientExtras().toString());
+
+ // Since people can forget to add tests here for new fields, do one last
+ // sanity check based on bits-on-wire equality.
+ final byte[] firstBytes = marshall(first);
+ final byte[] secondBytes = marshall(second);
+ if (!Arrays.equals(firstBytes, secondBytes)) {
+ Log.w(TAG, "First: " + HexDump.dumpHexString(firstBytes));
+ Log.w(TAG, "Second: " + HexDump.dumpHexString(secondBytes));
+ fail("Raw JobInfo aren't equal; see logs for details");
+ }
+ }
+
+ private static byte[] marshall(Parcelable p) {
+ final Parcel parcel = Parcel.obtain();
+ try {
+ p.writeToParcel(parcel, 0);
+ return parcel.marshall();
+ } finally {
+ parcel.recycle();
+ }
}
/**
@@ -312,7 +438,7 @@ public class JobStoreTest extends AndroidTestCase {
*/
private void compareTimestampsSubjectToIoLatency(String error, long ts1, long ts2) {
final long DELTA_MILLIS = 700L; // We allow up to 700ms of latency for IO read/writes.
- assertTrue(error, Math.abs(ts1 - ts2) < DELTA_MILLIS + IO_WAIT);
+ assertTrue(error, Math.abs(ts1 - ts2) < DELTA_MILLIS);
}
private static class StubClass {}
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/HarmfulDigestsTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/HarmfulDigestsTests.java
new file mode 100644
index 000000000000..a34f95eed040
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/HarmfulDigestsTests.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.watchlist;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.HexDump;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+/**
+ * runtest frameworks-services -c com.android.server.net.watchlist.HarmfulDigestsTests
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class HarmfulDigestsTests {
+
+ private static final byte[] TEST_DIGEST_1 = HexDump.hexStringToByteArray("AAAAAA");
+ private static final byte[] TEST_DIGEST_2 = HexDump.hexStringToByteArray("BBBBBB");
+ private static final byte[] TEST_DIGEST_3 = HexDump.hexStringToByteArray("AAAABB");
+ private static final byte[] TEST_DIGEST_4 = HexDump.hexStringToByteArray("BBBBAA");
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testHarmfulDigests_setAndContains() throws Exception {
+ HarmfulDigests harmfulDigests = new HarmfulDigests(
+ Arrays.asList(new byte[][] {TEST_DIGEST_1}));
+ assertTrue(harmfulDigests.contains(TEST_DIGEST_1));
+ assertFalse(harmfulDigests.contains(TEST_DIGEST_2));
+ assertFalse(harmfulDigests.contains(TEST_DIGEST_3));
+ assertFalse(harmfulDigests.contains(TEST_DIGEST_4));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java
new file mode 100644
index 000000000000..ccd3cdd3a20b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.watchlist;
+
+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.junit.Assert.fail;
+
+import android.net.ConnectivityMetricsEvent;
+import android.net.IIpConnectivityMetrics;
+import android.net.INetdEventCallback;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteException;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.server.ServiceThread;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * runtest frameworks-services -c com.android.server.net.watchlist.NetworkWatchlistServiceTests
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class NetworkWatchlistServiceTests {
+
+ private static final long NETWOR_EVENT_TIMEOUT_SEC = 1;
+ private static final String TEST_HOST = "testhost.com";
+ private static final String TEST_IP = "7.6.8.9";
+ private static final String[] TEST_IPS =
+ new String[] {"1.2.3.4", "4.6.8.9", "2001:0db8:0001:0000:0000:0ab9:C0A8:0102"};
+
+ private static class TestHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case WatchlistLoggingHandler.LOG_WATCHLIST_EVENT_MSG:
+ onLogEvent();
+ break;
+ case WatchlistLoggingHandler.REPORT_RECORDS_IF_NECESSARY_MSG:
+ onAggregateEvent();
+ break;
+ default:
+ fail("Unexpected message: " + msg.what);
+ }
+ }
+
+ public void onLogEvent() {}
+ public void onAggregateEvent() {}
+ }
+
+ private static class TestIIpConnectivityMetrics implements IIpConnectivityMetrics {
+
+ int counter = 0;
+ INetdEventCallback callback = null;
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+
+ @Override
+ public int logEvent(ConnectivityMetricsEvent connectivityMetricsEvent)
+ throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public boolean addNetdEventCallback(int callerType, INetdEventCallback callback) {
+ counter++;
+ this.callback = callback;
+ return true;
+ }
+
+ @Override
+ public boolean removeNetdEventCallback(int callerType) {
+ counter--;
+ return true;
+ }
+ };
+
+ ServiceThread mHandlerThread;
+ WatchlistLoggingHandler mWatchlistHandler;
+ NetworkWatchlistService mWatchlistService;
+
+ @Before
+ public void setUp() {
+ mHandlerThread = new ServiceThread("NetworkWatchlistServiceTests",
+ Process.THREAD_PRIORITY_BACKGROUND, /* allowIo */ false);
+ mHandlerThread.start();
+ mWatchlistHandler = new WatchlistLoggingHandler(InstrumentationRegistry.getContext(),
+ mHandlerThread.getLooper());
+ mWatchlistService = new NetworkWatchlistService(InstrumentationRegistry.getContext(),
+ mHandlerThread, mWatchlistHandler, null);
+ }
+
+ @After
+ public void tearDown() {
+ mHandlerThread.quitSafely();
+ }
+
+ @Test
+ public void testStartStopWatchlistLogging() throws Exception {
+ TestIIpConnectivityMetrics connectivityMetrics = new TestIIpConnectivityMetrics() {
+ @Override
+ public boolean addNetdEventCallback(int callerType, INetdEventCallback callback) {
+ super.addNetdEventCallback(callerType, callback);
+ assertEquals(callerType, INetdEventCallback.CALLBACK_CALLER_NETWORK_WATCHLIST);
+ return true;
+ }
+
+ @Override
+ public boolean removeNetdEventCallback(int callerType) {
+ super.removeNetdEventCallback(callerType);
+ assertEquals(callerType, INetdEventCallback.CALLBACK_CALLER_NETWORK_WATCHLIST);
+ return true;
+ }
+ };
+ assertEquals(connectivityMetrics.counter, 0);
+ mWatchlistService.mIpConnectivityMetrics = connectivityMetrics;
+ assertTrue(mWatchlistService.startWatchlistLoggingImpl());
+ assertEquals(connectivityMetrics.counter, 1);
+ assertTrue(mWatchlistService.startWatchlistLoggingImpl());
+ assertEquals(connectivityMetrics.counter, 1);
+ assertTrue(mWatchlistService.stopWatchlistLoggingImpl());
+ assertEquals(connectivityMetrics.counter, 0);
+ assertTrue(mWatchlistService.stopWatchlistLoggingImpl());
+ assertEquals(connectivityMetrics.counter, 0);
+ assertTrue(mWatchlistService.startWatchlistLoggingImpl());
+ assertEquals(connectivityMetrics.counter, 1);
+ assertTrue(mWatchlistService.stopWatchlistLoggingImpl());
+ assertEquals(connectivityMetrics.counter, 0);
+ }
+
+ @Test
+ public void testNetworkEvents() throws Exception {
+ TestIIpConnectivityMetrics connectivityMetrics = new TestIIpConnectivityMetrics();
+ mWatchlistService.mIpConnectivityMetrics = connectivityMetrics;
+ assertTrue(mWatchlistService.startWatchlistLoggingImpl());
+
+ // Test DNS events
+ final CountDownLatch testDnsLatch = new CountDownLatch(1);
+ final Object[] dnsParams = new Object[3];
+ final WatchlistLoggingHandler testDnsHandler =
+ new WatchlistLoggingHandler(InstrumentationRegistry.getContext(),
+ mHandlerThread.getLooper()) {
+ @Override
+ public void asyncNetworkEvent(String host, String[] ipAddresses, int uid) {
+ dnsParams[0] = host;
+ dnsParams[1] = ipAddresses;
+ dnsParams[2] = uid;
+ testDnsLatch.countDown();
+ }
+ };
+ mWatchlistService.mNetworkWatchlistHandler = testDnsHandler;
+ connectivityMetrics.callback.onDnsEvent(TEST_HOST, TEST_IPS, TEST_IPS.length, 123L, 456);
+ if (!testDnsLatch.await(NETWOR_EVENT_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for network event");
+ }
+ assertEquals(TEST_HOST, dnsParams[0]);
+ for (int i = 0; i < TEST_IPS.length; i++) {
+ assertEquals(TEST_IPS[i], ((String[])dnsParams[1])[i]);
+ }
+ assertEquals(456, dnsParams[2]);
+
+ // Test connect events
+ final CountDownLatch testConnectLatch = new CountDownLatch(1);
+ final Object[] connectParams = new Object[3];
+ final WatchlistLoggingHandler testConnectHandler =
+ new WatchlistLoggingHandler(InstrumentationRegistry.getContext(),
+ mHandlerThread.getLooper()) {
+ @Override
+ public void asyncNetworkEvent(String host, String[] ipAddresses, int uid) {
+ connectParams[0] = host;
+ connectParams[1] = ipAddresses;
+ connectParams[2] = uid;
+ testConnectLatch.countDown();
+ }
+ };
+ mWatchlistService.mNetworkWatchlistHandler = testConnectHandler;
+ connectivityMetrics.callback.onConnectEvent(TEST_IP, 80, 123L, 456);
+ if (!testConnectLatch.await(NETWOR_EVENT_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for network event");
+ }
+ assertNull(connectParams[0]);
+ assertEquals(1, ((String[]) connectParams[1]).length);
+ assertEquals(TEST_IP, ((String[]) connectParams[1])[0]);
+ assertEquals(456, connectParams[2]);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java
new file mode 100644
index 000000000000..e356b13d01d5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net.watchlist;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+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 java.util.Arrays;
+
+/**
+ * runtest frameworks-services -c com.android.server.net.watchlist.WatchlistLoggingHandlerTests
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class WatchlistLoggingHandlerTests {
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testWatchlistLoggingHandler_getAllSubDomains() throws Exception {
+ String[] subDomains = WatchlistLoggingHandler.getAllSubDomains("abc.def.gh.i.jkl.mm");
+ assertTrue(Arrays.equals(subDomains, new String[] {"abc.def.gh.i.jkl.mm",
+ "def.gh.i.jkl.mm", "gh.i.jkl.mm", "i.jkl.mm", "jkl.mm", "mm"}));
+ subDomains = WatchlistLoggingHandler.getAllSubDomains(null);
+ assertNull(subDomains);
+ subDomains = WatchlistLoggingHandler.getAllSubDomains("jkl.mm");
+ assertTrue(Arrays.equals(subDomains, new String[] {"jkl.mm", "mm"}));
+ subDomains = WatchlistLoggingHandler.getAllSubDomains("abc");
+ assertTrue(Arrays.equals(subDomains, new String[] {"abc"}));
+ subDomains = WatchlistLoggingHandler.getAllSubDomains("jkl.mm.");
+ assertTrue(Arrays.equals(subDomains, new String[] {"jkl.mm.", "mm."}));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java
new file mode 100644
index 000000000000..f3cb98078602
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.watchlist;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.HexDump;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+
+/**
+ * runtest frameworks-services -c com.android.server.net.watchlist.WatchlistSettingsTests
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class WatchlistSettingsTests {
+
+ private static final String TEST_XML_1 = "NetworkWatchlistTest/watchlist_settings_test1.xml";
+ private static final String TEST_CC_DOMAIN = "test-cc-domain.com";
+ private static final String TEST_CC_IP = "127.0.0.2";
+ private static final String TEST_NOT_EXIST_CC_DOMAIN = "test-not-exist-cc-domain.com";
+ private static final String TEST_NOT_EXIST_CC_IP = "1.2.3.4";
+ private static final String TEST_SHA256_ONLY_DOMAIN = "test-cc-match-sha256-only.com";
+ private static final String TEST_SHA256_ONLY_IP = "127.0.0.3";
+ private static final String TEST_CRC32_ONLY_DOMAIN = "test-cc-match-crc32-only.com";
+ private static final String TEST_CRC32_ONLY_IP = "127.0.0.4";
+
+ private static final String TEST_NEW_CC_DOMAIN = "test-new-cc-domain.com";
+ private static final byte[] TEST_NEW_CC_DOMAIN_SHA256 = HexDump.hexStringToByteArray(
+ "B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43");
+ private static final byte[] TEST_NEW_CC_DOMAIN_CRC32 = HexDump.hexStringToByteArray("76795BD3");
+
+ private static final String TEST_NEW_CC_IP = "1.1.1.2";
+ private static final byte[] TEST_NEW_CC_IP_SHA256 = HexDump.hexStringToByteArray(
+ "721BAB5E313CF0CC76B10F9592F18B9D1B8996497501A3306A55B3AE9F1CC87C");
+ private static final byte[] TEST_NEW_CC_IP_CRC32 = HexDump.hexStringToByteArray("940B8BEE");
+
+ private Context mContext;
+ private File mTestXmlFile;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ mTestXmlFile = new File(mContext.getFilesDir(), "test_watchlist_settings.xml");
+ mTestXmlFile.delete();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mTestXmlFile.delete();
+ }
+
+ @Test
+ public void testWatchlistSettings_parsing() throws Exception {
+ copyWatchlistSettingsXml(mContext, TEST_XML_1, mTestXmlFile);
+ WatchlistSettings settings = new WatchlistSettings(mTestXmlFile);
+ assertTrue(settings.containsDomain(TEST_CC_DOMAIN));
+ assertTrue(settings.containsIp(TEST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
+ assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
+ }
+
+ @Test
+ public void testWatchlistSettings_writeSettingsToDisk() throws Exception {
+ copyWatchlistSettingsXml(mContext, TEST_XML_1, mTestXmlFile);
+ WatchlistSettings settings = new WatchlistSettings(mTestXmlFile);
+ settings.writeSettingsToDisk(Arrays.asList(TEST_NEW_CC_DOMAIN_CRC32),
+ Arrays.asList(TEST_NEW_CC_DOMAIN_SHA256), Arrays.asList(TEST_NEW_CC_IP_CRC32),
+ Arrays.asList(TEST_NEW_CC_IP_SHA256));
+ // Ensure old watchlist is not in memory
+ assertFalse(settings.containsDomain(TEST_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
+ assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
+ // Ensure new watchlist is in memory
+ assertTrue(settings.containsDomain(TEST_NEW_CC_DOMAIN));
+ assertTrue(settings.containsIp(TEST_NEW_CC_IP));
+ // Reload settings from disk and test again
+ settings = new WatchlistSettings(mTestXmlFile);
+ // Ensure old watchlist is not in memory
+ assertFalse(settings.containsDomain(TEST_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
+ assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
+ // Ensure new watchlist is in memory
+ assertTrue(settings.containsDomain(TEST_NEW_CC_DOMAIN));
+ assertTrue(settings.containsIp(TEST_NEW_CC_IP));
+ }
+
+ @Test
+ public void testWatchlistSettings_writeSettingsToMemory() throws Exception {
+ copyWatchlistSettingsXml(mContext, TEST_XML_1, mTestXmlFile);
+ WatchlistSettings settings = new WatchlistSettings(mTestXmlFile);
+ settings.writeSettingsToMemory(Arrays.asList(TEST_NEW_CC_DOMAIN_CRC32),
+ Arrays.asList(TEST_NEW_CC_DOMAIN_SHA256), Arrays.asList(TEST_NEW_CC_IP_CRC32),
+ Arrays.asList(TEST_NEW_CC_IP_SHA256));
+ // Ensure old watchlist is not in memory
+ assertFalse(settings.containsDomain(TEST_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
+ assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
+ // Ensure new watchlist is in memory
+ assertTrue(settings.containsDomain(TEST_NEW_CC_DOMAIN));
+ assertTrue(settings.containsIp(TEST_NEW_CC_IP));
+ // Reload settings from disk and test again
+ settings = new WatchlistSettings(mTestXmlFile);
+ // Ensure old watchlist is in memory
+ assertTrue(settings.containsDomain(TEST_CC_DOMAIN));
+ assertTrue(settings.containsIp(TEST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
+ assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
+ // Ensure new watchlist is not in memory
+ assertFalse(settings.containsDomain(TEST_NEW_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_NEW_CC_IP));;
+ }
+
+ private static void copyWatchlistSettingsXml(Context context, String xmlAsset, File outFile)
+ throws IOException {
+ writeToFile(outFile, readAsset(context, xmlAsset));
+
+ }
+
+ private static String readAsset(Context context, String assetPath) throws IOException {
+ final StringBuilder sb = new StringBuilder();
+ try (BufferedReader br = new BufferedReader(
+ new InputStreamReader(
+ context.getResources().getAssets().open(assetPath)))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ sb.append(line);
+ sb.append(System.lineSeparator());
+ }
+ }
+ return sb.toString();
+ }
+
+ private static void writeToFile(File path, String content)
+ throws IOException {
+ path.getParentFile().mkdirs();
+
+ try (FileWriter writer = new FileWriter(path)) {
+ writer.write(content);
+ }
+ }
+}
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 6bb5bc6cd162..025ebc36f99b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -453,7 +453,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
}
@Override
- boolean injectCheckAccessShortcutsPermission(int callingPid, int callingUid) {
+ boolean injectHasAccessShortcutsPermission(int callingPid, int callingUid) {
return mInjectCheckAccessShortcutsPermission;
}
@@ -1648,7 +1648,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
protected void assertShortcutLaunchable(@NonNull String packageName, @NonNull String shortcutId,
int userId) {
assertNotNull(launchShortcutAndGetIntent(packageName, shortcutId, userId));
- assertNotNull(launchShortcutAndGetIntent_withShortcutInfo(packageName, shortcutId, userId));
}
protected void assertShortcutNotLaunched(@NonNull String packageName,
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 b5e8e1ca046f..f92b575bc976 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -1918,7 +1918,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
// Make sure FLAG_MATCH_ALL_PINNED will be ignored.
assertWith(mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
/* activity =*/ null, ShortcutQuery.FLAG_MATCH_PINNED
- | ShortcutQuery.FLAG_MATCH_ALL_PINNED), getCallingUser()))
+ | ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER), getCallingUser()))
.isEmpty();
// Make sure the special permission works.
@@ -1928,14 +1928,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
assertWith(mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
/* activity =*/ null, ShortcutQuery.FLAG_MATCH_PINNED
- | ShortcutQuery.FLAG_MATCH_ALL_PINNED), getCallingUser()))
+ | ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER), getCallingUser()))
.haveIds("s1", "s2");
assertWith(mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
/* activity =*/ null, ShortcutQuery.FLAG_MATCH_PINNED), getCallingUser()))
.isEmpty();
+ assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", getCallingUser().getIdentifier());
+
mInjectCheckAccessShortcutsPermission = false;
+ assertShortcutNotLaunched(CALLING_PACKAGE_2, "s1", getCallingUser().getIdentifier());
+
assertShortcutIds(assertAllDynamic(
mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
/* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
@@ -2106,6 +2110,62 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
});
}
+ public void testPinShortcutAndGetPinnedShortcuts_assistant() {
+ // Create some shortcuts.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+
+ // Pin some.
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ list("s3", "s4"), getCallingUser());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(
+ makeShortcut("s1"))));
+ });
+
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ final ShortcutQuery allPinned = new ShortcutQuery().setQueryFlags(
+ ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER);
+
+ assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0))
+ .isEmpty();
+
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+ assertShortcutNotLaunched(CALLING_PACKAGE_1, "s3", USER_0);
+ assertShortcutNotLaunched(CALLING_PACKAGE_1, "s4", USER_0);
+
+ // Make it the assistant app.
+ mInternal.setShortcutHostPackage("assistant", LAUNCHER_2, USER_0);
+ assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0))
+ .haveIds("s3");
+
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+ assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+ assertShortcutNotLaunched(CALLING_PACKAGE_1, "s4", USER_0);
+
+ mInternal.setShortcutHostPackage("another-type", LAUNCHER_3, USER_0);
+ assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0))
+ .haveIds("s3");
+
+ mInternal.setShortcutHostPackage("assistant", null, USER_0);
+ assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0))
+ .isEmpty();
+
+ mInternal.setShortcutHostPackage("assistant", LAUNCHER_2, USER_0);
+ assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0))
+ .haveIds("s3");
+
+ mInternal.setShortcutHostPackage("assistant", LAUNCHER_1, USER_0);
+ assertWith(mLauncherApps.getShortcuts(allPinned, HANDLE_USER_0))
+ .isEmpty();
+ });
+ }
+
public void testPinShortcutAndGetPinnedShortcuts_crossProfile_plusLaunch() {
// Create some shortcuts.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index b656d5e9a343..dd9a8abff8f1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -309,6 +309,8 @@ public class UserManagerTest extends AndroidTestCase {
@MediumTest
public void testAddRestrictedProfile() throws Exception {
+ assertFalse("There should be no associated restricted profiles before the test",
+ mUserManager.hasRestrictedProfiles());
UserInfo userInfo = createRestrictedProfile("Profile");
assertNotNull(userInfo);
@@ -324,6 +326,9 @@ public class UserManagerTest extends AndroidTestCase {
userInfo.id);
assertEquals("Restricted profile should have setting LOCATION_MODE set to "
+ "LOCATION_MODE_OFF by default", locationMode, Settings.Secure.LOCATION_MODE_OFF);
+
+ assertTrue("Newly created profile should be associated with the current user",
+ mUserManager.hasRestrictedProfiles());
}
@MediumTest
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
index 480be2e90ed2..882bf32fcb68 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -89,6 +89,7 @@ public class UserRestrictionsUtilsTest extends AndroidTestCase {
assertFalse(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_RECORD_AUDIO));
assertFalse(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_WALLPAPER));
assertTrue(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_ADD_USER));
+ assertTrue(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_USER_SWITCH));
}
public void testCanProfileOwnerChange() {
@@ -97,6 +98,8 @@ public class UserRestrictionsUtilsTest extends AndroidTestCase {
UserManager.DISALLOW_RECORD_AUDIO, user));
assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
UserManager.DISALLOW_WALLPAPER, user));
+ assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
+ UserManager.DISALLOW_USER_SWITCH, user));
assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
UserManager.DISALLOW_ADD_USER, user));
assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
@@ -109,6 +112,8 @@ public class UserRestrictionsUtilsTest extends AndroidTestCase {
UserManager.DISALLOW_WALLPAPER, user));
assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
UserManager.DISALLOW_ADD_USER, user));
+ assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
+ UserManager.DISALLOW_USER_SWITCH, user));
assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
UserManager.DISALLOW_ADJUST_VOLUME, user));
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/crossprofile/CrossProfileAppsServiceImplTest.java b/services/tests/servicestests/src/com/android/server/pm/crossprofile/CrossProfileAppsServiceImplTest.java
new file mode 100644
index 000000000000..880b77ed81da
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/crossprofile/CrossProfileAppsServiceImplTest.java
@@ -0,0 +1,449 @@
+package com.android.server.pm.crossprofile;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.app.AppOpsManager;
+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.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.platform.test.annotations.Presubmit;
+import android.util.SparseArray;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Build/Install/Run:
+ * bit FrameworksServicesTests:com.android.server.pm.crossprofile.CrossProfileAppsServiceImplTest
+ */
+@Presubmit
+@RunWith(MockitoJUnitRunner.class)
+public class CrossProfileAppsServiceImplTest {
+ private static final String PACKAGE_ONE = "com.one";
+ private static final int PACKAGE_ONE_UID = 1111;
+ private static final ComponentName ACTIVITY_COMPONENT =
+ new ComponentName("com.one", "test");
+
+ private static final String PACKAGE_TWO = "com.two";
+ private static final int PACKAGE_TWO_UID = 2222;
+
+ private static final int PRIMARY_USER = 0;
+ private static final int PROFILE_OF_PRIMARY_USER = 10;
+ private static final int SECONDARY_USER = 11;
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private PackageManagerInternal mPackageManagerInternal;
+ @Mock
+ private AppOpsManager mAppOpsManager;
+
+ private TestInjector mTestInjector;
+ private ActivityInfo mActivityInfo;
+ private CrossProfileAppsServiceImpl mCrossProfileAppsServiceImpl;
+
+ private SparseArray<Boolean> mUserEnabled = new SparseArray<>();
+
+ @Before
+ public void initCrossProfileAppsServiceImpl() {
+ mTestInjector = new TestInjector();
+ mCrossProfileAppsServiceImpl = new CrossProfileAppsServiceImpl(mContext, mTestInjector);
+ }
+
+ @Before
+ public void setupEnabledProfiles() {
+ mUserEnabled.put(PRIMARY_USER, true);
+ mUserEnabled.put(PROFILE_OF_PRIMARY_USER, true);
+ mUserEnabled.put(SECONDARY_USER, true);
+
+ when(mUserManager.getEnabledProfileIds(anyInt())).thenAnswer(
+ invocation -> {
+ List<Integer> users = new ArrayList<>();
+ final int targetUser = invocation.getArgument(0);
+ users.add(targetUser);
+
+ int profileUserId = -1;
+ if (targetUser == PRIMARY_USER) {
+ profileUserId = PROFILE_OF_PRIMARY_USER;
+ } else if (targetUser == PROFILE_OF_PRIMARY_USER) {
+ profileUserId = PRIMARY_USER;
+ }
+
+ if (profileUserId != -1 && mUserEnabled.get(profileUserId)) {
+ users.add(profileUserId);
+ }
+ return users.stream().mapToInt(i -> i).toArray();
+ });
+ }
+
+ @Before
+ public void setupCaller() {
+ mTestInjector.setCallingUid(PACKAGE_ONE_UID);
+ mTestInjector.setCallingUserId(PRIMARY_USER);
+ }
+
+ @Before
+ public void setupPackage() throws Exception {
+ // PACKAGE_ONE are installed in all users.
+ mockAppsInstalled(PACKAGE_ONE, PRIMARY_USER, true);
+ mockAppsInstalled(PACKAGE_ONE, PROFILE_OF_PRIMARY_USER, true);
+ mockAppsInstalled(PACKAGE_ONE, SECONDARY_USER, true);
+
+ // Packages are resolved to their corresponding UID.
+ doAnswer(invocation -> {
+ final int uid = invocation.getArgument(0);
+ final String packageName = invocation.getArgument(1);
+ if (uid == PACKAGE_ONE_UID && PACKAGE_ONE.equals(packageName)) {
+ return null;
+ } else if (uid ==PACKAGE_TWO_UID && PACKAGE_TWO.equals(packageName)) {
+ return null;
+ }
+ throw new SecurityException("Not matching");
+ }).when(mAppOpsManager).checkPackage(anyInt(), anyString());
+
+ // The intent is resolved to the ACTIVITY_COMPONENT.
+ mockActivityLaunchIntentResolvedTo(ACTIVITY_COMPONENT);
+ }
+
+ @Test
+ public void getTargetUserProfiles_fromPrimaryUser_installed() throws Exception {
+ List<UserHandle> targetProfiles =
+ mCrossProfileAppsServiceImpl.getTargetUserProfiles(PACKAGE_ONE);
+ assertThat(targetProfiles).containsExactly(UserHandle.of(PROFILE_OF_PRIMARY_USER));
+ }
+
+ @Test
+ public void getTargetUserProfiles_fromPrimaryUser_notInstalled() throws Exception {
+ mockAppsInstalled(PACKAGE_ONE, PROFILE_OF_PRIMARY_USER, false);
+
+ List<UserHandle> targetProfiles =
+ mCrossProfileAppsServiceImpl.getTargetUserProfiles(PACKAGE_ONE);
+ assertThat(targetProfiles).isEmpty();
+ }
+
+ @Test
+ public void getTargetUserProfiles_fromPrimaryUser_userNotEnabled() throws Exception {
+ mUserEnabled.put(PROFILE_OF_PRIMARY_USER, false);
+
+ List<UserHandle> targetProfiles =
+ mCrossProfileAppsServiceImpl.getTargetUserProfiles(PACKAGE_ONE);
+ assertThat(targetProfiles).isEmpty();
+ }
+
+ @Test
+ public void getTargetUserProfiles_fromSecondaryUser() throws Exception {
+ mTestInjector.setCallingUserId(SECONDARY_USER);
+
+ List<UserHandle> targetProfiles =
+ mCrossProfileAppsServiceImpl.getTargetUserProfiles(PACKAGE_ONE);
+ assertThat(targetProfiles).isEmpty();
+ }
+
+ @Test
+ public void getTargetUserProfiles_fromProfile_installed() throws Exception {
+ mTestInjector.setCallingUserId(PROFILE_OF_PRIMARY_USER);
+
+ List<UserHandle> targetProfiles =
+ mCrossProfileAppsServiceImpl.getTargetUserProfiles(PACKAGE_ONE);
+ assertThat(targetProfiles).containsExactly(UserHandle.of(PRIMARY_USER));
+ }
+
+ @Test
+ public void getTargetUserProfiles_fromProfile_notInstalled() throws Exception {
+ mTestInjector.setCallingUserId(PROFILE_OF_PRIMARY_USER);
+ mockAppsInstalled(PACKAGE_ONE, PRIMARY_USER, false);
+
+ List<UserHandle> targetProfiles =
+ mCrossProfileAppsServiceImpl.getTargetUserProfiles(PACKAGE_ONE);
+ assertThat(targetProfiles).isEmpty();
+ }
+
+ @Test(expected = SecurityException.class)
+ public void getTargetUserProfiles_fakeCaller() throws Exception {
+ mCrossProfileAppsServiceImpl.getTargetUserProfiles(PACKAGE_TWO);
+ }
+
+ @Test
+ public void startActivityAsUser_currentUser() throws Exception {
+ assertThrows(
+ SecurityException.class,
+ () ->
+ mCrossProfileAppsServiceImpl.startActivityAsUser(
+ PACKAGE_ONE,
+ ACTIVITY_COMPONENT,
+ null,
+ null,
+ UserHandle.of(PRIMARY_USER)));
+
+ verify(mContext, never())
+ .startActivityAsUser(
+ any(Intent.class),
+ nullable(Bundle.class),
+ any(UserHandle.class));
+ }
+
+ @Test
+ public void startActivityAsUser_profile_successWithOption() throws Exception {
+ Bundle options = Bundle.forPair("test_key", "test_value");
+
+ mCrossProfileAppsServiceImpl.startActivityAsUser(
+ PACKAGE_ONE,
+ ACTIVITY_COMPONENT,
+ null,
+ options,
+ UserHandle.of(PROFILE_OF_PRIMARY_USER));
+
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
+
+ verify(mContext)
+ .startActivityAsUser(
+ intentCaptor.capture(),
+ bundleCaptor.capture(),
+ eq(UserHandle.of(PROFILE_OF_PRIMARY_USER)));
+
+ Intent intent = intentCaptor.getValue();
+ assertEquals(ACTIVITY_COMPONENT, intent.getComponent());
+
+ Bundle bundle = bundleCaptor.getValue();
+ assertEquals("test_value", bundle.getString("test_key"));
+ }
+
+ @Test
+ public void startActivityAsUser_profile_notInstalled() throws Exception {
+ mockAppsInstalled(PACKAGE_ONE, PROFILE_OF_PRIMARY_USER, false);
+
+ assertThrows(
+ SecurityException.class,
+ () ->
+ mCrossProfileAppsServiceImpl.startActivityAsUser(
+ PACKAGE_ONE,
+ ACTIVITY_COMPONENT,
+ null,
+ null,
+ UserHandle.of(PROFILE_OF_PRIMARY_USER)));
+
+ verify(mContext, never())
+ .startActivityAsUser(
+ any(Intent.class),
+ nullable(Bundle.class),
+ any(UserHandle.class));
+ }
+
+ @Test
+ public void startActivityAsUser_profile_fakeCaller() throws Exception {
+ assertThrows(
+ SecurityException.class,
+ () ->
+ mCrossProfileAppsServiceImpl.startActivityAsUser(
+ PACKAGE_TWO,
+ ACTIVITY_COMPONENT,
+ null,
+ null,
+ UserHandle.of(PROFILE_OF_PRIMARY_USER)));
+
+ verify(mContext, never())
+ .startActivityAsUser(
+ any(Intent.class),
+ nullable(Bundle.class),
+ any(UserHandle.class));
+ }
+
+ @Test
+ public void startActivityAsUser_profile_notExported() throws Exception {
+ mActivityInfo.exported = false;
+
+ assertThrows(
+ SecurityException.class,
+ () ->
+ mCrossProfileAppsServiceImpl.startActivityAsUser(
+ PACKAGE_ONE,
+ ACTIVITY_COMPONENT,
+ null,
+ null,
+ UserHandle.of(PROFILE_OF_PRIMARY_USER)));
+
+ verify(mContext, never())
+ .startActivityAsUser(
+ any(Intent.class),
+ nullable(Bundle.class),
+ any(UserHandle.class));
+ }
+
+ @Test
+ public void startActivityAsUser_profile_anotherPackage() throws Exception {
+ assertThrows(
+ SecurityException.class,
+ () ->
+ mCrossProfileAppsServiceImpl.startActivityAsUser(
+ PACKAGE_ONE,
+ new ComponentName(PACKAGE_TWO, "test"),
+ null,
+ null,
+ UserHandle.of(PROFILE_OF_PRIMARY_USER)));
+
+ verify(mContext, never())
+ .startActivityAsUser(
+ any(Intent.class),
+ nullable(Bundle.class),
+ any(UserHandle.class));
+ }
+
+ @Test
+ public void startActivityAsUser_secondaryUser() throws Exception {
+ assertThrows(
+ SecurityException.class,
+ () ->
+ mCrossProfileAppsServiceImpl.startActivityAsUser(
+ PACKAGE_ONE,
+ ACTIVITY_COMPONENT,
+ null,
+ null,
+ UserHandle.of(SECONDARY_USER)));
+
+ verify(mContext, never())
+ .startActivityAsUser(
+ any(Intent.class),
+ nullable(Bundle.class),
+ any(UserHandle.class));
+ }
+
+ @Test
+ public void startActivityAsUser_fromProfile_success() throws Exception {
+ mTestInjector.setCallingUserId(PROFILE_OF_PRIMARY_USER);
+
+ mCrossProfileAppsServiceImpl.startActivityAsUser(
+ PACKAGE_ONE,
+ ACTIVITY_COMPONENT,
+ null,
+ null,
+ UserHandle.of(PRIMARY_USER));
+
+ verify(mContext)
+ .startActivityAsUser(
+ any(Intent.class),
+ nullable(Bundle.class),
+ eq(UserHandle.of(PRIMARY_USER)));
+ }
+
+ private void mockAppsInstalled(String packageName, int user, boolean installed) {
+ when(mPackageManagerInternal.getPackageInfo(
+ eq(packageName),
+ anyInt(),
+ anyInt(),
+ eq(user)))
+ .thenReturn(installed ? createInstalledPackageInfo() : null);
+ }
+
+ private PackageInfo createInstalledPackageInfo() {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.applicationInfo.enabled = true;
+ return packageInfo;
+ }
+
+ private void mockActivityLaunchIntentResolvedTo(ComponentName componentName) {
+ ResolveInfo resolveInfo = new ResolveInfo();
+ ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.packageName = componentName.getPackageName();
+ activityInfo.name = componentName.getClassName();
+ activityInfo.exported = true;
+ resolveInfo.activityInfo = activityInfo;
+ mActivityInfo = activityInfo;
+
+ when(mPackageManagerInternal.queryIntentActivities(
+ any(Intent.class), anyInt(), anyInt(), anyInt()))
+ .thenReturn(Collections.singletonList(resolveInfo));
+ }
+
+ private class TestInjector implements CrossProfileAppsServiceImpl.Injector {
+ private int mCallingUid;
+ private int mCallingUserId;
+
+ public void setCallingUid(int uid) {
+ mCallingUid = uid;
+ }
+
+ public void setCallingUserId(int userId) {
+ mCallingUserId = userId;
+ }
+
+ @Override
+ public int getCallingUid() {
+ return mCallingUid;
+ }
+
+ @Override
+ public int getCallingUserId() {
+ return mCallingUserId;
+ }
+
+ @Override
+ public UserHandle getCallingUserHandle() {
+ return UserHandle.of(mCallingUserId);
+ }
+
+ @Override
+ public long clearCallingIdentity() {
+ return 0;
+ }
+
+ @Override
+ public void restoreCallingIdentity(long token) {
+ }
+
+ @Override
+ public UserManager getUserManager() {
+ return mUserManager;
+ }
+
+ @Override
+ public PackageManagerInternal getPackageManagerInternal() {
+ return mPackageManagerInternal;
+ }
+
+ @Override
+ public PackageManager getPackageManager() {
+ return mPackageManager;
+ }
+
+ @Override
+ public AppOpsManager getAppOpsManager() {
+ return mAppOpsManager;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
index 69589e7d1f66..5b6225e79f8e 100644
--- a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
@@ -15,12 +15,16 @@
*/
package com.android.server.power;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.Handler;
+import android.provider.Settings;
+import android.provider.Settings.Global;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArrayMap;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
+import com.android.frameworks.servicestests.R;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -37,7 +41,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
private static final float DEFAULT_BRIGHTNESS_FACTOR = 0.5f;
private static final float PRECISION = 0.001f;
private static final int GPS_MODE = 0;
- private static final int DEFAULT_GPS_MODE = 1;
+ private static final int DEFAULT_GPS_MODE = 0;
private static final String BATTERY_SAVER_CONSTANTS = "vibration_disabled=true,"
+ "animation_disabled=false,"
+ "soundtrigger_disabled=true,"
@@ -50,15 +54,34 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
+ "gps_mode=0";
private static final String BATTERY_SAVER_INCORRECT_CONSTANTS = "vi*,!=,,true";
+ private class BatterySaverPolicyForTest extends BatterySaverPolicy {
+ public BatterySaverPolicyForTest(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ String getGlobalSetting(String key) {
+ return mMockGlobalSettings.get(key);
+ }
+
+ @Override
+ int getDeviceSpecificConfigResId() {
+ return mDeviceSpecificConfigResId;
+ }
+ }
+
@Mock
Handler mHandler;
- private BatterySaverPolicy mBatterySaverPolicy;
+ private BatterySaverPolicyForTest mBatterySaverPolicy;
+
+ private final ArrayMap<String, String> mMockGlobalSettings = new ArrayMap<>();
+ private int mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_1;
public void setUp() throws Exception {
super.setUp();
MockitoAnnotations.initMocks(this);
- mBatterySaverPolicy = new BatterySaverPolicy(mHandler);
- mBatterySaverPolicy.start(getContext().getContentResolver());
+ mBatterySaverPolicy = new BatterySaverPolicyForTest(mHandler);
+ mBatterySaverPolicy.systemReady(getContext());
}
@SmallTest
@@ -103,7 +126,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
@SmallTest
public void testGetBatterySaverPolicy_PolicyDataSaver_DefaultValueCorrect() {
- mBatterySaverPolicy.updateConstants("");
+ mBatterySaverPolicy.updateConstantsLocked("", "");
final PowerSaveState batterySaverStateOn =
mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.DATA_SAVER, BATTERY_SAVER_ON);
assertThat(batterySaverStateOn.batterySaverEnabled).isFalse();
@@ -133,7 +156,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
@SmallTest
public void testUpdateConstants_getCorrectData() {
- mBatterySaverPolicy.updateConstants(BATTERY_SAVER_CONSTANTS);
+ mBatterySaverPolicy.updateConstantsLocked(BATTERY_SAVER_CONSTANTS, "");
final PowerSaveState vibrationState =
mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.VIBRATION, BATTERY_SAVER_ON);
@@ -178,12 +201,12 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
@SmallTest
public void testUpdateConstants_IncorrectData_NotCrash() {
//Should not crash
- mBatterySaverPolicy.updateConstants(BATTERY_SAVER_INCORRECT_CONSTANTS);
- mBatterySaverPolicy.updateConstants(null);
+ mBatterySaverPolicy.updateConstantsLocked(BATTERY_SAVER_INCORRECT_CONSTANTS, "");
+ mBatterySaverPolicy.updateConstantsLocked(null, "");
}
private void testServiceDefaultValue(@ServiceType int type) {
- mBatterySaverPolicy.updateConstants("");
+ mBatterySaverPolicy.updateConstantsLocked("", "");
final PowerSaveState batterySaverStateOn =
mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_ON);
assertThat(batterySaverStateOn.batterySaverEnabled).isTrue();
@@ -192,4 +215,37 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_OFF);
assertThat(batterySaverStateOff.batterySaverEnabled).isFalse();
}
+
+ public void testDeviceSpecific() {
+ mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_1;
+ mMockGlobalSettings.put(Global.BATTERY_SAVER_CONSTANTS, "");
+ mMockGlobalSettings.put(Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS, "");
+
+ mBatterySaverPolicy.onChangeForTest();
+ assertThat(mBatterySaverPolicy.getFileValues(true).toString()).isEqualTo("{}");
+ assertThat(mBatterySaverPolicy.getFileValues(false).toString()).isEqualTo("{}");
+
+
+ mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_2;
+
+ mBatterySaverPolicy.onChangeForTest();
+ assertThat(mBatterySaverPolicy.getFileValues(true).toString()).isEqualTo("{}");
+ assertThat(mBatterySaverPolicy.getFileValues(false).toString())
+ .isEqualTo("{/sys/a=1, /sys/b=2}");
+
+
+ mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_3;
+
+ mBatterySaverPolicy.onChangeForTest();
+ assertThat(mBatterySaverPolicy.getFileValues(true).toString()).isEqualTo("{/proc/c=4}");
+ assertThat(mBatterySaverPolicy.getFileValues(false).toString()).isEqualTo("{/sys/a=3}");
+
+
+ mMockGlobalSettings.put(Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS,
+ "file-on:/proc/z=4");
+
+ mBatterySaverPolicy.onChangeForTest();
+ assertThat(mBatterySaverPolicy.getFileValues(true).toString()).isEqualTo("{/proc/z=4}");
+ assertThat(mBatterySaverPolicy.getFileValues(false).toString()).isEqualTo("{}");
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 4559660351b0..5039e424c4dc 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -16,32 +16,28 @@
package com.android.server.power;
-import android.content.Context;
+import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
+import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.when;
+
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.os.PowerManager;
import android.os.PowerSaveState;
import android.os.SystemProperties;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
-import android.text.TextUtils;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
+
+import com.android.server.power.batterysaver.BatterySaverController;
+
import org.junit.Rule;
-import org.junit.rules.TemporaryFolder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
-import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
-import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
-import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.when;
-
/**
* Tests for {@link com.android.server.power.PowerManagerService}
*/
@@ -66,7 +62,7 @@ public class PowerManagerServiceTest extends AndroidTestCase {
.setBrightnessFactor(BRIGHTNESS_FACTOR)
.build();
when(mBatterySaverPolicy.getBatterySaverPolicy(
- eq(BatterySaverPolicy.ServiceType.SCREEN_BRIGHTNESS), anyBoolean()))
+ eq(PowerManager.ServiceType.SCREEN_BRIGHTNESS), anyBoolean()))
.thenReturn(mPowerSaveState);
mDisplayPowerRequest = new DisplayPowerRequest();
mService = new PowerManagerService(getContext(), mBatterySaverPolicy);
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 67ffe5847cbc..39d256a21f16 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
@@ -16,16 +16,14 @@
package com.android.server.usage;
-import static android.app.usage.AppStandby.REASON_TIMEOUT;
-import static android.app.usage.AppStandby.STANDBY_BUCKET_ACTIVE;
-import static android.app.usage.AppStandby.STANDBY_BUCKET_RARE;
-
import android.app.usage.AppStandby;
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;
@@ -111,5 +109,9 @@ public class AppIdleHistoryTests extends AndroidTestCase {
assertEquals(aih.getAppStandbyBucket(PACKAGE_1, USER_ID, 5000), STANDBY_BUCKET_RARE);
assertEquals(aih.getAppStandbyBucket(PACKAGE_2, USER_ID, 5000), STANDBY_BUCKET_ACTIVE);
assertEquals(aih.getAppStandbyReason(PACKAGE_1, USER_ID, 5000), REASON_TIMEOUT);
+
+ assertTrue(aih.shouldInformListeners(PACKAGE_1, USER_ID, 5000, STANDBY_BUCKET_RARE));
+ assertFalse(aih.shouldInformListeners(PACKAGE_1, USER_ID, 5000, STANDBY_BUCKET_RARE));
+ assertTrue(aih.shouldInformListeners(PACKAGE_1, USER_ID, 5000, STANDBY_BUCKET_FREQUENT));
}
} \ No newline at end of file
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 9846d6f6f346..8531baf5f329 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -16,11 +16,7 @@
package com.android.server.usage;
-import static android.app.usage.AppStandby.STANDBY_BUCKET_ACTIVE;
-import static android.app.usage.AppStandby.STANDBY_BUCKET_FREQUENT;
-import static android.app.usage.AppStandby.STANDBY_BUCKET_RARE;
-import static android.app.usage.AppStandby.STANDBY_BUCKET_WORKING_SET;
-
+import static android.app.usage.AppStandby.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -251,10 +247,22 @@ public class AppStandbyControllerTests {
false));
}
+ private void reportEvent(AppStandbyController controller, long elapsedTime) {
+ // Back to ACTIVE on event
+ UsageEvents.Event ev = new UsageEvents.Event();
+ ev.mPackage = PACKAGE_1;
+ ev.mEventType = UsageEvents.Event.USER_INTERACTION;
+ controller.reportEvent(ev, elapsedTime, USER_ID);
+ }
+
@Test
public void testBuckets() throws Exception {
AppStandbyController controller = setupController();
+ assertTimeout(controller, 0, STANDBY_BUCKET_NEVER);
+
+ reportEvent(controller, 0);
+
// ACTIVE bucket
assertTimeout(controller, 11 * HOUR_MS, STANDBY_BUCKET_ACTIVE);
@@ -270,11 +278,7 @@ public class AppStandbyControllerTests {
// RARE bucket
assertTimeout(controller, 9 * DAY_MS, STANDBY_BUCKET_RARE);
- // Back to ACTIVE on event
- UsageEvents.Event ev = new UsageEvents.Event();
- ev.mPackage = PACKAGE_1;
- ev.mEventType = UsageEvents.Event.USER_INTERACTION;
- controller.reportEvent(ev, mInjector.mElapsedRealtime, USER_ID);
+ reportEvent(controller, 9 * DAY_MS);
assertTimeout(controller, 9 * DAY_MS, STANDBY_BUCKET_ACTIVE);
@@ -287,6 +291,10 @@ public class AppStandbyControllerTests {
AppStandbyController controller = setupController();
mInjector.setDisplayOn(false);
+ assertTimeout(controller, 0, STANDBY_BUCKET_NEVER);
+
+ reportEvent(controller, 0);
+
// ACTIVE bucket
assertTimeout(controller, 11 * HOUR_MS, STANDBY_BUCKET_ACTIVE);
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index ea4f4b907824..bb882641c55f 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -46,11 +46,13 @@ import static org.junit.Assert.assertTrue;
* bit FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests
*/
@SmallTest
-@Presubmit
+// TODO: b/68267650
+// @Presubmit
@RunWith(AndroidJUnit4.class)
public class AppWindowTokenTests extends WindowTestsBase {
@Test
+ @Presubmit
public void testAddWindow_Order() throws Exception {
final WindowTestUtils.TestAppWindowToken token =
new WindowTestUtils.TestAppWindowToken(mDisplayContent);
@@ -79,6 +81,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
}
@Test
+ @Presubmit
public void testFindMainWindow() throws Exception {
final WindowTestUtils.TestAppWindowToken token =
new WindowTestUtils.TestAppWindowToken(mDisplayContent);
@@ -97,6 +100,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
}
@Test
+ @Presubmit
public void testGetTopFullscreenWindow() throws Exception {
final WindowTestUtils.TestAppWindowToken token =
new WindowTestUtils.TestAppWindowToken(mDisplayContent);
@@ -187,6 +191,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
}
@Test
+ @Presubmit
public void testGetOrientation() throws Exception {
final WindowTestUtils.TestAppWindowToken token =
new WindowTestUtils.TestAppWindowToken(mDisplayContent);
@@ -211,6 +216,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
}
@Test
+ @Presubmit
public void testKeyguardFlagsDuringRelaunch() throws Exception {
final WindowTestUtils.TestAppWindowToken token =
new WindowTestUtils.TestAppWindowToken(mDisplayContent);
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 27c5eab2d14c..693264cbe4ee 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -18,10 +18,14 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+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_UNSPECIFIED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.junit.Assert.assertEquals;
@@ -31,6 +35,7 @@ import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import android.annotation.SuppressLint;
import android.content.res.Configuration;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
@@ -379,6 +384,31 @@ public class DisplayContentTests extends WindowTestsBase {
assertEquals(-1, orderedDisplayIds.indexOfValue(dc.getDisplayId()));
}
+ @Test
+ @SuppressLint("InlinedApi")
+ public void testOrientationDefinedByKeyguard() {
+ final DisplayContent dc = createNewDisplay();
+ // Create a window that requests landscape orientation. It will define device orientation
+ // by default.
+ final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
+ window.mAppToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+
+ final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR, dc, "keyguard");
+ keyguard.mHasSurface = true;
+ keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+
+ assertEquals("Screen orientation must be defined by the app window by default",
+ SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
+
+ keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
+ assertEquals("Visible keyguard must influence device orientation",
+ SCREEN_ORIENTATION_PORTRAIT, dc.getOrientation());
+
+ sWm.setKeyguardGoingAway(true);
+ assertEquals("Keyguard that is going away must not influence device orientation",
+ SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
+ }
+
private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
int expectedBaseHeight, int expectedBaseDensity) {
assertEquals(displayContent.mBaseDisplayWidth, expectedBaseWidth);
diff --git a/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java
new file mode 100644
index 000000000000..f23bd6209614
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.graphics.Color.BLUE;
+import static android.graphics.Color.RED;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Gravity.BOTTOM;
+import static android.view.Gravity.LEFT;
+import static android.view.Gravity.RIGHT;
+import static android.view.Gravity.TOP;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static org.junit.Assert.assertEquals;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.media.ImageReader;
+import android.os.Handler;
+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.Pair;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+/**
+ * Tests for the {@link android.view.WindowManager.LayoutParams#PRIVATE_FLAG_IS_SCREEN_DECOR} flag.
+ *
+ * Build/Install/Run:
+ * bit FrameworksServicesTests:com.android.server.wm.ScreenDecorWindowTests
+ */
+// TODO: Add test for FLAG_FULLSCREEN which hides the status bar and also other flags.
+// TODO: Test non-Activity windows.
+@SmallTest
+// TODO(b/68957554)
+//@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ScreenDecorWindowTests {
+
+ private final Context mContext = InstrumentationRegistry.getTargetContext();
+ private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
+
+ private WindowManager mWm;
+ private ArrayList<View> mWindows = new ArrayList<>();
+
+ private Activity mTestActivity;
+ private VirtualDisplay mDisplay;
+ private ImageReader mImageReader;
+
+ private int mDecorThickness;
+ private int mHalfDecorThickness;
+
+ @Before
+ public void setUp() {
+ final Pair<VirtualDisplay, ImageReader> result = createDisplay();
+ mDisplay = result.first;
+ mImageReader = result.second;
+ final Display display = mDisplay.getDisplay();
+ final Context dContext = mContext.createDisplayContext(display);
+ mWm = dContext.getSystemService(WindowManager.class);
+ mTestActivity = startActivityOnDisplay(TestActivity.class, display.getDisplayId());
+ final Point size = new Point();
+ mDisplay.getDisplay().getRealSize(size);
+ mDecorThickness = Math.min(size.x, size.y) / 3;
+ mHalfDecorThickness = mDecorThickness / 2;
+ }
+
+ @After
+ public void tearDown() {
+ while (!mWindows.isEmpty()) {
+ removeWindow(mWindows.get(0));
+ }
+ finishActivity(mTestActivity);
+ mDisplay.release();
+ mImageReader.close();
+ }
+
+ @Test
+ public void testScreenSides() throws Exception {
+ // Decor on top
+ final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
+ WindowInsets insets = getInsets(mTestActivity);
+ assertGreaterOrEqual(insets.getSystemWindowInsetTop(), mDecorThickness);
+
+ // Decor at the bottom
+ updateWindow(decorWindow, BOTTOM, MATCH_PARENT, mDecorThickness, 0, 0);
+ insets = getInsets(mTestActivity);
+ assertGreaterOrEqual(insets.getSystemWindowInsetBottom(), mDecorThickness);
+
+ // Decor to the left
+ updateWindow(decorWindow, LEFT, mDecorThickness, MATCH_PARENT, 0, 0);
+ insets = getInsets(mTestActivity);
+ assertGreaterOrEqual(insets.getSystemWindowInsetLeft(), mDecorThickness);
+
+ // Decor to the right
+ updateWindow(decorWindow, RIGHT, mDecorThickness, MATCH_PARENT, 0, 0);
+ insets = getInsets(mTestActivity);
+ assertGreaterOrEqual(insets.getSystemWindowInsetRight(), mDecorThickness);
+ }
+
+ @Test
+ public void testMultipleDecors() throws Exception {
+ // Test 2 decor windows on-top.
+ createDecorWindow(TOP, MATCH_PARENT, mHalfDecorThickness);
+ WindowInsets insets = getInsets(mTestActivity);
+ assertGreaterOrEqual(insets.getSystemWindowInsetTop(), mHalfDecorThickness);
+ createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
+ insets = getInsets(mTestActivity);
+ assertGreaterOrEqual(insets.getSystemWindowInsetTop(), mDecorThickness);
+
+ // And one at the bottom.
+ createDecorWindow(BOTTOM, MATCH_PARENT, mHalfDecorThickness);
+ insets = getInsets(mTestActivity);
+ assertGreaterOrEqual(insets.getSystemWindowInsetTop(), mDecorThickness);
+ assertGreaterOrEqual(insets.getSystemWindowInsetBottom(), mHalfDecorThickness);
+ }
+
+ @Test
+ public void testFlagChange() throws Exception {
+ WindowInsets initialInsets = getInsets(mTestActivity);
+
+ final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
+ WindowInsets insets = getInsets(mTestActivity);
+ assertEquals(mDecorThickness, insets.getSystemWindowInsetTop());
+
+ updateWindow(decorWindow, TOP, MATCH_PARENT, mDecorThickness,
+ 0, PRIVATE_FLAG_IS_SCREEN_DECOR);
+ insets = getInsets(mTestActivity);
+ assertEquals(initialInsets.getSystemWindowInsetTop(), insets.getSystemWindowInsetTop());
+
+ updateWindow(decorWindow, TOP, MATCH_PARENT, mDecorThickness,
+ PRIVATE_FLAG_IS_SCREEN_DECOR, PRIVATE_FLAG_IS_SCREEN_DECOR);
+ insets = getInsets(mTestActivity);
+ assertEquals(mDecorThickness, insets.getSystemWindowInsetTop());
+ }
+
+ @Test
+ public void testRemoval() throws Exception {
+ WindowInsets initialInsets = getInsets(mTestActivity);
+
+ final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
+ WindowInsets insets = getInsets(mTestActivity);
+ assertGreaterOrEqual(insets.getSystemWindowInsetTop(), mDecorThickness);
+
+ removeWindow(decorWindow);
+ insets = getInsets(mTestActivity);
+ assertEquals(initialInsets.getSystemWindowInsetTop(), insets.getSystemWindowInsetTop());
+ }
+
+ private View createAppWindow() {
+ return createWindow("appWindow", TOP, MATCH_PARENT, MATCH_PARENT, BLUE,
+ FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR, 0);
+ }
+
+ private View createDecorWindow(int gravity, int width, int height) {
+ return createWindow("decorWindow", gravity, width, height, RED,
+ FLAG_LAYOUT_IN_SCREEN, PRIVATE_FLAG_IS_SCREEN_DECOR);
+ }
+
+ private View createWindow(String name, int gravity, int width, int height, int color, int flags,
+ int privateFlags) {
+
+ final View[] viewHolder = new View[1];
+ final int finalFlag = flags
+ | FLAG_NOT_FOCUSABLE | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_NOT_TOUCHABLE;
+
+ // Needs to run on the UI thread.
+ Handler.getMain().runWithScissors(() -> {
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ width, height, TYPE_APPLICATION_OVERLAY, finalFlag, PixelFormat.OPAQUE);
+ lp.gravity = gravity;
+ lp.privateFlags |= privateFlags;
+
+ final TextView view = new TextView(mContext);
+ view.setText("ScreenDecorWindowTests - " + name);
+ view.setBackgroundColor(color);
+ mWm.addView(view, lp);
+ mWindows.add(view);
+ viewHolder[0] = view;
+ }, 0);
+
+ waitForIdle();
+ return viewHolder[0];
+ }
+
+ private void updateWindow(View v, int gravity, int width, int height,
+ int privateFlags, int privateFlagsMask) {
+ // Needs to run on the UI thread.
+ Handler.getMain().runWithScissors(() -> {
+ final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) v.getLayoutParams();
+ lp.gravity = gravity;
+ lp.width = width;
+ lp.height = height;
+ setPrivateFlags(lp, privateFlags, privateFlagsMask);
+
+ mWm.updateViewLayout(v, lp);
+ }, 0);
+
+ waitForIdle();
+ }
+
+ private void removeWindow(View v) {
+ Handler.getMain().runWithScissors(() -> mWm.removeView(v), 0);
+ mWindows.remove(v);
+ waitForIdle();
+ }
+
+ private WindowInsets getInsets(View v) {
+ return new WindowInsets(v.getRootWindowInsets());
+ }
+
+ private WindowInsets getInsets(Activity a) {
+ return new WindowInsets(a.getWindow().getDecorView().getRootWindowInsets());
+ }
+
+ /**
+ * Set the flags of the window, as per the
+ * {@link WindowManager.LayoutParams WindowManager.LayoutParams}
+ * flags.
+ *
+ * @param flags The new window flags (see WindowManager.LayoutParams).
+ * @param mask Which of the window flag bits to modify.
+ */
+ public void setPrivateFlags(WindowManager.LayoutParams lp, int flags, int mask) {
+ lp.flags = (lp.flags & ~mask) | (flags & mask);
+ }
+
+ /** Asserts that the first entry is greater than or equal to the second entry. */
+ private void assertGreaterOrEqual(int first, int second) throws Exception {
+ Assert.assertTrue("Excepted " + first + " >= " + second, first >= second);
+ }
+
+ private void finishActivity(Activity a) {
+ if (a == null) {
+ return;
+ }
+ a.finish();
+ waitForIdle();
+ }
+
+ private void waitForIdle() {
+ mInstrumentation.waitForIdleSync();
+ }
+
+ private Activity startActivityOnDisplay(Class<?> cls, int displayId) {
+ final Intent intent = new Intent(mContext, cls);
+ intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(displayId);
+ final Activity activity = mInstrumentation.startActivitySync(intent, options.toBundle());
+ waitForIdle();
+
+ assertEquals(displayId, activity.getDisplay().getDisplayId());
+ return activity;
+ }
+
+ private Pair<VirtualDisplay, ImageReader> createDisplay() {
+ final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
+ final DisplayInfo displayInfo = new DisplayInfo();
+ final Display defaultDisplay = dm.getDisplay(DEFAULT_DISPLAY);
+ defaultDisplay.getDisplayInfo(displayInfo);
+ final String name = "ScreenDecorWindowTests";
+ int flags = VIRTUAL_DISPLAY_FLAG_PRESENTATION | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+
+ final ImageReader imageReader = ImageReader.newInstance(
+ displayInfo.logicalWidth, displayInfo.logicalHeight, PixelFormat.RGBA_8888, 2);
+
+ final VirtualDisplay display = dm.createVirtualDisplay(name, displayInfo.logicalWidth,
+ displayInfo.logicalHeight, displayInfo.logicalDensityDpi, imageReader.getSurface(),
+ flags);
+
+ return Pair.create(display, imageReader);
+ }
+
+ public static class TestActivity extends Activity {
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
index 99f2685c6ce7..96fbc1402296 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
@@ -32,7 +32,6 @@ import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.ArraySet;
-import com.android.internal.util.Predicate;
import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem;
import org.junit.Test;
@@ -200,4 +199,16 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa
new File(sFilesDir.getPath() + "/snapshots/2_reduced.jpg")};
assertTrueForFiles(existsFiles, File::exists, " must exist");
}
+
+ /**
+ * Private predicate definition.
+ *
+ * This is needed because com.android.internal.util.Predicate is deprecated
+ * and can only be used with classes fron android.test.runner. This cannot
+ * use java.util.function.Predicate because that is not present on all API
+ * versions that this test must run on.
+ */
+ private interface Predicate<T> {
+ boolean apply(T t);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 9f57f4993ed5..53d0bfbb5cf7 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -17,7 +17,7 @@
package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManagerPolicy.NAV_BAR_BOTTOM;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -133,11 +133,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public void setDisplayOverscan(Display display, int left, int top, int right, int bottom) {
-
- }
-
- @Override
public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp) {
return 0;
}
@@ -148,8 +143,8 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
-
+ public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
+ boolean hasStatusBarServicePermission) {
}
@Override
@@ -189,7 +184,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
@Override
public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
- return false;
+ return attrs.type == TYPE_STATUS_BAR;
}
@Override
@@ -290,40 +285,11 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
- int displayRotation, int uiMode) {
-
- }
-
- @Override
public int getSystemDecorLayerLw() {
return 0;
}
@Override
- public void getContentRectLw(Rect r) {
-
- }
-
- @Override
- public void layoutWindowLw(WindowState win,
- WindowState attached) {
-
- }
-
- @Override
- public boolean getInsetHintLw(WindowManager.LayoutParams attrs, Rect taskBounds,
- int displayRotation, int displayWidth, int displayHeight, Rect outContentInsets,
- Rect outStableInsets, Rect outOutsets) {
- return false;
- }
-
- @Override
- public void finishLayoutLw() {
-
- }
-
- @Override
public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
}
@@ -582,11 +548,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public int getInputMethodWindowVisibleHeightLw() {
- return 0;
- }
-
- @Override
public void setCurrentUserLw(int newUserId) {
}
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index e5d3915dde4c..c5ca33041f41 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -103,7 +103,7 @@ public class AppIdleHistory {
long lastUsedScreenTime;
@StandbyBuckets int currentBucket;
String bucketingReason;
- int lastInformedState;
+ int lastInformedBucket;
}
AppIdleHistory(File storageDir, long elapsedRealtime) {
@@ -333,13 +333,12 @@ public class AppIdleHistory {
}
boolean shouldInformListeners(String packageName, int userId,
- long elapsedRealtime, boolean isIdle) {
+ long elapsedRealtime, int bucket) {
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName,
elapsedRealtime, true);
- int targetState = isIdle? STATE_IDLE : STATE_ACTIVE;
- if (appUsageHistory.lastInformedState != (isIdle ? STATE_IDLE : STATE_ACTIVE)) {
- appUsageHistory.lastInformedState = targetState;
+ if (appUsageHistory.lastInformedBucket != bucket) {
+ appUsageHistory.lastInformedBucket = bucket;
return true;
}
return false;
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 17fde57907d7..5623a68f158d 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -160,7 +160,6 @@ public class AppStandbyController {
private final Context mContext;
// TODO: Provide a mechanism to set an external bucketing service
- private boolean mUseInternalBucketingHeuristics = true;
private AppWidgetManager mAppWidgetManager;
private PowerManager mPowerManager;
@@ -367,29 +366,33 @@ public class AppStandbyController {
Slog.d(TAG, " Checking idle state for " + packageName);
}
if (isSpecial) {
- maybeInformListeners(packageName, userId, elapsedRealtime, false);
- } else if (mUseInternalBucketingHeuristics) {
+ maybeInformListeners(packageName, userId, elapsedRealtime,
+ AppStandby.STANDBY_BUCKET_ACTIVE);
+ } else {
synchronized (mAppIdleLock) {
- int oldBucket = mAppIdleHistory.getAppStandbyBucket(packageName, userId,
- elapsedRealtime);
String bucketingReason = mAppIdleHistory.getAppStandbyReason(packageName,
userId, elapsedRealtime);
- if (bucketingReason != null
- && (bucketingReason.equals(AppStandby.REASON_FORCED)
- || bucketingReason.startsWith(AppStandby.REASON_PREDICTED))) {
+ // If the bucket was forced by the developer, leave it alone
+ if (AppStandby.REASON_FORCED.equals(bucketingReason)) {
continue;
}
- int newBucket = getBucketForLocked(packageName, userId,
- elapsedRealtime);
- if (DEBUG) {
- Slog.d(TAG, " Old bucket=" + oldBucket
- + ", newBucket=" + newBucket);
- }
- if (oldBucket != newBucket) {
- mAppIdleHistory.setAppStandbyBucket(packageName, userId,
- elapsedRealtime, newBucket, AppStandby.REASON_TIMEOUT);
- maybeInformListeners(packageName, userId, elapsedRealtime,
- newBucket >= AppStandby.STANDBY_BUCKET_RARE);
+ // 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);
+ int newBucket = getBucketForLocked(packageName, userId,
+ elapsedRealtime);
+ if (DEBUG) {
+ Slog.d(TAG, " Old bucket=" + oldBucket
+ + ", newBucket=" + newBucket);
+ }
+ if (oldBucket < newBucket) {
+ mAppIdleHistory.setAppStandbyBucket(packageName, userId,
+ elapsedRealtime, newBucket, AppStandby.REASON_TIMEOUT);
+ maybeInformListeners(packageName, userId, elapsedRealtime,
+ newBucket);
+ }
}
}
}
@@ -403,12 +406,12 @@ public class AppStandbyController {
}
private void maybeInformListeners(String packageName, int userId,
- long elapsedRealtime, boolean isIdle) {
+ long elapsedRealtime, int bucket) {
synchronized (mAppIdleLock) {
if (mAppIdleHistory.shouldInformListeners(packageName, userId,
- elapsedRealtime, isIdle)) {
+ elapsedRealtime, bucket)) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
- userId, isIdle ? 1 : 0, packageName));
+ userId, bucket, packageName));
}
}
}
@@ -461,11 +464,13 @@ public class AppStandbyController {
if (DEBUG) Slog.i(TAG, "DeviceIdleMode changed to " + deviceIdle);
boolean paroled = false;
synchronized (mAppIdleLock) {
- final long timeSinceLastParole = mInjector.currentTimeMillis() - mLastAppIdleParoledTime;
+ final long timeSinceLastParole =
+ mInjector.currentTimeMillis() - mLastAppIdleParoledTime;
if (!deviceIdle
&& timeSinceLastParole >= mAppIdleParoleIntervalMillis) {
if (DEBUG) {
- Slog.i(TAG, "Bringing idle apps out of inactive state due to deviceIdleMode=false");
+ Slog.i(TAG,
+ "Bringing idle apps out of inactive state due to deviceIdleMode=false");
}
paroled = true;
} else if (deviceIdle) {
@@ -491,7 +496,8 @@ public class AppStandbyController {
|| event.mEventType == UsageEvents.Event.USER_INTERACTION)) {
mAppIdleHistory.reportUsage(event.mPackage, userId, elapsedRealtime);
if (previouslyIdle) {
- maybeInformListeners(event.mPackage, userId, elapsedRealtime, false);
+ maybeInformListeners(event.mPackage, userId, elapsedRealtime,
+ AppStandby.STANDBY_BUCKET_ACTIVE);
notifyBatteryStats(event.mPackage, userId, false);
}
}
@@ -729,7 +735,8 @@ public class AppStandbyController {
void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
String reason, long elapsedRealtime) {
- mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket, reason);
+ mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
+ reason);
}
private boolean isActiveDeviceAdmin(String packageName, int userId) {
@@ -786,9 +793,10 @@ public class AppStandbyController {
return packageName != null && packageName.equals(activeScorer);
}
- void informListeners(String packageName, int userId, boolean isIdle) {
+ void informListeners(String packageName, int userId, int bucket) {
+ final boolean idle = bucket >= AppStandby.STANDBY_BUCKET_RARE;
for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
- listener.onAppIdleStateChanged(packageName, userId, isIdle);
+ listener.onAppIdleStateChanged(packageName, userId, idle, bucket);
}
}
@@ -1037,7 +1045,7 @@ public class AppStandbyController {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_INFORM_LISTENERS:
- informListeners((String) msg.obj, msg.arg1, msg.arg2 == 1);
+ informListeners((String) msg.obj, msg.arg1, msg.arg2);
break;
case MSG_FORCE_IDLE_STATE:
@@ -1187,7 +1195,8 @@ public class AppStandbyController {
mAppStandbyScreenThresholds = parseLongArray(screenThresholdsValue,
SCREEN_TIME_THRESHOLDS);
- String elapsedThresholdsValue = mParser.getString(KEY_ELAPSED_TIME_THRESHOLDS, null);
+ String elapsedThresholdsValue = mParser.getString(KEY_ELAPSED_TIME_THRESHOLDS,
+ null);
mAppStandbyElapsedThresholds = parseLongArray(elapsedThresholdsValue,
ELAPSED_TIME_THRESHOLDS);
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index e65d36087ca9..1b057f9b9681 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -893,7 +893,7 @@ public class UsbDeviceManager {
updateCurrentAccessory();
}
if (mBootCompleted) {
- if (!mConnected) {
+ if (!mConnected && !hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT)) {
// restore defaults when USB is disconnected
setEnabledFunctions(null, !mAdbEnabled, false);
}
diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
index ebb5a62ce7ec..917e651bb425 100644
--- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
@@ -32,9 +32,10 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.XmlResourceParser;
+import android.hardware.usb.AccessoryFilter;
+import android.hardware.usb.DeviceFilter;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.AsyncTask;
import android.os.Environment;
@@ -58,7 +59,6 @@ import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileInputStream;
@@ -71,7 +71,6 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
class UsbProfileGroupSettingsManager {
private static final String TAG = UsbProfileGroupSettingsManager.class.getSimpleName();
@@ -157,404 +156,6 @@ class UsbProfileGroupSettingsManager {
}
}
- // This class is used to describe a USB device.
- // When used in HashMaps all values must be specified,
- // but wildcards can be used for any of the fields in
- // the package meta-data.
- private static class DeviceFilter {
- // USB Vendor ID (or -1 for unspecified)
- public final int mVendorId;
- // USB Product ID (or -1 for unspecified)
- public final int mProductId;
- // USB device or interface class (or -1 for unspecified)
- public final int mClass;
- // USB device subclass (or -1 for unspecified)
- public final int mSubclass;
- // USB device protocol (or -1 for unspecified)
- public final int mProtocol;
- // USB device manufacturer name string (or null for unspecified)
- public final String mManufacturerName;
- // USB device product name string (or null for unspecified)
- public final String mProductName;
- // USB device serial number string (or null for unspecified)
- public final String mSerialNumber;
-
- public DeviceFilter(int vid, int pid, int clasz, int subclass, int protocol,
- String manufacturer, String product, String serialnum) {
- mVendorId = vid;
- mProductId = pid;
- mClass = clasz;
- mSubclass = subclass;
- mProtocol = protocol;
- mManufacturerName = manufacturer;
- mProductName = product;
- mSerialNumber = serialnum;
- }
-
- public DeviceFilter(UsbDevice device) {
- mVendorId = device.getVendorId();
- mProductId = device.getProductId();
- mClass = device.getDeviceClass();
- mSubclass = device.getDeviceSubclass();
- mProtocol = device.getDeviceProtocol();
- mManufacturerName = device.getManufacturerName();
- mProductName = device.getProductName();
- mSerialNumber = device.getSerialNumber();
- }
-
- public static DeviceFilter read(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- int vendorId = -1;
- int productId = -1;
- int deviceClass = -1;
- int deviceSubclass = -1;
- int deviceProtocol = -1;
- String manufacturerName = null;
- String productName = null;
- String serialNumber = null;
-
- int count = parser.getAttributeCount();
- for (int i = 0; i < count; i++) {
- String name = parser.getAttributeName(i);
- String value = parser.getAttributeValue(i);
- // Attribute values are ints or strings
- if ("manufacturer-name".equals(name)) {
- manufacturerName = value;
- } else if ("product-name".equals(name)) {
- productName = value;
- } else if ("serial-number".equals(name)) {
- serialNumber = value;
- } else {
- int intValue;
- int radix = 10;
- if (value != null && value.length() > 2 && value.charAt(0) == '0' &&
- (value.charAt(1) == 'x' || value.charAt(1) == 'X')) {
- // allow hex values starting with 0x or 0X
- radix = 16;
- value = value.substring(2);
- }
- try {
- intValue = Integer.parseInt(value, radix);
- } catch (NumberFormatException e) {
- Slog.e(TAG, "invalid number for field " + name, e);
- continue;
- }
- if ("vendor-id".equals(name)) {
- vendorId = intValue;
- } else if ("product-id".equals(name)) {
- productId = intValue;
- } else if ("class".equals(name)) {
- deviceClass = intValue;
- } else if ("subclass".equals(name)) {
- deviceSubclass = intValue;
- } else if ("protocol".equals(name)) {
- deviceProtocol = intValue;
- }
- }
- }
- return new DeviceFilter(vendorId, productId,
- deviceClass, deviceSubclass, deviceProtocol,
- manufacturerName, productName, serialNumber);
- }
-
- public void write(XmlSerializer serializer) throws IOException {
- serializer.startTag(null, "usb-device");
- if (mVendorId != -1) {
- serializer.attribute(null, "vendor-id", Integer.toString(mVendorId));
- }
- if (mProductId != -1) {
- serializer.attribute(null, "product-id", Integer.toString(mProductId));
- }
- if (mClass != -1) {
- serializer.attribute(null, "class", Integer.toString(mClass));
- }
- if (mSubclass != -1) {
- serializer.attribute(null, "subclass", Integer.toString(mSubclass));
- }
- if (mProtocol != -1) {
- serializer.attribute(null, "protocol", Integer.toString(mProtocol));
- }
- if (mManufacturerName != null) {
- serializer.attribute(null, "manufacturer-name", mManufacturerName);
- }
- if (mProductName != null) {
- serializer.attribute(null, "product-name", mProductName);
- }
- if (mSerialNumber != null) {
- serializer.attribute(null, "serial-number", mSerialNumber);
- }
- serializer.endTag(null, "usb-device");
- }
-
- private boolean matches(int clasz, int subclass, int protocol) {
- return ((mClass == -1 || clasz == mClass) &&
- (mSubclass == -1 || subclass == mSubclass) &&
- (mProtocol == -1 || protocol == mProtocol));
- }
-
- public boolean matches(UsbDevice device) {
- if (mVendorId != -1 && device.getVendorId() != mVendorId) return false;
- if (mProductId != -1 && device.getProductId() != mProductId) return false;
- if (mManufacturerName != null && device.getManufacturerName() == null) return false;
- if (mProductName != null && device.getProductName() == null) return false;
- if (mSerialNumber != null && device.getSerialNumber() == null) return false;
- if (mManufacturerName != null && device.getManufacturerName() != null &&
- !mManufacturerName.equals(device.getManufacturerName())) return false;
- if (mProductName != null && device.getProductName() != null &&
- !mProductName.equals(device.getProductName())) return false;
- if (mSerialNumber != null && device.getSerialNumber() != null &&
- !mSerialNumber.equals(device.getSerialNumber())) return false;
-
- // check device class/subclass/protocol
- if (matches(device.getDeviceClass(), device.getDeviceSubclass(),
- device.getDeviceProtocol())) return true;
-
- // if device doesn't match, check the interfaces
- int count = device.getInterfaceCount();
- for (int i = 0; i < count; i++) {
- UsbInterface intf = device.getInterface(i);
- if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(),
- intf.getInterfaceProtocol())) return true;
- }
-
- return false;
- }
-
- /**
- * If the device described by {@code device} covered by this filter?
- *
- * @param device The device
- *
- * @return {@code true} iff this filter covers the {@code device}
- */
- public boolean contains(DeviceFilter device) {
- // -1 and null means "match anything"
-
- if (mVendorId != -1 && device.mVendorId != mVendorId) return false;
- if (mProductId != -1 && device.mProductId != mProductId) return false;
- if (mManufacturerName != null && !Objects.equals(mManufacturerName,
- device.mManufacturerName)) {
- return false;
- }
- if (mProductName != null && !Objects.equals(mProductName, device.mProductName)) {
- return false;
- }
- if (mSerialNumber != null
- && !Objects.equals(mSerialNumber, device.mSerialNumber)) {
- return false;
- }
-
- // check device class/subclass/protocol
- return matches(device.mClass, device.mSubclass, device.mProtocol);
- }
-
- @Override
- public boolean equals(Object obj) {
- // can't compare if we have wildcard strings
- if (mVendorId == -1 || mProductId == -1 ||
- mClass == -1 || mSubclass == -1 || mProtocol == -1) {
- return false;
- }
- if (obj instanceof DeviceFilter) {
- DeviceFilter filter = (DeviceFilter)obj;
-
- if (filter.mVendorId != mVendorId ||
- filter.mProductId != mProductId ||
- filter.mClass != mClass ||
- filter.mSubclass != mSubclass ||
- filter.mProtocol != mProtocol) {
- return(false);
- }
- if ((filter.mManufacturerName != null &&
- mManufacturerName == null) ||
- (filter.mManufacturerName == null &&
- mManufacturerName != null) ||
- (filter.mProductName != null &&
- mProductName == null) ||
- (filter.mProductName == null &&
- mProductName != null) ||
- (filter.mSerialNumber != null &&
- mSerialNumber == null) ||
- (filter.mSerialNumber == null &&
- mSerialNumber != null)) {
- return(false);
- }
- if ((filter.mManufacturerName != null &&
- mManufacturerName != null &&
- !mManufacturerName.equals(filter.mManufacturerName)) ||
- (filter.mProductName != null &&
- mProductName != null &&
- !mProductName.equals(filter.mProductName)) ||
- (filter.mSerialNumber != null &&
- mSerialNumber != null &&
- !mSerialNumber.equals(filter.mSerialNumber))) {
- return false;
- }
- return true;
- }
- if (obj instanceof UsbDevice) {
- UsbDevice device = (UsbDevice)obj;
- if (device.getVendorId() != mVendorId ||
- device.getProductId() != mProductId ||
- device.getDeviceClass() != mClass ||
- device.getDeviceSubclass() != mSubclass ||
- device.getDeviceProtocol() != mProtocol) {
- return(false);
- }
- if ((mManufacturerName != null && device.getManufacturerName() == null) ||
- (mManufacturerName == null && device.getManufacturerName() != null) ||
- (mProductName != null && device.getProductName() == null) ||
- (mProductName == null && device.getProductName() != null) ||
- (mSerialNumber != null && device.getSerialNumber() == null) ||
- (mSerialNumber == null && device.getSerialNumber() != null)) {
- return(false);
- }
- if ((device.getManufacturerName() != null &&
- !mManufacturerName.equals(device.getManufacturerName())) ||
- (device.getProductName() != null &&
- !mProductName.equals(device.getProductName())) ||
- (device.getSerialNumber() != null &&
- !mSerialNumber.equals(device.getSerialNumber()))) {
- return false;
- }
- return true;
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return (((mVendorId << 16) | mProductId) ^
- ((mClass << 16) | (mSubclass << 8) | mProtocol));
- }
-
- @Override
- public String toString() {
- return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId +
- ",mClass=" + mClass + ",mSubclass=" + mSubclass +
- ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName +
- ",mProductName=" + mProductName + ",mSerialNumber=" + mSerialNumber +
- "]";
- }
- }
-
- // This class is used to describe a USB accessory.
- // When used in HashMaps all values must be specified,
- // but wildcards can be used for any of the fields in
- // the package meta-data.
- private static class AccessoryFilter {
- // USB accessory manufacturer (or null for unspecified)
- public final String mManufacturer;
- // USB accessory model (or null for unspecified)
- public final String mModel;
- // USB accessory version (or null for unspecified)
- public final String mVersion;
-
- public AccessoryFilter(String manufacturer, String model, String version) {
- mManufacturer = manufacturer;
- mModel = model;
- mVersion = version;
- }
-
- public AccessoryFilter(UsbAccessory accessory) {
- mManufacturer = accessory.getManufacturer();
- mModel = accessory.getModel();
- mVersion = accessory.getVersion();
- }
-
- public static AccessoryFilter read(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- String manufacturer = null;
- String model = null;
- String version = null;
-
- int count = parser.getAttributeCount();
- for (int i = 0; i < count; i++) {
- String name = parser.getAttributeName(i);
- String value = parser.getAttributeValue(i);
-
- if ("manufacturer".equals(name)) {
- manufacturer = value;
- } else if ("model".equals(name)) {
- model = value;
- } else if ("version".equals(name)) {
- version = value;
- }
- }
- return new AccessoryFilter(manufacturer, model, version);
- }
-
- public void write(XmlSerializer serializer)throws IOException {
- serializer.startTag(null, "usb-accessory");
- if (mManufacturer != null) {
- serializer.attribute(null, "manufacturer", mManufacturer);
- }
- if (mModel != null) {
- serializer.attribute(null, "model", mModel);
- }
- if (mVersion != null) {
- serializer.attribute(null, "version", mVersion);
- }
- serializer.endTag(null, "usb-accessory");
- }
-
- public boolean matches(UsbAccessory acc) {
- if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false;
- if (mModel != null && !acc.getModel().equals(mModel)) return false;
- return !(mVersion != null && !acc.getVersion().equals(mVersion));
- }
-
- /**
- * Is the accessories described {@code accessory} covered by this filter?
- *
- * @param accessory A filter describing the accessory
- *
- * @return {@code true} iff this the filter covers the accessory
- */
- public boolean contains(AccessoryFilter accessory) {
- if (mManufacturer != null && !Objects.equals(accessory.mManufacturer, mManufacturer)) {
- return false;
- }
- if (mModel != null && !Objects.equals(accessory.mModel, mModel)) return false;
- return !(mVersion != null && !Objects.equals(accessory.mVersion, mVersion));
- }
-
- @Override
- public boolean equals(Object obj) {
- // can't compare if we have wildcard strings
- if (mManufacturer == null || mModel == null || mVersion == null) {
- return false;
- }
- if (obj instanceof AccessoryFilter) {
- AccessoryFilter filter = (AccessoryFilter)obj;
- return (mManufacturer.equals(filter.mManufacturer) &&
- mModel.equals(filter.mModel) &&
- mVersion.equals(filter.mVersion));
- }
- if (obj instanceof UsbAccessory) {
- UsbAccessory accessory = (UsbAccessory)obj;
- return (mManufacturer.equals(accessory.getManufacturer()) &&
- mModel.equals(accessory.getModel()) &&
- mVersion.equals(accessory.getVersion()));
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
- (mModel == null ? 0 : mModel.hashCode()) ^
- (mVersion == null ? 0 : mVersion.hashCode()));
- }
-
- @Override
- public String toString() {
- return "AccessoryFilter[mManufacturer=\"" + mManufacturer +
- "\", mModel=\"" + mModel +
- "\", mVersion=\"" + mVersion + "\"]";
- }
- }
-
private class MyPackageMonitor extends PackageMonitor {
@Override
public void onPackageAdded(String packageName, int uid) {
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index f53eb15d482b..25c54b3e51eb 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -36,12 +36,12 @@ import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent;
import android.hardware.soundtrigger.SoundTriggerModule;
import android.os.DeadObjectException;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.RemoteException;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Slog;
import com.android.internal.logging.MetricsLogger;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 925219d64967..e0d9c7397748 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -198,7 +198,10 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
mShowArgs = args;
mShowFlags = flags;
+ disabledContext |= getUserDisabledShowContextLocked();
mAssistDataRequester.requestAssistData(topActivities,
+ (flags & VoiceInteractionSession.SHOW_WITH_ASSIST) != 0,
+ (flags & VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0,
(disabledContext & VoiceInteractionSession.SHOW_WITH_ASSIST) == 0,
(disabledContext & VoiceInteractionSession.SHOW_WITH_SCREENSHOT) == 0,
mCallingUid, mSessionComponentName.getPackageName());
@@ -215,6 +218,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
mShowFlags = 0;
} catch (RemoteException e) {
}
+ mAssistDataRequester.processPendingAssistData();
} else if (showCallback != null) {
mPendingShowCallbacks.add(showCallback);
}
@@ -237,11 +241,16 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
@Override
public void onAssistDataReceivedLocked(Bundle data, int activityIndex, int activityCount) {
+ // Return early if we have no session
+ if (mSession == null) {
+ return;
+ }
+
if (data == null) {
try {
mSession.handleAssist(null, null, null, 0, 0);
} catch (RemoteException e) {
- // Can't happen
+ // Ignore
}
} else {
final Bundle assistData = data.getBundle(ASSIST_KEY_DATA);
@@ -267,17 +276,22 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
mSession.handleAssist(assistData, structure, content, activityIndex,
activityCount);
} catch (RemoteException e) {
- // Can't happen
+ // Ignore
}
}
}
@Override
public void onAssistScreenshotReceivedLocked(Bitmap screenshot) {
+ // Return early if we have no session
+ if (mSession == null) {
+ return;
+ }
+
try {
mSession.handleScreenshot(screenshot);
} catch (RemoteException e) {
- // Can't happen
+ // Ignore
}
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index e13bd6193719..a07f2bbf3323 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -855,6 +855,39 @@ public final class Call {
*/
public static abstract class Callback {
/**
+ * @hide
+ */
+ @IntDef({HANDOVER_FAILURE_DEST_APP_REJECTED, HANDOVER_FAILURE_DEST_NOT_SUPPORTED,
+ HANDOVER_FAILURE_DEST_INVALID_PERM, HANDOVER_FAILURE_DEST_USER_REJECTED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface HandoverFailureErrors {}
+
+ /**
+ * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when the app
+ * to handover the call rejects handover.
+ */
+ public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1;
+
+ /**
+ * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when there is
+ * an error associated with unsupported handover.
+ */
+ public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2;
+
+ /**
+ * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when there
+ * are some permission errors associated with APIs doing handover.
+ */
+ public static final int HANDOVER_FAILURE_DEST_INVALID_PERM = 3;
+
+ /**
+ * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when user
+ * rejects handover.
+ */
+ public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4;
+
+
+ /**
* Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
*
* @param call The {@code Call} invoking this method.
@@ -989,6 +1022,21 @@ public final class Call {
* {@link android.telecom.Connection.RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
*/
public void onRttInitiationFailure(Call call, int reason) {}
+
+ /**
+ * Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount}
+ * has completed successfully.
+ * @param call The call which had initiated handover.
+ */
+ public void onHandoverComplete(Call call) {}
+
+ /**
+ * Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount}
+ * has failed.
+ * @param call The call which had initiated handover.
+ * @param failureReason Error reason for failure
+ */
+ public void onHandoverFailed(Call call, @HandoverFailureErrors int failureReason) {}
}
/**
@@ -1367,6 +1415,24 @@ public final class Call {
}
/**
+ * Initiates a handover of this {@link Call} to the {@link ConnectionService} identified
+ * by {@code toHandle}. The videoState specified indicates the desired video state after the
+ * handover.
+ * <p>
+ * A handover request is initiated by the user from one app to indicate a desire
+ * to handover a call to another.
+ *
+ * @param toHandle {@link PhoneAccountHandle} of the {@link ConnectionService} to handover
+ * this call to.
+ * @param videoState Indicates the video state desired after the handover.
+ * @param extras Bundle containing extra information to be passed to the
+ * {@link ConnectionService}
+ */
+ public void handoverTo(PhoneAccountHandle toHandle, int videoState, Bundle extras) {
+ mInCallAdapter.handoverTo(mTelecomCallId, toHandle, videoState, extras);
+ }
+
+ /**
* Terminate the RTT session on this call. The resulting state change will be notified via
* the {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
*/
diff --git a/telecomm/java/android/telecom/CallAudioState.java b/telecomm/java/android/telecom/CallAudioState.java
index f601d8b545ac..4b827d2e29a2 100644
--- a/telecomm/java/android/telecom/CallAudioState.java
+++ b/telecomm/java/android/telecom/CallAudioState.java
@@ -16,16 +16,35 @@
package android.telecom;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothDevice;
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
import java.util.Locale;
+import java.util.Objects;
+import java.util.stream.Collectors;
/**
* Encapsulates the telecom audio state, including the current audio routing, supported audio
* routing and mute.
*/
public final class CallAudioState implements Parcelable {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value={ROUTE_EARPIECE, ROUTE_BLUETOOTH, ROUTE_WIRED_HEADSET, ROUTE_SPEAKER},
+ flag=true)
+ public @interface CallAudioRoute {}
+
/** Direct the audio stream through the device's earpiece. */
public static final int ROUTE_EARPIECE = 0x00000001;
@@ -55,6 +74,8 @@ public final class CallAudioState implements Parcelable {
private final boolean isMuted;
private final int route;
private final int supportedRouteMask;
+ private final BluetoothDevice activeBluetoothDevice;
+ private final Collection<BluetoothDevice> supportedBluetoothDevices;
/**
* Constructor for a {@link CallAudioState} object.
@@ -73,10 +94,21 @@ public final class CallAudioState implements Parcelable {
* {@link #ROUTE_WIRED_HEADSET}
* {@link #ROUTE_SPEAKER}
*/
- public CallAudioState(boolean muted, int route, int supportedRouteMask) {
- this.isMuted = muted;
+ public CallAudioState(boolean muted, @CallAudioRoute int route,
+ @CallAudioRoute int supportedRouteMask) {
+ this(muted, route, supportedRouteMask, null, Collections.emptyList());
+ }
+
+ /** @hide */
+ public CallAudioState(boolean isMuted, @CallAudioRoute int route,
+ @CallAudioRoute int supportedRouteMask,
+ @Nullable BluetoothDevice activeBluetoothDevice,
+ @NonNull Collection<BluetoothDevice> supportedBluetoothDevices) {
+ this.isMuted = isMuted;
this.route = route;
this.supportedRouteMask = supportedRouteMask;
+ this.activeBluetoothDevice = activeBluetoothDevice;
+ this.supportedBluetoothDevices = supportedBluetoothDevices;
}
/** @hide */
@@ -84,6 +116,8 @@ public final class CallAudioState implements Parcelable {
isMuted = state.isMuted();
route = state.getRoute();
supportedRouteMask = state.getSupportedRouteMask();
+ activeBluetoothDevice = state.activeBluetoothDevice;
+ supportedBluetoothDevices = state.getSupportedBluetoothDevices();
}
/** @hide */
@@ -92,6 +126,8 @@ public final class CallAudioState implements Parcelable {
isMuted = state.isMuted();
route = state.getRoute();
supportedRouteMask = state.getSupportedRouteMask();
+ activeBluetoothDevice = null;
+ supportedBluetoothDevices = Collections.emptyList();
}
@Override
@@ -103,17 +139,32 @@ public final class CallAudioState implements Parcelable {
return false;
}
CallAudioState state = (CallAudioState) obj;
- return isMuted() == state.isMuted() && getRoute() == state.getRoute() &&
- getSupportedRouteMask() == state.getSupportedRouteMask();
+ if (supportedBluetoothDevices.size() != state.supportedBluetoothDevices.size()) {
+ return false;
+ }
+ for (BluetoothDevice device : supportedBluetoothDevices) {
+ if (!state.supportedBluetoothDevices.contains(device)) {
+ return false;
+ }
+ }
+ return Objects.equals(activeBluetoothDevice, state.activeBluetoothDevice) && isMuted() ==
+ state.isMuted() && getRoute() == state.getRoute() && getSupportedRouteMask() ==
+ state.getSupportedRouteMask();
}
@Override
public String toString() {
+ String bluetoothDeviceList = supportedBluetoothDevices.stream()
+ .map(BluetoothDevice::getAddress).collect(Collectors.joining(", "));
+
return String.format(Locale.US,
- "[AudioState isMuted: %b, route: %s, supportedRouteMask: %s]",
+ "[AudioState isMuted: %b, route: %s, supportedRouteMask: %s, " +
+ "activeBluetoothDevice: [%s], supportedBluetoothDevices: [%s]]",
isMuted,
audioRouteToString(route),
- audioRouteToString(supportedRouteMask));
+ audioRouteToString(supportedRouteMask),
+ activeBluetoothDevice,
+ bluetoothDeviceList);
}
/**
@@ -126,6 +177,7 @@ public final class CallAudioState implements Parcelable {
/**
* @return The current audio route being used.
*/
+ @CallAudioRoute
public int getRoute() {
return route;
}
@@ -133,11 +185,27 @@ public final class CallAudioState implements Parcelable {
/**
* @return Bit mask of all routes supported by this call.
*/
+ @CallAudioRoute
public int getSupportedRouteMask() {
return supportedRouteMask;
}
/**
+ * @return The {@link BluetoothDevice} through which audio is being routed.
+ * Will not be {@code null} if {@link #getRoute()} returns {@link #ROUTE_BLUETOOTH}.
+ */
+ public BluetoothDevice getActiveBluetoothDevice() {
+ return activeBluetoothDevice;
+ }
+
+ /**
+ * @return {@link List} of {@link BluetoothDevice}s that can be used for this call.
+ */
+ public Collection<BluetoothDevice> getSupportedBluetoothDevices() {
+ return supportedBluetoothDevices;
+ }
+
+ /**
* Converts the provided audio route into a human readable string representation.
*
* @param route to convert into a string.
@@ -177,7 +245,13 @@ public final class CallAudioState implements Parcelable {
boolean isMuted = source.readByte() == 0 ? false : true;
int route = source.readInt();
int supportedRouteMask = source.readInt();
- return new CallAudioState(isMuted, route, supportedRouteMask);
+ BluetoothDevice activeBluetoothDevice = source.readParcelable(
+ ClassLoader.getSystemClassLoader());
+ List<BluetoothDevice> supportedBluetoothDevices = new ArrayList<>();
+ source.readParcelableList(supportedBluetoothDevices,
+ ClassLoader.getSystemClassLoader());
+ return new CallAudioState(isMuted, route,
+ supportedRouteMask, activeBluetoothDevice, supportedBluetoothDevices);
}
@Override
@@ -202,6 +276,8 @@ public final class CallAudioState implements Parcelable {
destination.writeByte((byte) (isMuted ? 1 : 0));
destination.writeInt(route);
destination.writeInt(supportedRouteMask);
+ destination.writeParcelable(activeBluetoothDevice, 0);
+ destination.writeParcelableList(new ArrayList<>(supportedBluetoothDevices), 0);
}
private static void listAppend(StringBuffer buffer, String str) {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 8ba934ccdb8b..2bb1c4ed648c 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -25,6 +25,7 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.Notification;
+import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.hardware.camera2.CameraManager;
import android.net.Uri;
@@ -819,7 +820,7 @@ public abstract class Connection extends Conferenceable {
public void onConnectionEvent(Connection c, String event, Bundle extras) {}
/** @hide */
public void onConferenceSupportedChanged(Connection c, boolean isConferenceSupported) {}
- public void onAudioRouteChanged(Connection c, int audioRoute) {}
+ public void onAudioRouteChanged(Connection c, int audioRoute, String bluetoothAddress) {}
public void onRttInitiationSuccess(Connection c) {}
public void onRttInitiationFailure(Connection c, int reason) {}
public void onRttSessionRemotelyTerminated(Connection c) {}
@@ -1683,6 +1684,8 @@ public abstract class Connection extends Conferenceable {
// The internal telecom call ID associated with this connection.
private String mTelecomCallId;
+ // The PhoneAccountHandle associated with this connection.
+ private PhoneAccountHandle mPhoneAccountHandle;
private int mState = STATE_NEW;
private CallAudioState mCallAudioState;
private Uri mAddress;
@@ -2576,7 +2579,29 @@ public abstract class Connection extends Conferenceable {
*/
public final void setAudioRoute(int route) {
for (Listener l : mListeners) {
- l.onAudioRouteChanged(this, route);
+ l.onAudioRouteChanged(this, route, null);
+ }
+ }
+
+ /**
+ *
+ * Request audio routing to a specific bluetooth device. Calling this method may result in
+ * the device routing audio to a different bluetooth device than the one specified if the
+ * bluetooth stack is unable to route audio to the requested device.
+ * A list of available devices can be obtained via
+ * {@link CallAudioState#getSupportedBluetoothDevices()}
+ *
+ * <p>
+ * Used by self-managed {@link ConnectionService}s which wish to use bluetooth audio for a
+ * self-managed {@link Connection} (see {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.)
+ * <p>
+ * See also {@link InCallService#requestBluetoothAudio(String)}
+ * @param bluetoothAddress The address of the bluetooth device to connect to, as returned by
+ * {@link BluetoothDevice#getAddress()}.
+ */
+ public void requestBluetoothAudio(@NonNull String bluetoothAddress) {
+ for (Listener l : mListeners) {
+ l.onAudioRouteChanged(this, CallAudioState.ROUTE_BLUETOOTH, bluetoothAddress);
}
}
@@ -3076,6 +3101,27 @@ public abstract class Connection extends Conferenceable {
}
/**
+ * Sets the {@link PhoneAccountHandle} associated with this connection.
+ *
+ * @hide
+ */
+ public void setPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
+ if (mPhoneAccountHandle != phoneAccountHandle) {
+ mPhoneAccountHandle = phoneAccountHandle;
+ notifyPhoneAccountChanged(phoneAccountHandle);
+ }
+ }
+
+ /**
+ * Returns the {@link PhoneAccountHandle} associated with this connection.
+ *
+ * @hide
+ */
+ public PhoneAccountHandle getPhoneAccountHandle() {
+ return mPhoneAccountHandle;
+ }
+
+ /**
* Sends an event associated with this {@code Connection} with associated event extras to the
* {@link InCallService}.
* <p>
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index a81fba95c4ed..7e8330667237 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1294,10 +1294,10 @@ public abstract class ConnectionService extends Service {
}
@Override
- public void onAudioRouteChanged(Connection c, int audioRoute) {
+ public void onAudioRouteChanged(Connection c, int audioRoute, String bluetoothAddress) {
String id = mIdByConnection.get(c);
if (id != null) {
- mAdapter.setAudioRoute(id, audioRoute);
+ mAdapter.setAudioRoute(id, audioRoute, bluetoothAddress);
}
}
@@ -1382,7 +1382,7 @@ public abstract class ConnectionService extends Service {
connection.setTelecomCallId(callId);
if (connection.getState() != Connection.STATE_DISCONNECTED) {
- addConnection(callId, connection);
+ addConnection(request.getAccountHandle(), callId, connection);
}
Uri address = connection.getAddress();
@@ -1846,6 +1846,7 @@ public abstract class ConnectionService extends Service {
mAdapter.setIsConferenced(connectionId, id);
}
}
+ onConferenceAdded(conference);
}
}
@@ -2033,6 +2034,43 @@ public abstract class ConnectionService extends Service {
}
/**
+ * Called by Telecom on the initiating side of the handover to create an instance of a
+ * handover connection.
+ * @param fromPhoneAccountHandle {@link PhoneAccountHandle} associated with the
+ * ConnectionService which needs to handover the call.
+ * @param request Details about the call which needs to be handover.
+ * @return Connection object corresponding to the handover call.
+ */
+ public Connection onCreateOutgoingHandoverConnection(PhoneAccountHandle fromPhoneAccountHandle,
+ ConnectionRequest request) {
+ return null;
+ }
+
+ /**
+ * Called by Telecom on the receiving side of the handover to request the
+ * {@link ConnectionService} to create an instance of a handover connection.
+ * @param fromPhoneAccountHandle {@link PhoneAccountHandle} associated with the
+ * ConnectionService which needs to handover the call.
+ * @param request Details about the call which needs to be handover.
+ * @return {@link Connection} object corresponding to the handover call.
+ */
+ public Connection onCreateIncomingHandoverConnection(PhoneAccountHandle fromPhoneAccountHandle,
+ ConnectionRequest request) {
+ return null;
+ }
+
+ /**
+ * Called by Telecom in response to a {@code TelecomManager#acceptHandover()}
+ * invocation which failed.
+ * @param request Details about the call which needs to be handover.
+ * @param error Reason for handover failure as defined in
+ * {@link android.telecom.Call.Callback#HANDOVER_FAILURE_DEST_INVALID_PERM}
+ */
+ public void onHandoverFailed(ConnectionRequest request, int error) {
+ return;
+ }
+
+ /**
* Create a {@code Connection} for a new unknown call. An unknown call is a call originating
* from the ConnectionService that was neither a user-initiated outgoing call, nor an incoming
* call created using
@@ -2056,6 +2094,30 @@ public abstract class ConnectionService extends Service {
public void onConference(Connection connection1, Connection connection2) {}
/**
+ * Called when a connection is added.
+ * @hide
+ */
+ public void onConnectionAdded(Connection connection) {}
+
+ /**
+ * Called when a connection is removed.
+ * @hide
+ */
+ public void onConnectionRemoved(Connection connection) {}
+
+ /**
+ * Called when a conference is added.
+ * @hide
+ */
+ public void onConferenceAdded(Conference conference) {}
+
+ /**
+ * Called when a conference is removed.
+ * @hide
+ */
+ public void onConferenceRemoved(Conference conference) {}
+
+ /**
* Indicates that a remote conference has been created for existing {@link RemoteConnection}s.
* When this method is invoked, this {@link ConnectionService} should create its own
* representation of the conference call and send it to telecom using {@link #addConference}.
@@ -2122,16 +2184,18 @@ public abstract class ConnectionService extends Service {
// prefix for a unique incremental call ID.
id = handle.getComponentName().getClassName() + "@" + getNextCallId();
}
- addConnection(id, connection);
+ addConnection(handle, id, connection);
return id;
}
- private void addConnection(String callId, Connection connection) {
+ private void addConnection(PhoneAccountHandle handle, String callId, Connection connection) {
connection.setTelecomCallId(callId);
mConnectionById.put(callId, connection);
mIdByConnection.put(connection, callId);
connection.addConnectionListener(mConnectionListener);
connection.setConnectionService(this);
+ connection.setPhoneAccountHandle(handle);
+ onConnectionAdded(connection);
}
/** {@hide} */
@@ -2143,6 +2207,7 @@ public abstract class ConnectionService extends Service {
mConnectionById.remove(id);
mIdByConnection.remove(connection);
mAdapter.removeCall(id);
+ onConnectionRemoved(connection);
}
}
@@ -2179,6 +2244,8 @@ public abstract class ConnectionService extends Service {
mConferenceById.remove(id);
mIdByConference.remove(conference);
mAdapter.removeCall(id);
+
+ onConferenceRemoved(conference);
}
}
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index 111fcc7869b4..92a9dc2303c8 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -520,11 +520,14 @@ final class ConnectionServiceAdapter implements DeathRecipient {
* @param callId The unique ID of the call.
* @param audioRoute The new audio route (see {@code CallAudioState#ROUTE_*}).
*/
- void setAudioRoute(String callId, int audioRoute) {
- Log.v(this, "setAudioRoute: %s %s", callId, CallAudioState.audioRouteToString(audioRoute));
+ void setAudioRoute(String callId, int audioRoute, String bluetoothAddress) {
+ Log.v(this, "setAudioRoute: %s %s %s", callId,
+ CallAudioState.audioRouteToString(audioRoute),
+ bluetoothAddress);
for (IConnectionServiceAdapter adapter : mAdapters) {
try {
- adapter.setAudioRoute(callId, audioRoute, Log.getExternalSession());
+ adapter.setAudioRoute(callId, audioRoute,
+ bluetoothAddress, Log.getExternalSession());
} catch (RemoteException ignored) {
}
}
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index b1617f4db801..3fbdeb1effb0 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -298,8 +298,8 @@ final class ConnectionServiceAdapterServant {
case MSG_SET_AUDIO_ROUTE: {
SomeArgs args = (SomeArgs) msg.obj;
try {
- mDelegate.setAudioRoute((String) args.arg1, args.argi1,
- (Session.Info) args.arg2);
+ mDelegate.setAudioRoute((String) args.arg1, args.argi1, (String) args.arg2,
+ (Session.Info) args.arg3);
} finally {
args.recycle();
}
@@ -548,12 +548,12 @@ final class ConnectionServiceAdapterServant {
@Override
public final void setAudioRoute(String connectionId, int audioRoute,
- Session.Info sessionInfo) {
-
+ String bluetoothAddress, Session.Info sessionInfo) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = connectionId;
args.argi1 = audioRoute;
- args.arg2 = sessionInfo;
+ args.arg2 = bluetoothAddress;
+ args.arg3 = sessionInfo;
mHandler.obtainMessage(MSG_SET_AUDIO_ROUTE, args).sendToTarget();
}
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 9559a28c0bef..4bc2a9b149f2 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -16,6 +16,7 @@
package android.telecom;
+import android.bluetooth.BluetoothDevice;
import android.os.Bundle;
import android.os.RemoteException;
@@ -128,7 +129,22 @@ public final class InCallAdapter {
*/
public void setAudioRoute(int route) {
try {
- mAdapter.setAudioRoute(route);
+ mAdapter.setAudioRoute(route, null);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Request audio routing to a specific bluetooth device. Calling this method may result in
+ * the device routing audio to a different bluetooth device than the one specified. A list of
+ * available devices can be obtained via {@link CallAudioState#getSupportedBluetoothDevices()}
+ *
+ * @param bluetoothAddress The address of the bluetooth device to connect to, as returned by
+ * {@link BluetoothDevice#getAddress()}, or {@code null} if no device is preferred.
+ */
+ public void requestBluetoothAudio(String bluetoothAddress) {
+ try {
+ mAdapter.setAudioRoute(CallAudioState.ROUTE_BLUETOOTH, bluetoothAddress);
} catch (RemoteException e) {
}
}
@@ -419,4 +435,21 @@ public final class InCallAdapter {
} catch (RemoteException ignored) {
}
}
+
+
+ /**
+ * Initiates a handover of this {@link Call} to the {@link ConnectionService} identified
+ * by destAcct.
+ * @param callId The callId of the Call which calls this function.
+ * @param destAcct ConnectionService to which the call should be handed over.
+ * @param videoState The video state desired after the handover.
+ * @param extras Extra information to be passed to ConnectionService
+ */
+ public void handoverTo(String callId, PhoneAccountHandle destAcct, int videoState,
+ Bundle extras) {
+ try {
+ mAdapter.handoverTo(callId, destAcct, videoState, extras);
+ } catch (RemoteException ignored) {
+ }
+ }
}
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index e384d4696ab0..d558bbaea6d3 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -16,9 +16,11 @@
package android.telecom;
+import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
import android.app.Service;
+import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.hardware.camera2.CameraManager;
import android.net.Uri;
@@ -377,6 +379,22 @@ public abstract class InCallService extends Service {
}
/**
+ * Request audio routing to a specific bluetooth device. Calling this method may result in
+ * the device routing audio to a different bluetooth device than the one specified if the
+ * bluetooth stack is unable to route audio to the requested device.
+ * A list of available devices can be obtained via
+ * {@link CallAudioState#getSupportedBluetoothDevices()}
+ *
+ * @param bluetoothAddress The address of the bluetooth device to connect to, as returned by
+ * {@link BluetoothDevice#getAddress()}.
+ */
+ public final void requestBluetoothAudio(@NonNull String bluetoothAddress) {
+ if (mPhone != null) {
+ mPhone.requestBluetoothAudio(bluetoothAddress);
+ }
+ }
+
+ /**
* Invoked when the {@code Phone} has been created. This is a signal to the in-call experience
* to start displaying in-call information to the user. Each instance of {@code InCallService}
* will have only one {@code Phone}, and this method will be called exactly once in the lifetime
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index 066f6c26dd52..421b1a4b22a5 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -17,7 +17,9 @@
package android.telecom;
import android.annotation.SystemApi;
+import android.bluetooth.BluetoothDevice;
import android.os.Bundle;
+import android.os.RemoteException;
import android.util.ArrayMap;
import java.util.Collections;
@@ -295,6 +297,18 @@ public final class Phone {
}
/**
+ * Request audio routing to a specific bluetooth device. Calling this method may result in
+ * the device routing audio to a different bluetooth device than the one specified. A list of
+ * available devices can be obtained via {@link CallAudioState#getSupportedBluetoothDevices()}
+ *
+ * @param bluetoothAddress The address of the bluetooth device to connect to, as returned by
+ * {@link BluetoothDevice#getAddress()}, or {@code null} if no device is preferred.
+ */
+ public void requestBluetoothAudio(String bluetoothAddress) {
+ mInCallAdapter.requestBluetoothAudio(bluetoothAddress);
+ }
+
+ /**
* Turns the proximity sensor on. When this request is made, the proximity sensor will
* become active, and the touch screen and display will be turned off when the user's face
* is detected to be in close proximity to the screen. This operation is a no-op on devices
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 691e7cf1d34f..74b9465070c5 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -86,13 +86,11 @@ public final class PhoneAccount implements Parcelable {
/**
* Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
* indicates whether this {@link PhoneAccount} is capable of supporting a request to handover a
- * connection (see {@link android.telecom.Call#EVENT_REQUEST_HANDOVER}) to this
- * {@link PhoneAccount} from a {@link PhoneAccount} specifying
- * {@link #EXTRA_SUPPORTS_HANDOVER_FROM}.
+ * connection (see {@code android.telecom.Call#handoverTo()}) to this {@link PhoneAccount} from
+ * a {@link PhoneAccount} specifying {@link #EXTRA_SUPPORTS_HANDOVER_FROM}.
* <p>
* A handover request is initiated by the user from the default dialer app to indicate a desire
* to handover a call from one {@link PhoneAccount}/{@link ConnectionService} to another.
- * @hide
*/
public static final String EXTRA_SUPPORTS_HANDOVER_TO =
"android.telecom.extra.SUPPORTS_HANDOVER_TO";
@@ -113,12 +111,11 @@ public final class PhoneAccount implements Parcelable {
* Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
* indicates whether this {@link PhoneAccount} is capable of supporting a request to handover a
* connection from this {@link PhoneAccount} to another {@link PhoneAccount}.
- * (see {@link android.telecom.Call#EVENT_REQUEST_HANDOVER}) which specifies
+ * (see {@code android.telecom.Call#handoverTo()}) which specifies
* {@link #EXTRA_SUPPORTS_HANDOVER_TO}.
* <p>
* A handover request is initiated by the user from the default dialer app to indicate a desire
* to handover a call from one {@link PhoneAccount}/{@link ConnectionService} to another.
- * @hide
*/
public static final String EXTRA_SUPPORTS_HANDOVER_FROM =
"android.telecom.extra.SUPPORTS_HANDOVER_FROM";
@@ -132,7 +129,6 @@ public final class PhoneAccount implements Parcelable {
* <p>
* By default, Self-Managed {@link PhoneAccount}s do not log their calls to the call log.
* Setting this extra to {@code true} provides a means for them to log their calls.
- * @hide
*/
public static final String EXTRA_LOG_SELF_MANAGED_CALLS =
"android.telecom.extra.LOG_SELF_MANAGED_CALLS";
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 2cc431436acb..85906ad116be 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -398,7 +398,8 @@ final class RemoteConnectionService {
}
@Override
- public void setAudioRoute(String callId, int audioRoute, Session.Info sessionInfo) {
+ public void setAudioRoute(String callId, int audioRoute, String bluetoothAddress,
+ Session.Info sessionInfo) {
if (hasConnection(callId)) {
// TODO(3pcalls): handle this for remote connections.
// Likely we don't want to do anything since it doesn't make sense for self-managed
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 9e52c71be264..da32e0bebdb1 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1750,6 +1750,41 @@ public class TelecomManager {
return false;
}
+ /**
+ * Called from the recipient side of a handover to indicate a desire to accept the handover
+ * of an ongoing call to another {@link ConnectionService} identified by
+ * {@link PhoneAccountHandle} destAcct. For managed {@link ConnectionService}s, the specified
+ * {@link PhoneAccountHandle} must have been registered with {@link #registerPhoneAccount} and
+ * the user must have enabled the corresponding {@link PhoneAccount}. This can be checked using
+ * {@link #getPhoneAccount}. Self-managed {@link ConnectionService}s must have
+ * {@link android.Manifest.permission#MANAGE_OWN_CALLS} to handover a call to it.
+ * <p>
+ * Once invoked, this method will cause the system to bind to the {@link ConnectionService}
+ * associated with the {@link PhoneAccountHandle} destAcct and call
+ * (See {@link ConnectionService#onCreateIncomingHandoverConnection}).
+ * <p>
+ * For a managed {@link ConnectionService}, a {@link SecurityException} will be thrown if either
+ * the {@link PhoneAccountHandle} destAcct does not correspond to a registered
+ * {@link PhoneAccount} or the associated {@link PhoneAccount} is not currently enabled by the
+ * user.
+ * <p>
+ * For a self-managed {@link ConnectionService}, a {@link SecurityException} will be thrown if
+ * the calling app does not have {@link android.Manifest.permission#MANAGE_OWN_CALLS}.
+ *
+ * @param srcAddr The {@link android.net.Uri} of the ongoing call to handover to the caller’s
+ * {@link ConnectionService}.
+ * @param videoState Video state after the handover.
+ * @param destAcct The {@link PhoneAccountHandle} registered to the calling package.
+ */
+ public void acceptHandover(Uri srcAddr, int videoState, PhoneAccountHandle destAcct) {
+ try {
+ if (isServiceConnected()) {
+ getTelecomService().acceptHandover(srcAddr, videoState, destAcct);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException acceptHandover: " + e);
+ }
+ }
private ITelecomService getTelecomService() {
if (mTelecomServiceOverride != null) {
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index d20da1862a28..da2015f6b99b 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -103,7 +103,8 @@ oneway interface IConnectionServiceAdapter {
void removeExtras(String callId, in List<String> keys, in Session.Info sessionInfo);
- void setAudioRoute(String callId, int audioRoute, in Session.Info sessionInfo);
+ void setAudioRoute(String callId, int audioRoute, String bluetoothAddress,
+ in Session.Info sessionInfo);
void onConnectionEvent(String callId, String event, in Bundle extras,
in Session.Info sessionInfo);
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index 73fa29af2ca4..23ac940edfa8 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -39,7 +39,7 @@ oneway interface IInCallAdapter {
void mute(boolean shouldMute);
- void setAudioRoute(int route);
+ void setAudioRoute(int route, String bluetoothAddress);
void playDtmfTone(String callId, char digit);
@@ -77,4 +77,7 @@ oneway interface IInCallAdapter {
void stopRtt(String callId);
void setRttMode(String callId, int mode);
+
+ void handoverTo(String callId, in PhoneAccountHandle destAcct, int videoState,
+ in Bundle extras);
}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 8ebac2c6273a..3460754ff9eb 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -274,4 +274,9 @@ interface ITelecomService {
* @see TelecomServiceImpl#waitOnHandler
*/
void waitOnHandlers();
+
+ /**
+ * @see TelecomServiceImpl#acceptHandover
+ */
+ void acceptHandover(in Uri srcAddr, int videoState, in PhoneAccountHandle destAcct);
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 3fc220857676..1db6ef7b10f0 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -855,6 +855,14 @@ public class CarrierConfigManager {
public static final String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool";
/**
+ * Default Enhanced 4G LTE mode enabled. When this is {@code true}, Enhanced 4G LTE mode by
+ * default is on, otherwise if {@code false}, Enhanced 4G LTE mode by default is off.
+ * @hide
+ */
+ public static final String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL =
+ "enhanced_4g_lte_on_by_default_bool";
+
+ /**
* Determine whether IMS apn can be shown.
*/
public static final String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
@@ -1643,6 +1651,33 @@ public class CarrierConfigManager {
public static final String KEY_FEATURE_ACCESS_CODES_STRING_ARRAY =
"feature_access_codes_string_array";
+ /**
+ * Determines if the carrier wants to identify high definition calls in the call log.
+ * @hide
+ */
+ public static final String KEY_IDENTIFY_HIGH_DEFINITION_CALLS_IN_CALL_LOG_BOOL =
+ "identify_high_definition_calls_in_call_log_bool";
+
+ /**
+ * Flag specifying whether to use the {@link ServiceState} roaming status, which can be
+ * affected by other carrier configs (e.g.
+ * {@link #KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY}), when setting the SPN display.
+ * <p>
+ * If {@code true}, the SPN display uses {@link ServiceState#getRoaming}.
+ * If {@code false} the SPN display checks if the current MCC/MNC is different from the
+ * SIM card's MCC/MNC.
+ *
+ * @see KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY
+ * @see KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY
+ * @see KEY_NON_ROAMING_OPERATOR_STRING_ARRAY
+ * @see KEY_ROAMING_OPERATOR_STRING_ARRAY
+ * @see KEY_FORCE_HOME_NETWORK_BOOL
+ *
+ * @hide
+ */
+ public static final String KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL =
+ "spn_display_rule_use_roaming_from_service_state_bool";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -1785,6 +1820,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL, true);
sDefaults.putBoolean(KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, true);
sDefaults.putBoolean(KEY_HIDE_ENHANCED_4G_LTE_BOOL, false);
+ sDefaults.putBoolean(KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL, true);
sDefaults.putBoolean(KEY_HIDE_IMS_APN_BOOL, false);
sDefaults.putBoolean(KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, false);
sDefaults.putBoolean(KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL, false);
@@ -1920,6 +1956,8 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_SHOW_IMS_REGISTRATION_STATUS_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);
}
/**
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index afff6d548e86..9ccfa942af5f 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -204,16 +204,6 @@ public class PhoneStateListener {
public static final int LISTEN_VOLTE_STATE = 0x00004000;
/**
- * Listen for OEM hook raw event
- *
- * @see #onOemHookRawEvent
- * @hide
- * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
- */
- @Deprecated
- public static final int LISTEN_OEM_HOOK_RAW_EVENT = 0x00008000;
-
- /**
* Listen for carrier network changes indicated by a carrier app.
*
* @see #onCarrierNetworkRequest
@@ -359,9 +349,6 @@ public class PhoneStateListener {
case LISTEN_DATA_ACTIVATION_STATE:
PhoneStateListener.this.onDataActivationStateChanged((int)msg.obj);
break;
- case LISTEN_OEM_HOOK_RAW_EVENT:
- PhoneStateListener.this.onOemHookRawEvent((byte[])msg.obj);
- break;
case LISTEN_CARRIER_NETWORK_CHANGE:
PhoneStateListener.this.onCarrierNetworkChange((boolean)msg.obj);
break;
@@ -556,16 +543,6 @@ public class PhoneStateListener {
}
/**
- * Callback invoked when OEM hook raw event is received. Requires
- * the READ_PRIVILEGED_PHONE_STATE permission.
- * @param rawData is the byte array of the OEM hook raw data.
- * @hide
- */
- public void onOemHookRawEvent(byte[] rawData) {
- // default implementation empty
- }
-
- /**
* Callback invoked when telephony has received notice from a carrier
* app that a network action that could result in connectivity loss
* has been requested by an app using
@@ -677,10 +654,6 @@ public class PhoneStateListener {
send(LISTEN_DATA_ACTIVATION_STATE, 0, 0, activationState);
}
- public void onOemHookRawEvent(byte[] rawData) {
- send(LISTEN_OEM_HOOK_RAW_EVENT, 0, 0, rawData);
- }
-
public void onCarrierNetworkChange(boolean active) {
send(LISTEN_CARRIER_NETWORK_CHANGE, 0, 0, active);
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 924f0deff333..5d0392680c00 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -338,16 +338,18 @@ public final class SmsManager {
/**
* Send a text based SMS without writing it into the SMS Provider.
*
+ * <p>
+ * The message will be sent directly over the network and will not be visible in SMS
+ * applications. Intended for internal carrier use only.
+ * </p>
+ *
* <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)
- * @hide
*/
- @SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void sendTextMessageWithoutPersisting(
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 88f4880a98f8..2f39ddb1a79e 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -360,6 +360,42 @@ public class SubscriptionManager {
public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
/**
+ * TelephonyProvider column name for enable Volte.
+ *@hide
+ */
+ public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+
+ /**
+ * TelephonyProvider column name for enable VT (Video Telephony over IMS)
+ *@hide
+ */
+ public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+
+ /**
+ * TelephonyProvider column name for enable Wifi calling
+ *@hide
+ */
+ public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+
+ /**
+ * TelephonyProvider column name for Wifi calling mode
+ *@hide
+ */
+ public static final String WFC_IMS_MODE = "wfc_ims_mode";
+
+ /**
+ * TelephonyProvider column name for Wifi calling mode in roaming
+ *@hide
+ */
+ public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
+
+ /**
+ * TelephonyProvider column name for enable Wifi calling in roaming
+ *@hide
+ */
+ public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+
+ /**
* Broadcast Action: The user has changed one of the default subs related to
* data, phone calls, or sms</p>
*
diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/telephony/Telephony.java
index 216d28cb49ba..d7b6142a5de6 100644
--- a/telephony/java/android/telephony/Telephony.java
+++ b/telephony/java/android/telephony/Telephony.java
@@ -2828,6 +2828,26 @@ public final class Telephony {
* @hide
*/
public static final int CARRIER_DELETED_BUT_PRESENT_IN_XML = 6;
+
+ /**
+ * The owner of the APN.
+ * <p>Type: INTEGER</p>
+ * @hide
+ */
+ public static final String OWNED_BY = "owned_by";
+
+ /**
+ * Possible value for the OWNED_BY field.
+ * APN is owned by DPC.
+ * @hide
+ */
+ public static final int OWNED_BY_DPC = 0;
+ /**
+ * Possible value for the OWNED_BY field.
+ * APN is owned by other sources.
+ * @hide
+ */
+ public static final int OWNED_BY_OTHERS = 1;
}
/**
@@ -3273,4 +3293,69 @@ public final class Telephony {
*/
public static final String IS_USING_CARRIER_AGGREGATION = "is_using_carrier_aggregation";
}
+
+ /**
+ * Contains carrier identification information.
+ * @hide
+ */
+ public static final class CarrierIdentification implements BaseColumns {
+ /**
+ * Numeric operator ID (as String). {@code MCC + MNC}
+ * <P>Type: TEXT </P>
+ */
+ public static final String MCCMNC = "mccmnc";
+
+ /**
+ * Group id level 1 (as String).
+ * <P>Type: TEXT </P>
+ */
+ public static final String GID1 = "gid1";
+
+ /**
+ * Group id level 2 (as String).
+ * <P>Type: TEXT </P>
+ */
+ public static final String GID2 = "gid2";
+
+ /**
+ * Public Land Mobile Network name.
+ * <P>Type: TEXT </P>
+ */
+ public static final String PLMN = "plmn";
+
+ /**
+ * Prefix xpattern of IMSI (International Mobile Subscriber Identity).
+ * <P>Type: TEXT </P>
+ */
+ public static final String IMSI_PREFIX_XPATTERN = "imsi_prefix_xpattern";
+
+ /**
+ * Service Provider Name.
+ * <P>Type: TEXT </P>
+ */
+ public static final String SPN = "spn";
+
+ /**
+ * Prefer APN name.
+ * <P>Type: TEXT </P>
+ */
+ public static final String APN = "apn";
+
+ /**
+ * User facing carrier name.
+ * <P>Type: TEXT </P>
+ */
+ public static final String NAME = "carrier_name";
+
+ /**
+ * A unique carrier id
+ * <P>Type: INTEGER </P>
+ */
+ public static final String CID = "carrier_id";
+
+ /**
+ * The {@code content://} URI for this table.
+ */
+ public static final Uri CONTENT_URI = Uri.parse("content://carrier_identification");
+ }
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 42c3de563492..4ffb3c3213c6 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5709,29 +5709,6 @@ public class TelephonyManager {
return retVal;
}
- /**
- * Returns the result and response from RIL for oem request
- *
- * @param oemReq the data is sent to ril.
- * @param oemResp the respose data from RIL.
- * @return negative value request was not handled or get error
- * 0 request was handled succesfully, but no response data
- * positive value success, data length of response
- * @hide
- * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
- */
- @Deprecated
- public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null)
- return telephony.invokeOemRilRequestRaw(oemReq, oemResp);
- } catch (RemoteException ex) {
- } catch (NullPointerException ex) {
- }
- return -1;
- }
-
/** @hide */
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 92a21b6fb85f..7bcdcdcc30ba 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -73,8 +73,8 @@ public final class TelephonyScanManager {
/**
* Informs the user that there is some error about the scan.
*
- * This callback will be called whenever there is any error about the scan, but the scan
- * won't stop unless the onComplete() callback is called.
+ * This callback will be called whenever there is any error about the scan, and the scan
+ * will be terminated. onComplete() will NOT be called.
*/
public void onError(int error) {}
}
diff --git a/telephony/java/android/telephony/euicc/DownloadableSubscription.java b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
index b5484e344a1c..01041c8b1360 100644
--- a/telephony/java/android/telephony/euicc/DownloadableSubscription.java
+++ b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
@@ -53,6 +53,8 @@ public final class DownloadableSubscription implements Parcelable {
@Nullable
public final String encodedActivationCode;
+ @Nullable private String confirmationCode;
+
// see getCarrierName and setCarrierName
@Nullable
private String carrierName;
@@ -66,6 +68,7 @@ public final class DownloadableSubscription implements Parcelable {
private DownloadableSubscription(Parcel in) {
encodedActivationCode = in.readString();
+ confirmationCode = in.readString();
carrierName = in.readString();
accessRules = in.createTypedArray(UiccAccessRule.CREATOR);
}
@@ -83,6 +86,21 @@ public final class DownloadableSubscription implements Parcelable {
}
/**
+ * Sets the confirmation code.
+ */
+ public void setConfirmationCode(String confirmationCode) {
+ this.confirmationCode = confirmationCode;
+ }
+
+ /**
+ * Returns the confirmation code.
+ */
+ @Nullable
+ public String getConfirmationCode() {
+ return confirmationCode;
+ }
+
+ /**
* Set the user-visible carrier name.
* @hide
*
@@ -134,6 +152,7 @@ public final class DownloadableSubscription implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(encodedActivationCode);
+ dest.writeString(confirmationCode);
dest.writeString(carrierName);
dest.writeTypedArray(accessRules, flags);
}
diff --git a/telephony/java/android/telephony/ims/ImsServiceProxy.java b/telephony/java/android/telephony/ims/ImsServiceProxy.java
deleted file mode 100644
index 038e295d8822..000000000000
--- a/telephony/java/android/telephony/ims/ImsServiceProxy.java
+++ /dev/null
@@ -1,335 +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.telephony.ims;
-
-import android.app.PendingIntent;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.telephony.ims.feature.IRcsFeature;
-import android.telephony.ims.feature.ImsFeature;
-import android.util.Log;
-
-import com.android.ims.ImsCallProfile;
-import com.android.ims.internal.IImsCallSession;
-import com.android.ims.internal.IImsCallSessionListener;
-import com.android.ims.internal.IImsConfig;
-import com.android.ims.internal.IImsEcbm;
-import com.android.ims.internal.IImsMultiEndpoint;
-import com.android.ims.internal.IImsRegistrationListener;
-import com.android.ims.internal.IImsServiceController;
-import com.android.ims.internal.IImsServiceFeatureListener;
-import com.android.ims.internal.IImsUt;
-
-/**
- * A container of the IImsServiceController binder, which implements all of the ImsFeatures that
- * the platform currently supports: MMTel and RCS.
- * @hide
- */
-
-public class ImsServiceProxy extends ImsServiceProxyCompat implements IRcsFeature {
-
- protected String LOG_TAG = "ImsServiceProxy";
- private final int mSupportedFeature;
-
- // Start by assuming the proxy is available for usage.
- private boolean mIsAvailable = true;
- // ImsFeature Status from the ImsService. Cached.
- private Integer mFeatureStatusCached = null;
- private ImsServiceProxy.INotifyStatusChanged mStatusCallback;
- private final Object mLock = new Object();
-
- public interface INotifyStatusChanged {
- void notifyStatusChanged();
- }
-
- private final IImsServiceFeatureListener mListenerBinder =
- new IImsServiceFeatureListener.Stub() {
-
- @Override
- public void imsFeatureCreated(int slotId, int feature) throws RemoteException {
- // The feature has been re-enabled. This may happen when the service crashes.
- synchronized (mLock) {
- if (!mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
- Log.i(LOG_TAG, "Feature enabled on slotId: " + slotId + " for feature: " +
- feature);
- mIsAvailable = true;
- }
- }
- }
-
- @Override
- public void imsFeatureRemoved(int slotId, int feature) throws RemoteException {
- synchronized (mLock) {
- if (mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
- Log.i(LOG_TAG, "Feature disabled on slotId: " + slotId + " for feature: " +
- feature);
- mIsAvailable = false;
- }
- }
- }
-
- @Override
- public void imsStatusChanged(int slotId, int feature, int status) throws RemoteException {
- synchronized (mLock) {
- Log.i(LOG_TAG, "imsStatusChanged: slot: " + slotId + " feature: " + feature +
- " status: " + status);
- if (mSlotId == slotId && feature == mSupportedFeature) {
- mFeatureStatusCached = status;
- if (mStatusCallback != null) {
- mStatusCallback.notifyStatusChanged();
- }
- }
- }
- }
- };
-
- public ImsServiceProxy(int slotId, IBinder binder, int featureType) {
- super(slotId, binder);
- mSupportedFeature = featureType;
- }
-
- public ImsServiceProxy(int slotId, int featureType) {
- super(slotId, null /*IBinder*/);
- mSupportedFeature = featureType;
- }
-
- public IImsServiceFeatureListener getListener() {
- return mListenerBinder;
- }
-
- public void setBinder(IBinder binder) {
- mBinder = binder;
- }
-
- @Override
- public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
- throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).startSession(mSlotId, mSupportedFeature,
- incomingCallIntent, listener);
- }
- }
-
- @Override
- public void endSession(int sessionId) throws RemoteException {
- synchronized (mLock) {
- // Only check to make sure the binder connection still exists. This method should
- // still be able to be called when the state is STATE_NOT_AVAILABLE.
- checkBinderConnection();
- getServiceInterface(mBinder).endSession(mSlotId, mSupportedFeature, sessionId);
- }
- }
-
- @Override
- public boolean isConnected(int callServiceType, int callType)
- throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).isConnected(mSlotId, mSupportedFeature,
- callServiceType, callType);
- }
- }
-
- @Override
- public boolean isOpened() throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).isOpened(mSlotId, mSupportedFeature);
- }
- }
-
- @Override
- public void addRegistrationListener(IImsRegistrationListener listener)
- throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- getServiceInterface(mBinder).addRegistrationListener(mSlotId, mSupportedFeature,
- listener);
- }
- }
-
- @Override
- public void removeRegistrationListener(IImsRegistrationListener listener)
- throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- getServiceInterface(mBinder).removeRegistrationListener(mSlotId, mSupportedFeature,
- listener);
- }
- }
-
- @Override
- public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
- throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).createCallProfile(mSlotId, mSupportedFeature,
- sessionId, callServiceType, callType);
- }
- }
-
- @Override
- public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
- IImsCallSessionListener listener) throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).createCallSession(mSlotId, mSupportedFeature,
- sessionId, profile, listener);
- }
- }
-
- @Override
- public IImsCallSession getPendingCallSession(int sessionId, String callId)
- throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).getPendingCallSession(mSlotId, mSupportedFeature,
- sessionId, callId);
- }
- }
-
- @Override
- public IImsUt getUtInterface() throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).getUtInterface(mSlotId, mSupportedFeature);
- }
- }
-
- @Override
- public IImsConfig getConfigInterface() throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).getConfigInterface(mSlotId, mSupportedFeature);
- }
- }
-
- @Override
- public void turnOnIms() throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- getServiceInterface(mBinder).turnOnIms(mSlotId, mSupportedFeature);
- }
- }
-
- @Override
- public void turnOffIms() throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- getServiceInterface(mBinder).turnOffIms(mSlotId, mSupportedFeature);
- }
- }
-
- @Override
- public IImsEcbm getEcbmInterface() throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).getEcbmInterface(mSlotId, mSupportedFeature);
- }
- }
-
- @Override
- public void setUiTTYMode(int uiTtyMode, Message onComplete)
- throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- getServiceInterface(mBinder).setUiTTYMode(mSlotId, mSupportedFeature, uiTtyMode,
- onComplete);
- }
- }
-
- @Override
- public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).getMultiEndpointInterface(mSlotId,
- mSupportedFeature);
- }
- }
-
- @Override
- public int getFeatureStatus() {
- synchronized (mLock) {
- if (isBinderAlive() && mFeatureStatusCached != null) {
- Log.i(LOG_TAG, "getFeatureStatus - returning cached: " + mFeatureStatusCached);
- return mFeatureStatusCached;
- }
- }
- // Don't synchronize on Binder call.
- Integer status = retrieveFeatureStatus();
- synchronized (mLock) {
- if (status == null) {
- return ImsFeature.STATE_NOT_AVAILABLE;
- }
- // Cache only non-null value for feature status.
- mFeatureStatusCached = status;
- }
- Log.i(LOG_TAG, "getFeatureStatus - returning " + status);
- return status;
- }
-
- /**
- * Internal method used to retrieve the feature status from the corresponding ImsService.
- */
- private Integer retrieveFeatureStatus() {
- if (mBinder != null) {
- try {
- return getServiceInterface(mBinder).getFeatureStatus(mSlotId, mSupportedFeature);
- } catch (RemoteException e) {
- // Status check failed, don't update cache
- }
- }
- return null;
- }
-
- /**
- * @param c Callback that will fire when the feature status has changed.
- */
- public void setStatusCallback(INotifyStatusChanged c) {
- mStatusCallback = c;
- }
-
- /**
- * @return Returns true if the ImsService is ready to take commands, false otherwise. If this
- * method returns false, it doesn't mean that the Binder connection is not available (use
- * {@link #isBinderReady()} to check that), but that the ImsService is not accepting commands
- * at this time.
- *
- * For example, for DSDS devices, only one slot can be {@link ImsFeature#STATE_READY} to take
- * commands at a time, so the other slot must stay at {@link ImsFeature#STATE_NOT_AVAILABLE}.
- */
- public boolean isBinderReady() {
- return isBinderAlive() && getFeatureStatus() == ImsFeature.STATE_READY;
- }
-
- @Override
- public boolean isBinderAlive() {
- return mIsAvailable && mBinder != null && mBinder.isBinderAlive();
- }
-
- protected void checkServiceIsReady() throws RemoteException {
- if (!isBinderReady()) {
- throw new RemoteException("ImsServiceProxy is not ready to accept commands.");
- }
- }
-
- private IImsServiceController getServiceInterface(IBinder b) {
- return IImsServiceController.Stub.asInterface(b);
- }
-}
diff --git a/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java b/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java
deleted file mode 100644
index bbd5f0279913..000000000000
--- a/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java
+++ /dev/null
@@ -1,183 +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.telephony.ims;
-
-import android.app.PendingIntent;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.telephony.ims.feature.IMMTelFeature;
-import android.telephony.ims.feature.ImsFeature;
-
-import com.android.ims.ImsCallProfile;
-import com.android.ims.internal.IImsCallSession;
-import com.android.ims.internal.IImsCallSessionListener;
-import com.android.ims.internal.IImsConfig;
-import com.android.ims.internal.IImsEcbm;
-import com.android.ims.internal.IImsMultiEndpoint;
-import com.android.ims.internal.IImsRegistrationListener;
-import com.android.ims.internal.IImsService;
-import com.android.ims.internal.IImsUt;
-
-/**
- * Compatibility class that implements the new ImsService IMMTelFeature interface, but
- * uses the old IImsService interface to support older devices that implement the deprecated
- * opt/net/ims interface.
- * @hide
- */
-
-public class ImsServiceProxyCompat implements IMMTelFeature {
-
- private static final int SERVICE_ID = ImsFeature.MMTEL;
-
- protected final int mSlotId;
- protected IBinder mBinder;
-
- public ImsServiceProxyCompat(int slotId, IBinder binder) {
- mSlotId = slotId;
- mBinder = binder;
- }
-
- @Override
- public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
- throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).open(mSlotId, ImsFeature.MMTEL, incomingCallIntent,
- listener);
- }
-
- @Override
- public void endSession(int sessionId) throws RemoteException {
- checkBinderConnection();
- getServiceInterface(mBinder).close(sessionId);
- }
-
- @Override
- public boolean isConnected(int callServiceType, int callType)
- throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).isConnected(SERVICE_ID, callServiceType, callType);
- }
-
- @Override
- public boolean isOpened() throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).isOpened(SERVICE_ID);
- }
-
- @Override
- public void addRegistrationListener(IImsRegistrationListener listener)
- throws RemoteException {
- checkBinderConnection();
- getServiceInterface(mBinder).addRegistrationListener(mSlotId, ImsFeature.MMTEL, listener);
- }
-
- @Override
- public void removeRegistrationListener(IImsRegistrationListener listener)
- throws RemoteException {
- // Not Implemented in old ImsService. If the registration listener becomes invalid, the
- // ImsService will remove.
- }
-
- @Override
- public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
- throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).createCallProfile(sessionId, callServiceType, callType);
- }
-
- @Override
- public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
- IImsCallSessionListener listener) throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).createCallSession(sessionId, profile, listener);
- }
-
- @Override
- public IImsCallSession getPendingCallSession(int sessionId, String callId)
- throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).getPendingCallSession(sessionId, callId);
- }
-
- @Override
- public IImsUt getUtInterface() throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).getUtInterface(SERVICE_ID);
- }
-
- @Override
- public IImsConfig getConfigInterface() throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).getConfigInterface(mSlotId);
- }
-
- @Override
- public void turnOnIms() throws RemoteException {
- checkBinderConnection();
- getServiceInterface(mBinder).turnOnIms(mSlotId);
- }
-
- @Override
- public void turnOffIms() throws RemoteException {
- checkBinderConnection();
- getServiceInterface(mBinder).turnOffIms(mSlotId);
- }
-
- @Override
- public IImsEcbm getEcbmInterface() throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).getEcbmInterface(SERVICE_ID);
- }
-
- @Override
- public void setUiTTYMode(int uiTtyMode, Message onComplete)
- throws RemoteException {
- checkBinderConnection();
- getServiceInterface(mBinder).setUiTTYMode(SERVICE_ID, uiTtyMode, onComplete);
- }
-
- @Override
- public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).getMultiEndpointInterface(SERVICE_ID);
- }
-
- /**
- * Base implementation, always returns READY for compatibility with old ImsService.
- */
- public int getFeatureStatus() {
- return ImsFeature.STATE_READY;
- }
-
- /**
- * @return false if the binder connection is no longer alive.
- */
- public boolean isBinderAlive() {
- return mBinder != null && mBinder.isBinderAlive();
- }
-
- private IImsService getServiceInterface(IBinder b) {
- return IImsService.Stub.asInterface(b);
- }
-
- protected void checkBinderConnection() throws RemoteException {
- if (!isBinderAlive()) {
- throw new RemoteException("ImsServiceProxy is not available for that feature.");
- }
- }
-}
diff --git a/telephony/java/android/telephony/ims/feature/IMMTelFeature.java b/telephony/java/android/telephony/ims/feature/IMMTelFeature.java
deleted file mode 100644
index d65e27ebbb51..000000000000
--- a/telephony/java/android/telephony/ims/feature/IMMTelFeature.java
+++ /dev/null
@@ -1,187 +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.telephony.ims.feature;
-
-import android.app.PendingIntent;
-import android.os.Message;
-import android.os.RemoteException;
-
-import com.android.ims.ImsCallProfile;
-import com.android.ims.internal.IImsCallSession;
-import com.android.ims.internal.IImsCallSessionListener;
-import com.android.ims.internal.IImsConfig;
-import com.android.ims.internal.IImsEcbm;
-import com.android.ims.internal.IImsMultiEndpoint;
-import com.android.ims.internal.IImsRegistrationListener;
-import com.android.ims.internal.IImsUt;
-
-/**
- * MMTel interface for an ImsService. When updating this interface, ensure that base implementations
- * of your changes are also present in MMTelFeature for compatibility with older versions of the
- * MMTel feature.
- * @hide
- */
-
-public interface IMMTelFeature {
-
- /**
- * Notifies the MMTel feature that you would like to start a session. This should always be
- * done before making/receiving IMS calls. The IMS service will register the device to the
- * operator's network with the credentials (from ISIM) periodically in order to receive calls
- * from the operator's network. When the IMS service receives a new call, it will send out an
- * intent with the provided action string. The intent contains a call ID extra
- * {@link IImsCallSession#getCallId} and it can be used to take a call.
- *
- * @param incomingCallIntent When an incoming call is received, the IMS service will call
- * {@link PendingIntent#send} to send back the intent to the caller with
- * {@link #INCOMING_CALL_RESULT_CODE} as the result code and the intent to fill in the call ID;
- * It cannot be null.
- * @param listener To listen to IMS registration events; It cannot be null
- * @return an integer (greater than 0) representing the session id associated with the session
- * that has been started.
- */
- int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
- throws RemoteException;
-
- /**
- * End a previously started session using the associated sessionId.
- * @param sessionId an integer (greater than 0) representing the ongoing session. See
- * {@link #startSession}.
- */
- void endSession(int sessionId) throws RemoteException;
-
- /**
- * Checks if the IMS service has successfully registered to the IMS network with the specified
- * service & call type.
- *
- * @param callServiceType a service type that is specified in {@link ImsCallProfile}
- * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
- * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
- * @param callType a call type that is specified in {@link ImsCallProfile}
- * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
- * {@link ImsCallProfile#CALL_TYPE_VOICE}
- * {@link ImsCallProfile#CALL_TYPE_VT}
- * {@link ImsCallProfile#CALL_TYPE_VS}
- * @return true if the specified service id is connected to the IMS network; false otherwise
- * @throws RemoteException
- */
- boolean isConnected(int callServiceType, int callType) throws RemoteException;
-
- /**
- * Checks if the specified IMS service is opened.
- *
- * @return true if the specified service id is opened; false otherwise
- */
- boolean isOpened() throws RemoteException;
-
- /**
- * Add a new registration listener for the client associated with the session Id.
- * @param listener An implementation of IImsRegistrationListener.
- */
- void addRegistrationListener(IImsRegistrationListener listener)
- throws RemoteException;
-
- /**
- * Remove a previously registered listener using {@link #addRegistrationListener} for the client
- * associated with the session Id.
- * @param listener A previously registered IImsRegistrationListener
- */
- void removeRegistrationListener(IImsRegistrationListener listener)
- throws RemoteException;
-
- /**
- * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
- *
- * @param sessionId a session id which is obtained from {@link #startSession}
- * @param callServiceType a service type that is specified in {@link ImsCallProfile}
- * {@link ImsCallProfile#SERVICE_TYPE_NONE}
- * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
- * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
- * @param callType a call type that is specified in {@link ImsCallProfile}
- * {@link ImsCallProfile#CALL_TYPE_VOICE}
- * {@link ImsCallProfile#CALL_TYPE_VT}
- * {@link ImsCallProfile#CALL_TYPE_VT_TX}
- * {@link ImsCallProfile#CALL_TYPE_VT_RX}
- * {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
- * {@link ImsCallProfile#CALL_TYPE_VS}
- * {@link ImsCallProfile#CALL_TYPE_VS_TX}
- * {@link ImsCallProfile#CALL_TYPE_VS_RX}
- * @return a {@link ImsCallProfile} object
- */
- ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
- throws RemoteException;
-
- /**
- * Creates a {@link ImsCallSession} with the specified call profile.
- * Use other methods, if applicable, instead of interacting with
- * {@link ImsCallSession} directly.
- *
- * @param sessionId a session id which is obtained from {@link #startSession}
- * @param profile a call profile to make the call
- * @param listener An implementation of IImsCallSessionListener.
- */
- IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
- IImsCallSessionListener listener) throws RemoteException;
-
- /**
- * Retrieves the call session associated with a pending call.
- *
- * @param sessionId a session id which is obtained from {@link #startSession}
- * @param callId a call id to make the call
- */
- IImsCallSession getPendingCallSession(int sessionId, String callId) throws RemoteException;
-
- /**
- * @return The Ut interface for the supplementary service configuration.
- */
- IImsUt getUtInterface() throws RemoteException;
-
- /**
- * @return The config interface for IMS Configuration
- */
- IImsConfig getConfigInterface() throws RemoteException;
-
- /**
- * Signal the MMTelFeature to turn on IMS when it has been turned off using {@link #turnOffIms}
- * @param sessionId a session id which is obtained from {@link #startSession}
- */
- void turnOnIms() throws RemoteException;
-
- /**
- * Signal the MMTelFeature to turn off IMS when it has been turned on using {@link #turnOnIms}
- * @param sessionId a session id which is obtained from {@link #startSession}
- */
- void turnOffIms() throws RemoteException;
-
- /**
- * @return The Emergency call-back mode interface for emergency VoLTE calls that support it.
- */
- IImsEcbm getEcbmInterface() throws RemoteException;
-
- /**
- * Sets the current UI TTY mode for the MMTelFeature.
- * @param uiTtyMode An integer containing the new UI TTY Mode.
- * @param onComplete A {@link Message} to be used when the mode has been set.
- * @throws RemoteException
- */
- void setUiTTYMode(int uiTtyMode, Message onComplete) throws RemoteException;
-
- /**
- * @return MultiEndpoint interface for DEP notifications
- */
- IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException;
-}
diff --git a/telephony/java/android/telephony/ims/feature/MMTelFeature.java b/telephony/java/android/telephony/ims/feature/MMTelFeature.java
index a71f0bf0c7fd..758c379fcdd1 100644
--- a/telephony/java/android/telephony/ims/feature/MMTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MMTelFeature.java
@@ -32,90 +32,183 @@ import java.util.ArrayList;
import java.util.List;
/**
- * Base implementation, which implements all methods in IMMTelFeature. Any class wishing to use
- * MMTelFeature should extend this class and implement all methods that the service supports.
+ * Base implementation for MMTel.
+ * Any class wishing to use MMTelFeature should extend this class and implement all methods that the
+ * service supports.
*
* @hide
*/
-public class MMTelFeature extends ImsFeature implements IMMTelFeature {
-
- @Override
+public class MMTelFeature extends ImsFeature {
+
+ /**
+ * Notifies the MMTel feature that you would like to start a session. This should always be
+ * done before making/receiving IMS calls. The IMS service will register the device to the
+ * operator's network with the credentials (from ISIM) periodically in order to receive calls
+ * from the operator's network. When the IMS service receives a new call, it will send out an
+ * intent with the provided action string. The intent contains a call ID extra
+ * {@link IImsCallSession#getCallId} and it can be used to take a call.
+ *
+ * @param incomingCallIntent When an incoming call is received, the IMS service will call
+ * {@link PendingIntent#send} to send back the intent to the caller with
+ * ImsManager#INCOMING_CALL_RESULT_CODE as the result code and the intent to fill in the call
+ * ID; It cannot be null.
+ * @param listener To listen to IMS registration events; It cannot be null
+ * @return an integer (greater than 0) representing the session id associated with the session
+ * that has been started.
+ */
public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener) {
return 0;
}
- @Override
+ /**
+ * End a previously started session using the associated sessionId.
+ * @param sessionId an integer (greater than 0) representing the ongoing session. See
+ * {@link #startSession}.
+ */
public void endSession(int sessionId) {
}
- @Override
+ /**
+ * Checks if the IMS service has successfully registered to the IMS network with the specified
+ * service & call type.
+ *
+ * @param callSessionType a service type that is specified in {@link ImsCallProfile}
+ * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
+ * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
+ * @param callType a call type that is specified in {@link ImsCallProfile}
+ * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
+ * {@link ImsCallProfile#CALL_TYPE_VOICE}
+ * {@link ImsCallProfile#CALL_TYPE_VT}
+ * {@link ImsCallProfile#CALL_TYPE_VS}
+ * @return true if the specified service id is connected to the IMS network; false otherwise
+ */
public boolean isConnected(int callSessionType, int callType) {
return false;
}
- @Override
+ /**
+ * Checks if the specified IMS service is opened.
+ *
+ * @return true if the specified service id is opened; false otherwise
+ */
public boolean isOpened() {
return false;
}
- @Override
+ /**
+ * Add a new registration listener for the client associated with the session Id.
+ * @param listener An implementation of IImsRegistrationListener.
+ */
public void addRegistrationListener(IImsRegistrationListener listener) {
}
- @Override
+ /**
+ * Remove a previously registered listener using {@link #addRegistrationListener} for the client
+ * associated with the session Id.
+ * @param listener A previously registered IImsRegistrationListener
+ */
public void removeRegistrationListener(IImsRegistrationListener listener) {
}
- @Override
+ /**
+ * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
+ *
+ * @param sessionId a session id which is obtained from {@link #startSession}
+ * @param callSessionType a service type that is specified in {@link ImsCallProfile}
+ * {@link ImsCallProfile#SERVICE_TYPE_NONE}
+ * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
+ * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
+ * @param callType a call type that is specified in {@link ImsCallProfile}
+ * {@link ImsCallProfile#CALL_TYPE_VOICE}
+ * {@link ImsCallProfile#CALL_TYPE_VT}
+ * {@link ImsCallProfile#CALL_TYPE_VT_TX}
+ * {@link ImsCallProfile#CALL_TYPE_VT_RX}
+ * {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
+ * {@link ImsCallProfile#CALL_TYPE_VS}
+ * {@link ImsCallProfile#CALL_TYPE_VS_TX}
+ * {@link ImsCallProfile#CALL_TYPE_VS_RX}
+ * @return a {@link ImsCallProfile} object
+ */
public ImsCallProfile createCallProfile(int sessionId, int callSessionType, int callType) {
return null;
}
- @Override
+ /**
+ * Creates a {@link ImsCallSession} with the specified call profile.
+ * Use other methods, if applicable, instead of interacting with
+ * {@link ImsCallSession} directly.
+ *
+ * @param sessionId a session id which is obtained from {@link #startSession}
+ * @param profile a call profile to make the call
+ * @param listener An implementation of IImsCallSessionListener.
+ */
public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
IImsCallSessionListener listener) {
return null;
}
- @Override
+ /**
+ * Retrieves the call session associated with a pending call.
+ *
+ * @param sessionId a session id which is obtained from {@link #startSession}
+ * @param callId a call id to make the call
+ */
public IImsCallSession getPendingCallSession(int sessionId, String callId) {
return null;
}
- @Override
+ /**
+ * @return The Ut interface for the supplementary service configuration.
+ */
public IImsUt getUtInterface() {
return null;
}
- @Override
+ /**
+ * @return The config interface for IMS Configuration
+ */
public IImsConfig getConfigInterface() {
return null;
}
- @Override
+ /**
+ * Signal the MMTelFeature to turn on IMS when it has been turned off using {@link #turnOffIms}
+ */
public void turnOnIms() {
}
- @Override
+ /**
+ * Signal the MMTelFeature to turn off IMS when it has been turned on using {@link #turnOnIms}
+ */
public void turnOffIms() {
}
- @Override
+ /**
+ * @return The Emergency call-back mode interface for emergency VoLTE calls that support it.
+ */
public IImsEcbm getEcbmInterface() {
return null;
}
- @Override
+ /**
+ * Sets the current UI TTY mode for the MMTelFeature.
+ * @param uiTtyMode An integer containing the new UI TTY Mode.
+ * @param onComplete A {@link Message} to be used when the mode has been set.
+ */
public void setUiTTYMode(int uiTtyMode, Message onComplete) {
}
- @Override
+ /**
+ * @return MultiEndpoint interface for DEP notifications
+ */
public IImsMultiEndpoint getMultiEndpointInterface() {
return null;
}
- @Override
+ /**
+ * {@inheritDoc}
+ */
public void onFeatureRemoved() {
}
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 9cddc1b934db..332cca3e5696 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -18,11 +18,11 @@ package android.telephony.ims.feature;
/**
* Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend
- * this class and provide implementations of the IRcsFeature methods that they support.
+ * this class and provide implementations of the RcsFeature methods that they support.
* @hide
*/
-public class RcsFeature extends ImsFeature implements IRcsFeature {
+public class RcsFeature extends ImsFeature {
public RcsFeature() {
super();
diff --git a/telephony/java/android/telephony/mbms/DownloadStateCallback.java b/telephony/java/android/telephony/mbms/DownloadStateCallback.java
index 892fbf078ea1..9f60cc36a306 100644
--- a/telephony/java/android/telephony/mbms/DownloadStateCallback.java
+++ b/telephony/java/android/telephony/mbms/DownloadStateCallback.java
@@ -38,7 +38,7 @@ public class DownloadStateCallback {
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({ALL_UPDATES, PROGRESS_UPDATES, STATE_UPDATES})
+ @IntDef(flag = true, value = {ALL_UPDATES, PROGRESS_UPDATES, STATE_UPDATES})
public @interface FilterFlag {}
/**
diff --git a/telephony/java/android/telephony/mbms/FileInfo.java b/telephony/java/android/telephony/mbms/FileInfo.java
index 0d737b589d06..e064adb5f7b5 100644
--- a/telephony/java/android/telephony/mbms/FileInfo.java
+++ b/telephony/java/android/telephony/mbms/FileInfo.java
@@ -17,10 +17,13 @@
package android.telephony.mbms;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/**
* Describes a single file that is available over MBMS.
*/
@@ -47,6 +50,7 @@ public final class FileInfo implements Parcelable {
* @hide
*/
@SystemApi
+ @TestApi
public FileInfo(Uri uri, String mimeType) {
this.uri = uri;
this.mimeType = mimeType;
@@ -82,4 +86,23 @@ public final class FileInfo implements Parcelable {
public String getMimeType() {
return mimeType;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ FileInfo fileInfo = (FileInfo) o;
+ return Objects.equals(uri, fileInfo.uri) &&
+ Objects.equals(mimeType, fileInfo.mimeType);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(uri, mimeType);
+ }
}
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
index 9af1eb9e14d7..9ef188cfd2b3 100644
--- a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
@@ -165,16 +165,16 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
Log.w(LOG_TAG, "Download result did not include a result code. Ignoring.");
return false;
}
+ if (!intent.hasExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST)) {
+ Log.w(LOG_TAG, "Download result did not include the associated request. Ignoring.");
+ return false;
+ }
// We do not need to verify below extras if the result is not success.
if (MbmsDownloadSession.RESULT_SUCCESSFUL !=
intent.getIntExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT,
MbmsDownloadSession.RESULT_CANCELLED)) {
return true;
}
- if (!intent.hasExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST)) {
- Log.w(LOG_TAG, "Download result did not include the associated request. Ignoring.");
- return false;
- }
if (!intent.hasExtra(VendorUtils.EXTRA_TEMP_FILE_ROOT)) {
Log.w(LOG_TAG, "Download result did not include the temp file root. Ignoring.");
return false;
@@ -242,10 +242,12 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
int result = intent.getIntExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT,
MbmsDownloadSession.RESULT_CANCELLED);
intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT, result);
+ intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST, request);
if (result != MbmsDownloadSession.RESULT_SUCCESSFUL) {
Log.i(LOG_TAG, "Download request indicated a failed download. Aborting.");
context.sendBroadcast(intentForApp);
+ setResultCode(RESULT_OK);
return;
}
@@ -273,7 +275,6 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_COMPLETED_FILE_URI,
stagedFileLocation);
intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_FILE_INFO, completedFileInfo);
- intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST, request);
context.sendBroadcast(intentForApp);
setResultCode(RESULT_OK);
diff --git a/telephony/java/android/telephony/mbms/UriPathPair.java b/telephony/java/android/telephony/mbms/UriPathPair.java
index 187e9eedab48..dd20a692eab3 100644
--- a/telephony/java/android/telephony/mbms/UriPathPair.java
+++ b/telephony/java/android/telephony/mbms/UriPathPair.java
@@ -17,6 +17,7 @@
package android.telephony.mbms;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.content.ContentResolver;
import android.net.Uri;
import android.os.Parcel;
@@ -29,6 +30,7 @@ import android.telephony.mbms.vendor.VendorUtils;
* @hide
*/
@SystemApi
+@TestApi
public final class UriPathPair implements Parcelable {
private final Uri mFilePathUri;
private final Uri mContentUri;
diff --git a/telephony/java/android/telephony/mbms/vendor/VendorUtils.java b/telephony/java/android/telephony/mbms/vendor/VendorUtils.java
index a43f12244168..f1cac8cf8286 100644
--- a/telephony/java/android/telephony/mbms/vendor/VendorUtils.java
+++ b/telephony/java/android/telephony/mbms/vendor/VendorUtils.java
@@ -17,6 +17,7 @@
package android.telephony.mbms.vendor;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -34,6 +35,7 @@ import java.util.List;
* @hide
*/
@SystemApi
+@TestApi
public class VendorUtils {
/**
diff --git a/telephony/java/com/android/ims/internal/IImsServiceController.aidl b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
index bb06d7e085a7..f1e2262ee80c 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceController.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
@@ -31,7 +31,7 @@ import com.android.ims.internal.IImsUt;
import android.os.Message;
/**
- * See ImsService and IMMTelFeature for more information.
+ * See ImsService and MMTelFeature for more information.
* {@hide}
*/
interface IImsServiceController {
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index e9c5461ab421..ac161397af04 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -45,7 +45,6 @@ oneway interface IPhoneStateListener {
void onVoLteServiceStateChanged(in VoLteServiceState lteState);
void onVoiceActivationStateChanged(int activationState);
void onDataActivationStateChanged(int activationState);
- void onOemHookRawEvent(in byte[] rawData);
void onCarrierNetworkChange(in boolean active);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 2ac11b55d4fd..3cc9bde8423e 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1000,17 +1000,6 @@ interface ITelephony {
in List<String> cdmaNonRoamingList);
/**
- * Returns the result and response from RIL for oem request
- *
- * @param oemReq the data is sent to ril.
- * @param oemResp the respose data from RIL.
- * @return negative value request was not handled or get error
- * 0 request was handled succesfully, but no response data
- * positive value success, data length of response
- */
- int invokeOemRilRequestRaw(in byte[] oemReq, out byte[] oemResp);
-
- /**
* Check if any mobile Radios need to be shutdown.
*
* @return true is any mobile radio needs to be shutdown
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 2c2206c390f8..75d8f3fcb9b6 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -67,7 +67,6 @@ interface ITelephonyRegistry {
void notifyVoLteServiceStateChanged(in VoLteServiceState lteState);
void notifySimActivationStateChangedForPhoneId(in int phoneId, in int subId,
int activationState, int activationType);
- void notifyOemHookRawEventForSubscriber(in int subId, in byte[] rawData);
void notifySubscriptionInfoChanged();
void notifyCarrierNetworkChange(in boolean active);
}
diff --git a/test-mock/Android.mk b/test-mock/Android.mk
new file mode 100644
index 000000000000..18da8b8bd687
--- /dev/null
+++ b/test-mock/Android.mk
@@ -0,0 +1,144 @@
+#
+# 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)
+
+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)/../legacy-test/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)))
+
+# Generate the stub source files for android.test.mock.stubs
+# ==========================================================
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(android_test_mock_source_files)
+
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src/android/test/mock
+
+ANDROID_TEST_MOCK_OUTPUT_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.mock.stubs_intermediates/api.txt
+ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.mock.stubs_intermediates/removed.txt
+
+ANDROID_TEST_MOCK_API_FILE := $(LOCAL_PATH)/api/android-test-mock-current.txt
+ANDROID_TEST_MOCK_REMOVED_API_FILE := $(LOCAL_PATH)/api/android-test-mock-removed.txt
+
+LOCAL_DROIDDOC_OPTIONS:= \
+ -stubpackages android.test.mock \
+ -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.mock.stubs_intermediates/src \
+ -nodocs \
+ -api $(ANDROID_TEST_MOCK_OUTPUT_API_FILE) \
+ -removedApi $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE) \
+
+LOCAL_UNINSTALLABLE_MODULE := true
+LOCAL_MODULE := android-test-mock-api-stubs-gen
+
+include $(BUILD_DROIDDOC)
+
+# Remember the target that will trigger the code generation.
+android_test_mock_gen_stamp := $(full_target)
+
+# Add some additional dependencies
+$(ANDROID_TEST_MOCK_OUTPUT_API_FILE): $(full_target)
+$(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE): $(full_target)
+
+# Build the android.test.mock.stubs library
+# =========================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := android.test.mock.stubs
+
+LOCAL_SOURCE_FILES_ALL_GENERATED := true
+
+# Make sure to run droiddoc first to generate the stub source files.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(android_test_mock_gen_stamp)
+android_test_mock_gen_stamp :=
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Archive a copy of the classes.jar in SDK build.
+$(call dist-for-goals,sdk win_sdk,$(full_classes_jar):android.test.mock.stubs.jar)
+
+# Check that the android.test.mock.stubs library has not changed
+# ==============================================================
+
+# Check that the API we're building hasn't changed from the not-yet-released
+# SDK version.
+$(eval $(call check-api, \
+ check-android-test-mock-api-current, \
+ $(ANDROID_TEST_MOCK_API_FILE), \
+ $(ANDROID_TEST_MOCK_OUTPUT_API_FILE), \
+ $(ANDROID_TEST_MOCK_REMOVED_API_FILE), \
+ $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE), \
+ -error 2 -error 3 -error 4 -error 5 -error 6 \
+ -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
+ -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 \
+ -error 25 -error 26 -error 27, \
+ cat $(LOCAL_PATH)/api/apicheck_msg_android_test_mock.txt, \
+ check-android-test-mock-api, \
+ $(call doc-timestamp-for,android-test-mock-api-stubs-gen) \
+ ))
+
+.PHONY: check-android-test-mock-api
+checkapi: check-android-test-mock-api
+
+.PHONY: update-android-test-mock-api
+update-api: update-android-test-mock-api
+
+update-android-test-mock-api: $(ANDROID_TEST_MOCK_OUTPUT_API_FILE) | $(ACP)
+ @echo Copying current.txt
+ $(hide) $(ACP) $(ANDROID_TEST_MOCK_OUTPUT_API_FILE) $(ANDROID_TEST_MOCK_API_FILE)
+ @echo Copying removed.txt
+ $(hide) $(ACP) $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_MOCK_REMOVED_API_FILE)
+
+# Build the android.test.mock.sdk library
+# =======================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := android.test.mock.sdk
+LOCAL_SDK_VERSION := current
+
+LOCAL_STATIC_JAVA_LIBRARIES := android.test.mock.stubs
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+endif # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
diff --git a/test-runner/api/android-test-mock-current.txt b/test-mock/api/android-test-mock-current.txt
index 93bbf6c5c024..93bbf6c5c024 100644
--- a/test-runner/api/android-test-mock-current.txt
+++ b/test-mock/api/android-test-mock-current.txt
diff --git a/test-runner/api/android-test-mock-removed.txt b/test-mock/api/android-test-mock-removed.txt
index 9920f63d1632..9920f63d1632 100644
--- a/test-runner/api/android-test-mock-removed.txt
+++ b/test-mock/api/android-test-mock-removed.txt
diff --git a/test-runner/api/apicheck_msg_android_test_mock.txt b/test-mock/api/apicheck_msg_android_test_mock.txt
index e388935bf798..e388935bf798 100644
--- a/test-runner/api/apicheck_msg_android_test_mock.txt
+++ b/test-mock/api/apicheck_msg_android_test_mock.txt
diff --git a/test-runner/src/android/test/mock/MockApplication.java b/test-mock/src/android/test/mock/MockApplication.java
index 3257ecf11066..3257ecf11066 100644
--- a/test-runner/src/android/test/mock/MockApplication.java
+++ b/test-mock/src/android/test/mock/MockApplication.java
diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-mock/src/android/test/mock/MockContentProvider.java
index d5f3ce880b8f..d5f3ce880b8f 100644
--- a/test-runner/src/android/test/mock/MockContentProvider.java
+++ b/test-mock/src/android/test/mock/MockContentProvider.java
diff --git a/test-runner/src/android/test/mock/MockContentResolver.java b/test-mock/src/android/test/mock/MockContentResolver.java
index a70152c8b732..a70152c8b732 100644
--- a/test-runner/src/android/test/mock/MockContentResolver.java
+++ b/test-mock/src/android/test/mock/MockContentResolver.java
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 5e5ba462cfca..5e5ba462cfca 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
diff --git a/test-runner/src/android/test/mock/MockCursor.java b/test-mock/src/android/test/mock/MockCursor.java
index 576f24ad6384..576f24ad6384 100644
--- a/test-runner/src/android/test/mock/MockCursor.java
+++ b/test-mock/src/android/test/mock/MockCursor.java
diff --git a/test-runner/src/android/test/mock/MockDialogInterface.java b/test-mock/src/android/test/mock/MockDialogInterface.java
index d0a5a097918d..d0a5a097918d 100644
--- a/test-runner/src/android/test/mock/MockDialogInterface.java
+++ b/test-mock/src/android/test/mock/MockDialogInterface.java
diff --git a/test-runner/src/android/test/mock/MockIContentProvider.java b/test-mock/src/android/test/mock/MockIContentProvider.java
index 112d7eef3dbe..112d7eef3dbe 100644
--- a/test-runner/src/android/test/mock/MockIContentProvider.java
+++ b/test-mock/src/android/test/mock/MockIContentProvider.java
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-mock/src/android/test/mock/MockPackageManager.java
index 7e08f51cd87d..7e08f51cd87d 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-mock/src/android/test/mock/MockPackageManager.java
diff --git a/test-runner/src/android/test/mock/MockResources.java b/test-mock/src/android/test/mock/MockResources.java
index 880343e5e780..880343e5e780 100644
--- a/test-runner/src/android/test/mock/MockResources.java
+++ b/test-mock/src/android/test/mock/MockResources.java
diff --git a/test-runner/src/android/test/mock/package.html b/test-mock/src/android/test/mock/package.html
index c0fcd1ea336a..c0fcd1ea336a 100644
--- a/test-runner/src/android/test/mock/package.html
+++ b/test-mock/src/android/test/mock/package.html
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index 29a95e65dbf3..d0f5b3248c29 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -16,14 +16,11 @@
LOCAL_PATH:= $(call my-dir)
-android_test_mock_source_files := $(call all-java-files-under, src/android/test/mock)
-
# Build the android.test.runner library
# =====================================
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
- $(filter-out $(android_test_mock_source_files), $(call all-java-files-under, src))
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_JAVA_LIBRARIES := \
core-oj \
@@ -42,7 +39,12 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework legacy-test
+LOCAL_JAVA_LIBRARIES := \
+ core-oj \
+ core-libart \
+ framework \
+ legacy-test \
+ android.test.mock \
LOCAL_JARJAR_RULES := $(LOCAL_PATH)/../legacy-test/jarjar-rules.txt
@@ -50,14 +52,14 @@ 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)))
+
# Generate the stub source files for android.test.runner.stubs
# ============================================================
include $(CLEAR_VARS)
-# Exclude android.test.mock classes as stubs for them are created in the
-# android.test.mock.stubs target
-LOCAL_SRC_FILES := \
- $(filter-out $(android_test_mock_source_files), $(call all-java-files-under, src))
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_JAVA_LIBRARIES := \
core-oj \
@@ -149,111 +151,4 @@ update-android-test-runner-api: $(ANDROID_TEST_RUNNER_OUTPUT_API_FILE) | $(ACP)
@echo Copying removed.txt
$(hide) $(ACP) $(ANDROID_TEST_RUNNER_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_RUNNER_REMOVED_API_FILE)
-# Build the android.test.mock library
-# ===================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(android_test_mock_source_files)
-
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
-
-LOCAL_MODULE:= android.test.mock
-
-include $(BUILD_JAVA_LIBRARY)
-
-# Generate the stub source files for android.test.mock.stubs
-# ==========================================================
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(android_test_mock_source_files)
-
-LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src/android/test/mock
-
-ANDROID_TEST_MOCK_OUTPUT_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.mock.stubs_intermediates/api.txt
-ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.mock.stubs_intermediates/removed.txt
-
-ANDROID_TEST_MOCK_API_FILE := $(LOCAL_PATH)/api/android-test-mock-current.txt
-ANDROID_TEST_MOCK_REMOVED_API_FILE := $(LOCAL_PATH)/api/android-test-mock-removed.txt
-
-LOCAL_DROIDDOC_OPTIONS:= \
- -stubpackages android.test.mock \
- -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.mock.stubs_intermediates/src \
- -nodocs \
- -api $(ANDROID_TEST_MOCK_OUTPUT_API_FILE) \
- -removedApi $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE) \
-
-LOCAL_UNINSTALLABLE_MODULE := true
-LOCAL_MODULE := android-test-mock-api-stubs-gen
-
-include $(BUILD_DROIDDOC)
-
-# Remember the target that will trigger the code generation.
-android_test_mock_gen_stamp := $(full_target)
-
-# Add some additional dependencies
-$(ANDROID_TEST_MOCK_OUTPUT_API_FILE): $(full_target)
-$(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE): $(full_target)
-
-# Build the android.test.mock.stubs library
-# =========================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := android.test.mock.stubs
-
-LOCAL_SOURCE_FILES_ALL_GENERATED := true
-
-# Make sure to run droiddoc first to generate the stub source files.
-LOCAL_ADDITIONAL_DEPENDENCIES := $(android_test_mock_gen_stamp)
-android_test_mock_gen_stamp :=
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# Archive a copy of the classes.jar in SDK build.
-$(call dist-for-goals,sdk win_sdk,$(full_classes_jar):android.test.mock.stubs.jar)
-
-# Check that the android.test.mock.stubs library has not changed
-# ==============================================================
-
-# Check that the API we're building hasn't changed from the not-yet-released
-# SDK version.
-$(eval $(call check-api, \
- check-android-test-mock-api-current, \
- $(ANDROID_TEST_MOCK_API_FILE), \
- $(ANDROID_TEST_MOCK_OUTPUT_API_FILE), \
- $(ANDROID_TEST_MOCK_REMOVED_API_FILE), \
- $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE), \
- -error 2 -error 3 -error 4 -error 5 -error 6 \
- -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
- -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 \
- -error 25 -error 26 -error 27, \
- cat $(LOCAL_PATH)/api/apicheck_msg_android_test_mock.txt, \
- check-android-test-mock-api, \
- $(call doc-timestamp-for,android-test-mock-api-stubs-gen) \
- ))
-
-.PHONY: check-android-test-mock-api
-checkapi: check-android-test-mock-api
-
-.PHONY: update-android-test-mock-api
-update-api: update-android-test-mock-api
-
-update-android-test-mock-api: $(ANDROID_TEST_MOCK_OUTPUT_API_FILE) | $(ACP)
- @echo Copying current.txt
- $(hide) $(ACP) $(ANDROID_TEST_MOCK_OUTPUT_API_FILE) $(ANDROID_TEST_MOCK_API_FILE)
- @echo Copying removed.txt
- $(hide) $(ACP) $(ANDROID_TEST_MOCK_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_MOCK_REMOVED_API_FILE)
-
-# Build the android.test.mock.sdk library
-# =======================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := android.test.mock.sdk
-LOCAL_SDK_VERSION := current
-
-LOCAL_STATIC_JAVA_LIBRARIES := android.test.mock.stubs
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# additionally, build unit tests in a separate .apk
-include $(call all-makefiles-under,$(LOCAL_PATH))
+endif # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
diff --git a/tests/FeatureSplit/feature1/Android.mk b/tests/FeatureSplit/feature1/Android.mk
index b3ea97b03d5d..e6ba5c2d04c9 100644
--- a/tests/FeatureSplit/feature1/Android.mk
+++ b/tests/FeatureSplit/feature1/Android.mk
@@ -26,6 +26,6 @@ LOCAL_APK_LIBRARIES := FeatureSplitBase
LOCAL_RES_LIBRARIES := FeatureSplitBase
LOCAL_AAPT_FLAGS += --package-id 0x80
-LOCAL_AAPT_FLAGS += --rename-manifest-package com.android.test.split.feature
+LOCAL_AAPT_FLAGS += --custom-package com.android.test.split.feature.one
include $(BUILD_PACKAGE)
diff --git a/tests/FeatureSplit/feature1/AndroidManifest.xml b/tests/FeatureSplit/feature1/AndroidManifest.xml
index 4e7d15102a6e..b87361faac62 100644
--- a/tests/FeatureSplit/feature1/AndroidManifest.xml
+++ b/tests/FeatureSplit/feature1/AndroidManifest.xml
@@ -15,13 +15,13 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.split.feature.one"
+ package="com.android.test.split.feature"
featureSplit="feature1">
<uses-sdk android:minSdkVersion="21" />
<application>
- <activity android:name=".One" android:label="Feature One">
+ <activity android:name=".one.One" android:label="Feature One">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/tests/FeatureSplit/feature1/res/values/values.xml b/tests/FeatureSplit/feature1/res/values/values.xml
index 0e3e73c32480..7d58865b546e 100644
--- a/tests/FeatureSplit/feature1/res/values/values.xml
+++ b/tests/FeatureSplit/feature1/res/values/values.xml
@@ -20,7 +20,7 @@
<integer name="test_integer2">200</integer>
<color name="test_color2">#00ff00</color>
<string-array name="string_array2">
- <item>@*com.android.test.split.feature:string/app_title</item>
+ <item>@string/app_title</item>
</string-array>
</resources>
diff --git a/tests/FeatureSplit/feature2/Android.mk b/tests/FeatureSplit/feature2/Android.mk
index e2fd90384538..c8e860942fa3 100644
--- a/tests/FeatureSplit/feature2/Android.mk
+++ b/tests/FeatureSplit/feature2/Android.mk
@@ -26,6 +26,6 @@ LOCAL_APK_LIBRARIES := FeatureSplitBase
LOCAL_RES_LIBRARIES := FeatureSplitBase
LOCAL_AAPT_FLAGS += --package-id 0x81
-LOCAL_AAPT_FLAGS += --rename-manifest-package com.android.test.split.feature
+LOCAL_AAPT_FLAGS += --custom-package com.android.test.split.feature.two
include $(BUILD_PACKAGE)
diff --git a/tests/FeatureSplit/feature2/AndroidManifest.xml b/tests/FeatureSplit/feature2/AndroidManifest.xml
index bfe6f38201bd..abd0b5eb6933 100644
--- a/tests/FeatureSplit/feature2/AndroidManifest.xml
+++ b/tests/FeatureSplit/feature2/AndroidManifest.xml
@@ -15,7 +15,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.split.feature.two"
+ package="com.android.test.split.feature"
featureSplit="feature2">
<uses-sdk android:minSdkVersion="21" />
diff --git a/tests/FeatureSplit/feature2/res/values/values.xml b/tests/FeatureSplit/feature2/res/values/values.xml
index 2fa6f907b8ab..af5ed1b79b26 100644
--- a/tests/FeatureSplit/feature2/res/values/values.xml
+++ b/tests/FeatureSplit/feature2/res/values/values.xml
@@ -18,7 +18,7 @@
<integer name="test_integer3">300</integer>
<color name="test_color3">#0000ff</color>
<string-array name="string_array3">
- <item>@*com.android.test.split.feature:string/app_title</item>
+ <item>@string/app_title</item>
</string-array>
</resources>
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 9caf9d0f6e26..ebf5f6854c6f 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -282,6 +282,15 @@
<category android:name="com.android.test.hwui.TEST" />
</intent-filter>
</activity>
+
+ <activity
+ android:name="ColoredShadowsActivity"
+ android:label="View/ColoredShadows">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.hwui.TEST" />
+ </intent-filter>
+ </activity>
<activity
android:name="OpaqueActivity"
diff --git a/tests/HwAccelerationTest/res/layout/colored_shadows_activity.xml b/tests/HwAccelerationTest/res/layout/colored_shadows_activity.xml
new file mode 100644
index 000000000000..18633250cfcb
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/colored_shadows_activity.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/colored_grid">
+ <include layout="@layout/colored_shadows_row" />
+ <include layout="@layout/colored_shadows_row" />
+ <include layout="@layout/colored_shadows_row" />
+ <include layout="@layout/colored_shadows_row" />
+ <include layout="@layout/colored_shadows_row" />
+ <include layout="@layout/colored_shadows_row" />
+ <include layout="@layout/colored_shadows_row" />
+</LinearLayout>
diff --git a/tests/HwAccelerationTest/res/layout/colored_shadows_row.xml b/tests/HwAccelerationTest/res/layout/colored_shadows_row.xml
new file mode 100644
index 000000000000..61b075974926
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/colored_shadows_row.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="25dp"
+ android:paddingBottom="25dp"
+ android:clipToPadding="false" >
+ <View android:id="@+id/grey"
+ android:layout_width="50dp"
+ android:layout_height="50dp"
+ android:elevation="16dp"
+ android:background="#3C4043"
+ android:layout_marginLeft="20dp" />
+ <View android:id="@+id/blue"
+ android:layout_width="50dp"
+ android:layout_height="50dp"
+ android:elevation="16dp"
+ android:background="#185ABC"
+ android:layout_marginLeft="20dp"/>
+ <View android:id="@+id/red"
+ android:layout_width="50dp"
+ android:layout_height="50dp"
+ android:elevation="16dp"
+ android:background="#B31412"
+ android:layout_marginLeft="20dp"/>
+ <View android:id="@+id/yellow"
+ android:layout_width="50dp"
+ android:layout_height="50dp"
+ android:elevation="16dp"
+ android:background="#EA8600"
+ android:layout_marginLeft="20dp"/>
+ <View android:id="@+id/green"
+ android:layout_width="50dp"
+ android:layout_height="50dp"
+ android:elevation="16dp"
+ android:background="#137333"
+ android:layout_marginLeft="20dp"/>
+</LinearLayout>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredShadowsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredShadowsActivity.java
new file mode 100644
index 000000000000..135c93c97af2
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredShadowsActivity.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.hwui;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class ColoredShadowsActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.colored_shadows_activity);
+ ViewGroup grid = findViewById(R.id.colored_grid);
+ for (int i = 0; i < grid.getChildCount(); i++) {
+ setShadowColors((ViewGroup) grid.getChildAt(i), i);
+ }
+ }
+
+ private void setShadowColors(ViewGroup row, int rowIndex) {
+ for (int i = 0; i < row.getChildCount(); i++) {
+ View view = row.getChildAt(i);
+ view.setShadowColor(shadowColorFor(view));
+ view.setElevation(6.0f * (rowIndex + 1));
+ }
+ }
+
+ private int shadowColorFor(View view) {
+ switch (view.getId()) {
+ case R.id.grey: return 0xFF3C4043;
+ case R.id.blue: return 0xFF185ABC;
+ case R.id.red: return 0xFFB31412;
+ case R.id.yellow: return 0xFFEA8600;
+ case R.id.green: return 0xFF137333;
+ default: return 0xFF000000;
+ }
+ }
+
+}
diff --git a/tests/UiBench/Android.mk b/tests/UiBench/Android.mk
index 0824c26ef9f1..60327e5cb2a4 100644
--- a/tests/UiBench/Android.mk
+++ b/tests/UiBench/Android.mk
@@ -10,25 +10,11 @@ LOCAL_SRC_FILES := $(call all-java-files-under,src)
# use appcompat/support lib from the tree, so improvements/
# regressions are reflected in test data
-LOCAL_RESOURCE_DIR := \
- $(LOCAL_PATH)/res \
- frameworks/support/core-ui/res \
- frameworks/support/design/res \
- frameworks/support/v7/appcompat/res \
- frameworks/support/v7/cardview/res \
- frameworks/support/v7/recyclerview/res \
- frameworks/support/v17/leanback/res
-
-LOCAL_AAPT_FLAGS := \
- --auto-add-overlay \
- --extra-packages android.support.coreui \
- --extra-packages android.support.design \
- --extra-packages android.support.v7.appcompat \
- --extra-packages android.support.v7.cardview \
- --extra-packages android.support.v7.recyclerview \
- --extra-packages android.support.v17.leanback
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_USE_AAPT2 := true
+
+LOCAL_STATIC_ANDROID_LIBRARIES := \
android-support-design \
android-support-v4 \
android-support-v7-appcompat \
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index f2de7db936e1..c6b4a54f3b0b 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -92,6 +92,15 @@
</intent-filter>
</activity>
<activity
+ android:name=".TrivialAnimationActivityWideGamut"
+ android:label="General/Trivial Animation (Wide Gamut)"
+ android:colorMode="wideColorGamut">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.uibench.TEST" />
+ </intent-filter>
+ </activity>
+ <activity
android:name=".TrivialListActivity"
android:label="General/Trivial ListView" >
<intent-filter>
diff --git a/tests/UiBench/src/com/android/test/uibench/TrivialAnimationActivityWideGamut.java b/tests/UiBench/src/com/android/test/uibench/TrivialAnimationActivityWideGamut.java
new file mode 100644
index 000000000000..c492753d8b7a
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/TrivialAnimationActivityWideGamut.java
@@ -0,0 +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.test.uibench;
+
+public class TrivialAnimationActivityWideGamut extends TrivialAnimationActivity { }
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
new file mode 100644
index 000000000000..fcbb9da8fc94
--- /dev/null
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -0,0 +1,208 @@
+/*
+ * 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.net;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+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;
+
+import java.util.Arrays;
+import java.util.Random;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MacAddressTest {
+
+ static class AddrTypeTestCase {
+ byte[] addr;
+ MacAddressType expected;
+
+ static AddrTypeTestCase of(MacAddressType expected, int... addr) {
+ AddrTypeTestCase t = new AddrTypeTestCase();
+ t.expected = expected;
+ t.addr = toByteArray(addr);
+ return t;
+ }
+ }
+
+ @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)
+ };
+
+ for (AddrTypeTestCase t : testcases) {
+ MacAddressType 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);
+
+ if (got != null) {
+ assertEquals(got, new MacAddress(t.addr).addressType());
+ }
+ }
+ }
+
+ @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[] 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"),
+ };
+
+ for (MacAddress mac : multicastAddresses) {
+ String msg = mac.toString() + " expected to be a multicast address";
+ assertTrue(msg, mac.isMulticastAddress());
+ }
+ for (MacAddress mac : unicastAddresses) {
+ String msg = mac.toString() + " expected not to be a multicast address";
+ assertFalse(msg, mac.isMulticastAddress());
+ }
+ }
+
+ @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[] universalAddresses = {
+ new MacAddress("00:01:44:55:66:77"),
+ new MacAddress("08:00:22:33:44:55"),
+ };
+
+ for (MacAddress mac : localAddresses) {
+ String msg = mac.toString() + " expected to be a locally assigned address";
+ assertTrue(msg, mac.isLocallyAssigned());
+ }
+ for (MacAddress mac : universalAddresses) {
+ String msg = mac.toString() + " expected not to be globally unique address";
+ assertFalse(msg, mac.isLocallyAssigned());
+ }
+ }
+
+ @Test
+ public void testMacAddressConversions() {
+ final int iterations = 10000;
+ for (int i = 0; i < iterations; i++) {
+ MacAddress mac = MacAddress.getRandomAddress();
+
+ String stringRepr = mac.toString();
+ byte[] bytesRepr = mac.toByteArray();
+
+ assertEquals(mac, new MacAddress(stringRepr));
+ assertEquals(mac, new MacAddress(bytesRepr));
+ }
+ }
+
+ @Test
+ public void testMacAddressRandomGeneration() {
+ final int iterations = 1000;
+ final String expectedAndroidOui = "da:a1:19";
+ for (int i = 0; i < iterations; i++) {
+ MacAddress mac = MacAddress.getRandomAddress();
+ String stringRepr = mac.toString();
+
+ assertTrue(stringRepr + " expected to be a locally assigned address",
+ mac.isLocallyAssigned());
+ assertTrue(stringRepr + " expected to begin with " + expectedAndroidOui,
+ stringRepr.startsWith(expectedAndroidOui));
+ }
+
+ 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");
+ for (int i = 0; i < iterations; i++) {
+ MacAddress mac = MacAddress.getRandomAddress(base, r);
+ String stringRepr = mac.toString();
+
+ assertTrue(stringRepr + " expected to be a locally assigned address",
+ mac.isLocallyAssigned());
+ assertTrue(stringRepr + " expected to begin with " + expectedLocalOui,
+ stringRepr.startsWith(expectedLocalOui));
+ }
+ }
+
+ @Test
+ public void testConstructorInputValidation() {
+ String[] invalidStringAddresses = {
+ null,
+ "",
+ "abcd",
+ "1:2:3:4:5",
+ "1:2:3:4:5:6:7",
+ "10000:2:3:4:5:6",
+ };
+
+ for (String s : invalidStringAddresses) {
+ try {
+ MacAddress mac = new MacAddress(s);
+ fail("new MacAddress(" + s + ") should have failed, but returned " + mac);
+ } catch (IllegalArgumentException excepted) {
+ }
+ }
+
+ byte[][] invalidBytesAddresses = {
+ null,
+ {},
+ {1,2,3,4,5},
+ {1,2,3,4,5,6,7},
+ };
+
+ for (byte[] b : invalidBytesAddresses) {
+ try {
+ MacAddress mac = new MacAddress(b);
+ fail("new MacAddress(" + Arrays.toString(b)
+ + ") should have failed, but returned " + mac);
+ } catch (IllegalArgumentException excepted) {
+ }
+ }
+ }
+
+ static byte[] toByteArray(int... in) {
+ byte[] out = new byte[in.length];
+ for (int i = 0; i < in.length; i++) {
+ out[i] = (byte) in[i];
+ }
+ return out;
+ }
+}
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
index 7346f9f95041..cd2d0985c793 100644
--- a/tests/net/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -16,6 +16,7 @@
package android.net;
+import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
@@ -26,13 +27,12 @@ import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
-
-import android.net.NetworkCapabilities;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
@@ -159,4 +159,25 @@ public class NetworkCapabilitiesTest {
assertNotEquals("", nc1.describeImmutableDifferences(nc2));
assertEquals("", nc1.describeImmutableDifferences(nc1));
}
+
+ @Test
+ public void testLinkBandwidthUtils() {
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, NetworkCapabilities
+ .minBandwidth(LINK_BANDWIDTH_UNSPECIFIED, LINK_BANDWIDTH_UNSPECIFIED));
+ assertEquals(10, NetworkCapabilities
+ .minBandwidth(LINK_BANDWIDTH_UNSPECIFIED, 10));
+ assertEquals(10, NetworkCapabilities
+ .minBandwidth(10, LINK_BANDWIDTH_UNSPECIFIED));
+ assertEquals(10, NetworkCapabilities
+ .minBandwidth(10, 20));
+
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, NetworkCapabilities
+ .maxBandwidth(LINK_BANDWIDTH_UNSPECIFIED, LINK_BANDWIDTH_UNSPECIFIED));
+ assertEquals(10, NetworkCapabilities
+ .maxBandwidth(LINK_BANDWIDTH_UNSPECIFIED, 10));
+ assertEquals(10, NetworkCapabilities
+ .maxBandwidth(10, LINK_BANDWIDTH_UNSPECIFIED));
+ assertEquals(20, NetworkCapabilities
+ .maxBandwidth(10, 20));
+ }
}
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index 99a2ad942003..725ddb9ccbca 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -29,9 +29,7 @@ import static org.mockito.Mockito.verify;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
-import android.net.apf.ApfCapabilities;
-import android.net.apf.ApfFilter;
-import android.net.apf.ApfGenerator;
+import android.net.apf.ApfFilter.ApfConfiguration;
import android.net.apf.ApfGenerator.IllegalInstructionException;
import android.net.apf.ApfGenerator.Register;
import android.net.ip.IpManager;
@@ -99,12 +97,24 @@ public class ApfTest {
// least the minimum packet size.
private final static int MIN_PKT_SIZE = 15;
+ private static final ApfCapabilities MOCK_APF_CAPABILITIES =
+ new ApfCapabilities(2, 1700, ARPHRD_ETHER);
+
private final static boolean DROP_MULTICAST = true;
private final static boolean ALLOW_MULTICAST = false;
private final static boolean DROP_802_3_FRAMES = true;
private final static boolean ALLOW_802_3_FRAMES = false;
+ private static ApfConfiguration getDefaultConfig() {
+ ApfFilter.ApfConfiguration config = new ApfConfiguration();
+ config.apfCapabilities = MOCK_APF_CAPABILITIES;
+ config.multicastFilter = ALLOW_MULTICAST;
+ config.ieee802_3Filter = ALLOW_802_3_FRAMES;
+ config.ethTypeBlackList = new int[0];
+ return config;
+ }
+
private static String label(int code) {
switch (code) {
case PASS: return "PASS";
@@ -619,15 +629,13 @@ public class ApfTest {
private static class TestApfFilter extends ApfFilter {
public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
- private FileDescriptor mWriteSocket;
+ private FileDescriptor mWriteSocket;
private final long mFixedTimeMs = SystemClock.elapsedRealtime();
- public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
- boolean ieee802_3Filter, int[] ethTypeBlackList,
+ public TestApfFilter(ApfConfiguration config, IpManager.Callback ipManagerCallback,
IpConnectivityLog log) throws Exception {
- super(new ApfCapabilities(2, 1700, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
- ipManagerCallback, multicastFilter, ieee802_3Filter, ethTypeBlackList, log);
+ super(config, NetworkInterface.getByName("lo"), ipManagerCallback, log);
}
// Pretend an RA packet has been received and show it to ApfFilter.
@@ -755,10 +763,10 @@ public class ApfTest {
LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
LinkProperties lp = new LinkProperties();
lp.addLinkAddress(link);
- final int[] ethTypeBlackList = {};
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST,
- ALLOW_802_3_FRAMES, ethTypeBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ config.multicastFilter = DROP_MULTICAST;
+ TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
byte[] program = ipManagerCallback.getApfProgram();
@@ -808,10 +816,9 @@ public class ApfTest {
@Test
public void testApfFilterIPv6() throws Exception {
- final int[] ethTypeBlackList = {};
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- ALLOW_802_3_FRAMES, ethTypeBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
byte[] program = ipManagerCallback.getApfProgram();
// Verify empty IPv6 packet is passed
@@ -846,15 +853,15 @@ public class ApfTest {
final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
final byte[] multicastIpv4Addr = {(byte)224,0,0,1};
final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
- final int[] ethTypeBlackList = {};
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24);
LinkProperties lp = new LinkProperties();
lp.addLinkAddress(link);
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
byte[] program = ipManagerCallback.getApfProgram();
@@ -916,8 +923,9 @@ public class ApfTest {
// Verify it can be initialized to on
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
- apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST,
- DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+ config.multicastFilter = DROP_MULTICAST;
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
program = ipManagerCallback.getApfProgram();
assertDrop(program, mcastv4packet.array());
@@ -938,10 +946,9 @@ public class ApfTest {
LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
LinkProperties lp = new LinkProperties();
lp.addLinkAddress(link);
- final int[] ethTypeBlackList = {};
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- ALLOW_802_3_FRAMES, ethTypeBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
byte[] program = ipManagerCallback.getApfProgram();
@@ -962,8 +969,8 @@ public class ApfTest {
// Now turn on the filter
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
- apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
program = ipManagerCallback.getApfProgram();
@@ -993,8 +1000,8 @@ public class ApfTest {
final int[] ipv4BlackList = {ETH_P_IP};
final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- ALLOW_802_3_FRAMES, emptyBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
byte[] program = ipManagerCallback.getApfProgram();
@@ -1015,8 +1022,8 @@ public class ApfTest {
// Now add IPv4 to the black list
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
- apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- ALLOW_802_3_FRAMES, ipv4BlackList, mLog);
+ config.ethTypeBlackList = ipv4BlackList;
+ apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
program = ipManagerCallback.getApfProgram();
@@ -1031,8 +1038,8 @@ public class ApfTest {
// Now let us have both IPv4 and IPv6 in the black list
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
- apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- ALLOW_802_3_FRAMES, ipv4Ipv6BlackList, mLog);
+ config.ethTypeBlackList = ipv4Ipv6BlackList;
+ apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
program = ipManagerCallback.getApfProgram();
@@ -1070,10 +1077,11 @@ public class ApfTest {
@Test
public void testApfFilterArp() throws Exception {
- final int[] ethTypeBlackList = {};
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ config.multicastFilter = DROP_MULTICAST;
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
// Verify initially ARP request filter is off, and GARP filter is on.
verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
@@ -1194,9 +1202,10 @@ public class ApfTest {
@Test
public void testApfFilterRa() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- final int[] ethTypeBlackList = {};
- TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST,
- DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ config.multicastFilter = DROP_MULTICAST;
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
byte[] program = ipManagerCallback.getApfProgram();
final int ROUTER_LIFETIME = 1000;
@@ -1338,10 +1347,11 @@ public class ApfTest {
public void testRaParsing() throws Exception {
final int maxRandomPacketSize = 512;
final Random r = new Random();
- final int[] ethTypeBlackList = {};
MockIpManagerCallback cb = new MockIpManagerCallback();
- TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST,
- DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ config.multicastFilter = DROP_MULTICAST;
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ TestApfFilter apfFilter = new TestApfFilter(config, cb, mLog);
for (int i = 0; i < 1000; i++) {
byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
r.nextBytes(packet);
@@ -1358,10 +1368,11 @@ public class ApfTest {
public void testRaProcessing() throws Exception {
final int maxRandomPacketSize = 512;
final Random r = new Random();
- final int[] ethTypeBlackList = {};
MockIpManagerCallback cb = new MockIpManagerCallback();
- TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST,
- DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ config.multicastFilter = DROP_MULTICAST;
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ TestApfFilter apfFilter = new TestApfFilter(config, cb, mLog);
for (int i = 0; i < 1000; i++) {
byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
r.nextBytes(packet);
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 27a29b68e12d..113cd37f1a27 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -23,21 +23,44 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.ConnectivityManager.getNetworkTypeName;
-import static android.net.NetworkCapabilities.*;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IA;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
+
+import static com.android.internal.util.TestUtils.waitForIdleHandler;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static com.android.internal.util.TestUtils.waitForIdleHandler;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.NotificationManager;
@@ -45,7 +68,6 @@ import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
@@ -64,7 +86,6 @@ import android.net.MatchAllNetworkSpecifier;
import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
-import android.net.NetworkConfig;
import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
@@ -79,13 +100,9 @@ import android.net.util.MultinetworkPolicyTracker;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
-import android.os.MessageQueue;
-import android.os.Messenger;
-import android.os.MessageQueue.IdleHandler;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
@@ -96,10 +113,8 @@ import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.test.mock.MockContentResolver;
-import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
-import android.util.LogPrinter;
import com.android.internal.util.WakeupMessage;
import com.android.internal.util.test.BroadcastInterceptingContext;
@@ -109,7 +124,6 @@ import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.connectivity.MockableSystemProperties;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkMonitor;
-import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult;
import com.android.server.net.NetworkPinner;
import com.android.server.net.NetworkPolicyManagerInternal;
@@ -160,6 +174,7 @@ public class ConnectivityServiceTest {
@Mock IpConnectivityMetrics.Logger mMetricsService;
@Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
+ @Mock INetworkStatsService mStatsService;
// This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods
// do not go through ConnectivityService but talk to netd directly, so they don't automatically
@@ -858,7 +873,7 @@ public class ConnectivityServiceTest {
NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
mService = new WrappedConnectivityService(mServiceContext,
mock(INetworkManagementService.class),
- mock(INetworkStatsService.class),
+ mStatsService,
mock(INetworkPolicyManager.class),
mock(IpConnectivityLog.class));
@@ -3440,6 +3455,40 @@ public class ConnectivityServiceTest {
mCm.unregisterNetworkCallback(networkCallback);
}
+ @Test
+ public void testStatsIfacesChanged() throws Exception {
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+
+ // Simple connection should have updated ifaces
+ mCellNetworkAgent.connect(false);
+ waitForIdle();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ reset(mStatsService);
+
+ // Metered change should update ifaces
+ mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ waitForIdle();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ reset(mStatsService);
+
+ mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ waitForIdle();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ reset(mStatsService);
+
+ // Captive portal change shouldn't update ifaces
+ mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
+ waitForIdle();
+ verify(mStatsService, never()).forceUpdateIfaces();
+ reset(mStatsService);
+
+ // Roaming change should update ifaces
+ mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
+ waitForIdle();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ reset(mStatsService);
+ }
+
private void checkDirectlyConnectedRoutes(Object callbackObj,
Collection<LinkAddress> linkAddresses, Collection<RouteInfo> otherRoutes) {
assertTrue(callbackObj instanceof LinkProperties);
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 9e97d84ba680..5c031eb11372 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -64,6 +64,13 @@ public class IpSecServiceParameterizedTest {
return Arrays.asList(new Object[][] {{"8.8.4.4"}, {"2601::10"}});
}
+ private static final byte[] AEAD_KEY = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x73, 0x61, 0x6C, 0x74
+ };
private static final byte[] CRYPT_KEY = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
@@ -87,7 +94,7 @@ public class IpSecServiceParameterizedTest {
private static final IpSecAlgorithm CRYPT_ALGO =
new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
private static final IpSecAlgorithm AEAD_ALGO =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, CRYPT_KEY, CRYPT_KEY.length * 4);
+ new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
private static final int[] DIRECTIONS =
new int[] {IpSecTransform.DIRECTION_IN, IpSecTransform.DIRECTION_OUT};
@@ -262,7 +269,7 @@ public class IpSecServiceParameterizedTest {
eq(new byte[] {}),
eq(0),
eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM),
- eq(CRYPT_KEY),
+ eq(AEAD_KEY),
anyInt(),
anyInt(),
anyInt(),
@@ -283,7 +290,7 @@ public class IpSecServiceParameterizedTest {
eq(new byte[] {}),
eq(0),
eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM),
- eq(CRYPT_KEY),
+ eq(AEAD_KEY),
anyInt(),
anyInt(),
anyInt(),
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index 7b0703851441..8e579aa68eae 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -23,7 +23,11 @@ import static android.system.OsConstants.SOCK_DGRAM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -46,6 +50,8 @@ import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
import org.junit.Before;
import org.junit.Test;
@@ -57,6 +63,8 @@ import org.junit.runner.RunWith;
public class IpSecServiceTest {
private static final int DROID_SPI = 0xD1201D;
+ private static final int MAX_NUM_ENCAP_SOCKETS = 100;
+ private static final int MAX_NUM_SPIS = 100;
private static final int TEST_UDP_ENCAP_INVALID_PORT = 100;
private static final int TEST_UDP_ENCAP_PORT_OUT_RANGE = 100000;
@@ -260,4 +268,115 @@ public class IpSecServiceTest {
}
}
}
+
+ /**
+ * 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 {
+ List<IpSecUdpEncapResponse> openUdpEncapSockets = new ArrayList<IpSecUdpEncapResponse>();
+ // Reserve sockets until it fails.
+ for (int i = 0; i < MAX_NUM_ENCAP_SOCKETS; i++) {
+ IpSecUdpEncapResponse newUdpEncapSocket =
+ mIpSecService.openUdpEncapsulationSocket(0, new Binder());
+ assertNotNull(newUdpEncapSocket);
+ if (IpSecManager.Status.OK != newUdpEncapSocket.status) {
+ break;
+ }
+ openUdpEncapSockets.add(newUdpEncapSocket);
+ }
+ // Assert that the total sockets quota has a reasonable limit.
+ assertTrue(
+ openUdpEncapSockets.size() > 0
+ && openUdpEncapSockets.size() < MAX_NUM_ENCAP_SOCKETS);
+
+ // Try to reserve one more UDP encapsulation socket, and should fail.
+ IpSecUdpEncapResponse extraUdpEncapSocket =
+ mIpSecService.openUdpEncapsulationSocket(0, new Binder());
+ assertNotNull(extraUdpEncapSocket);
+ assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraUdpEncapSocket.status);
+
+ // Close one of the open UDP encapsulation scokets.
+ mIpSecService.closeUdpEncapsulationSocket(openUdpEncapSockets.get(0).resourceId);
+ openUdpEncapSockets.get(0).fileDescriptor.close();
+ openUdpEncapSockets.remove(0);
+
+ // Try to reserve one more UDP encapsulation socket, and should be successful.
+ extraUdpEncapSocket = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
+ assertNotNull(extraUdpEncapSocket);
+ assertEquals(IpSecManager.Status.OK, extraUdpEncapSocket.status);
+ openUdpEncapSockets.add(extraUdpEncapSocket);
+
+ // Close open UDP sockets.
+ for (IpSecUdpEncapResponse openSocket : openUdpEncapSockets) {
+ mIpSecService.closeUdpEncapsulationSocket(openSocket.resourceId);
+ openSocket.fileDescriptor.close();
+ }
+ }
+
+ /**
+ * 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 {
+ List<IpSecSpiResponse> reservedSpis = new ArrayList<IpSecSpiResponse>();
+ // Return the same SPI for all SPI allocation since IpSecService only
+ // tracks the resource ID.
+ when(mMockNetd.ipSecAllocateSpi(
+ anyInt(),
+ eq(IpSecTransform.DIRECTION_OUT),
+ anyString(),
+ eq(InetAddress.getLoopbackAddress().getHostAddress()),
+ anyInt()))
+ .thenReturn(DROID_SPI);
+ // Reserve spis until it fails.
+ for (int i = 0; i < MAX_NUM_SPIS; i++) {
+ IpSecSpiResponse newSpi =
+ mIpSecService.reserveSecurityParameterIndex(
+ 0x1,
+ InetAddress.getLoopbackAddress().getHostAddress(),
+ DROID_SPI + i,
+ new Binder());
+ assertNotNull(newSpi);
+ if (IpSecManager.Status.OK != newSpi.status) {
+ break;
+ }
+ reservedSpis.add(newSpi);
+ }
+ // Assert that the SPI quota has a reasonable limit.
+ assertTrue(reservedSpis.size() > 0 && reservedSpis.size() < MAX_NUM_SPIS);
+
+ // Try to reserve one more SPI, and should fail.
+ IpSecSpiResponse extraSpi =
+ mIpSecService.reserveSecurityParameterIndex(
+ 0x1,
+ InetAddress.getLoopbackAddress().getHostAddress(),
+ DROID_SPI + MAX_NUM_SPIS,
+ new Binder());
+ assertNotNull(extraSpi);
+ assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraSpi.status);
+
+ // Release one reserved spi.
+ mIpSecService.releaseSecurityParameterIndex(reservedSpis.get(0).resourceId);
+ reservedSpis.remove(0);
+
+ // Should successfully reserve one more spi.
+ extraSpi =
+ mIpSecService.reserveSecurityParameterIndex(
+ 0x1,
+ InetAddress.getLoopbackAddress().getHostAddress(),
+ DROID_SPI + MAX_NUM_SPIS,
+ new Binder());
+ assertNotNull(extraSpi);
+ assertEquals(IpSecManager.Status.OK, extraSpi.status);
+
+ // Release reserved SPIs.
+ for (IpSecSpiResponse spiResp : reservedSpis) {
+ mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
+ }
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
index ad6ebf933776..0656c5fd9e94 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
@@ -198,37 +198,33 @@ public class IpConnectivityEventBuilderTest {
@Test
public void testDefaultNetworkEventSerialization() {
- DefaultNetworkEvent ev = new DefaultNetworkEvent();
+ DefaultNetworkEvent ev = new DefaultNetworkEvent(1001);
ev.netId = 102;
- ev.prevNetId = 101;
- ev.transportTypes = new int[]{1, 2, 3};
- ev.prevIPv4 = true;
- ev.prevIPv6 = true;
+ ev.transports = 2;
+ ev.previousTransports = 4;
+ ev.ipv4 = true;
+ ev.initialScore = 20;
+ ev.finalScore = 60;
+ ev.durationMs = 54;
+ ev.validatedMs = 27;
String want = String.join("\n",
"dropped_events: 0",
"events <",
" if_name: \"\"",
- " link_layer: 0",
+ " link_layer: 4",
" network_id: 102",
" time_ms: 0",
- " transports: 0",
+ " transports: 2",
" default_network_event <",
- " default_network_duration_ms: 0",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " network_id <",
- " network_id: 102",
- " >",
+ " default_network_duration_ms: 54",
+ " final_score: 60",
+ " initial_score: 20",
+ " ip_support: 1",
" no_default_network_duration_ms: 0",
- " previous_network_id <",
- " network_id: 101",
- " >",
- " previous_network_ip_support: 3",
- " transport_types: 1",
- " transport_types: 2",
- " transport_types: 3",
+ " previous_default_network_link_layer: 1",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 27",
" >",
">",
"version: 2\n");
@@ -341,7 +337,6 @@ public class IpConnectivityEventBuilderTest {
public void testNetworkEventSerialization() {
ConnectivityMetricsEvent ev = describeIpEvent(
aType(NetworkEvent.class),
- anInt(100),
anInt(5),
aLong(20410));
@@ -356,9 +351,6 @@ public class IpConnectivityEventBuilderTest {
" network_event <",
" event_type: 5",
" latency_ms: 20410",
- " network_id <",
- " network_id: 100",
- " >",
" >",
">",
"version: 2\n");
@@ -512,6 +504,13 @@ public class IpConnectivityEventBuilderTest {
stats.rootWakeups = 2;
stats.systemWakeups = 3;
stats.noUidWakeups = 3;
+ stats.l2UnicastCount = 5;
+ stats.l2MulticastCount = 1;
+ stats.l2BroadcastCount = 2;
+ stats.ethertypes.put(0x800, 3);
+ stats.ethertypes.put(0x86dd, 3);
+ stats.ipNextHeaders.put(6, 5);
+
IpConnectivityEvent got = IpConnectivityEventBuilder.toProto(stats);
String want = String.join("\n",
@@ -525,6 +524,21 @@ public class IpConnectivityEventBuilderTest {
" wakeup_stats <",
" application_wakeups: 5",
" duration_sec: 0",
+ " ethertype_counts <",
+ " key: 2048",
+ " value: 3",
+ " >",
+ " ethertype_counts <",
+ " key: 34525",
+ " value: 3",
+ " >",
+ " ip_next_header_counts <",
+ " key: 6",
+ " value: 5",
+ " >",
+ " l2_broadcast_count: 2",
+ " l2_multicast_count: 1",
+ " l2_unicast_count: 5",
" no_uid_wakeups: 3",
" non_application_wakeups: 1",
" root_wakeups: 2",
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 6c1decc3b3b8..10d6deba61df 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -78,6 +78,9 @@ public class IpConnectivityMetricsTest {
private static final String EXAMPLE_IPV4 = "192.0.2.1";
private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1";
+ private static final byte[] MAC_ADDR =
+ {(byte)0x84, (byte)0xc9, (byte)0xb2, (byte)0x6a, (byte)0xed, (byte)0x4b};
+
@Mock Context mCtx;
@Mock IIpConnectivityMetrics mMockService;
@Mock ConnectivityManager mCm;
@@ -188,119 +191,99 @@ public class IpConnectivityMetricsTest {
{makeNai(102, 50, true, true, cell), makeNai(103, 20, true, false, wifi)},
};
+ long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
+ long durationMs = 1001;
for (NetworkAgentInfo[] pair : defaultNetworks) {
- mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(pair[1], pair[0]);
+ timeMs += durationMs;
+ durationMs += durationMs;
+ mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs, pair[1], pair[0]);
}
String want = String.join("\n",
"dropped_events: 0",
"events <",
" if_name: \"\"",
- " link_layer: 0",
- " network_id: 100",
+ " link_layer: 5",
+ " network_id: 0",
" time_ms: 0",
" transports: 0",
" default_network_event <",
- " default_network_duration_ms: 0",
+ " default_network_duration_ms: 1001",
" final_score: 0",
" initial_score: 0",
" ip_support: 0",
- " network_id <",
- " network_id: 100",
- " >",
" no_default_network_duration_ms: 0",
- " previous_network_id <",
- " network_id: 0",
- " >",
+ " previous_default_network_link_layer: 0",
" previous_network_ip_support: 0",
- " transport_types: 0",
+ " validation_duration_ms: 0",
" >",
">",
"events <",
" if_name: \"\"",
- " link_layer: 0",
- " network_id: 101",
+ " link_layer: 2",
+ " network_id: 100",
" time_ms: 0",
- " transports: 0",
+ " transports: 1",
" default_network_event <",
- " default_network_duration_ms: 0",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " network_id <",
- " network_id: 101",
- " >",
+ " default_network_duration_ms: 2002",
+ " final_score: 50",
+ " initial_score: 10",
+ " ip_support: 3",
" no_default_network_duration_ms: 0",
- " previous_network_id <",
- " network_id: 100",
- " >",
- " previous_network_ip_support: 3",
- " transport_types: 1",
+ " previous_default_network_link_layer: 0",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 2002",
" >",
">",
"events <",
" if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
+ " link_layer: 4",
+ " network_id: 101",
" time_ms: 0",
- " transports: 0",
+ " transports: 2",
" default_network_event <",
- " default_network_duration_ms: 0",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " network_id <",
- " network_id: 0",
- " >",
+ " default_network_duration_ms: 4004",
+ " final_score: 60",
+ " initial_score: 20",
+ " ip_support: 1",
" no_default_network_duration_ms: 0",
- " previous_network_id <",
- " network_id: 101",
- " >",
- " previous_network_ip_support: 1",
+ " previous_default_network_link_layer: 2",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 4004",
" >",
">",
"events <",
" if_name: \"\"",
- " link_layer: 0",
- " network_id: 102",
+ " link_layer: 5",
+ " network_id: 0",
" time_ms: 0",
" transports: 0",
" default_network_event <",
- " default_network_duration_ms: 0",
+ " default_network_duration_ms: 8008",
" final_score: 0",
" initial_score: 0",
" ip_support: 0",
- " network_id <",
- " network_id: 102",
- " >",
" no_default_network_duration_ms: 0",
- " previous_network_id <",
- " network_id: 0",
- " >",
+ " previous_default_network_link_layer: 4",
" previous_network_ip_support: 0",
- " transport_types: 0",
+ " validation_duration_ms: 0",
" >",
">",
"events <",
" if_name: \"\"",
- " link_layer: 0",
- " network_id: 103",
+ " link_layer: 2",
+ " network_id: 102",
" time_ms: 0",
- " transports: 0",
+ " transports: 1",
" default_network_event <",
- " default_network_duration_ms: 0",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " network_id <",
- " network_id: 103",
- " >",
+ " default_network_duration_ms: 16016",
+ " final_score: 50",
+ " initial_score: 10",
+ " ip_support: 3",
" no_default_network_duration_ms: 0",
- " previous_network_id <",
- " network_id: 102",
- " >",
- " previous_network_ip_support: 3",
- " transport_types: 1",
+ " previous_default_network_link_layer: 4",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 16016",
" >",
">",
"version: 2\n");
@@ -371,20 +354,29 @@ public class IpConnectivityMetricsTest {
dnsEvent(101, EVENT_GETHOSTBYNAME, 0, 34);
// iface, uid
- wakeupEvent("wlan0", 1000);
- wakeupEvent("rmnet0", 10123);
- wakeupEvent("wlan0", 1000);
- wakeupEvent("rmnet0", 10008);
- wakeupEvent("wlan0", -1);
- wakeupEvent("wlan0", 10008);
- wakeupEvent("rmnet0", 1000);
-
+ final byte[] mac = {0x48, 0x7c, 0x2b, 0x6a, 0x3e, 0x4b};
+ final String srcIp = "192.168.2.1";
+ final String dstIp = "192.168.2.23";
+ final int sport = 2356;
+ final int dport = 13489;
+ final long now = 1001L;
+ final int v4 = 0x800;
+ final int tcp = 6;
+ final int udp = 17;
+ wakeupEvent("wlan0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
+ wakeupEvent("wlan0", 10123, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
+ wakeupEvent("wlan0", 1000, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
+ wakeupEvent("wlan0", 10008, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
+ wakeupEvent("wlan0", -1, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
+ wakeupEvent("wlan0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
+
+ long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
NetworkAgentInfo cellNai = makeNai(100, 50, false, true, cell);
NetworkAgentInfo wifiNai = makeNai(101, 60, true, false, wifi);
- mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(cellNai, null);
- mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(wifiNai, cellNai);
+ mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs + 200, cellNai, null);
+ mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs + 300, wifiNai, cellNai);
String want = String.join("\n",
"dropped_events: 0",
@@ -473,46 +465,36 @@ public class IpConnectivityMetricsTest {
">",
"events <",
" if_name: \"\"",
- " link_layer: 0",
- " network_id: 100",
+ " link_layer: 5",
+ " network_id: 0",
" time_ms: 0",
" transports: 0",
" default_network_event <",
- " default_network_duration_ms: 0",
+ " default_network_duration_ms: 200",
" final_score: 0",
" initial_score: 0",
" ip_support: 0",
- " network_id <",
- " network_id: 100",
- " >",
" no_default_network_duration_ms: 0",
- " previous_network_id <",
- " network_id: 0",
- " >",
+ " previous_default_network_link_layer: 0",
" previous_network_ip_support: 0",
- " transport_types: 0",
+ " validation_duration_ms: 0",
" >",
">",
"events <",
" if_name: \"\"",
- " link_layer: 0",
- " network_id: 101",
+ " link_layer: 2",
+ " network_id: 100",
" time_ms: 0",
- " transports: 0",
+ " transports: 1",
" default_network_event <",
- " default_network_duration_ms: 0",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " network_id <",
- " network_id: 101",
- " >",
+ " default_network_duration_ms: 100",
+ " final_score: 50",
+ " initial_score: 50",
+ " ip_support: 2",
" no_default_network_duration_ms: 0",
- " previous_network_id <",
- " network_id: 100",
- " >",
- " previous_network_ip_support: 2",
- " transport_types: 1",
+ " previous_default_network_link_layer: 0",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 100",
" >",
">",
"events <",
@@ -589,34 +571,33 @@ public class IpConnectivityMetricsTest {
">",
"events <",
" if_name: \"\"",
- " link_layer: 2",
- " network_id: 0",
- " time_ms: 0",
- " transports: 0",
- " wakeup_stats <",
- " application_wakeups: 2",
- " duration_sec: 0",
- " no_uid_wakeups: 0",
- " non_application_wakeups: 0",
- " root_wakeups: 0",
- " system_wakeups: 1",
- " total_wakeups: 3",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
" link_layer: 4",
" network_id: 0",
" time_ms: 0",
" transports: 0",
" wakeup_stats <",
- " application_wakeups: 1",
+ " application_wakeups: 3",
" duration_sec: 0",
+ " ethertype_counts <",
+ " key: 2048",
+ " value: 6",
+ " >",
+ " ip_next_header_counts <",
+ " key: 6",
+ " value: 3",
+ " >",
+ " ip_next_header_counts <",
+ " key: 17",
+ " value: 3",
+ " >",
+ " l2_broadcast_count: 0",
+ " l2_multicast_count: 0",
+ " l2_unicast_count: 6",
" no_uid_wakeups: 1",
" non_application_wakeups: 0",
" root_wakeups: 0",
" system_wakeups: 2",
- " total_wakeups: 4",
+ " total_wakeups: 6",
" >",
">",
"version: 2\n");
@@ -639,9 +620,10 @@ public class IpConnectivityMetricsTest {
mNetdListener.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
}
- void wakeupEvent(String iface, int uid) throws Exception {
+ void wakeupEvent(String iface, int uid, int ether, int ip, byte[] mac, String srcIp,
+ String dstIp, int sport, int dport, long now) throws Exception {
String prefix = NetdEventListenerService.WAKEUP_EVENT_IFACE_PREFIX + iface;
- mNetdListener.onWakeupEvent(prefix, uid, uid, 0);
+ mNetdListener.onWakeupEvent(prefix, uid, ether, ip, mac, srcIp, dstIp, sport, dport, now);
}
NetworkAgentInfo makeNai(int netId, int score, boolean ipv4, boolean ipv6, long transports) {
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 6723601fc5c3..67805c944943 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -61,7 +61,10 @@ public class NetdEventListenerServiceTest {
private static final String EXAMPLE_IPV4 = "192.0.2.1";
private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1";
- NetdEventListenerService mNetdEventListenerService;
+ private static final byte[] MAC_ADDR =
+ {(byte)0x84, (byte)0xc9, (byte)0xb2, (byte)0x6a, (byte)0xed, (byte)0x4b};
+
+ NetdEventListenerService mService;
ConnectivityManager mCm;
@Before
@@ -75,29 +78,49 @@ public class NetdEventListenerServiceTest {
when(mCm.getNetworkCapabilities(new Network(100))).thenReturn(ncWifi);
when(mCm.getNetworkCapabilities(new Network(101))).thenReturn(ncCell);
- mNetdEventListenerService = new NetdEventListenerService(mCm);
+ mService = new NetdEventListenerService(mCm);
}
@Test
public void testWakeupEventLogging() throws Exception {
final int BUFFER_LENGTH = NetdEventListenerService.WAKEUP_EVENT_BUFFER_LENGTH;
-
- // Assert no events
- String[] events1 = listNetdEvent();
- assertEquals(new String[]{""}, events1);
-
- long now = System.currentTimeMillis();
- String prefix = "iface:wlan0";
- int[] uids = { 10001, 10002, 10004, 1000, 10052, 10023, 10002, 10123, 10004 };
- for (int uid : uids) {
- mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, now);
- }
-
- String[] events2 = listNetdEvent();
+ final long now = System.currentTimeMillis();
+ final String iface = "wlan0";
+ final byte[] mac = MAC_ADDR;
+ final String srcIp = "192.168.2.1";
+ final String dstIp = "192.168.2.23";
+ final String srcIp6 = "2001:db8:4:fd00:a585:13d1:6a23:4fb4";
+ final String dstIp6 = "2001:db8:4006:807::200a";
+ final int sport = 2356;
+ final int dport = 13489;
+
+ final int v4 = 0x800;
+ final int v6 = 0x86dd;
+ final int tcp = 6;
+ final int udp = 17;
+ final int icmp6 = 58;
+
+ // Baseline without any event
+ String[] baseline = listNetdEvent();
+
+ int[] uids = {10001, 10002, 10004, 1000, 10052, 10023, 10002, 10123, 10004};
+ wakeupEvent(iface, uids[0], v4, tcp, mac, srcIp, dstIp, sport, dport, now);
+ wakeupEvent(iface, uids[1], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
+ wakeupEvent(iface, uids[2], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
+ wakeupEvent(iface, uids[3], v4, icmp6, mac, srcIp, dstIp, sport, dport, now);
+ wakeupEvent(iface, uids[4], v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
+ wakeupEvent(iface, uids[5], v4, tcp, mac, srcIp, dstIp, sport, dport, now);
+ wakeupEvent(iface, uids[6], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
+ wakeupEvent(iface, uids[7], v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
+ wakeupEvent(iface, uids[8], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
+
+ String[] events2 = remove(listNetdEvent(), baseline);
int expectedLength2 = uids.length + 1; // +1 for the WakeupStats line
assertEquals(expectedLength2, events2.length);
assertContains(events2[0], "WakeupStats");
assertContains(events2[0], "wlan0");
+ assertContains(events2[0], "0x800");
+ assertContains(events2[0], "0x86dd");
for (int i = 0; i < uids.length; i++) {
String got = events2[i+1];
assertContains(got, "WakeupEvent");
@@ -108,10 +131,10 @@ public class NetdEventListenerServiceTest {
int uid = 20000;
for (int i = 0; i < BUFFER_LENGTH * 2; i++) {
long ts = now + 10;
- mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, ts);
+ wakeupEvent(iface, uid, 0x800, 6, mac, srcIp, dstIp, 23, 24, ts);
}
- String[] events3 = listNetdEvent();
+ String[] events3 = remove(listNetdEvent(), baseline);
int expectedLength3 = BUFFER_LENGTH + 1; // +1 for the WakeupStats line
assertEquals(expectedLength3, events3.length);
assertContains(events2[0], "WakeupStats");
@@ -124,9 +147,9 @@ public class NetdEventListenerServiceTest {
}
uid = 45678;
- mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, now);
+ wakeupEvent(iface, uid, 0x800, 6, mac, srcIp, dstIp, 23, 24, now);
- String[] events4 = listNetdEvent();
+ String[] events4 = remove(listNetdEvent(), baseline);
String lastEvent = events4[events4.length - 1];
assertContains(lastEvent, "WakeupEvent");
assertContains(lastEvent, "wlan0");
@@ -135,21 +158,36 @@ public class NetdEventListenerServiceTest {
@Test
public void testWakeupStatsLogging() throws Exception {
- wakeupEvent("wlan0", 1000);
- wakeupEvent("rmnet0", 10123);
- wakeupEvent("wlan0", 1000);
- wakeupEvent("rmnet0", 10008);
- wakeupEvent("wlan0", -1);
- wakeupEvent("wlan0", 10008);
- wakeupEvent("rmnet0", 1000);
- wakeupEvent("wlan0", 10004);
- wakeupEvent("wlan0", 1000);
- wakeupEvent("wlan0", 0);
- wakeupEvent("wlan0", -1);
- wakeupEvent("rmnet0", 10052);
- wakeupEvent("wlan0", 0);
- wakeupEvent("rmnet0", 1000);
- wakeupEvent("wlan0", 1010);
+ final byte[] mac = MAC_ADDR;
+ final String srcIp = "192.168.2.1";
+ final String dstIp = "192.168.2.23";
+ final String srcIp6 = "2401:fa00:4:fd00:a585:13d1:6a23:4fb4";
+ final String dstIp6 = "2404:6800:4006:807::200a";
+ final int sport = 2356;
+ final int dport = 13489;
+ final long now = 1001L;
+
+ final int v4 = 0x800;
+ final int v6 = 0x86dd;
+ final int tcp = 6;
+ final int udp = 17;
+ final int icmp6 = 58;
+
+ wakeupEvent("wlan0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
+ wakeupEvent("rmnet0", 10123, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
+ wakeupEvent("wlan0", 1000, v4, udp, mac, srcIp, dstIp, sport, dport, now);
+ wakeupEvent("rmnet0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
+ wakeupEvent("wlan0", -1, v6, icmp6, mac, srcIp6, dstIp6, sport, dport, now);
+ wakeupEvent("wlan0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
+ wakeupEvent("rmnet0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
+ wakeupEvent("wlan0", 10004, v4, udp, mac, srcIp, dstIp, sport, dport, now);
+ wakeupEvent("wlan0", 1000, v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
+ wakeupEvent("wlan0", 0, v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
+ wakeupEvent("wlan0", -1, v6, icmp6, mac, srcIp6, dstIp6, sport, dport, now);
+ wakeupEvent("rmnet0", 10052, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
+ wakeupEvent("wlan0", 0, v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
+ wakeupEvent("rmnet0", 1000, v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
+ wakeupEvent("wlan0", 1010, v4, udp, mac, srcIp, dstIp, sport, dport, now);
String got = flushStatistics();
String want = String.join("\n",
@@ -163,6 +201,21 @@ public class NetdEventListenerServiceTest {
" wakeup_stats <",
" application_wakeups: 3",
" duration_sec: 0",
+ " ethertype_counts <",
+ " key: 2048",
+ " value: 4",
+ " >",
+ " ethertype_counts <",
+ " key: 34525",
+ " value: 1",
+ " >",
+ " ip_next_header_counts <",
+ " key: 6",
+ " value: 5",
+ " >",
+ " l2_broadcast_count: 0",
+ " l2_multicast_count: 0",
+ " l2_unicast_count: 5",
" no_uid_wakeups: 0",
" non_application_wakeups: 0",
" root_wakeups: 0",
@@ -179,6 +232,29 @@ public class NetdEventListenerServiceTest {
" wakeup_stats <",
" application_wakeups: 2",
" duration_sec: 0",
+ " ethertype_counts <",
+ " key: 2048",
+ " value: 5",
+ " >",
+ " ethertype_counts <",
+ " key: 34525",
+ " value: 5",
+ " >",
+ " ip_next_header_counts <",
+ " key: 6",
+ " value: 3",
+ " >",
+ " ip_next_header_counts <",
+ " key: 17",
+ " value: 5",
+ " >",
+ " ip_next_header_counts <",
+ " key: 58",
+ " value: 2",
+ " >",
+ " l2_broadcast_count: 0",
+ " l2_multicast_count: 0",
+ " l2_unicast_count: 10",
" no_uid_wakeups: 2",
" non_application_wakeups: 1",
" root_wakeups: 2",
@@ -402,7 +478,7 @@ public class NetdEventListenerServiceTest {
Thread connectEventAction(int netId, int error, int latencyMs, String ipAddr) {
return new Thread(() -> {
try {
- mNetdEventListenerService.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
+ mService.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
} catch (Exception e) {
fail(e.toString());
}
@@ -410,12 +486,13 @@ public class NetdEventListenerServiceTest {
}
void dnsEvent(int netId, int type, int result, int latency) throws Exception {
- mNetdEventListenerService.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
+ mService.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
}
- void wakeupEvent(String iface, int uid) throws Exception {
+ void wakeupEvent(String iface, int uid, int ether, int ip, byte[] mac, String srcIp,
+ String dstIp, int sport, int dport, long now) throws Exception {
String prefix = NetdEventListenerService.WAKEUP_EVENT_IFACE_PREFIX + iface;
- mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, 0);
+ mService.onWakeupEvent(prefix, uid, ether, ip, mac, srcIp, dstIp, sport, dport, now);
}
void asyncDump(long durationMs) throws Exception {
@@ -423,7 +500,7 @@ public class NetdEventListenerServiceTest {
final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
new Thread(() -> {
while (System.currentTimeMillis() < stop) {
- mNetdEventListenerService.dump(pw);
+ mService.list(pw);
}
}).start();
}
@@ -432,7 +509,7 @@ public class NetdEventListenerServiceTest {
String flushStatistics() throws Exception {
IpConnectivityMetrics metricsService =
new IpConnectivityMetrics(mock(Context.class), (ctx) -> 2000);
- metricsService.mNetdListener = mNetdEventListenerService;
+ metricsService.mNetdListener = mService;
StringWriter buffer = new StringWriter();
PrintWriter writer = new PrintWriter(buffer);
@@ -454,11 +531,23 @@ public class NetdEventListenerServiceTest {
String[] listNetdEvent() throws Exception {
StringWriter buffer = new StringWriter();
PrintWriter writer = new PrintWriter(buffer);
- mNetdEventListenerService.list(writer);
+ mService.list(writer);
return buffer.toString().split("\\n");
}
static void assertContains(String got, String want) {
assertTrue(got + " did not contain \"" + want + "\"", got.contains(want));
}
+
+ static <T> T[] remove(T[] array, T[] filtered) {
+ List<T> c = Arrays.asList(filtered);
+ int next = 0;
+ for (int i = 0; i < array.length; i++) {
+ if (c.contains(array[i])) {
+ continue;
+ }
+ array[next++] = array[i];
+ }
+ return Arrays.copyOf(array, next);
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index fe396c3a5c40..c29363cd1a4f 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -20,11 +20,30 @@ import static android.content.pm.UserInfo.FLAG_ADMIN;
import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
import static android.content.pm.UserInfo.FLAG_PRIMARY;
import static android.content.pm.UserInfo.FLAG_RESTRICTED;
+import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.AdditionalMatchers.*;
-import static org.mockito.Mockito.*;
+import static org.mockito.AdditionalMatchers.aryEq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
@@ -36,6 +55,9 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.NetworkInfo.DetailedState;
import android.net.UidRange;
import android.net.VpnService;
@@ -45,17 +67,17 @@ import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
-import android.support.test.runner.AndroidJUnit4;
import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import android.util.ArrayMap;
import android.util.ArraySet;
import com.android.internal.R;
import com.android.internal.net.VpnConfig;
-import org.junit.runner.RunWith;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.InOrder;
import org.mockito.Mock;
@@ -64,6 +86,7 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@@ -114,6 +137,7 @@ public class VpnTest {
@Mock private AppOpsManager mAppOps;
@Mock private NotificationManager mNotificationManager;
@Mock private Vpn.SystemServices mSystemServices;
+ @Mock private ConnectivityManager mConnectivityManager;
@Before
public void setUp() throws Exception {
@@ -127,6 +151,8 @@ public class VpnTest {
when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
.thenReturn(mNotificationManager);
+ when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
+ .thenReturn(mConnectivityManager);
when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
.thenReturn(Resources.getSystem().getString(
R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
@@ -397,6 +423,66 @@ public class VpnTest {
order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
}
+ @Test
+ public void testCapabilities() {
+ final Vpn vpn = createVpn(primaryUser.id);
+ setMockedUsers(primaryUser);
+
+ final Network mobile = new Network(1);
+ final Network wifi = new Network(2);
+
+ final Map<Network, NetworkCapabilities> networks = new HashMap<>();
+ networks.put(mobile, new NetworkCapabilities()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_METERED)
+ .setLinkDownstreamBandwidthKbps(10));
+ networks.put(wifi, new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_ROAMING)
+ .setLinkUpstreamBandwidthKbps(20));
+ setMockedNetworks(networks);
+
+ final NetworkCapabilities caps = new NetworkCapabilities();
+
+ Vpn.updateCapabilities(mConnectivityManager, new Network[] { }, caps);
+ assertTrue(caps.hasTransport(TRANSPORT_VPN));
+ assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
+ assertFalse(caps.hasTransport(TRANSPORT_WIFI));
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
+ assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+
+ Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile }, caps);
+ assertTrue(caps.hasTransport(TRANSPORT_VPN));
+ assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
+ assertFalse(caps.hasTransport(TRANSPORT_WIFI));
+ assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
+ assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+
+ Vpn.updateCapabilities(mConnectivityManager, new Network[] { wifi }, caps);
+ assertTrue(caps.hasTransport(TRANSPORT_VPN));
+ assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
+ assertTrue(caps.hasTransport(TRANSPORT_WIFI));
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
+ assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
+ assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+
+ Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile, wifi }, caps);
+ assertTrue(caps.hasTransport(TRANSPORT_VPN));
+ assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
+ assertTrue(caps.hasTransport(TRANSPORT_WIFI));
+ assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
+ assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
+ assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+ }
+
/**
* Mock some methods of vpn object.
*/
@@ -463,4 +549,11 @@ public class VpnTest {
} catch (Exception e) {
}
}
+
+ private void setMockedNetworks(final Map<Network, NetworkCapabilities> networks) {
+ doAnswer(invocation -> {
+ final Network network = (Network) invocation.getArguments()[0];
+ return networks.get(network);
+ }).when(mConnectivityManager).getNetworkCapabilities(any());
+ }
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 7f1bc5bb7e9d..65be5ffb32a2 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -1158,9 +1158,8 @@ public class NetworkStatsServiceTest {
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_IFACE);
final NetworkCapabilities capabilities = new NetworkCapabilities();
- if (!isMetered) {
- capabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- }
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, !isMetered);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
return new NetworkState(info, prop, capabilities, null, null, TEST_SSID);
}
@@ -1176,6 +1175,8 @@ public class NetworkStatsServiceTest {
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_IFACE);
final NetworkCapabilities capabilities = new NetworkCapabilities();
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
return new NetworkState(info, prop, capabilities, null, subscriberId, null);
}
@@ -1185,6 +1186,8 @@ public class NetworkStatsServiceTest {
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(iface);
final NetworkCapabilities capabilities = new NetworkCapabilities();
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
return new NetworkState(info, prop, capabilities, null, null, null);
}
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 058504d7520d..eb3a99ae6331 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -16,6 +16,7 @@
toolSources = [
"cmd/Compile.cpp",
+ "cmd/Convert.cpp",
"cmd/Diff.cpp",
"cmd/Dump.cpp",
"cmd/Link.cpp",
@@ -112,6 +113,7 @@ cc_library_host_static {
"optimize/VersionCollapser.cpp",
"process/SymbolTable.cpp",
"split/TableSplitter.cpp",
+ "text/Printer.cpp",
"text/Unicode.cpp",
"text/Utf8Iterator.cpp",
"util/BigBuffer.cpp",
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
new file mode 100644
index 000000000000..e0c9d1c04498
--- /dev/null
+++ b/tools/aapt2/Android.mk
@@ -0,0 +1,7 @@
+include $(CLEAR_VARS)
+
+.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
+
diff --git a/tools/aapt2/ConfigDescription.cpp b/tools/aapt2/ConfigDescription.cpp
index 59a6e1281783..f621660cb8ad 100644
--- a/tools/aapt2/ConfigDescription.cpp
+++ b/tools/aapt2/ConfigDescription.cpp
@@ -882,6 +882,11 @@ std::string ConfigDescription::GetBcp47LanguageTag(bool canonicalize) const {
return std::string(locale);
}
+std::string ConfigDescription::to_string() const {
+ const android::String8 str = toString();
+ return std::string(str.string(), str.size());
+}
+
bool ConfigDescription::Dominates(const ConfigDescription& o) const {
if (*this == o) {
return true;
diff --git a/tools/aapt2/ConfigDescription.h b/tools/aapt2/ConfigDescription.h
index c1d0e1084186..f71955247d78 100644
--- a/tools/aapt2/ConfigDescription.h
+++ b/tools/aapt2/ConfigDescription.h
@@ -64,6 +64,8 @@ struct ConfigDescription : public android::ResTable_config {
// Returns the BCP-47 language tag of this configuration's locale.
std::string GetBcp47LanguageTag(bool canonicalize = false) const;
+ std::string to_string() const;
+
/**
* A configuration X dominates another configuration Y, if X has at least the
* precedence of Y and X is strictly more general than Y: for any type defined
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 61c304b2c048..08efc276fe86 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -17,7 +17,6 @@
#include "Debug.h"
#include <algorithm>
-#include <iostream>
#include <map>
#include <memory>
#include <queue>
@@ -25,120 +24,244 @@
#include <vector>
#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
#include "ResourceTable.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
+#include "text/Printer.h"
#include "util/Util.h"
+using ::aapt::text::Printer;
+using ::android::StringPiece;
+using ::android::base::StringPrintf;
+
namespace aapt {
namespace {
-class PrintVisitor : public ConstValueVisitor {
+class ValueHeadlinePrinter : public ConstValueVisitor {
public:
using ConstValueVisitor::Visit;
+ explicit ValueHeadlinePrinter(const std::string& package, Printer* printer)
+ : package_(package), printer_(printer) {
+ }
+
void Visit(const Attribute* attr) override {
- std::cout << "(attr) type=";
- attr->PrintMask(&std::cout);
- static constexpr uint32_t kMask =
- android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS;
- if (attr->type_mask & kMask) {
- for (const auto& symbol : attr->symbols) {
- std::cout << "\n " << symbol.symbol.name.value().entry;
- if (symbol.symbol.id) {
- std::cout << " (" << symbol.symbol.id.value() << ")";
- }
- std::cout << " = " << symbol.value;
- }
+ printer_->Print("(attr) type=");
+ printer_->Print(attr->MaskString());
+ if (!attr->symbols.empty()) {
+ printer_->Print(StringPrintf(" size=%zd", attr->symbols.size()));
}
}
void Visit(const Style* style) override {
- std::cout << "(style)";
+ printer_->Print(StringPrintf("(style) size=%zd", style->entries.size()));
if (style->parent) {
+ printer_->Print(" parent=");
+
const Reference& parent_ref = style->parent.value();
- std::cout << " parent=";
if (parent_ref.name) {
if (parent_ref.private_reference) {
- std::cout << "*";
+ printer_->Print("*");
+ }
+
+ const ResourceName& parent_name = parent_ref.name.value();
+ if (package_ != parent_name.package) {
+ printer_->Print(parent_name.package);
+ printer_->Print(":");
+ }
+ printer_->Print(to_string(parent_name.type));
+ printer_->Print("/");
+ printer_->Print(parent_name.entry);
+ if (parent_ref.id) {
+ printer_->Print(" (");
+ printer_->Print(parent_ref.id.value().to_string());
+ printer_->Print(")");
}
- std::cout << parent_ref.name.value() << " ";
+ } else if (parent_ref.id) {
+ printer_->Print(parent_ref.id.value().to_string());
+ } else {
+ printer_->Print("???");
}
+ }
+ }
+
+ void Visit(const Array* array) override {
+ printer_->Print(StringPrintf("(array) size=%zd", array->elements.size()));
+ }
+
+ void Visit(const Plural* plural) override {
+ size_t count = std::count_if(plural->values.begin(), plural->values.end(),
+ [](const std::unique_ptr<Item>& v) { return v != nullptr; });
+ printer_->Print(StringPrintf("(plurals) size=%zd", count));
+ }
+
+ void Visit(const Styleable* styleable) override {
+ printer_->Println(StringPrintf("(styleable) size=%zd", styleable->entries.size()));
+ }
- if (parent_ref.id) {
- std::cout << parent_ref.id.value();
+ void VisitItem(const Item* item) override {
+ // Pretty much guaranteed to be one line.
+ if (const Reference* ref = ValueCast<Reference>(item)) {
+ // Special case Reference so that we can print local resources without a package name.
+ ref->PrettyPrint(package_, printer_);
+ } else {
+ item->PrettyPrint(printer_);
+ }
+ }
+
+ private:
+ std::string package_;
+ Printer* printer_;
+};
+
+class ValueBodyPrinter : public ConstValueVisitor {
+ public:
+ using ConstValueVisitor::Visit;
+
+ explicit ValueBodyPrinter(const std::string& package, Printer* printer)
+ : package_(package), printer_(printer) {
+ }
+
+ void Visit(const Attribute* attr) override {
+ constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS;
+ if (attr->type_mask & kMask) {
+ for (const auto& symbol : attr->symbols) {
+ printer_->Print(symbol.symbol.name.value().entry);
+ if (symbol.symbol.id) {
+ printer_->Print("(");
+ printer_->Print(symbol.symbol.id.value().to_string());
+ printer_->Print(")");
+ }
+ printer_->Println(StringPrintf("=0x%08x", symbol.value));
}
}
+ }
+ void Visit(const Style* style) override {
for (const auto& entry : style->entries) {
- std::cout << "\n ";
if (entry.key.name) {
const ResourceName& name = entry.key.name.value();
- if (!name.package.empty()) {
- std::cout << name.package << ":";
+ if (!name.package.empty() && name.package != package_) {
+ printer_->Print(name.package);
+ printer_->Print(":");
}
- std::cout << name.entry;
- }
+ printer_->Print(name.entry);
- if (entry.key.id) {
- std::cout << "(" << entry.key.id.value() << ")";
+ if (entry.key.id) {
+ printer_->Print("(");
+ printer_->Print(entry.key.id.value().to_string());
+ printer_->Print(")");
+ }
+ } else if (entry.key.id) {
+ printer_->Print(entry.key.id.value().to_string());
+ } else {
+ printer_->Print("???");
}
- std::cout << "=" << *entry.value;
+ printer_->Print("=");
+ PrintItem(*entry.value);
+ printer_->Println();
}
}
void Visit(const Array* array) override {
- array->Print(&std::cout);
+ const size_t count = array->elements.size();
+ printer_->Print("[");
+ if (count > 0) {
+ for (size_t i = 0u; i < count; i++) {
+ if (i != 0u && i % 4u == 0u) {
+ printer_->Println();
+ printer_->Print(" ");
+ }
+ PrintItem(*array->elements[i]);
+ if (i != count - 1) {
+ printer_->Print(", ");
+ }
+ }
+ printer_->Println("]");
+ }
}
void Visit(const Plural* plural) override {
- plural->Print(&std::cout);
+ constexpr std::array<const char*, Plural::Count> kPluralNames = {
+ {"zero", "one", "two", "few", "many", "other"}};
+
+ for (size_t i = 0; i < Plural::Count; i++) {
+ if (plural->values[i] != nullptr) {
+ printer_->Print(StringPrintf("%s=", kPluralNames[i]));
+ PrintItem(*plural->values[i]);
+ printer_->Println();
+ }
+ }
}
void Visit(const Styleable* styleable) override {
- std::cout << "(styleable)";
for (const auto& attr : styleable->entries) {
- std::cout << "\n ";
if (attr.name) {
const ResourceName& name = attr.name.value();
- if (!name.package.empty()) {
- std::cout << name.package << ":";
+ if (!name.package.empty() && name.package != package_) {
+ printer_->Print(name.package);
+ printer_->Print(":");
+ }
+ printer_->Print(name.entry);
+
+ if (attr.id) {
+ printer_->Print("(");
+ printer_->Print(attr.id.value().to_string());
+ printer_->Print(")");
}
- std::cout << name.entry;
}
if (attr.id) {
- std::cout << "(" << attr.id.value() << ")";
+ printer_->Print(attr.id.value().to_string());
}
}
}
void VisitItem(const Item* item) override {
- item->Print(&std::cout);
+ // Intentionally left empty, we already printed the Items.
}
+
+ private:
+ void PrintItem(const Item& item) {
+ if (const Reference* ref = ValueCast<Reference>(&item)) {
+ // Special case Reference so that we can print local resources without a package name.
+ ref->PrettyPrint(package_, printer_);
+ } else {
+ item.PrettyPrint(printer_);
+ }
+ }
+
+ std::string package_;
+ Printer* printer_;
};
} // namespace
-void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options) {
- PrintVisitor visitor;
-
+void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options,
+ Printer* printer) {
for (const auto& package : table.packages) {
- std::cout << "Package name=" << package->name;
+ ValueHeadlinePrinter headline_printer(package->name, printer);
+ ValueBodyPrinter body_printer(package->name, printer);
+
+ printer->Print("Package name=");
+ printer->Print(package->name);
if (package->id) {
- std::cout << " id=" << std::hex << (int)package->id.value() << std::dec;
+ printer->Print(StringPrintf(" id=%02x", package->id.value()));
}
- std::cout << std::endl;
+ printer->Println();
+ printer->Indent();
for (const auto& type : package->types) {
- std::cout << "\n type " << type->type;
+ printer->Print("type ");
+ printer->Print(to_string(type->type));
if (type->id) {
- std::cout << " id=" << std::hex << (int)type->id.value() << std::dec;
+ printer->Print(StringPrintf(" id=%02x", type->id.value()));
}
- std::cout << " entryCount=" << type->entries.size() << std::endl;
+ printer->Println(StringPrintf(" entryCount=%zd", type->entries.size()));
std::vector<const ResourceEntry*> sorted_entries;
for (const auto& entry : type->entries) {
@@ -156,35 +279,54 @@ void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions&
sorted_entries.insert(iter, entry.get());
}
+ printer->Indent();
for (const ResourceEntry* entry : sorted_entries) {
const ResourceId id(package->id.value_or_default(0), type->id.value_or_default(0),
entry->id.value_or_default(0));
- const ResourceName name(package->name, type->type, entry->name);
- std::cout << " spec resource " << id << " " << name;
+ printer->Print("resource ");
+ printer->Print(id.to_string());
+ printer->Print(" ");
+
+ // Write the name without the package (this is obvious and too verbose).
+ printer->Print(to_string(type->type));
+ printer->Print("/");
+ printer->Print(entry->name);
+
switch (entry->symbol_status.state) {
case SymbolState::kPublic:
- std::cout << " PUBLIC";
+ printer->Print(" PUBLIC");
break;
case SymbolState::kPrivate:
- std::cout << " _PRIVATE_";
+ printer->Print(" _PRIVATE_");
break;
- default:
+ case SymbolState::kUndefined:
+ // Print nothing.
break;
}
- std::cout << std::endl;
+ printer->Println();
+ printer->Indent();
for (const auto& value : entry->values) {
- std::cout << " (" << value->config << ") ";
- value->value->Accept(&visitor);
+ printer->Print("(");
+ printer->Print(value->config.to_string());
+ printer->Print(") ");
+ value->value->Accept(&headline_printer);
if (options.show_sources && !value->value->GetSource().path.empty()) {
- std::cout << " src=" << value->value->GetSource();
+ printer->Print(" src=");
+ printer->Print(value->value->GetSource().to_string());
}
- std::cout << std::endl;
+ printer->Println();
+ printer->Indent();
+ value->value->Accept(&body_printer);
+ printer->Undent();
}
+ printer->Undent();
}
+ printer->Undent();
}
+ printer->Undent();
}
}
diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h
index 296d04bd49bd..3c1ee4c0cdba 100644
--- a/tools/aapt2/Debug.h
+++ b/tools/aapt2/Debug.h
@@ -22,6 +22,7 @@
#include "Resource.h"
#include "ResourceTable.h"
+#include "text/Printer.h"
#include "xml/XmlDom.h"
namespace aapt {
@@ -31,9 +32,9 @@ struct DebugPrintTableOptions {
};
struct Debug {
- static void PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options = {});
- static void PrintStyleGraph(ResourceTable* table,
- const ResourceName& target_style);
+ static void PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options,
+ text::Printer* printer);
+ static void PrintStyleGraph(ResourceTable* table, const ResourceName& target_style);
static void DumpHex(const void* data, size_t len);
static void DumpXml(const xml::XmlResource& doc);
};
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index ae32ee965b48..5981401195a4 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -21,43 +21,139 @@
#include "format/Archive.h"
#include "format/binary/TableFlattener.h"
#include "format/binary/XmlFlattener.h"
+#include "format/proto/ProtoDeserialize.h"
#include "io/BigBufferStream.h"
#include "io/Util.h"
#include "xml/XmlDom.h"
-namespace aapt {
+using ::aapt::io::IFile;
+using ::aapt::io::IFileCollection;
+using ::aapt::xml::XmlResource;
+using ::android::StringPiece;
+using ::std::unique_ptr;
-using xml::XmlResource;
+namespace aapt {
-std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(IAaptContext* context,
- const android::StringPiece& path) {
+std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(const StringPiece& path, IDiagnostics* diag) {
Source source(path);
std::string error;
std::unique_ptr<io::ZipFileCollection> apk = io::ZipFileCollection::Create(path, &error);
- if (!apk) {
- context->GetDiagnostics()->Error(DiagMessage(source) << error);
+ if (apk == nullptr) {
+ diag->Error(DiagMessage(path) << "failed opening zip: " << error);
+ 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);
+ }
+ 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) {
+ io::IFile* table_file = collection->FindFile(kProtoResourceTablePath);
+ if (table_file == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to find " << kProtoResourceTablePath);
+ return {};
+ }
+
+ std::unique_ptr<io::InputStream> in = table_file->OpenInputStream();
+ if (in == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to open " << 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 {};
+ }
+
+ io::IFile* manifest_file = collection->FindFile(kAndroidManifestPath);
+ if (manifest_file == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to find " << kAndroidManifestPath);
+ return {};
+ }
+
+ std::unique_ptr<io::InputStream> manifest_in = manifest_file->OpenInputStream();
+ if (manifest_in == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to open " << kAndroidManifestPath);
+ return {};
+ }
+
+ pb::XmlNode pb_node;
+ io::ZeroCopyInputAdaptor manifest_adaptor(manifest_in.get());
+ if (!pb_node.ParseFromZeroCopyStream(&manifest_adaptor)) {
+ diag->Error(DiagMessage(source) << "failed to read proto " << kAndroidManifestPath);
+ return {};
+ }
+
+ std::unique_ptr<xml::XmlResource> manifest = DeserializeXmlResourceFromPb(pb_node, &error);
+ if (manifest == nullptr) {
+ diag->Error(DiagMessage(source)
+ << "failed to deserialize proto " << kAndroidManifestPath << ": " << error);
return {};
}
+ return util::make_unique<LoadedApk>(source, std::move(collection), std::move(table),
+ std::move(manifest));
+}
+
+std::unique_ptr<LoadedApk> LoadedApk::LoadBinaryApkFromFileCollection(
+ const Source& source, unique_ptr<io::IFileCollection> collection, IDiagnostics* diag) {
+ io::IFile* table_file = collection->FindFile(kApkResourceTablePath);
+ if (table_file == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to find " << kApkResourceTablePath);
- io::IFile* file = apk->FindFile("resources.arsc");
- if (!file) {
- context->GetDiagnostics()->Error(DiagMessage(source) << "no resources.arsc found");
return {};
}
- std::unique_ptr<io::IData> data = file->OpenAsData();
- if (!data) {
- context->GetDiagnostics()->Error(DiagMessage(source) << "could not open resources.arsc");
+ 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(context, table.get(), source, data->data(), data->size(), apk.get());
+ BinaryResourceParser parser(diag, table.get(), source, data->data(), data->size(),
+ collection.get());
if (!parser.Parse()) {
return {};
}
- return util::make_unique<LoadedApk>(source, std::move(apk), std::move(table));
+ io::IFile* manifest_file = collection->FindFile(kAndroidManifestPath);
+ if (manifest_file == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to find " << kAndroidManifestPath);
+ return {};
+ }
+
+ std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData();
+ if (manifest_data == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to open " << kAndroidManifestPath);
+ return {};
+ }
+
+ std::string error;
+ std::unique_ptr<xml::XmlResource> manifest =
+ xml::Inflate(manifest_data->data(), manifest_data->size(), &error);
+ if (manifest == nullptr) {
+ diag->Error(DiagMessage(source)
+ << "failed to parse binary " << kAndroidManifestPath << ": " << error);
+ return {};
+ }
+ return util::make_unique<LoadedApk>(source, std::move(collection), std::move(table),
+ std::move(manifest));
}
bool LoadedApk::WriteToArchive(IAaptContext* context, const TableFlattenerOptions& options,
@@ -139,8 +235,7 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table
return false;
}
} else {
- uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u;
- if (!io::CopyFileToArchive(context, file, path, compression_flags, writer)) {
+ if (!io::CopyFileToArchivePreserveCompression(context, file, path, writer)) {
return false;
}
}
@@ -148,26 +243,4 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table
return true;
}
-std::unique_ptr<xml::XmlResource> LoadedApk::InflateManifest(IAaptContext* context) {
- IDiagnostics* diag = context->GetDiagnostics();
-
- io::IFile* manifest_file = GetFileCollection()->FindFile("AndroidManifest.xml");
- if (manifest_file == nullptr) {
- diag->Error(DiagMessage(source_) << "no AndroidManifest.xml found");
- return {};
- }
-
- std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData();
- if (manifest_data == nullptr) {
- diag->Error(DiagMessage(manifest_file->GetSource()) << "could not open AndroidManifest.xml");
- return {};
- }
-
- std::unique_ptr<xml::XmlResource> manifest =
- xml::Inflate(manifest_data->data(), manifest_data->size(), diag, manifest_file->GetSource());
- if (manifest == nullptr) {
- diag->Error(DiagMessage() << "failed to read binary AndroidManifest.xml");
- }
- return manifest;
-}
} // namespace aapt
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
index d2dd5cf2bc67..ef97de301ad5 100644
--- a/tools/aapt2/LoadedApk.h
+++ b/tools/aapt2/LoadedApk.h
@@ -29,20 +29,41 @@
namespace aapt {
+constexpr static const char kApkResourceTablePath[] = "resources.arsc";
+constexpr static const char kProtoResourceTablePath[] = "resources.pb";
+constexpr static const char kAndroidManifestPath[] = "AndroidManifest.xml";
+
// Info about an APK loaded in memory.
class LoadedApk {
public:
- LoadedApk(
- const Source& source,
- std::unique_ptr<io::IFileCollection> apk,
- std::unique_ptr<ResourceTable> table)
- : source_(source), apk_(std::move(apk)), table_(std::move(table)) {}
- virtual ~LoadedApk() = default;
+ // Loads both binary and proto APKs from disk.
+ static std::unique_ptr<LoadedApk> LoadApkFromPath(const ::android::StringPiece& path,
+ IDiagnostics* diag);
+
+ // Loads a proto APK from the given file collection.
+ static std::unique_ptr<LoadedApk> LoadProtoApkFromFileCollection(
+ const Source& source, std::unique_ptr<io::IFileCollection> collection, IDiagnostics* diag);
+
+ // Loads a binary APK from the given file collection.
+ static std::unique_ptr<LoadedApk> LoadBinaryApkFromFileCollection(
+ const Source& source, std::unique_ptr<io::IFileCollection> collection, IDiagnostics* diag);
+
+ LoadedApk(const Source& source, std::unique_ptr<io::IFileCollection> apk,
+ std::unique_ptr<ResourceTable> table, std::unique_ptr<xml::XmlResource> manifest)
+ : source_(source),
+ apk_(std::move(apk)),
+ table_(std::move(table)),
+ manifest_(std::move(manifest)) {
+ }
io::IFileCollection* GetFileCollection() {
return apk_.get();
}
+ const ResourceTable* GetResourceTable() const {
+ return table_.get();
+ }
+
ResourceTable* GetResourceTable() {
return table_.get();
}
@@ -51,6 +72,10 @@ class LoadedApk {
return source_;
}
+ const xml::XmlResource* GetManifest() const {
+ return manifest_.get();
+ }
+
/**
* Writes the APK on disk at the given path, while also removing the resource
* files that are not referenced in the resource table.
@@ -71,11 +96,6 @@ class LoadedApk {
const TableFlattenerOptions& options, FilterChain* filters,
IArchiveWriter* writer, xml::XmlResource* manifest = nullptr);
- /** Inflates the AndroidManifest.xml file from the APK. */
- std::unique_ptr<xml::XmlResource> InflateManifest(IAaptContext* context);
-
- static std::unique_ptr<LoadedApk> LoadApkFromPath(IAaptContext* context,
- const android::StringPiece& path);
private:
DISALLOW_COPY_AND_ASSIGN(LoadedApk);
@@ -83,6 +103,7 @@ class LoadedApk {
Source source_;
std::unique_ptr<io::IFileCollection> apk_;
std::unique_ptr<ResourceTable> table_;
+ std::unique_ptr<xml::XmlResource> manifest_;
};
} // namespace aapt
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 36ab30c7fb6e..808b29cfd844 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -50,7 +50,7 @@ static void PrintVersion() {
}
static void PrintUsage() {
- std::cerr << "\nusage: aapt2 [compile|link|dump|diff|optimize|version] ..." << std::endl;
+ std::cerr << "\nusage: aapt2 [compile|link|dump|diff|optimize|convert|version] ..." << std::endl;
}
extern int Compile(const std::vector<StringPiece>& args, IDiagnostics* diagnostics);
@@ -58,6 +58,7 @@ extern int Link(const std::vector<StringPiece>& args, IDiagnostics* diagnostics)
extern int Dump(const std::vector<StringPiece>& args);
extern int Diff(const std::vector<StringPiece>& args);
extern int Optimize(const std::vector<StringPiece>& args);
+extern int Convert(const std::vector<StringPiece>& args);
static int ExecuteCommand(const StringPiece& command, const std::vector<StringPiece>& args,
IDiagnostics* diagnostics) {
@@ -71,6 +72,8 @@ static int ExecuteCommand(const StringPiece& command, const std::vector<StringPi
return Diff(args);
} else if (command == "optimize") {
return Optimize(args);
+ } else if (command == "convert") {
+ return Convert(args);
} else if (command == "version") {
PrintVersion();
return 0;
diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp
index a9f5f298e019..b78f48ce7f17 100644
--- a/tools/aapt2/Resource.cpp
+++ b/tools/aapt2/Resource.cpp
@@ -17,13 +17,34 @@
#include "Resource.h"
#include <map>
+#include <sstream>
#include <string>
-using android::StringPiece;
+#include "android-base/stringprintf.h"
+
+using ::android::StringPiece;
+using ::android::base::StringPrintf;
namespace aapt {
-StringPiece ToString(ResourceType type) {
+std::string ResourceId::to_string() const {
+ return StringPrintf("0x%08x", id);
+}
+
+std::string ResourceName::to_string() const {
+ return ResourceNameRef(*this).to_string();
+}
+
+std::string ResourceNameRef::to_string() const {
+ std::ostringstream str_stream;
+ if (!package.empty()) {
+ str_stream << package << ":";
+ }
+ str_stream << type << "/" << entry;
+ return str_stream.str();
+}
+
+StringPiece to_string(ResourceType type) {
switch (type) {
case ResourceType::kAnim:
return "anim";
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index 87b986784961..96a02033fc1d 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -69,11 +69,10 @@ enum class ResourceType {
kXml,
};
-android::StringPiece ToString(ResourceType type);
+android::StringPiece to_string(ResourceType type);
/**
- * Returns a pointer to a valid ResourceType, or nullptr if
- * the string was invalid.
+ * Returns a pointer to a valid ResourceType, or nullptr if the string was invalid.
*/
const ResourceType* ParseResourceType(const android::StringPiece& str);
@@ -92,7 +91,7 @@ struct ResourceName {
int compare(const ResourceName& other) const;
bool is_valid() const;
- std::string ToString() const;
+ std::string to_string() const;
};
/**
@@ -115,8 +114,10 @@ struct ResourceNameRef {
ResourceNameRef& operator=(ResourceNameRef&& rhs) = default;
ResourceNameRef& operator=(const ResourceName& rhs);
- ResourceName ToResourceName() const;
bool is_valid() const;
+
+ ResourceName ToResourceName() const;
+ std::string to_string() const;
};
constexpr const uint8_t kAppPackageId = 0x7fu;
@@ -149,6 +150,8 @@ struct ResourceId {
uint8_t package_id() const;
uint8_t type_id() const;
uint16_t entry_id() const;
+
+ std::string to_string() const;
};
struct SourcedResourceName {
@@ -229,7 +232,9 @@ inline bool ResourceId::is_valid() const {
return (id & 0xff000000u) != 0 && (id & 0x00ff0000u) != 0;
}
-inline bool ResourceId::is_valid_dynamic() const { return (id & 0x00ff0000u) != 0; }
+inline bool ResourceId::is_valid_dynamic() const {
+ return (id & 0x00ff0000u) != 0;
+}
inline uint8_t ResourceId::package_id() const {
return static_cast<uint8_t>(id >> 24);
@@ -259,24 +264,16 @@ inline bool operator!=(const ResourceId& lhs, const ResourceId& rhs) {
return lhs.id != rhs.id;
}
-inline ::std::ostream& operator<<(::std::ostream& out,
- const ResourceId& res_id) {
- std::ios_base::fmtflags old_flags = out.flags();
- char old_fill = out.fill();
- out << "0x" << std::internal << std::setfill('0') << std::setw(8) << std::hex
- << res_id.id;
- out.flags(old_flags);
- out.fill(old_fill);
- return out;
+inline ::std::ostream& operator<<(::std::ostream& out, const ResourceId& res_id) {
+ return out << res_id.to_string();
}
//
// ResourceType implementation.
//
-inline ::std::ostream& operator<<(::std::ostream& out,
- const ResourceType& val) {
- return out << ToString(val);
+inline ::std::ostream& operator<<(::std::ostream& out, const ResourceType& val) {
+ return out << to_string(val);
}
//
@@ -315,18 +312,8 @@ inline bool operator!=(const ResourceName& lhs, const ResourceName& rhs) {
std::tie(rhs.package, rhs.type, rhs.entry);
}
-inline ::std::ostream& operator<<(::std::ostream& out,
- const ResourceName& name) {
- if (!name.package.empty()) {
- out << name.package << ":";
- }
- return out << name.type << "/" << name.entry;
-}
-
-inline std::string ResourceName::ToString() const {
- std::stringstream stream;
- stream << *this;
- return stream.str();
+inline ::std::ostream& operator<<(::std::ostream& out, const ResourceName& name) {
+ return out << name.to_string();
}
//
@@ -370,12 +357,8 @@ inline bool operator!=(const ResourceNameRef& lhs, const ResourceNameRef& rhs) {
std::tie(rhs.package, rhs.type, rhs.entry);
}
-inline ::std::ostream& operator<<(::std::ostream& out,
- const ResourceNameRef& name) {
- if (!name.package.empty()) {
- out << name.package << ":";
- }
- return out << name.type << "/" << name.entry;
+inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNameRef& name) {
+ return out << name.to_string();
}
inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
@@ -386,8 +369,7 @@ inline bool operator!=(const ResourceName& lhs, const ResourceNameRef& rhs) {
return ResourceNameRef(lhs) != rhs;
}
-inline bool operator==(const SourcedResourceName& lhs,
- const SourcedResourceName& rhs) {
+inline bool operator==(const SourcedResourceName& lhs, const SourcedResourceName& rhs) {
return lhs.name == rhs.name && lhs.line == rhs.line;
}
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index 082fd86604da..a782cd3672d1 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -17,9 +17,12 @@
#include "ResourceValues.h"
#include <algorithm>
+#include <cinttypes>
#include <limits>
#include <set>
+#include <sstream>
+#include "android-base/stringprintf.h"
#include "androidfw/ResourceTypes.h"
#include "Resource.h"
@@ -27,8 +30,18 @@
#include "ValueVisitor.h"
#include "util/Util.h"
+using ::aapt::text::Printer;
+using ::android::StringPiece;
+using ::android::base::StringPrintf;
+
namespace aapt {
+void Value::PrettyPrint(Printer* printer) const {
+ std::ostringstream str_stream;
+ Print(&str_stream);
+ printer->Print(str_stream.str());
+}
+
std::ostream& operator<<(std::ostream& out, const Value& value) {
value.Print(&out);
return out;
@@ -105,7 +118,7 @@ bool Reference::Equals(const Value* value) const {
bool Reference::Flatten(android::Res_value* out_value) const {
const ResourceId resid = id.value_or_default(ResourceId(0));
const bool dynamic = resid.is_valid_dynamic() && resid.package_id() != kFrameworkPackageId &&
- resid.package_id() != kAppPackageId;
+ resid.package_id() < kAppPackageId;
if (reference_type == Reference::Type::kResource) {
if (dynamic) {
@@ -155,6 +168,49 @@ void Reference::Print(std::ostream* out) const {
}
}
+static void PrettyPrintReferenceImpl(const Reference& ref, bool print_package, Printer* printer) {
+ switch (ref.reference_type) {
+ case Reference::Type::kResource:
+ printer->Print("@");
+ break;
+
+ case Reference::Type::kAttribute:
+ printer->Print("?");
+ break;
+ }
+
+ if (!ref.name && !ref.id) {
+ printer->Print("null");
+ return;
+ }
+
+ if (ref.private_reference) {
+ printer->Print("*");
+ }
+
+ if (ref.name) {
+ const ResourceName& name = ref.name.value();
+ if (print_package) {
+ printer->Print(name.to_string());
+ } else {
+ printer->Print(to_string(name.type));
+ printer->Print("/");
+ printer->Print(name.entry);
+ }
+ } else if (ref.id && ref.id.value().is_valid_dynamic()) {
+ printer->Print(ref.id.value().to_string());
+ }
+}
+
+void Reference::PrettyPrint(Printer* printer) const {
+ PrettyPrintReferenceImpl(*this, true /*print_package*/, printer);
+}
+
+void Reference::PrettyPrint(const StringPiece& package, Printer* printer) const {
+ const bool print_package = name ? package != name.value().package : true;
+ PrettyPrintReferenceImpl(*this, print_package, printer);
+}
+
bool Id::Equals(const Value* value) const {
return ValueCast<Id>(value) != nullptr;
}
@@ -165,11 +221,16 @@ bool Id::Flatten(android::Res_value* out) const {
return true;
}
-Id* Id::Clone(StringPool* /*new_pool*/) const { return new Id(*this); }
+Id* Id::Clone(StringPool* /*new_pool*/) const {
+ return new Id(*this);
+}
-void Id::Print(std::ostream* out) const { *out << "(id)"; }
+void Id::Print(std::ostream* out) const {
+ *out << "(id)";
+}
-String::String(const StringPool::Ref& ref) : value(ref) {}
+String::String(const StringPool::Ref& ref) : value(ref) {
+}
bool String::Equals(const Value* value) const {
const String* other = ValueCast<String>(value);
@@ -218,7 +279,14 @@ void String::Print(std::ostream* out) const {
*out << "(string) \"" << *value << "\"";
}
-StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {}
+void String::PrettyPrint(Printer* printer) const {
+ printer->Print("\"");
+ printer->Print(*value);
+ printer->Print("\"");
+}
+
+StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
+}
bool StyledString::Equals(const Value* value) const {
const StyledString* other = ValueCast<StyledString>(value);
@@ -269,7 +337,8 @@ void StyledString::Print(std::ostream* out) const {
}
}
-FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {}
+FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {
+}
bool FileReference::Equals(const Value* value) const {
const FileReference* other = ValueCast<FileReference>(value);
@@ -302,7 +371,8 @@ void FileReference::Print(std::ostream* out) const {
*out << "(file) " << *path;
}
-BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {}
+BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {
+}
BinaryPrimitive::BinaryPrimitive(uint8_t dataType, uint32_t data) {
value.dataType = dataType;
@@ -318,7 +388,7 @@ bool BinaryPrimitive::Equals(const Value* value) const {
this->value.data == other->value.data;
}
-bool BinaryPrimitive::Flatten(android::Res_value* out_value) const {
+bool BinaryPrimitive::Flatten(::android::Res_value* out_value) const {
out_value->dataType = value.dataType;
out_value->data = util::HostToDevice32(value.data);
return true;
@@ -329,32 +399,110 @@ BinaryPrimitive* BinaryPrimitive::Clone(StringPool* /*new_pool*/) const {
}
void BinaryPrimitive::Print(std::ostream* out) const {
+ *out << StringPrintf("(primitive) type=0x%02x data=0x%08x", value.dataType, value.data);
+}
+
+static std::string ComplexToString(uint32_t complex_value, bool fraction) {
+ using ::android::Res_value;
+
+ constexpr std::array<int, 4> kRadixShifts = {{23, 16, 8, 0}};
+
+ // Determine the radix that was used.
+ const uint32_t radix =
+ (complex_value >> Res_value::COMPLEX_RADIX_SHIFT) & Res_value::COMPLEX_RADIX_MASK;
+ const uint64_t mantissa = uint64_t{(complex_value >> Res_value::COMPLEX_MANTISSA_SHIFT) &
+ Res_value::COMPLEX_MANTISSA_MASK}
+ << kRadixShifts[radix];
+ const float value = mantissa * (1.0f / (1 << 23));
+
+ std::string str = StringPrintf("%f", value);
+
+ const int unit_type =
+ (complex_value >> Res_value::COMPLEX_UNIT_SHIFT) & Res_value::COMPLEX_UNIT_MASK;
+ if (fraction) {
+ switch (unit_type) {
+ case Res_value::COMPLEX_UNIT_FRACTION:
+ str += "%";
+ break;
+ case Res_value::COMPLEX_UNIT_FRACTION_PARENT:
+ str += "%p";
+ break;
+ default:
+ str += "???";
+ break;
+ }
+ } else {
+ switch (unit_type) {
+ case Res_value::COMPLEX_UNIT_PX:
+ str += "px";
+ break;
+ case Res_value::COMPLEX_UNIT_DIP:
+ str += "dp";
+ break;
+ case Res_value::COMPLEX_UNIT_SP:
+ str += "sp";
+ break;
+ case Res_value::COMPLEX_UNIT_PT:
+ str += "pt";
+ break;
+ case Res_value::COMPLEX_UNIT_IN:
+ str += "in";
+ break;
+ case Res_value::COMPLEX_UNIT_MM:
+ str += "mm";
+ break;
+ default:
+ str += "???";
+ break;
+ }
+ }
+ return str;
+}
+
+void BinaryPrimitive::PrettyPrint(Printer* printer) const {
+ using ::android::Res_value;
switch (value.dataType) {
- case android::Res_value::TYPE_NULL:
- if (value.data == android::Res_value::DATA_NULL_EMPTY) {
- *out << "(empty)";
+ case Res_value::TYPE_NULL:
+ if (value.data == Res_value::DATA_NULL_EMPTY) {
+ printer->Print("@empty");
} else {
- *out << "(null)";
+ printer->Print("@null");
}
break;
- case android::Res_value::TYPE_INT_DEC:
- *out << "(integer) " << static_cast<int32_t>(value.data);
+
+ case Res_value::TYPE_INT_DEC:
+ printer->Print(StringPrintf("%" PRIi32, static_cast<int32_t>(value.data)));
+ break;
+
+ case Res_value::TYPE_INT_HEX:
+ printer->Print(StringPrintf("0x%08x", value.data));
+ break;
+
+ case Res_value::TYPE_INT_BOOLEAN:
+ printer->Print(value.data != 0 ? "true" : "false");
+ break;
+
+ case Res_value::TYPE_INT_COLOR_ARGB8:
+ case Res_value::TYPE_INT_COLOR_RGB8:
+ case Res_value::TYPE_INT_COLOR_ARGB4:
+ case Res_value::TYPE_INT_COLOR_RGB4:
+ printer->Print(StringPrintf("#%08x", value.data));
break;
- case android::Res_value::TYPE_INT_HEX:
- *out << "(integer) 0x" << std::hex << value.data << std::dec;
+
+ case Res_value::TYPE_FLOAT:
+ printer->Print(StringPrintf("%g", *reinterpret_cast<const float*>(&value.data)));
break;
- case android::Res_value::TYPE_INT_BOOLEAN:
- *out << "(boolean) " << (value.data != 0 ? "true" : "false");
+
+ case Res_value::TYPE_DIMENSION:
+ printer->Print(ComplexToString(value.data, false /*fraction*/));
break;
- case android::Res_value::TYPE_INT_COLOR_ARGB8:
- case android::Res_value::TYPE_INT_COLOR_RGB8:
- case android::Res_value::TYPE_INT_COLOR_ARGB4:
- case android::Res_value::TYPE_INT_COLOR_RGB4:
- *out << "(color) #" << std::hex << value.data << std::dec;
+
+ case Res_value::TYPE_FRACTION:
+ printer->Print(ComplexToString(value.data, true /*fraction*/));
break;
+
default:
- *out << "(unknown 0x" << std::hex << (int)value.dataType << ") 0x"
- << std::hex << value.data << std::dec;
+ printer->Print(StringPrintf("(unknown 0x%02x) 0x%08x", value.dataType, value.data));
break;
}
}
@@ -424,107 +572,107 @@ Attribute* Attribute::Clone(StringPool* /*new_pool*/) const {
return new Attribute(*this);
}
-void Attribute::PrintMask(std::ostream* out) const {
+std::string Attribute::MaskString() const {
if (type_mask == android::ResTable_map::TYPE_ANY) {
- *out << "any";
- return;
+ return "any";
}
+ std::ostringstream out;
bool set = false;
if ((type_mask & android::ResTable_map::TYPE_REFERENCE) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "reference";
+ out << "reference";
}
if ((type_mask & android::ResTable_map::TYPE_STRING) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "string";
+ out << "string";
}
if ((type_mask & android::ResTable_map::TYPE_INTEGER) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "integer";
+ out << "integer";
}
if ((type_mask & android::ResTable_map::TYPE_BOOLEAN) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "boolean";
+ out << "boolean";
}
if ((type_mask & android::ResTable_map::TYPE_COLOR) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "color";
+ out << "color";
}
if ((type_mask & android::ResTable_map::TYPE_FLOAT) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "float";
+ out << "float";
}
if ((type_mask & android::ResTable_map::TYPE_DIMENSION) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "dimension";
+ out << "dimension";
}
if ((type_mask & android::ResTable_map::TYPE_FRACTION) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "fraction";
+ out << "fraction";
}
if ((type_mask & android::ResTable_map::TYPE_ENUM) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "enum";
+ out << "enum";
}
if ((type_mask & android::ResTable_map::TYPE_FLAGS) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "flags";
+ out << "flags";
}
+ return out.str();
}
void Attribute::Print(std::ostream* out) const {
- *out << "(attr) ";
- PrintMask(out);
+ *out << "(attr) " << MaskString();
if (!symbols.empty()) {
*out << " [" << util::Joiner(symbols, ", ") << "]";
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index fd242a109006..b2ec8bdd7c77 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -29,6 +29,7 @@
#include "Resource.h"
#include "StringPool.h"
#include "io/File.h"
+#include "text/Printer.h"
#include "util/Maybe.h"
namespace aapt {
@@ -106,6 +107,10 @@ class Value {
// Human readable printout of this value.
virtual void Print(std::ostream* out) const = 0;
+ // Human readable printout of this value that may omit some information for the sake
+ // of brevity and readability. Default implementation just calls Print().
+ virtual void PrettyPrint(text::Printer* printer) const;
+
friend std::ostream& operator<<(std::ostream& out, const Value& value);
protected:
@@ -162,6 +167,10 @@ struct Reference : public BaseItem<Reference> {
bool Flatten(android::Res_value* out_value) const override;
Reference* Clone(StringPool* new_pool) const override;
void Print(std::ostream* out) const override;
+ void PrettyPrint(text::Printer* printer) const override;
+
+ // Prints the reference without a package name if the package name matches the one given.
+ void PrettyPrint(const android::StringPiece& package, text::Printer* printer) const;
};
bool operator<(const Reference&, const Reference&);
@@ -224,6 +233,7 @@ struct String : public BaseItem<String> {
bool Flatten(android::Res_value* out_value) const override;
String* Clone(StringPool* new_pool) const override;
void Print(std::ostream* out) const override;
+ void PrettyPrint(text::Printer* printer) const override;
};
struct StyledString : public BaseItem<StyledString> {
@@ -274,6 +284,7 @@ struct BinaryPrimitive : public BaseItem<BinaryPrimitive> {
bool Flatten(android::Res_value* out_value) const override;
BinaryPrimitive* Clone(StringPool* new_pool) const override;
void Print(std::ostream* out) const override;
+ void PrettyPrint(text::Printer* printer) const override;
};
struct Attribute : public BaseValue<Attribute> {
@@ -294,7 +305,7 @@ struct Attribute : public BaseValue<Attribute> {
bool Equals(const Value* value) const override;
Attribute* Clone(StringPool* new_pool) const override;
- void PrintMask(std::ostream* out) const;
+ std::string MaskString() const;
void Print(std::ostream* out) const override;
bool Matches(const Item& item, DiagMessage* out_msg = nullptr) const;
};
diff --git a/tools/aapt2/Source.h b/tools/aapt2/Source.h
index d7f2a668477c..0f312d6998f1 100644
--- a/tools/aapt2/Source.h
+++ b/tools/aapt2/Source.h
@@ -20,16 +20,14 @@
#include <ostream>
#include <string>
+#include "android-base/stringprintf.h"
#include "androidfw/StringPiece.h"
#include "util/Maybe.h"
namespace aapt {
-/**
- * Represents a file on disk. Used for logging and
- * showing errors.
- */
+// Represents a file on disk. Used for logging and showing errors.
struct Source {
std::string path;
Maybe<size_t> line;
@@ -42,7 +40,16 @@ struct Source {
inline Source(const android::StringPiece& path, size_t line)
: path(path.to_string()), line(line) {}
- inline Source WithLine(size_t line) const { return Source(path, line); }
+ inline Source WithLine(size_t line) const {
+ return Source(path, line);
+ }
+
+ std::string to_string() const {
+ if (line) {
+ return ::android::base::StringPrintf("%s:%zd", path.c_str(), line.value());
+ }
+ return path;
+ }
};
//
@@ -50,11 +57,7 @@ struct Source {
//
inline ::std::ostream& operator<<(::std::ostream& out, const Source& source) {
- out << source.path;
- if (source.line) {
- out << ":" << source.line.value();
- }
- return out;
+ return out << source.to_string();
}
inline bool operator==(const Source& lhs, const Source& rhs) {
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 53910afff593..83512b9126da 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -674,7 +674,7 @@ int Compile(const std::vector<StringPiece>& args, IDiagnostics* diagnostics) {
// Determine how to compile the file based on its type.
auto compile_func = &CompileFile;
- if (path_data.resource_dir == "values") {
+ if (path_data.resource_dir == "values" && path_data.extension == "xml") {
compile_func = &CompileTable;
// We use a different extension (not necessary anymore, but avoids altering the existing
// build system logic).
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
new file mode 100644
index 000000000000..2bd2405612e3
--- /dev/null
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <vector>
+
+#include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
+
+#include "Flags.h"
+#include "LoadedApk.h"
+#include "ValueVisitor.h"
+#include "cmd/Util.h"
+#include "format/binary/TableFlattener.h"
+#include "format/binary/XmlFlattener.h"
+#include "format/proto/ProtoDeserialize.h"
+#include "format/proto/ProtoSerialize.h"
+#include "io/BigBufferStream.h"
+#include "io/Util.h"
+#include "process/IResourceTableConsumer.h"
+#include "process/SymbolTable.h"
+#include "util/Util.h"
+
+using ::android::StringPiece;
+using ::android::base::StringPrintf;
+using ::std::unique_ptr;
+using ::std::vector;
+
+namespace aapt {
+
+class IApkSerializer {
+ public:
+ IApkSerializer(IAaptContext* context, const Source& source) : context_(context), source_(source) {}
+
+ virtual bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
+ IArchiveWriter* writer) = 0;
+ virtual bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) = 0;
+ virtual bool SerializeFile(const FileReference* file, IArchiveWriter* writer) = 0;
+
+ virtual ~IApkSerializer() = default;
+
+ protected:
+ IAaptContext* context_;
+ Source source_;
+};
+
+bool ConvertApk(IAaptContext* context, unique_ptr<LoadedApk> apk, IApkSerializer* serializer,
+ IArchiveWriter* writer) {
+ if (!serializer->SerializeXml(apk->GetManifest(), kAndroidManifestPath, true /*utf16*/, writer)) {
+ context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ << "failed to serialize AndroidManifest.xml");
+ return false;
+ }
+
+ // 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
+
+ // Other files
+ std::unique_ptr<io::IFileCollectionIterator> iterator = apk->GetFileCollection()->Iterator();
+ while (iterator->HasNext()) {
+ io::IFile* file = iterator->Next();
+
+ std::string path = file->GetSource().path;
+ // The name of the path has the format "<zip-file-name>@<path-to-file>".
+ path = path.substr(path.find('@') + 1);
+
+ // Manifest, resource table and resources have already been taken care of.
+ if (path == kAndroidManifestPath ||
+ path == kApkResourceTablePath ||
+ path == kProtoResourceTablePath ||
+ path.find("res/") == 0) {
+ continue;
+ }
+
+ if (!io::CopyFileToArchivePreserveCompression(context, file, path, writer)) {
+ context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ << "failed to copy file " << path);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+class BinaryApkSerializer : public IApkSerializer {
+ public:
+ BinaryApkSerializer(IAaptContext* context, const Source& source,
+ const TableFlattenerOptions& options)
+ : IApkSerializer(context, source), tableFlattenerOptions_(options) {}
+
+ bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
+ IArchiveWriter* writer) override {
+ BigBuffer buffer(4096);
+ XmlFlattenerOptions options = {};
+ options.use_utf16 = utf16;
+ XmlFlattener flattener(&buffer, options);
+ if (!flattener.Consume(context_, xml)) {
+ return false;
+ }
+
+ io::BigBufferInputStream input_stream(&buffer);
+ return io::CopyInputStreamToArchive(context_, &input_stream, path, ArchiveEntry::kCompress,
+ writer);
+ }
+
+ bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) override {
+ BigBuffer buffer(4096);
+ TableFlattener table_flattener(tableFlattenerOptions_, &buffer);
+ if (!table_flattener.Consume(context_, table)) {
+ return false;
+ }
+
+ io::BigBufferInputStream input_stream(&buffer);
+ return io::CopyInputStreamToArchive(context_, &input_stream, kApkResourceTablePath,
+ ArchiveEntry::kAlign, writer);
+ }
+
+ bool SerializeFile(const FileReference* file, IArchiveWriter* writer) override {
+ if (file->type == ResourceFile::Type::kProtoXml) {
+ unique_ptr<io::InputStream> in = file->file->OpenInputStream();
+ if (in == nullptr) {
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << "failed to open file " << *file->path);
+ return false;
+ }
+
+ pb::XmlNode pb_node;
+ io::ZeroCopyInputAdaptor adaptor(in.get());
+ if (!pb_node.ParseFromZeroCopyStream(&adaptor)) {
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << "failed to parse proto XML " << *file->path);
+ return false;
+ }
+
+ std::string error;
+ unique_ptr<xml::XmlResource> xml = DeserializeXmlResourceFromPb(pb_node, &error);
+ if (xml == nullptr) {
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << "failed to deserialize proto XML "
+ << *file->path << ": " << error);
+ return false;
+ }
+
+ if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer)) {
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << "failed to serialize to binary XML: " << *file->path);
+ return false;
+ }
+ } else {
+ if (!io::CopyFileToArchivePreserveCompression(context_, file->file, *file->path, writer)) {
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << "failed to copy file " << *file->path);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private:
+ TableFlattenerOptions tableFlattenerOptions_;
+
+ DISALLOW_COPY_AND_ASSIGN(BinaryApkSerializer);
+};
+
+class ProtoApkSerializer : public IApkSerializer {
+ public:
+ ProtoApkSerializer(IAaptContext* context, const Source& source)
+ : IApkSerializer(context, source) {}
+
+ bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
+ IArchiveWriter* writer) override {
+ pb::XmlNode pb_node;
+ SerializeXmlResourceToPb(*xml, &pb_node);
+ return io::CopyProtoToArchive(context_, &pb_node, path, ArchiveEntry::kCompress, writer);
+ }
+
+ bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) override {
+ pb::ResourceTable pb_table;
+ SerializeTableToPb(*table, &pb_table);
+ return io::CopyProtoToArchive(context_, &pb_table, kProtoResourceTablePath,
+ ArchiveEntry::kCompress, writer);
+ }
+
+ bool SerializeFile(const FileReference* file, IArchiveWriter* writer) override {
+ if (file->type == ResourceFile::Type::kBinaryXml) {
+ std::unique_ptr<io::IData> data = file->file->OpenAsData();
+ if (!data) {
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << "failed to open file " << *file->path);
+ return false;
+ }
+
+ std::string error;
+ std::unique_ptr<xml::XmlResource> xml = xml::Inflate(data->data(), data->size(), &error);
+ if (xml == nullptr) {
+ context_->GetDiagnostics()->Error(DiagMessage(source_) << "failed to parse binary XML: "
+ << error);
+ return false;
+ }
+
+ if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer)) {
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << "failed to serialize to proto XML: " << *file->path);
+ return false;
+ }
+ } else {
+ if (!io::CopyFileToArchivePreserveCompression(context_, file->file, *file->path, writer)) {
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << "failed to copy file " << *file->path);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProtoApkSerializer);
+};
+
+class Context : public IAaptContext {
+ public:
+ Context() : mangler_({}), symbols_(&mangler_) {
+ }
+
+ PackageType GetPackageType() override {
+ return PackageType::kApp;
+ }
+
+ SymbolTable* GetExternalSymbols() override {
+ return &symbols_;
+ }
+
+ IDiagnostics* GetDiagnostics() override {
+ return &diag_;
+ }
+
+ const std::string& GetCompilationPackage() override {
+ return package_;
+ }
+
+ uint8_t GetPackageId() override {
+ // Nothing should call this.
+ UNIMPLEMENTED(FATAL) << "PackageID should not be necessary";
+ return 0;
+ }
+
+ NameMangler* GetNameMangler() override {
+ UNIMPLEMENTED(FATAL);
+ return nullptr;
+ }
+
+ bool IsVerbose() override {
+ return verbose_;
+ }
+
+ int GetMinSdkVersion() override {
+ return 0u;
+ }
+
+ bool verbose_ = false;
+ std::string package_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Context);
+
+ NameMangler mangler_;
+ SymbolTable symbols_;
+ StdErrDiagnostics diag_;
+};
+
+int Convert(const vector<StringPiece>& args) {
+
+ static const char* kOutputFormatProto = "proto";
+ static const char* kOutputFormatBinary = "binary";
+
+ Context context;
+ std::string output_path;
+ Maybe<std::string> output_format;
+ TableFlattenerOptions options;
+ Flags flags =
+ Flags()
+ .RequiredFlag("-o", "Output path", &output_path)
+ .OptionalFlag("--output-format", StringPrintf("Format of the output. Accepted values are "
+ "'%s' and '%s'. When not set, defaults to '%s'.", kOutputFormatProto,
+ kOutputFormatBinary, kOutputFormatBinary), &output_format)
+ .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.use_sparse_entries)
+ .OptionalSwitch("-v", "Enables verbose logging", &context.verbose_);
+ if (!flags.Parse("aapt2 convert", args, &std::cerr)) {
+ return 1;
+ }
+
+ if (flags.GetArgs().size() != 1) {
+ std::cerr << "must supply a single proto APK\n";
+ flags.Usage("aapt2 convert", &std::cerr);
+ return 1;
+ }
+
+ const StringPiece& path = flags.GetArgs()[0];
+ unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(path, context.GetDiagnostics());
+ if (apk == nullptr) {
+ context.GetDiagnostics()->Error(DiagMessage(path) << "failed to load APK");
+ return 1;
+ }
+
+ Maybe<AppInfo> app_info =
+ ExtractAppInfoFromBinaryManifest(*apk->GetManifest(), context.GetDiagnostics());
+ if (!app_info) {
+ return 1;
+ }
+
+ context.package_ = app_info.value().package;
+
+ unique_ptr<IArchiveWriter> writer =
+ CreateZipFileArchiveWriter(context.GetDiagnostics(), output_path);
+ if (writer == nullptr) {
+ return 1;
+ }
+
+ unique_ptr<IApkSerializer> serializer;
+ if (!output_format || output_format.value() == kOutputFormatBinary) {
+ serializer.reset(new BinaryApkSerializer(&context, apk->GetSource(), options));
+ } else if (output_format.value() == kOutputFormatProto) {
+ serializer.reset(new ProtoApkSerializer(&context, apk->GetSource()));
+ } else {
+ context.GetDiagnostics()->Error(DiagMessage(path)
+ << "Invalid value for flag --output-format: "
+ << output_format.value());
+ return 1;
+ }
+
+
+ return ConvertApk(&context, std::move(apk), serializer.get(), writer.get()) ? 0 : 1;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp
index 625c47cec939..fc1f1d6342ae 100644
--- a/tools/aapt2/cmd/Diff.cpp
+++ b/tools/aapt2/cmd/Diff.cpp
@@ -357,8 +357,9 @@ int Diff(const std::vector<StringPiece>& args) {
return 1;
}
- std::unique_ptr<LoadedApk> apk_a = LoadedApk::LoadApkFromPath(&context, flags.GetArgs()[0]);
- std::unique_ptr<LoadedApk> apk_b = LoadedApk::LoadApkFromPath(&context, flags.GetArgs()[1]);
+ IDiagnostics* diag = context.GetDiagnostics();
+ std::unique_ptr<LoadedApk> apk_a = LoadedApk::LoadApkFromPath(flags.GetArgs()[0], diag);
+ std::unique_ptr<LoadedApk> apk_b = LoadedApk::LoadApkFromPath(flags.GetArgs()[1], diag);
if (!apk_a || !apk_b) {
return 1;
}
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 090c3fbc5731..bc7f5a86b043 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -14,8 +14,10 @@
* limitations under the License.
*/
+#include <cinttypes>
#include <vector>
+#include "android-base/stringprintf.h"
#include "androidfw/StringPiece.h"
#include "Debug.h"
@@ -27,9 +29,12 @@
#include "io/FileStream.h"
#include "io/ZipArchive.h"
#include "process/IResourceTableConsumer.h"
+#include "text/Printer.h"
#include "util/Files.h"
+using ::aapt::text::Printer;
using ::android::StringPiece;
+using ::android::base::StringPrintf;
namespace aapt {
@@ -48,16 +53,28 @@ static const char* ResourceFileTypeToString(const ResourceFile::Type& type) {
}
static void DumpCompiledFile(const ResourceFile& file, const Source& source, off64_t offset,
- size_t len) {
- std::cout << "Resource: " << file.name << "\n"
- << "Config: " << file.config << "\n"
- << "Source: " << file.source << "\n"
- << "Type: " << ResourceFileTypeToString(file.type) << "\n"
- << "DataOff: " << offset << "\n"
- << "DataLen: " << len << "\n";
+ size_t len, Printer* printer) {
+ printer->Print("Resource: ");
+ printer->Println(file.name.to_string());
+
+ printer->Print("Config: ");
+ printer->Println(file.config.to_string());
+
+ printer->Print("Source: ");
+ printer->Println(file.source.to_string());
+
+ printer->Print("Type: ");
+ printer->Println(ResourceFileTypeToString(file.type));
+
+ printer->Println(StringPrintf("Data: offset=%" PRIi64 " length=%zd", offset, len));
}
static bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
+ // Use a smaller buffer so that there is less latency for dumping to stdout.
+ constexpr size_t kStdOutBufferSize = 1024u;
+ io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
+ Printer printer(&fout);
+
DebugPrintTableOptions print_options;
print_options.show_sources = true;
@@ -78,11 +95,13 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
return false;
}
- if (!DeserializeTableFromPb(pb_table, &table, &err)) {
+ if (!DeserializeTableFromPb(pb_table, zip.get(), &table, &err)) {
context->GetDiagnostics()->Error(DiagMessage(file_path)
<< "failed to parse table: " << err);
return false;
}
+
+ printer.Println("Proto APK");
} else if (io::IFile* file = zip->FindFile("resources.arsc")) {
std::unique_ptr<io::IData> data = file->OpenAsData();
if (!data) {
@@ -90,13 +109,16 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
return false;
}
- BinaryResourceParser parser(context, &table, Source(file_path), data->data(), data->size());
+ BinaryResourceParser parser(context->GetDiagnostics(), &table, Source(file_path),
+ data->data(), data->size());
if (!parser.Parse()) {
return false;
}
+
+ printer.Println("Binary APK");
}
- Debug::PrintTable(table, print_options);
+ Debug::PrintTable(table, print_options, &printer);
return true;
}
@@ -117,9 +139,12 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
return false;
}
+ printer.Println("AAPT2 Container (APC)");
ContainerReaderEntry* entry;
while ((entry = reader.Next()) != nullptr) {
if (entry->Type() == ContainerEntryType::kResTable) {
+ printer.Println("kResTable");
+
pb::ResourceTable pb_table;
if (!entry->GetResTable(&pb_table)) {
context->GetDiagnostics()->Error(DiagMessage(file_path)
@@ -129,14 +154,17 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
ResourceTable table;
err.clear();
- if (!DeserializeTableFromPb(pb_table, &table, &err)) {
+ if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &err)) {
context->GetDiagnostics()->Error(DiagMessage(file_path)
<< "failed to parse table: " << err);
continue;
}
- Debug::PrintTable(table, print_options);
+ printer.Indent();
+ Debug::PrintTable(table, print_options, &printer);
+ printer.Undent();
} else if (entry->Type() == ContainerEntryType::kResFile) {
+ printer.Println("kResFile");
pb::internal::CompiledFile pb_compiled_file;
off64_t offset;
size_t length;
@@ -154,7 +182,9 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
continue;
}
- DumpCompiledFile(file, Source(file_path), offset, length);
+ printer.Indent();
+ DumpCompiledFile(file, Source(file_path), offset, length, &printer);
+ printer.Undent();
}
}
return true;
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index e0dae1b7ed4e..66b5a7af3677 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -29,6 +29,7 @@
#include "AppInfo.h"
#include "Debug.h"
#include "Flags.h"
+#include "LoadedApk.h"
#include "Locale.h"
#include "NameMangler.h"
#include "ResourceUtils.h"
@@ -39,7 +40,6 @@
#include "filter/ConfigFilter.h"
#include "format/Archive.h"
#include "format/Container.h"
-#include "format/binary/BinaryResourceParser.h"
#include "format/binary/TableFlattener.h"
#include "format/binary/XmlFlattener.h"
#include "format/proto/ProtoDeserialize.h"
@@ -71,9 +71,6 @@ using ::android::base::StringPrintf;
namespace aapt {
-constexpr static const char kApkResourceTablePath[] = "resources.arsc";
-constexpr static const char kProtoResourceTablePath[] = "resources.pb";
-
enum class OutputFormat {
kApk,
kProto,
@@ -298,23 +295,6 @@ static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml_res,
return false;
}
-static std::unique_ptr<ResourceTable> LoadTableFromPb(const Source& source, const void* data,
- size_t len, IDiagnostics* diag) {
- pb::ResourceTable pb_table;
- if (!pb_table.ParseFromArray(data, len)) {
- diag->Error(DiagMessage(source) << "invalid compiled table");
- return {};
- }
-
- std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
- std::string error;
- if (!DeserializeTableFromPb(pb_table, table.get(), &error)) {
- diag->Error(DiagMessage(source) << "invalid compiled table: " << error);
- return {};
- }
- return table;
-}
-
// Inflates an XML file from the source path.
static std::unique_ptr<xml::XmlResource> LoadXml(const std::string& path, IDiagnostics* diag) {
FileInputStream fin(path);
@@ -587,7 +567,7 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
pb::XmlNode pb_xml_node;
if (!pb_xml_node.ParseFromArray(data->data(), static_cast<int>(data->size()))) {
context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
- << "failed to parse proto xml");
+ << "failed to parse proto XML");
return false;
}
@@ -595,13 +575,15 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
file_op.xml_to_flatten = DeserializeXmlResourceFromPb(pb_xml_node, &error);
if (file_op.xml_to_flatten == nullptr) {
context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
- << "failed to deserialize proto xml: " << error);
+ << "failed to deserialize proto XML: " << error);
return false;
}
} else {
- file_op.xml_to_flatten = xml::Inflate(data->data(), data->size(),
- context_->GetDiagnostics(), file->GetSource());
+ std::string error_str;
+ file_op.xml_to_flatten = xml::Inflate(data->data(), data->size(), &error_str);
if (file_op.xml_to_flatten == nullptr) {
+ context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
+ << "failed to parse binary XML: " << error_str);
return false;
}
}
@@ -748,22 +730,29 @@ class LinkCommand {
file_collection_(util::make_unique<io::FileCollection>()) {
}
- /**
- * Creates a SymbolTable that loads symbols from the various APKs and caches
- * the results for faster lookup.
- */
+ // Creates a SymbolTable that loads symbols from the various APKs.
bool LoadSymbolsFromIncludePaths() {
- std::unique_ptr<AssetManagerSymbolSource> asset_source =
- util::make_unique<AssetManagerSymbolSource>();
+ auto asset_source = util::make_unique<AssetManagerSymbolSource>();
for (const std::string& path : options_.include_paths) {
if (context_->IsVerbose()) {
context_->GetDiagnostics()->Note(DiagMessage() << "including " << path);
}
- // First try to load the file as a static lib.
- std::string error_str;
- std::unique_ptr<ResourceTable> include_static = LoadStaticLibrary(path, &error_str);
- if (include_static) {
+ std::string error;
+ auto zip_collection = io::ZipFileCollection::Create(path, &error);
+ if (zip_collection == nullptr) {
+ context_->GetDiagnostics()->Error(DiagMessage() << "failed to open APK: " << error);
+ return false;
+ }
+
+ if (zip_collection->FindFile(kProtoResourceTablePath) != nullptr) {
+ // Load this as a static library include.
+ std::unique_ptr<LoadedApk> static_apk = LoadedApk::LoadProtoApkFromFileCollection(
+ Source(path), std::move(zip_collection), context_->GetDiagnostics());
+ if (static_apk == nullptr) {
+ return false;
+ }
+
if (context_->GetPackageType() != PackageType::kStaticLib) {
// Can't include static libraries when not building a static library (they have no IDs
// assigned).
@@ -772,13 +761,15 @@ class LinkCommand {
return false;
}
- // If we are using --no-static-lib-packages, we need to rename the
- // package of this table to our compilation package.
+ ResourceTable* table = static_apk->GetResourceTable();
+
+ // If we are using --no-static-lib-packages, we need to rename the package of this table to
+ // our compilation package.
if (options_.no_static_lib_packages) {
// Since package names can differ, and multiple packages can exist in a ResourceTable,
// we place the requirement that all static libraries are built with the package
// ID 0x7f. So if one is not found, this is an error.
- if (ResourceTablePackage* pkg = include_static->FindPackageById(kAppPackageId)) {
+ if (ResourceTablePackage* pkg = table->FindPackageById(kAppPackageId)) {
pkg->name = context_->GetCompilationPackage();
} else {
context_->GetDiagnostics()->Error(DiagMessage(path)
@@ -788,19 +779,14 @@ class LinkCommand {
}
context_->GetExternalSymbols()->AppendSource(
- util::make_unique<ResourceTableSymbolSource>(include_static.get()));
-
- static_table_includes_.push_back(std::move(include_static));
-
- } else if (!error_str.empty()) {
- // We had an error with reading, so fail.
- context_->GetDiagnostics()->Error(DiagMessage(path) << error_str);
- return false;
- }
-
- if (!asset_source->AddAssetPath(path)) {
- context_->GetDiagnostics()->Error(DiagMessage(path) << "failed to load include path");
- return false;
+ util::make_unique<ResourceTableSymbolSource>(table));
+ static_library_includes_.push_back(std::move(static_apk));
+ } else {
+ if (!asset_source->AddAssetPath(path)) {
+ context_->GetDiagnostics()->Error(DiagMessage()
+ << "failed to load include path " << path);
+ return false;
+ }
}
}
@@ -809,6 +795,9 @@ class LinkCommand {
for (auto& entry : asset_source->GetAssignedPackageIds()) {
if (entry.first > kFrameworkPackageId && entry.first < kAppPackageId) {
final_table_.included_packages_[entry.first] = entry.second;
+ } else if (entry.first == kAppPackageId) {
+ // Capture the included base feature package.
+ included_feature_base_ = entry.second;
}
}
@@ -1194,46 +1183,18 @@ class LinkCommand {
return true;
}
- std::unique_ptr<ResourceTable> LoadStaticLibrary(const std::string& input,
- std::string* out_error) {
- std::unique_ptr<io::ZipFileCollection> collection =
- io::ZipFileCollection::Create(input, out_error);
- if (!collection) {
- return {};
- }
- return LoadTablePbFromCollection(collection.get());
- }
-
- std::unique_ptr<ResourceTable> LoadTablePbFromCollection(io::IFileCollection* collection) {
- io::IFile* file = collection->FindFile(kProtoResourceTablePath);
- if (!file) {
- return {};
- }
-
- std::unique_ptr<io::IData> data = file->OpenAsData();
- return LoadTableFromPb(file->GetSource(), data->data(), data->size(),
- context_->GetDiagnostics());
- }
-
bool MergeStaticLibrary(const std::string& input, bool override) {
if (context_->IsVerbose()) {
context_->GetDiagnostics()->Note(DiagMessage() << "merging static library " << input);
}
- std::string error_str;
- std::unique_ptr<io::ZipFileCollection> collection =
- io::ZipFileCollection::Create(input, &error_str);
- if (!collection) {
- context_->GetDiagnostics()->Error(DiagMessage(input) << error_str);
- return false;
- }
-
- std::unique_ptr<ResourceTable> table = LoadTablePbFromCollection(collection.get());
- if (!table) {
+ std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(input, context_->GetDiagnostics());
+ if (apk == nullptr) {
context_->GetDiagnostics()->Error(DiagMessage(input) << "invalid static library");
return false;
}
+ ResourceTable* table = apk->GetResourceTable();
ResourceTablePackage* pkg = table->FindPackageById(kAppPackageId);
if (!pkg) {
context_->GetDiagnostics()->Error(DiagMessage(input) << "static library has no package");
@@ -1254,13 +1215,12 @@ class LinkCommand {
// Clear the package name, so as to make the resources look like they are coming from the
// local package.
pkg->name = "";
- result = table_merger_->Merge(Source(input), table.get(), override, collection.get());
+ result = table_merger_->Merge(Source(input), table, override);
} else {
// This is the proper way to merge libraries, where the package name is
// preserved and resource names are mangled.
- result =
- table_merger_->MergeAndMangle(Source(input), pkg->name, table.get(), collection.get());
+ result = table_merger_->MergeAndMangle(Source(input), pkg->name, table);
}
if (!result) {
@@ -1268,31 +1228,10 @@ class LinkCommand {
}
// Make sure to move the collection into the set of IFileCollections.
- collections_.push_back(std::move(collection));
+ merged_apks_.push_back(std::move(apk));
return true;
}
- bool MergeResourceTable(io::IFile* file, bool override) {
- if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage() << "merging resource table "
- << file->GetSource());
- }
-
- std::unique_ptr<io::IData> data = file->OpenAsData();
- if (!data) {
- context_->GetDiagnostics()->Error(DiagMessage(file->GetSource()) << "failed to open file");
- return false;
- }
-
- std::unique_ptr<ResourceTable> table =
- LoadTableFromPb(file->GetSource(), data->data(), data->size(), context_->GetDiagnostics());
- if (!table) {
- return false;
- }
-
- return table_merger_->Merge(file->GetSource(), table.get(), override);
- }
-
bool MergeCompiledFile(const ResourceFile& compiled_file, io::IFile* file, bool override) {
if (context_->IsVerbose()) {
context_->GetDiagnostics()->Note(DiagMessage()
@@ -1423,7 +1362,7 @@ class LinkCommand {
ResourceTable table;
std::string error;
- if (!DeserializeTableFromPb(pb_table, &table, &error)) {
+ if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &error)) {
context_->GetDiagnostics()->Error(DiagMessage(src)
<< "failed to deserialize resource table: " << error);
return false;
@@ -1529,11 +1468,48 @@ class LinkCommand {
return false;
}
- if (!FlattenTable(table, options_.output_format, writer)) {
+ // Hack to fix b/68820737.
+ // We need to modify the ResourceTable's package name, but that should NOT affect
+ // anything else being generated, which includes the Java classes.
+ // If required, the package name is modifed before flattening, and then modified back
+ // to its original name.
+ ResourceTablePackage* package_to_rewrite = nullptr;
+ if (context_->GetPackageId() > kAppPackageId &&
+ included_feature_base_ == make_value(context_->GetCompilationPackage())) {
+ // The base APK is included, and this is a feature split. If the base package is
+ // the same as this package, then we are building an old style Android Instant Apps feature
+ // split and must apply this workaround to avoid requiring namespaces support.
+ package_to_rewrite = table->FindPackage(context_->GetCompilationPackage());
+ if (package_to_rewrite != nullptr) {
+ CHECK_EQ(1u, table->packages.size()) << "can't change name of package when > 1 package";
+
+ std::string new_package_name =
+ StringPrintf("%s.%s", package_to_rewrite->name.c_str(),
+ app_info_.split_name.value_or_default("feature").c_str());
+
+ if (context_->IsVerbose()) {
+ context_->GetDiagnostics()->Note(
+ DiagMessage() << "rewriting resource package name for feature split to '"
+ << new_package_name << "'");
+ }
+ package_to_rewrite->name = new_package_name;
+ }
+ }
+
+ bool success = FlattenTable(table, options_.output_format, writer);
+
+ if (package_to_rewrite != nullptr) {
+ // Change the name back.
+ package_to_rewrite->name = context_->GetCompilationPackage();
+ if (package_to_rewrite->id) {
+ table->included_packages_.erase(package_to_rewrite->id.value());
+ }
+ }
+
+ if (!success) {
context_->GetDiagnostics()->Error(DiagMessage() << "failed to write resource table");
- return false;
}
- return true;
+ return success;
}
int Run(const std::vector<std::string>& input_files) {
@@ -1562,8 +1538,8 @@ class LinkCommand {
return 1;
}
- const AppInfo& app_info = maybe_app_info.value();
- context_->SetMinSdkVersion(app_info.min_sdk_version.value_or_default(0));
+ app_info_ = maybe_app_info.value();
+ context_->SetMinSdkVersion(app_info_.min_sdk_version.value_or_default(0));
context_->SetNameManglerPolicy(NameManglerPolicy{context_->GetCompilationPackage()});
@@ -1763,7 +1739,7 @@ class LinkCommand {
// Generate an AndroidManifest.xml for each split.
std::unique_ptr<xml::XmlResource> split_manifest =
- GenerateSplitManifest(app_info, *split_constraints_iter);
+ GenerateSplitManifest(app_info_, *split_constraints_iter);
XmlReferenceLinker linker;
if (!linker.Consume(context_, split_manifest.get())) {
@@ -1863,21 +1839,28 @@ class LinkCommand {
LinkContext* context_;
ResourceTable final_table_;
+ AppInfo app_info_;
+
std::unique_ptr<TableMerger> table_merger_;
// A pointer to the FileCollection representing the filesystem (not archives).
std::unique_ptr<io::FileCollection> file_collection_;
- // A vector of IFileCollections. This is mainly here to keep ownership of the
+ // A vector of IFileCollections. This is mainly here to retain ownership of the
// collections.
std::vector<std::unique_ptr<io::IFileCollection>> collections_;
- // A vector of ResourceTables. This is here to retain ownership, so that the
- // SymbolTable can use these.
- std::vector<std::unique_ptr<ResourceTable>> static_table_includes_;
+ // The set of merged APKs. This is mainly here to retain ownership of the APKs.
+ std::vector<std::unique_ptr<LoadedApk>> merged_apks_;
+
+ // The set of included APKs (not merged). This is mainly here to retain ownership of the APKs.
+ std::vector<std::unique_ptr<LoadedApk>> static_library_includes_;
// The set of shared libraries being used, mapping their assigned package ID to package name.
std::map<size_t, std::string> shared_libs_;
+
+ // The package name of the base application, if it is included.
+ Maybe<std::string> included_feature_base_;
};
int Link(const std::vector<StringPiece>& args, IDiagnostics* diagnostics) {
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 44e148ee9732..2bf91a530526 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -256,10 +256,8 @@ class OptimizeCommand {
for (auto& entry : config_sorted_files) {
FileReference* file_ref = entry.second;
- uint32_t compression_flags =
- file_ref->file->WasCompressed() ? ArchiveEntry::kCompress : 0u;
- if (!io::CopyFileToArchive(context_, file_ref->file, *file_ref->path, compression_flags,
- writer)) {
+ if (!io::CopyFileToArchivePreserveCompression(context_, file_ref->file, *file_ref->path,
+ writer)) {
return false;
}
}
@@ -281,15 +279,14 @@ class OptimizeCommand {
OptimizeContext* context_;
};
-bool ExtractAppDataFromManifest(OptimizeContext* context, LoadedApk* apk,
+bool ExtractAppDataFromManifest(OptimizeContext* context, const LoadedApk* apk,
OptimizeOptions* out_options) {
- std::unique_ptr<xml::XmlResource> manifest = apk->InflateManifest(context);
+ const xml::XmlResource* manifest = apk->GetManifest();
if (manifest == nullptr) {
return false;
}
- Maybe<AppInfo> app_info =
- ExtractAppInfoFromBinaryManifest(manifest.get(), context->GetDiagnostics());
+ Maybe<AppInfo> app_info = ExtractAppInfoFromBinaryManifest(*manifest, context->GetDiagnostics());
if (!app_info) {
context->GetDiagnostics()->Error(DiagMessage()
<< "failed to extract data from AndroidManifest.xml");
@@ -355,7 +352,7 @@ int Optimize(const std::vector<StringPiece>& args) {
}
const std::string& apk_path = flags.GetArgs()[0];
- std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(&context, apk_path);
+ std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(apk_path, context.GetDiagnostics());
if (!apk) {
return 1;
}
diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp
index 708bed80555b..8b3a6701b409 100644
--- a/tools/aapt2/cmd/Util.cpp
+++ b/tools/aapt2/cmd/Util.cpp
@@ -140,12 +140,27 @@ static xml::NamespaceDecl CreateAndroidNamespaceDecl() {
return decl;
}
+// Returns a copy of 'name' which conforms to the regex '[a-zA-Z]+[a-zA-Z0-9_]*' by
+// replacing nonconforming characters with underscores.
+//
+// See frameworks/base/core/java/android/content/pm/PackageParser.java which
+// checks this at runtime.
static std::string MakePackageSafeName(const std::string &name) {
std::string result(name);
+ bool first = true;
for (char &c : result) {
- if (c == '-') {
- c = '_';
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+ first = false;
+ continue;
}
+ if (!first) {
+ if (c >= '0' && c <= '9') {
+ continue;
+ }
+ }
+
+ c = '_';
+ first = false;
}
return result;
}
@@ -214,9 +229,10 @@ std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info,
return doc;
}
-static Maybe<std::string> ExtractCompiledString(xml::Attribute* attr, std::string* out_error) {
- if (attr->compiled_value != nullptr) {
- String* compiled_str = ValueCast<String>(attr->compiled_value.get());
+static Maybe<std::string> ExtractCompiledString(const xml::Attribute& attr,
+ std::string* out_error) {
+ if (attr.compiled_value != nullptr) {
+ const String* compiled_str = ValueCast<String>(attr.compiled_value.get());
if (compiled_str != nullptr) {
if (!compiled_str->value->empty()) {
return *compiled_str->value;
@@ -230,16 +246,16 @@ static Maybe<std::string> ExtractCompiledString(xml::Attribute* attr, std::strin
}
// Fallback to the plain text value if there is one.
- if (!attr->value.empty()) {
- return attr->value;
+ if (!attr.value.empty()) {
+ return attr.value;
}
*out_error = "value is an empty string";
return {};
}
-static Maybe<uint32_t> ExtractCompiledInt(xml::Attribute* attr, std::string* out_error) {
- if (attr->compiled_value != nullptr) {
- BinaryPrimitive* compiled_prim = ValueCast<BinaryPrimitive>(attr->compiled_value.get());
+static Maybe<uint32_t> ExtractCompiledInt(const xml::Attribute& attr, std::string* out_error) {
+ if (attr.compiled_value != nullptr) {
+ const BinaryPrimitive* compiled_prim = ValueCast<BinaryPrimitive>(attr.compiled_value.get());
if (compiled_prim != nullptr) {
if (compiled_prim->value.dataType >= android::Res_value::TYPE_FIRST_INT &&
compiled_prim->value.dataType <= android::Res_value::TYPE_LAST_INT) {
@@ -251,19 +267,19 @@ static Maybe<uint32_t> ExtractCompiledInt(xml::Attribute* attr, std::string* out
}
// Fallback to the plain text value if there is one.
- Maybe<uint32_t> integer = ResourceUtils::ParseInt(attr->value);
+ Maybe<uint32_t> integer = ResourceUtils::ParseInt(attr.value);
if (integer) {
return integer;
}
std::stringstream error_msg;
- error_msg << "'" << attr->value << "' is not a valid integer";
+ error_msg << "'" << attr.value << "' is not a valid integer";
*out_error = error_msg.str();
return {};
}
-static Maybe<int> ExtractSdkVersion(xml::Attribute* attr, std::string* out_error) {
- if (attr->compiled_value != nullptr) {
- BinaryPrimitive* compiled_prim = ValueCast<BinaryPrimitive>(attr->compiled_value.get());
+static Maybe<int> ExtractSdkVersion(const xml::Attribute& attr, std::string* out_error) {
+ if (attr.compiled_value != nullptr) {
+ const BinaryPrimitive* compiled_prim = ValueCast<BinaryPrimitive>(attr.compiled_value.get());
if (compiled_prim != nullptr) {
if (compiled_prim->value.dataType >= android::Res_value::TYPE_FIRST_INT &&
compiled_prim->value.dataType <= android::Res_value::TYPE_LAST_INT) {
@@ -273,7 +289,7 @@ static Maybe<int> ExtractSdkVersion(xml::Attribute* attr, std::string* out_error
return {};
}
- String* compiled_str = ValueCast<String>(attr->compiled_value.get());
+ const String* compiled_str = ValueCast<String>(attr.compiled_value.get());
if (compiled_str != nullptr) {
Maybe<int> sdk_version = ResourceUtils::ParseSdkVersion(*compiled_str->value);
if (sdk_version) {
@@ -288,19 +304,20 @@ static Maybe<int> ExtractSdkVersion(xml::Attribute* attr, std::string* out_error
}
// Fallback to the plain text value if there is one.
- Maybe<int> sdk_version = ResourceUtils::ParseSdkVersion(attr->value);
+ Maybe<int> sdk_version = ResourceUtils::ParseSdkVersion(attr.value);
if (sdk_version) {
return sdk_version;
}
std::stringstream error_msg;
- error_msg << "'" << attr->value << "' is not a valid SDK version";
+ error_msg << "'" << attr.value << "' is not a valid SDK version";
*out_error = error_msg.str();
return {};
}
-Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(xml::XmlResource* xml_res, IDiagnostics* diag) {
+Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res,
+ IDiagnostics* diag) {
// Make sure the first element is <manifest> with package attribute.
- xml::Element* manifest_el = xml_res->root.get();
+ const xml::Element* manifest_el = xml_res.root.get();
if (manifest_el == nullptr) {
return {};
}
@@ -308,63 +325,63 @@ Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(xml::XmlResource* xml_res, IDiag
AppInfo app_info;
if (!manifest_el->namespace_uri.empty() || manifest_el->name != "manifest") {
- diag->Error(DiagMessage(xml_res->file.source) << "root tag must be <manifest>");
+ diag->Error(DiagMessage(xml_res.file.source) << "root tag must be <manifest>");
return {};
}
- xml::Attribute* package_attr = manifest_el->FindAttribute({}, "package");
+ const xml::Attribute* package_attr = manifest_el->FindAttribute({}, "package");
if (!package_attr) {
- diag->Error(DiagMessage(xml_res->file.source) << "<manifest> must have a 'package' attribute");
+ diag->Error(DiagMessage(xml_res.file.source) << "<manifest> must have a 'package' attribute");
return {};
}
std::string error_msg;
- Maybe<std::string> maybe_package = ExtractCompiledString(package_attr, &error_msg);
+ Maybe<std::string> maybe_package = ExtractCompiledString(*package_attr, &error_msg);
if (!maybe_package) {
- diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
+ diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
<< "invalid package name: " << error_msg);
return {};
}
app_info.package = maybe_package.value();
- if (xml::Attribute* version_code_attr =
+ if (const xml::Attribute* version_code_attr =
manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode")) {
- Maybe<uint32_t> maybe_code = ExtractCompiledInt(version_code_attr, &error_msg);
+ Maybe<uint32_t> maybe_code = ExtractCompiledInt(*version_code_attr, &error_msg);
if (!maybe_code) {
- diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
+ diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
<< "invalid android:versionCode: " << error_msg);
return {};
}
app_info.version_code = maybe_code.value();
}
- if (xml::Attribute* revision_code_attr =
+ if (const xml::Attribute* revision_code_attr =
manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) {
- Maybe<uint32_t> maybe_code = ExtractCompiledInt(revision_code_attr, &error_msg);
+ Maybe<uint32_t> maybe_code = ExtractCompiledInt(*revision_code_attr, &error_msg);
if (!maybe_code) {
- diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
+ diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
<< "invalid android:revisionCode: " << error_msg);
return {};
}
app_info.revision_code = maybe_code.value();
}
- if (xml::Attribute* split_name_attr = manifest_el->FindAttribute({}, "split")) {
- Maybe<std::string> maybe_split_name = ExtractCompiledString(split_name_attr, &error_msg);
+ if (const xml::Attribute* split_name_attr = manifest_el->FindAttribute({}, "split")) {
+ Maybe<std::string> maybe_split_name = ExtractCompiledString(*split_name_attr, &error_msg);
if (!maybe_split_name) {
- diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
+ diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
<< "invalid split name: " << error_msg);
return {};
}
app_info.split_name = maybe_split_name.value();
}
- if (xml::Element* uses_sdk_el = manifest_el->FindChild({}, "uses-sdk")) {
- if (xml::Attribute* min_sdk =
+ if (const xml::Element* uses_sdk_el = manifest_el->FindChild({}, "uses-sdk")) {
+ if (const xml::Attribute* min_sdk =
uses_sdk_el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion")) {
- Maybe<int> maybe_sdk = ExtractSdkVersion(min_sdk, &error_msg);
+ Maybe<int> maybe_sdk = ExtractSdkVersion(*min_sdk, &error_msg);
if (!maybe_sdk) {
- diag->Error(DiagMessage(xml_res->file.source.WithLine(uses_sdk_el->line_number))
+ diag->Error(DiagMessage(xml_res.file.source.WithLine(uses_sdk_el->line_number))
<< "invalid android:minSdkVersion: " << error_msg);
return {};
}
diff --git a/tools/aapt2/cmd/Util.h b/tools/aapt2/cmd/Util.h
index fd9b39c67380..7611c1526104 100644
--- a/tools/aapt2/cmd/Util.h
+++ b/tools/aapt2/cmd/Util.h
@@ -57,7 +57,8 @@ std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info,
const SplitConstraints& constraints);
// Extracts relevant info from the AndroidManifest.xml.
-Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(xml::XmlResource* xml_res, IDiagnostics* diag);
+Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res,
+ IDiagnostics* diag);
} // namespace aapt
diff --git a/tools/aapt2/cmd/Util_test.cpp b/tools/aapt2/cmd/Util_test.cpp
index 9c33135f228d..0c527f6a90dc 100644
--- a/tools/aapt2/cmd/Util_test.cpp
+++ b/tools/aapt2/cmd/Util_test.cpp
@@ -24,15 +24,16 @@ namespace aapt {
TEST(UtilTest, SplitNamesAreSanitized) {
AppInfo app_info{"com.pkg"};
- SplitConstraints split_constraints{{test::ParseConfigOrDie("en-rUS-land")}};
+ SplitConstraints split_constraints{
+ {test::ParseConfigOrDie("en-rUS-land"), test::ParseConfigOrDie("b+sr+Latn")}};
const auto doc = GenerateSplitManifest(app_info, split_constraints);
const auto &root = doc->root;
EXPECT_EQ(root->name, "manifest");
- // split names cannot contain hyphens
- EXPECT_EQ(root->FindAttribute("", "split")->value, "config.en_rUS_land");
+ // split names cannot contain hyphens or plus signs.
+ EXPECT_EQ(root->FindAttribute("", "split")->value, "config.b_sr_Latn_en_rUS_land");
// but we should use resource qualifiers verbatim in 'targetConfig'.
- EXPECT_EQ(root->FindAttribute("", "targetConfig")->value, "en-rUS-land");
+ EXPECT_EQ(root->FindAttribute("", "targetConfig")->value, "b+sr+Latn,en-rUS-land");
}
} // namespace aapt
diff --git a/tools/aapt2/compile/InlineXmlFormatParser.cpp b/tools/aapt2/compile/InlineXmlFormatParser.cpp
index 8b6c524e5c8d..238e339c05af 100644
--- a/tools/aapt2/compile/InlineXmlFormatParser.cpp
+++ b/tools/aapt2/compile/InlineXmlFormatParser.cpp
@@ -164,7 +164,7 @@ bool InlineXmlFormatParser::Consume(IAaptContext* context, xml::XmlResource* doc
// Add the inline attribute to the parent.
parent_el->attributes.push_back(xml::Attribute{decl.attr_namespace_uri, decl.attr_name,
- "@" + new_doc->file.name.ToString()});
+ "@" + new_doc->file.name.to_string()});
// Delete the subtree.
for (auto iter = parent_el->children.begin(); iter != parent_el->children.end(); ++iter) {
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index 95eec4ae8248..5078678e08a3 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -73,29 +73,22 @@ class ReferenceIdToNameVisitor : public DescendingValueVisitor {
} // namespace
-BinaryResourceParser::BinaryResourceParser(IAaptContext* context, ResourceTable* table,
+BinaryResourceParser::BinaryResourceParser(IDiagnostics* diag, ResourceTable* table,
const Source& source, const void* data, size_t len,
io::IFileCollection* files)
- : context_(context),
- table_(table),
- source_(source),
- data_(data),
- data_len_(len),
- files_(files) {
+ : diag_(diag), table_(table), source_(source), data_(data), data_len_(len), files_(files) {
}
bool BinaryResourceParser::Parse() {
ResChunkPullParser parser(data_, data_len_);
if (!ResChunkPullParser::IsGoodEvent(parser.Next())) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt resources.arsc: " << parser.error());
+ diag_->Error(DiagMessage(source_) << "corrupt resources.arsc: " << parser.error());
return false;
}
if (parser.chunk()->type != android::RES_TABLE_TYPE) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << StringPrintf("unknown chunk of type 0x%02x",
+ diag_->Error(DiagMessage(source_) << StringPrintf("unknown chunk of type 0x%02x",
static_cast<int>(parser.chunk()->type)));
return false;
}
@@ -106,13 +99,12 @@ bool BinaryResourceParser::Parse() {
if (parser.Next() != ResChunkPullParser::Event::kEndDocument) {
if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- context_->GetDiagnostics()->Warn(
- DiagMessage(source_) << "invalid chunk trailing RES_TABLE_TYPE: " << parser.error());
+ diag_->Warn(DiagMessage(source_)
+ << "invalid chunk trailing RES_TABLE_TYPE: " << parser.error());
} else {
- context_->GetDiagnostics()->Warn(
- DiagMessage(source_) << StringPrintf(
- "unexpected chunk of type 0x%02x trailing RES_TABLE_TYPE",
- static_cast<int>(parser.chunk()->type)));
+ diag_->Warn(DiagMessage(source_)
+ << StringPrintf("unexpected chunk of type 0x%02x trailing RES_TABLE_TYPE",
+ static_cast<int>(parser.chunk()->type)));
}
}
return true;
@@ -122,7 +114,7 @@ bool BinaryResourceParser::Parse() {
bool BinaryResourceParser::ParseTable(const ResChunk_header* chunk) {
const ResTable_header* table_header = ConvertTo<ResTable_header>(chunk);
if (!table_header) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "corrupt ResTable_header chunk");
+ diag_->Error(DiagMessage(source_) << "corrupt ResTable_header chunk");
return false;
}
@@ -135,17 +127,15 @@ bool BinaryResourceParser::ParseTable(const ResChunk_header* chunk) {
status_t err =
value_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
if (err != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt string pool in ResTable: "
- << value_pool_.getError());
+ diag_->Error(DiagMessage(source_)
+ << "corrupt string pool in ResTable: " << value_pool_.getError());
return false;
}
// Reserve some space for the strings we are going to add.
table_->string_pool.HintWillAdd(value_pool_.size(), value_pool_.styleCount());
} else {
- context_->GetDiagnostics()->Warn(DiagMessage(source_)
- << "unexpected string pool in ResTable");
+ diag_->Warn(DiagMessage(source_) << "unexpected string pool in ResTable");
}
break;
@@ -156,16 +146,15 @@ bool BinaryResourceParser::ParseTable(const ResChunk_header* chunk) {
break;
default:
- context_->GetDiagnostics()->Warn(
- DiagMessage(source_) << "unexpected chunk type "
- << static_cast<int>(util::DeviceToHost16(parser.chunk()->type)));
+ diag_->Warn(DiagMessage(source_)
+ << "unexpected chunk type "
+ << static_cast<int>(util::DeviceToHost16(parser.chunk()->type)));
break;
}
}
if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt resource table: " << parser.error());
+ diag_->Error(DiagMessage(source_) << "corrupt resource table: " << parser.error());
return false;
}
return true;
@@ -176,14 +165,13 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
sizeof(ResTable_package) - sizeof(ResTable_package::typeIdOffset);
const ResTable_package* package_header = ConvertTo<ResTable_package, kMinPackageSize>(chunk);
if (!package_header) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "corrupt ResTable_package chunk");
+ diag_->Error(DiagMessage(source_) << "corrupt ResTable_package chunk");
return false;
}
uint32_t package_id = util::DeviceToHost32(package_header->id);
if (package_id > std::numeric_limits<uint8_t>::max()) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "package ID is too big (" << package_id << ")");
+ diag_->Error(DiagMessage(source_) << "package ID is too big (" << package_id << ")");
return false;
}
@@ -198,9 +186,8 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
ResourceTablePackage* package =
table_->CreatePackage(util::Utf16ToUtf8(package_name), static_cast<uint8_t>(package_id));
if (!package) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "incompatible package '" << package_name << "' with ID "
- << package_id);
+ diag_->Error(DiagMessage(source_)
+ << "incompatible package '" << package_name << "' with ID " << package_id);
return false;
}
@@ -218,8 +205,7 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
status_t err =
type_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
if (err != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt type string pool in "
+ diag_->Error(DiagMessage(source_) << "corrupt type string pool in "
<< "ResTable_package: " << type_pool_.getError());
return false;
}
@@ -227,13 +213,12 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
status_t err =
key_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
if (err != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt key string pool in "
+ diag_->Error(DiagMessage(source_) << "corrupt key string pool in "
<< "ResTable_package: " << key_pool_.getError());
return false;
}
} else {
- context_->GetDiagnostics()->Warn(DiagMessage(source_) << "unexpected string pool");
+ diag_->Warn(DiagMessage(source_) << "unexpected string pool");
}
break;
@@ -256,16 +241,15 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
break;
default:
- context_->GetDiagnostics()->Warn(
- DiagMessage(source_) << "unexpected chunk type "
- << static_cast<int>(util::DeviceToHost16(parser.chunk()->type)));
+ diag_->Warn(DiagMessage(source_)
+ << "unexpected chunk type "
+ << static_cast<int>(util::DeviceToHost16(parser.chunk()->type)));
break;
}
}
if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt ResTable_package: " << parser.error());
+ diag_->Error(DiagMessage(source_) << "corrupt ResTable_package: " << parser.error());
return false;
}
@@ -278,19 +262,18 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
bool BinaryResourceParser::ParseTypeSpec(const ResChunk_header* chunk) {
if (type_pool_.getError() != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "missing type string pool");
+ diag_->Error(DiagMessage(source_) << "missing type string pool");
return false;
}
const ResTable_typeSpec* type_spec = ConvertTo<ResTable_typeSpec>(chunk);
if (!type_spec) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "corrupt ResTable_typeSpec chunk");
+ diag_->Error(DiagMessage(source_) << "corrupt ResTable_typeSpec chunk");
return false;
}
if (type_spec->id == 0) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "ResTable_typeSpec has invalid id: " << type_spec->id);
+ diag_->Error(DiagMessage(source_) << "ResTable_typeSpec has invalid id: " << type_spec->id);
return false;
}
return true;
@@ -299,12 +282,12 @@ bool BinaryResourceParser::ParseTypeSpec(const ResChunk_header* chunk) {
bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
const ResChunk_header* chunk) {
if (type_pool_.getError() != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "missing type string pool");
+ diag_->Error(DiagMessage(source_) << "missing type string pool");
return false;
}
if (key_pool_.getError() != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "missing key string pool");
+ diag_->Error(DiagMessage(source_) << "missing key string pool");
return false;
}
@@ -312,13 +295,12 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
// a lot and has its own code to handle variable size.
const ResTable_type* type = ConvertTo<ResTable_type, kResTableTypeMinSize>(chunk);
if (!type) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "corrupt ResTable_type chunk");
+ diag_->Error(DiagMessage(source_) << "corrupt ResTable_type chunk");
return false;
}
if (type->id == 0) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "ResTable_type has invalid id: " << (int)type->id);
+ diag_->Error(DiagMessage(source_) << "ResTable_type has invalid id: " << (int)type->id);
return false;
}
@@ -329,9 +311,8 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
const ResourceType* parsed_type = ParseResourceType(type_str);
if (!parsed_type) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "invalid type name '" << type_str << "' for type with ID "
- << (int)type->id);
+ diag_->Error(DiagMessage(source_)
+ << "invalid type name '" << type_str << "' for type with ID " << (int)type->id);
return false;
}
@@ -360,14 +341,13 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
}
if (!resource_value) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "failed to parse value for resource " << name << " ("
+ diag_->Error(DiagMessage(source_) << "failed to parse value for resource " << name << " ("
<< res_id << ") with configuration '" << config << "'");
return false;
}
if (!table_->AddResourceAllowMangled(name, res_id, config, {}, std::move(resource_value),
- context_->GetDiagnostics())) {
+ diag_)) {
return false;
}
@@ -375,7 +355,7 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
Symbol symbol;
symbol.state = SymbolState::kPublic;
symbol.source = source_.WithLine(0);
- if (!table_->SetSymbolStateAllowMangled(name, res_id, symbol, context_->GetDiagnostics())) {
+ if (!table_->SetSymbolStateAllowMangled(name, res_id, symbol, diag_)) {
return false;
}
}
@@ -410,15 +390,14 @@ std::unique_ptr<Item> BinaryResourceParser::ParseValue(const ResourceNameRef& na
const android::Res_value& value) {
std::unique_ptr<Item> item = ResourceUtils::ParseBinaryResValue(name.type, config, value_pool_,
value, &table_->string_pool);
- if (files_ != nullptr && item != nullptr) {
+ if (files_ != nullptr) {
FileReference* file_ref = ValueCast<FileReference>(item.get());
if (file_ref != nullptr) {
file_ref->file = files_->FindFile(*file_ref->path);
if (file_ref->file == nullptr) {
- context_->GetDiagnostics()->Warn(DiagMessage()
- << "resource " << name << " for config '" << config
- << "' is a file reference to '" << *file_ref->path
- << "' but no such path exists");
+ diag_->Warn(DiagMessage() << "resource " << name << " for config '" << config
+ << "' is a file reference to '" << *file_ref->path
+ << "' but no such path exists");
}
}
}
@@ -432,7 +411,7 @@ std::unique_ptr<Value> BinaryResourceParser::ParseMapEntry(const ResourceNameRef
case ResourceType::kStyle:
return ParseStyle(name, config, map);
case ResourceType::kAttrPrivate:
- // fallthrough
+ // fallthrough
case ResourceType::kAttr:
return ParseAttr(name, config, map);
case ResourceType::kArray:
@@ -445,8 +424,8 @@ std::unique_ptr<Value> BinaryResourceParser::ParseMapEntry(const ResourceNameRef
// We can ignore the value here.
return util::make_unique<Id>();
default:
- context_->GetDiagnostics()->Error(DiagMessage() << "illegal map type '" << ToString(name.type)
- << "' (" << (int)name.type << ")");
+ diag_->Error(DiagMessage() << "illegal map type '" << to_string(name.type) << "' ("
+ << (int)name.type << ")");
break;
}
return {};
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.h b/tools/aapt2/format/binary/BinaryResourceParser.h
index dc9a3847a9c6..052f806e3b95 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.h
+++ b/tools/aapt2/format/binary/BinaryResourceParser.h
@@ -39,7 +39,7 @@ class BinaryResourceParser {
public:
// Creates a parser, which will read `len` bytes from `data`, and add any resources parsed to
// `table`. `source` is for logging purposes.
- BinaryResourceParser(IAaptContext* context, ResourceTable* table, const Source& source,
+ BinaryResourceParser(IDiagnostics* diag, ResourceTable* table, const Source& source,
const void* data, size_t data_len, io::IFileCollection* files = nullptr);
// Parses the binary resource table and returns true if successful.
@@ -80,7 +80,7 @@ class BinaryResourceParser {
*/
bool CollectMetaData(const android::ResTable_map& map_entry, Value* value);
- IAaptContext* context_;
+ IDiagnostics* diag_;
ResourceTable* table_;
const Source source_;
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 57565a53794b..2a51df3912e3 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -23,6 +23,7 @@
#include "android-base/logging.h"
#include "android-base/macros.h"
+#include "android-base/stringprintf.h"
#include "ResourceTable.h"
#include "ResourceValues.h"
@@ -472,7 +473,7 @@ class PackageFlattener {
expected_type_id++;
}
expected_type_id++;
- type_pool_.MakeRef(ToString(type->type));
+ type_pool_.MakeRef(to_string(type->type));
std::vector<ResourceEntry*> sorted_entries = CollectAndSortEntries(type);
if (sorted_entries.empty()) {
@@ -568,14 +569,6 @@ bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) {
ResTable_header* table_header = table_writer.StartChunk<ResTable_header>(RES_TABLE_TYPE);
table_header->packageCount = util::HostToDevice32(table->packages.size());
- // Write a self mapping entry for this package if the ID is non-standard (0x7f).
- if (context->GetPackageType() == PackageType::kApp) {
- const uint8_t package_id = context->GetPackageId();
- if (package_id != kFrameworkPackageId && package_id != kAppPackageId) {
- table->included_packages_[package_id] = context->GetCompilationPackage();
- }
- }
-
// Flatten the values string pool.
StringPool::FlattenUtf8(table_writer.buffer(), table->string_pool);
@@ -583,6 +576,22 @@ bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) {
// Flatten each package.
for (auto& package : table->packages) {
+ if (context->GetPackageType() == PackageType::kApp) {
+ // Write a self mapping entry for this package if the ID is non-standard (0x7f).
+ const uint8_t package_id = package->id.value();
+ if (package_id != kFrameworkPackageId && package_id != kAppPackageId) {
+ auto result = table->included_packages_.insert({package_id, package->name});
+ if (!result.second && result.first->second != package->name) {
+ // A mapping for this package ID already exists, and is a different package. Error!
+ context->GetDiagnostics()->Error(
+ DiagMessage() << android::base::StringPrintf(
+ "can't map package ID %02x to '%s'. Already mapped to '%s'", package_id,
+ package->name.c_str(), result.first->second.c_str()));
+ return false;
+ }
+ }
+ }
+
PackageFlattener flattener(context, package.get(), &table->included_packages_,
options_.use_sparse_entries);
if (!flattener.FlattenPackage(&package_buffer)) {
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index 6d7597372234..e11890bbd078 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -71,7 +71,8 @@ class TableFlattenerTest : public ::testing::Test {
return result;
}
- BinaryResourceParser parser(context, out_table, {}, content.data(), content.size());
+ BinaryResourceParser parser(context->GetDiagnostics(), out_table, {}, content.data(),
+ content.size());
if (!parser.Parse()) {
return ::testing::AssertionFailure() << "flattened ResTable is corrupt";
}
@@ -278,7 +279,7 @@ TEST_F(TableFlattenerTest, FlattenSparseEntryWithMinSdkO) {
// Attempt to parse the sparse contents.
ResourceTable sparse_table;
- BinaryResourceParser parser(context.get(), &sparse_table, Source("test.arsc"),
+ BinaryResourceParser parser(context->GetDiagnostics(), &sparse_table, Source("test.arsc"),
sparse_contents.data(), sparse_contents.size());
ASSERT_TRUE(parser.Parse());
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index 86bd86536cc4..0f0bce8bf5a7 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -371,7 +371,8 @@ static SymbolState DeserializeVisibilityFromPb(const pb::SymbolStatus_Visibility
}
static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStringPool& src_pool,
- ResourceTable* out_table, std::string* out_error) {
+ io::IFileCollection* files, ResourceTable* out_table,
+ std::string* out_error) {
Maybe<uint8_t> id;
if (pb_package.has_package_id()) {
id = static_cast<uint8_t>(pb_package.package_id().id());
@@ -444,7 +445,7 @@ static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStr
}
config_value->value = DeserializeValueFromPb(pb_config_value.value(), src_pool, config,
- &out_table->string_pool, out_error);
+ &out_table->string_pool, files, out_error);
if (config_value->value == nullptr) {
return false;
}
@@ -457,8 +458,8 @@ static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStr
return true;
}
-bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, ResourceTable* out_table,
- std::string* out_error) {
+bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, io::IFileCollection* files,
+ ResourceTable* out_table, std::string* out_error) {
// We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which
// causes errors when qualifying it with android::
using namespace android;
@@ -474,7 +475,7 @@ bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, ResourceTable* ou
}
for (const pb::Package& pb_package : pb_table.package()) {
- if (!DeserializePackageFromPb(pb_package, source_pool, out_table, out_error)) {
+ if (!DeserializePackageFromPb(pb_package, source_pool, files, out_table, out_error)) {
return false;
}
}
@@ -600,10 +601,11 @@ static size_t DeserializePluralEnumFromPb(const pb::Plural_Arity& arity) {
std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
const android::ResStringPool& src_pool,
const ConfigDescription& config,
- StringPool* value_pool, std::string* out_error) {
+ StringPool* value_pool, io::IFileCollection* files,
+ std::string* out_error) {
std::unique_ptr<Value> value;
if (pb_value.has_item()) {
- value = DeserializeItemFromPb(pb_value.item(), src_pool, config, value_pool, out_error);
+ value = DeserializeItemFromPb(pb_value.item(), src_pool, config, value_pool, files, out_error);
if (value == nullptr) {
return {};
}
@@ -651,8 +653,8 @@ std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
return {};
}
DeserializeItemMetaDataFromPb(pb_entry, src_pool, &entry.key);
- entry.value =
- DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, out_error);
+ entry.value = DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, files,
+ out_error);
if (entry.value == nullptr) {
return {};
}
@@ -680,8 +682,8 @@ std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
const pb::Array& pb_array = pb_compound_value.array();
std::unique_ptr<Array> array = util::make_unique<Array>();
for (const pb::Array_Element& pb_entry : pb_array.element()) {
- std::unique_ptr<Item> item =
- DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, out_error);
+ std::unique_ptr<Item> item = DeserializeItemFromPb(pb_entry.item(), src_pool, config,
+ value_pool, files, out_error);
if (item == nullptr) {
return {};
}
@@ -697,8 +699,8 @@ std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
std::unique_ptr<Plural> plural = util::make_unique<Plural>();
for (const pb::Plural_Entry& pb_entry : pb_plural.entry()) {
size_t plural_idx = DeserializePluralEnumFromPb(pb_entry.arity());
- plural->values[plural_idx] =
- DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, out_error);
+ plural->values[plural_idx] = DeserializeItemFromPb(pb_entry.item(), src_pool, config,
+ value_pool, files, out_error);
if (!plural->values[plural_idx]) {
return {};
}
@@ -727,7 +729,7 @@ std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
const android::ResStringPool& src_pool,
const ConfigDescription& config, StringPool* value_pool,
- std::string* out_error) {
+ io::IFileCollection* files, std::string* out_error) {
switch (pb_item.value_case()) {
case pb::Item::kRef: {
const pb::Reference& pb_ref = pb_item.ref();
@@ -774,6 +776,9 @@ std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
util::make_unique<FileReference>(value_pool->MakeRef(
pb_file.path(), StringPool::Context(StringPool::Context::kHighPriority, config)));
file_ref->type = DeserializeFileReferenceTypeFromPb(pb_file.type());
+ if (files != nullptr) {
+ file_ref->file = files->FindFile(*file_ref->path);
+ }
return std::move(file_ref);
} break;
@@ -825,7 +830,7 @@ bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el, Stri
}
if (pb_attr.has_compiled_item()) {
attr.compiled_value =
- DeserializeItemFromPb(pb_attr.compiled_item(), {}, {}, value_pool, out_error);
+ DeserializeItemFromPb(pb_attr.compiled_item(), {}, {}, value_pool, nullptr, out_error);
if (attr.compiled_value == nullptr) {
return {};
}
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.h b/tools/aapt2/format/proto/ProtoDeserialize.h
index 7dc54f242d94..0c581a17fa2e 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.h
+++ b/tools/aapt2/format/proto/ProtoDeserialize.h
@@ -27,6 +27,7 @@
#include "Resources.pb.h"
#include "ResourcesInternal.pb.h"
#include "StringPool.h"
+#include "io/File.h"
#include "xml/XmlDom.h"
namespace aapt {
@@ -34,12 +35,13 @@ namespace aapt {
std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
const android::ResStringPool& src_pool,
const ConfigDescription& config,
- StringPool* value_pool, std::string* out_error);
+ StringPool* value_pool, io::IFileCollection* files,
+ std::string* out_error);
std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
const android::ResStringPool& src_pool,
const ConfigDescription& config, StringPool* value_pool,
- std::string* out_error);
+ io::IFileCollection* files, std::string* out_error);
std::unique_ptr<xml::XmlResource> DeserializeXmlResourceFromPb(const pb::XmlNode& pb_node,
std::string* out_error);
@@ -50,8 +52,9 @@ bool DeserializeXmlFromPb(const pb::XmlNode& pb_node, xml::Element* out_el, Stri
bool DeserializeConfigFromPb(const pb::Configuration& pb_config, ConfigDescription* out_config,
std::string* out_error);
-bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, ResourceTable* out_table,
- std::string* out_error);
+// Optional io::IFileCollection used to lookup references to files in the ResourceTable.
+bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, io::IFileCollection* files,
+ ResourceTable* out_table, std::string* out_error);
bool DeserializeCompiledFileFromPb(const pb::internal::CompiledFile& pb_file,
ResourceFile* out_file, std::string* out_error);
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index 1d184fe5a8d2..97ce01a9de13 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -284,7 +284,7 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table
if (type->id) {
pb_type->mutable_type_id()->set_id(type->id.value());
}
- pb_type->set_name(ToString(type->type).to_string());
+ pb_type->set_name(to_string(type->type).to_string());
for (const std::unique_ptr<ResourceEntry>& entry : type->entries) {
pb::Entry* pb_entry = pb_type->add_entry();
@@ -328,7 +328,7 @@ static void SerializeReferenceToPb(const Reference& ref, pb::Reference* pb_ref)
pb_ref->set_id(ref.id.value_or_default(ResourceId(0x0)).id);
if (ref.name) {
- pb_ref->set_name(ref.name.value().ToString());
+ pb_ref->set_name(ref.name.value().to_string());
}
pb_ref->set_private_(ref.private_reference);
@@ -523,14 +523,14 @@ void SerializeItemToPb(const Item& item, pb::Item* out_item) {
}
void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file) {
- out_file->set_resource_name(file.name.ToString());
+ out_file->set_resource_name(file.name.to_string());
out_file->set_source_path(file.source.path);
out_file->set_type(SerializeFileReferenceTypeToPb(file.type));
SerializeConfig(file.config, out_file->mutable_config());
for (const SourcedResourceName& exported : file.exported_symbols) {
pb::internal::CompiledFile_Symbol* pb_symbol = out_file->add_exported_symbol();
- pb_symbol->set_resource_name(exported.name.ToString());
+ pb_symbol->set_resource_name(exported.name.to_string());
pb_symbol->mutable_source()->set_line_number(exported.line);
}
}
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index 8efac8ae6ffd..9649a4de2fe4 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -29,6 +29,12 @@ using ::testing::StrEq;
namespace aapt {
+class MockFileCollection : public io::IFileCollection {
+ public:
+ MOCK_METHOD1(FindFile, io::IFile*(const StringPiece& path));
+ MOCK_METHOD0(Iterator, std::unique_ptr<io::IFileCollectionIterator>());
+};
+
TEST(ProtoSerializeTest, SerializeSinglePackage) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
std::unique_ptr<ResourceTable> table =
@@ -86,9 +92,14 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) {
pb::ResourceTable pb_table;
SerializeTableToPb(*table, &pb_table);
+ test::TestFile file_a("res/layout/main.xml");
+ MockFileCollection files;
+ EXPECT_CALL(files, FindFile(Eq("res/layout/main.xml")))
+ .WillRepeatedly(::testing::Return(&file_a));
+
ResourceTable new_table;
std::string error;
- ASSERT_TRUE(DeserializeTableFromPb(pb_table, &new_table, &error));
+ ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
EXPECT_THAT(error, IsEmpty());
Id* new_id = test::GetValue<Id>(&new_table, "com.app.a:id/foo");
@@ -124,6 +135,11 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) {
ASSERT_TRUE(actual_ref->id);
EXPECT_THAT(*actual_ref, Eq(expected_ref));
+ FileReference* actual_file_ref =
+ test::GetValue<FileReference>(&new_table, "com.app.a:layout/main");
+ ASSERT_THAT(actual_file_ref, NotNull());
+ EXPECT_THAT(actual_file_ref->file, Eq(&file_a));
+
StyledString* actual_styled_str =
test::GetValue<StyledString>(&new_table, "com.app.a:string/styled");
ASSERT_THAT(actual_styled_str, NotNull());
diff --git a/tools/aapt2/integration-tests/NamespaceTest/App/Android.mk b/tools/aapt2/integration-tests/NamespaceTest/App/Android.mk
index 6ed07b0c5c73..94686c095bd8 100644
--- a/tools/aapt2/integration-tests/NamespaceTest/App/Android.mk
+++ b/tools/aapt2/integration-tests/NamespaceTest/App/Android.mk
@@ -25,5 +25,4 @@ LOCAL_SRC_FILES := $(call all-java-files-under,src)
LOCAL_STATIC_ANDROID_LIBRARIES := \
AaptTestNamespace_LibOne \
AaptTestNamespace_LibTwo
-LOCAL_AAPT_FLAGS := -v
include $(BUILD_PACKAGE)
diff --git a/tools/aapt2/io/FileStream.cpp b/tools/aapt2/io/FileStream.cpp
index 2f7a4b3479ca..4ff6d787cf0f 100644
--- a/tools/aapt2/io/FileStream.cpp
+++ b/tools/aapt2/io/FileStream.cpp
@@ -26,6 +26,7 @@
#include "android-base/utf8.h"
using ::android::base::SystemErrorCodeToString;
+using ::android::base::unique_fd;
namespace aapt {
namespace io {
@@ -100,7 +101,13 @@ std::string FileInputStream::GetError() const {
}
FileOutputStream::FileOutputStream(const std::string& path, int mode, size_t buffer_capacity)
- : FileOutputStream(::android::base::utf8::open(path.c_str(), mode), buffer_capacity) {
+ : FileOutputStream(unique_fd(::android::base::utf8::open(path.c_str(), mode)),
+ buffer_capacity) {
+}
+
+FileOutputStream::FileOutputStream(unique_fd fd, size_t buffer_capacity)
+ : FileOutputStream(fd.get(), buffer_capacity) {
+ owned_fd_ = std::move(fd);
}
FileOutputStream::FileOutputStream(int fd, size_t buffer_capacity)
@@ -118,7 +125,7 @@ FileOutputStream::~FileOutputStream() {
}
bool FileOutputStream::Next(void** data, size_t* size) {
- if (fd_ == -1 || HadError()) {
+ if (HadError()) {
return false;
}
@@ -159,7 +166,8 @@ bool FileOutputStream::FlushImpl() {
ssize_t n = TEMP_FAILURE_RETRY(write(fd_, buffer_.get(), buffer_offset_));
if (n < 0) {
error_ = SystemErrorCodeToString(errno);
- fd_.reset();
+ owned_fd_.reset();
+ fd_ = -1;
buffer_.reset();
return false;
}
diff --git a/tools/aapt2/io/FileStream.h b/tools/aapt2/io/FileStream.h
index 3b0766750eae..4ed1ad556f10 100644
--- a/tools/aapt2/io/FileStream.h
+++ b/tools/aapt2/io/FileStream.h
@@ -29,12 +29,15 @@
namespace aapt {
namespace io {
+constexpr size_t kDefaultBufferCapacity = 4096u;
+
class FileInputStream : public InputStream {
public:
- explicit FileInputStream(const std::string& path, size_t buffer_capacity = 4096);
+ explicit FileInputStream(const std::string& path,
+ size_t buffer_capacity = kDefaultBufferCapacity);
- // Takes ownership of `fd`.
- explicit FileInputStream(int fd, size_t buffer_capacity = 4096);
+ // Take ownership of `fd`.
+ explicit FileInputStream(int fd, size_t buffer_capacity = kDefaultBufferCapacity);
bool Next(const void** data, size_t* size) override;
@@ -61,10 +64,14 @@ class FileInputStream : public InputStream {
class FileOutputStream : public OutputStream {
public:
explicit FileOutputStream(const std::string& path, int mode = O_RDWR | O_CREAT | O_BINARY,
- size_t buffer_capacity = 4096);
+ size_t buffer_capacity = kDefaultBufferCapacity);
+
+ // Does not take ownership of `fd`.
+ explicit FileOutputStream(int fd, size_t buffer_capacity = kDefaultBufferCapacity);
// Takes ownership of `fd`.
- explicit FileOutputStream(int fd, size_t buffer_capacity = 4096);
+ explicit FileOutputStream(android::base::unique_fd fd,
+ size_t buffer_capacity = kDefaultBufferCapacity);
~FileOutputStream();
@@ -86,7 +93,8 @@ class FileOutputStream : public OutputStream {
bool FlushImpl();
- android::base::unique_fd fd_;
+ android::base::unique_fd owned_fd_;
+ int fd_;
std::string error_;
std::unique_ptr<uint8_t[]> buffer_;
size_t buffer_capacity_;
diff --git a/tools/aapt2/io/FileStream_test.cpp b/tools/aapt2/io/FileStream_test.cpp
index 68c3cb1f4156..a6d58caa07b7 100644
--- a/tools/aapt2/io/FileStream_test.cpp
+++ b/tools/aapt2/io/FileStream_test.cpp
@@ -87,10 +87,8 @@ TEST(FileOutputStreamTest, NextAndBackup) {
const std::string input = "this is a cool string";
TemporaryFile file;
- int fd = file.release();
- // FileOutputStream takes ownership.
- FileOutputStream out(fd, 10u);
+ FileOutputStream out(file.fd, 10u);
ASSERT_FALSE(out.HadError());
EXPECT_THAT(out.ByteCount(), Eq(0u));
@@ -118,10 +116,10 @@ TEST(FileOutputStreamTest, NextAndBackup) {
ASSERT_TRUE(out.Flush());
- lseek64(fd, 0, SEEK_SET);
+ lseek64(file.fd, 0, SEEK_SET);
std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(fd, &actual));
+ ASSERT_TRUE(android::base::ReadFdToString(file.fd, &actual));
EXPECT_THAT(actual, StrEq(input));
}
diff --git a/tools/aapt2/io/Util.cpp b/tools/aapt2/io/Util.cpp
index d270340a180c..97516322c4cb 100644
--- a/tools/aapt2/io/Util.cpp
+++ b/tools/aapt2/io/Util.cpp
@@ -18,6 +18,7 @@
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
+using ::android::StringPiece;
using ::google::protobuf::io::ZeroCopyOutputStream;
namespace aapt {
@@ -47,6 +48,12 @@ bool CopyFileToArchive(IAaptContext* context, io::IFile* file, const std::string
return CopyInputStreamToArchive(context, data.get(), out_path, compression_flags, writer);
}
+bool CopyFileToArchivePreserveCompression(IAaptContext* context, io::IFile* file,
+ const std::string& out_path, IArchiveWriter* writer) {
+ uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u;
+ return CopyFileToArchive(context, file, out_path, compression_flags, writer);
+}
+
bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::MessageLite* proto_msg,
const std::string& out_path, uint32_t compression_flags,
IArchiveWriter* writer) {
@@ -93,6 +100,25 @@ bool Copy(OutputStream* out, InputStream* in) {
return !in->HadError();
}
+bool Copy(OutputStream* out, const StringPiece& in) {
+ const char* in_buffer = in.data();
+ size_t in_len = in.size();
+ while (in_len != 0) {
+ void* out_buffer;
+ size_t out_len;
+ if (!out->Next(&out_buffer, &out_len)) {
+ return false;
+ }
+
+ const size_t bytes_to_copy = in_len < out_len ? in_len : out_len;
+ memcpy(out_buffer, in_buffer, bytes_to_copy);
+ out->BackUp(out_len - bytes_to_copy);
+ in_buffer += bytes_to_copy;
+ in_len -= bytes_to_copy;
+ }
+ return true;
+}
+
bool Copy(ZeroCopyOutputStream* out, InputStream* in) {
OutputStreamAdaptor adaptor(out);
return Copy(&adaptor, in);
diff --git a/tools/aapt2/io/Util.h b/tools/aapt2/io/Util.h
index 1e48508bb4b2..b07fb5399313 100644
--- a/tools/aapt2/io/Util.h
+++ b/tools/aapt2/io/Util.h
@@ -35,6 +35,9 @@ bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, const std:
bool CopyFileToArchive(IAaptContext* context, IFile* file, const std::string& out_path,
uint32_t compression_flags, IArchiveWriter* writer);
+bool CopyFileToArchivePreserveCompression(IAaptContext* context, IFile* file,
+ const std::string& out_path, IArchiveWriter* writer);
+
bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::MessageLite* proto_msg,
const std::string& out_path, uint32_t compression_flags,
IArchiveWriter* writer);
@@ -42,6 +45,7 @@ bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::MessageLite*
// Copies the data from in to out. Returns false if there was an error.
// If there was an error, check the individual streams' HadError/GetError methods.
bool Copy(OutputStream* out, InputStream* in);
+bool Copy(OutputStream* out, const ::android::StringPiece& in);
bool Copy(::google::protobuf::io::ZeroCopyOutputStream* out, InputStream* in);
class OutputStreamAdaptor : public io::OutputStream {
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 3ba4dd880607..91cef642fc3f 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -461,7 +461,7 @@ void JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const Reso
}
if (out_rewrite_method != nullptr) {
- const StringPiece& type_str = ToString(name.type);
+ const StringPiece& type_str = to_string(name.type);
out_rewrite_method->AppendStatement(StringPrintf("%s.%s = (%s.%s & 0x00ffffff) | (p << 24);",
type_str.data(), field_name.data(),
type_str.data(), field_name.data()));
@@ -584,7 +584,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
(options_.types == JavaClassGeneratorOptions::SymbolTypes::kPublic);
std::unique_ptr<ClassDefinition> class_def = util::make_unique<ClassDefinition>(
- ToString(type->type), ClassQualifier::kStatic, force_creation_if_empty);
+ to_string(type->type), ClassQualifier::kStatic, force_creation_if_empty);
if (!ProcessType(package_name_to_generate, *package, *type, class_def.get(),
rewrite_method.get(), out_r_txt)) {
return false;
diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp
index b9ae654a0ba6..b214d2169f50 100644
--- a/tools/aapt2/java/ProguardRules.cpp
+++ b/tools/aapt2/java/ProguardRules.cpp
@@ -345,15 +345,14 @@ bool WriteKeepSet(std::ostream* out, const KeepSet& keep_set) {
*out << "# Referenced at " << location.source << "\n";
}
if (keep_set.conditional_keep_rules_ && can_be_conditional) {
- *out << "-keep class " << entry.first << " {\n ifused class **.R$layout {\n";
+ *out << "-if class **.R$layout {\n";
for (const UsageLocation& location : locations) {
auto transformed_name = JavaClassGenerator::TransformToFieldName(location.name.entry);
- *out << " int " << transformed_name << ";\n";
+ *out << " int " << transformed_name << ";\n";
}
- *out << " };\n <init>(...);\n}\n" << std::endl;
- } else {
- *out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl;
+ *out << "}\n";
}
+ *out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl;
}
for (const auto& entry : keep_set.method_set_) {
diff --git a/tools/aapt2/java/ProguardRules_test.cpp b/tools/aapt2/java/ProguardRules_test.cpp
index df3ac8b0809f..802c56a47de4 100644
--- a/tools/aapt2/java/ProguardRules_test.cpp
+++ b/tools/aapt2/java/ProguardRules_test.cpp
@@ -130,7 +130,7 @@ TEST(ProguardRulesTest, IncludedLayoutRulesAreConditional) {
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
std::string actual = out.str();
- EXPECT_THAT(actual, HasSubstr("ifused class **.R$layout"));
+ EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
EXPECT_THAT(actual, HasSubstr("int foo"));
EXPECT_THAT(actual, HasSubstr("int bar"));
EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
@@ -152,7 +152,7 @@ TEST(ProguardRulesTest, AliasedLayoutRulesAreConditional) {
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
std::string actual = out.str();
- EXPECT_THAT(actual, HasSubstr("ifused class **.R$layout"));
+ EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
EXPECT_THAT(actual, HasSubstr("int foo"));
EXPECT_THAT(actual, HasSubstr("int bar"));
EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
@@ -174,7 +174,7 @@ TEST(ProguardRulesTest, NonLayoutReferencesAreUnconditional) {
ASSERT_TRUE(proguard::WriteKeepSet(&out, set));
std::string actual = out.str();
- EXPECT_THAT(actual, Not(HasSubstr("ifused")));
+ EXPECT_THAT(actual, Not(HasSubstr("-if")));
}
TEST(ProguardRulesTest, ViewOnClickRuleIsEmitted) {
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 6fb1793d90ed..de4fb736758c 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -127,9 +127,9 @@ static bool VerifyManifest(xml::Element* el, SourcePathDiagnostics* diag) {
diag->Error(DiagMessage(el->line_number)
<< "attribute 'package' in <manifest> tag must not be a reference");
return false;
- } else if (!util::IsJavaPackageName(attr->value)) {
+ } else if (!util::IsAndroidPackageName(attr->value)) {
diag->Error(DiagMessage(el->line_number)
- << "attribute 'package' in <manifest> tag is not a valid Java package name: '"
+ << "attribute 'package' in <manifest> tag is not a valid Android package name: '"
<< attr->value << "'");
return false;
}
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index 21c6b111b855..58d0607ed7b3 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -37,17 +37,14 @@ TableMerger::TableMerger(IAaptContext* context, ResourceTable* out_table,
CHECK(master_package_ != nullptr) << "package name or ID already taken";
}
-bool TableMerger::Merge(const Source& src, ResourceTable* table, bool overlay,
- io::IFileCollection* collection) {
+bool TableMerger::Merge(const Source& src, ResourceTable* table, bool overlay) {
// We allow adding new resources if this is not an overlay, or if the options allow overlays
// to add new resources.
- return MergeImpl(src, table, collection, overlay,
- options_.auto_add_overlay || !overlay /*allow_new*/);
+ return MergeImpl(src, table, overlay, options_.auto_add_overlay || !overlay /*allow_new*/);
}
// This will merge packages with the same package name (or no package name).
-bool TableMerger::MergeImpl(const Source& src, ResourceTable* table,
- io::IFileCollection* collection, bool overlay, bool allow_new) {
+bool TableMerger::MergeImpl(const Source& src, ResourceTable* table, bool overlay, bool allow_new) {
bool error = false;
for (auto& package : table->packages) {
// Only merge an empty package or the package we're building.
@@ -55,37 +52,20 @@ bool TableMerger::MergeImpl(const Source& src, ResourceTable* table,
// This is because at compile time it is unknown if the attributes are
// simply uses of the attribute or definitions.
if (package->name.empty() || context_->GetCompilationPackage() == package->name) {
- FileMergeCallback callback;
- if (collection) {
- callback = [&](const ResourceNameRef& name, const ConfigDescription& config,
- FileReference* new_file, FileReference* old_file) -> bool {
- // The old file's path points inside the APK, so we can use it as is.
- io::IFile* f = collection->FindFile(*old_file->path);
- if (!f) {
- context_->GetDiagnostics()->Error(DiagMessage(src)
- << "file '" << *old_file->path << "' not found");
- return false;
- }
-
- new_file->file = f;
- return true;
- };
- }
-
// Merge here. Once the entries are merged and mangled, any references to them are still
// valid. This is because un-mangled references are mangled, then looked up at resolution
// time. Also, when linking, we convert references with no package name to use the compilation
// package name.
- error |=
- !DoMerge(src, table, package.get(), false /* mangle */, overlay, allow_new, callback);
+ error |= !DoMerge(src, table, package.get(), false /*mangle*/, overlay, allow_new);
}
}
return !error;
}
-// This will merge and mangle resources from a static library.
+// This will merge and mangle resources from a static library. It is assumed that all FileReferences
+// have correctly set their io::IFile*.
bool TableMerger::MergeAndMangle(const Source& src, const StringPiece& package_name,
- ResourceTable* table, io::IFileCollection* collection) {
+ ResourceTable* table) {
bool error = false;
for (auto& package : table->packages) {
// Warn of packages with an unrelated ID.
@@ -96,23 +76,7 @@ bool TableMerger::MergeAndMangle(const Source& src, const StringPiece& package_n
bool mangle = package_name != context_->GetCompilationPackage();
merged_packages_.insert(package->name);
-
- auto callback = [&](const ResourceNameRef& name, const ConfigDescription& config,
- FileReference* new_file, FileReference* old_file) -> bool {
- // The old file's path points inside the APK, so we can use it as is.
- io::IFile* f = collection->FindFile(*old_file->path);
- if (!f) {
- context_->GetDiagnostics()->Error(DiagMessage(src)
- << "file '" << *old_file->path << "' not found");
- return false;
- }
-
- new_file->file = f;
- return true;
- };
-
- error |= !DoMerge(src, table, package.get(), mangle, false /*overlay*/, true /*allow_new*/,
- callback);
+ error |= !DoMerge(src, table, package.get(), mangle, false /*overlay*/, true /*allow_new*/);
}
return !error;
}
@@ -187,7 +151,7 @@ static ResourceTable::CollisionResult ResolveMergeCollision(Value* existing, Val
static ResourceTable::CollisionResult MergeConfigValue(IAaptContext* context,
const ResourceNameRef& res_name,
- const bool overlay,
+ bool overlay,
ResourceConfigValue* dst_config_value,
ResourceConfigValue* src_config_value,
StringPool* pool) {
@@ -220,10 +184,8 @@ static ResourceTable::CollisionResult MergeConfigValue(IAaptContext* context,
}
bool TableMerger::DoMerge(const Source& src, ResourceTable* src_table,
- ResourceTablePackage* src_package,
- const bool mangle_package, const bool overlay,
- const bool allow_new_resources,
- const FileMergeCallback& callback) {
+ ResourceTablePackage* src_package, bool mangle_package, bool overlay,
+ bool allow_new_resources) {
bool error = false;
for (auto& src_type : src_package->types) {
@@ -292,13 +254,6 @@ bool TableMerger::DoMerge(const Source& src, ResourceTable* src_table,
} else {
new_file_ref = std::unique_ptr<FileReference>(f->Clone(&master_table_->string_pool));
}
-
- if (callback) {
- if (!callback(res_name, src_config_value->config, new_file_ref.get(), f)) {
- error = true;
- continue;
- }
- }
dst_config_value->value = std::move(new_file_ref);
} else {
@@ -343,8 +298,8 @@ bool TableMerger::MergeFile(const ResourceFile& file_desc, bool overlay, io::IFi
->FindOrCreateValue(file_desc.config, {})
->value = std::move(file_ref);
- return DoMerge(file->GetSource(), &table, pkg, false /* mangle */, overlay /* overlay */,
- true /* allow_new */, {});
+ return DoMerge(file->GetSource(), &table, pkg, false /*mangle*/, overlay /*overlay*/,
+ true /*allow_new*/);
}
} // namespace aapt
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index d024aa47d952..47e23dded26f 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -40,6 +40,9 @@ struct TableMergerOptions {
// TableMerger takes resource tables and merges all packages within the tables that have the same
// package ID.
//
+// It is assumed that any FileReference values have their io::IFile pointer set to point to the
+// file they represent.
+//
// If a package has a different name, all the entries in that table have their names mangled
// to include the package name. This way there are no collisions. In order to do this correctly,
// the TableMerger needs to also mangle any FileReference paths. Once these are mangled, the
@@ -60,14 +63,11 @@ class TableMerger {
// Merges resources from the same or empty package. This is for local sources.
// If overlay is true, the resources are treated as overlays.
- // An io::IFileCollection is optional and used to find the referenced Files and process them.
- bool Merge(const Source& src, ResourceTable* table, bool overlay,
- io::IFileCollection* collection = nullptr);
+ bool Merge(const Source& src, ResourceTable* table, bool overlay);
// Merges resources from the given package, mangling the name. This is for static libraries.
- // An io::IFileCollection is needed in order to find the referenced Files and process them.
- bool MergeAndMangle(const Source& src, const android::StringPiece& package, ResourceTable* table,
- io::IFileCollection* collection);
+ // All FileReference values must have their io::IFile set.
+ bool MergeAndMangle(const Source& src, const android::StringPiece& package, ResourceTable* table);
// Merges a compiled file that belongs to this same or empty package.
bool MergeFile(const ResourceFile& fileDesc, bool overlay, io::IFile* file);
@@ -75,23 +75,16 @@ class TableMerger {
private:
DISALLOW_COPY_AND_ASSIGN(TableMerger);
- using FileMergeCallback = std::function<bool(const ResourceNameRef&,
- const ConfigDescription& config,
- FileReference*, FileReference*)>;
-
IAaptContext* context_;
ResourceTable* master_table_;
TableMergerOptions options_;
ResourceTablePackage* master_package_;
std::set<std::string> merged_packages_;
- bool MergeImpl(const Source& src, ResourceTable* src_table,
- io::IFileCollection* collection, bool overlay, bool allow_new);
+ bool MergeImpl(const Source& src, ResourceTable* src_table, bool overlay, bool allow_new);
- bool DoMerge(const Source& src, ResourceTable* src_table,
- ResourceTablePackage* src_package, const bool mangle_package,
- const bool overlay, const bool allow_new_resources,
- const FileMergeCallback& callback);
+ bool DoMerge(const Source& src, ResourceTable* src_table, ResourceTablePackage* src_package,
+ bool mangle_package, bool overlay, bool allow_new_resources);
std::unique_ptr<FileReference> CloneAndMangleFile(const std::string& package,
const FileReference& value);
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 3499809e5a83..6aab8ded24a5 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -22,11 +22,12 @@
using ::aapt::test::ValueEq;
using ::testing::Contains;
+using ::testing::Eq;
+using ::testing::Field;
using ::testing::NotNull;
-using ::testing::UnorderedElementsAreArray;
using ::testing::Pointee;
-using ::testing::Field;
-using ::testing::Eq;
+using ::testing::StrEq;
+using ::testing::UnorderedElementsAreArray;
namespace aapt {
@@ -67,10 +68,9 @@ TEST_F(TableMergerTest, SimpleMerge) {
ResourceTable final_table;
TableMerger merger(context_.get(), &final_table, TableMergerOptions{});
- io::FileCollection collection;
ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
- ASSERT_TRUE(merger.MergeAndMangle({}, "com.app.b", table_b.get(), &collection));
+ ASSERT_TRUE(merger.MergeAndMangle({}, "com.app.b", table_b.get()));
EXPECT_TRUE(merger.merged_packages().count("com.app.b") != 0);
@@ -122,32 +122,35 @@ TEST_F(TableMergerTest, MergeFileOverlay) {
}
TEST_F(TableMergerTest, MergeFileReferences) {
+ test::TestFile file_a("res/xml/file.xml");
+ test::TestFile file_b("res/xml/file.xml");
+
std::unique_ptr<ResourceTable> table_a =
test::ResourceTableBuilder()
.SetPackageId("com.app.a", 0x7f)
- .AddFileReference("com.app.a:xml/file", "res/xml/file.xml")
+ .AddFileReference("com.app.a:xml/file", "res/xml/file.xml", &file_a)
.Build();
std::unique_ptr<ResourceTable> table_b =
test::ResourceTableBuilder()
.SetPackageId("com.app.b", 0x7f)
- .AddFileReference("com.app.b:xml/file", "res/xml/file.xml")
+ .AddFileReference("com.app.b:xml/file", "res/xml/file.xml", &file_b)
.Build();
ResourceTable final_table;
TableMerger merger(context_.get(), &final_table, TableMergerOptions{});
- io::FileCollection collection;
- collection.InsertFile("res/xml/file.xml");
ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
- ASSERT_TRUE(merger.MergeAndMangle({}, "com.app.b", table_b.get(), &collection));
+ ASSERT_TRUE(merger.MergeAndMangle({}, "com.app.b", table_b.get()));
FileReference* f = test::GetValue<FileReference>(&final_table, "com.app.a:xml/file");
ASSERT_THAT(f, NotNull());
- EXPECT_EQ(std::string("res/xml/file.xml"), *f->path);
+ EXPECT_THAT(*f->path, StrEq("res/xml/file.xml"));
+ EXPECT_THAT(f->file, Eq(&file_a));
f = test::GetValue<FileReference>(&final_table, "com.app.a:xml/com.app.b$file");
ASSERT_THAT(f, NotNull());
- EXPECT_EQ(std::string("res/xml/com.app.b$file.xml"), *f->path);
+ EXPECT_THAT(*f->path, StrEq("res/xml/com.app.b$file.xml"));
+ EXPECT_THAT(f->file, Eq(&file_b));
}
TEST_F(TableMergerTest, OverrideResourceWithOverlay) {
diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp
index 680308871af7..473693ce4917 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -265,12 +265,14 @@ bool MultiApkGenerator::UpdateManifest(const Artifact& artifact,
const PostProcessingConfiguration& config,
std::unique_ptr<XmlResource>* updated_manifest,
IDiagnostics* diag) {
- *updated_manifest = apk_->InflateManifest(context_);
- XmlResource* manifest = updated_manifest->get();
- if (manifest == nullptr) {
+ const xml::XmlResource* apk_manifest = apk_->GetManifest();
+ if (apk_manifest == nullptr) {
return false;
}
+ *updated_manifest = apk_manifest->Clone();
+ XmlResource* manifest = updated_manifest->get();
+
// Make sure the first element is <manifest> with package attribute.
xml::Element* manifest_el = manifest->root.get();
if (manifest_el == nullptr) {
diff --git a/tools/aapt2/optimize/MultiApkGenerator_test.cpp b/tools/aapt2/optimize/MultiApkGenerator_test.cpp
index c8f3524748b6..30c9146b5444 100644
--- a/tools/aapt2/optimize/MultiApkGenerator_test.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator_test.cpp
@@ -106,7 +106,7 @@ class MultiApkGeneratorTest : public ::testing::Test {
TEST_F(MultiApkGeneratorTest, VersionFilterNewerVersion) {
std::unique_ptr<ResourceTable> table = BuildTable();
- LoadedApk apk = {{"test.apk"}, {}, std::move(table)};
+ LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(19).Build();
PostProcessingConfiguration empty_config;
TableFlattenerOptions table_flattener_options;
@@ -147,7 +147,7 @@ TEST_F(MultiApkGeneratorTest, VersionFilterNewerVersion) {
TEST_F(MultiApkGeneratorTest, VersionFilterOlderVersion) {
std::unique_ptr<ResourceTable> table = BuildTable();
- LoadedApk apk = {{"test.apk"}, {}, std::move(table)};
+ LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build();
PostProcessingConfiguration empty_config;
TableFlattenerOptions table_flattener_options;
@@ -186,7 +186,7 @@ TEST_F(MultiApkGeneratorTest, VersionFilterOlderVersion) {
TEST_F(MultiApkGeneratorTest, VersionFilterNoVersion) {
std::unique_ptr<ResourceTable> table = BuildTable();
- LoadedApk apk = {{"test.apk"}, {}, std::move(table)};
+ LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build();
PostProcessingConfiguration empty_config;
TableFlattenerOptions table_flattener_options;
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index 882a85b1c1bb..2d517c76944b 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -289,7 +289,7 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindByName(
const android::ResTable& table = assets_.getResources(false);
const std::u16string package16 = util::Utf8ToUtf16(name.package);
- const std::u16string type16 = util::Utf8ToUtf16(ToString(name.type));
+ const std::u16string type16 = util::Utf8ToUtf16(to_string(name.type));
const std::u16string entry16 = util::Utf8ToUtf16(name.entry);
uint32_t type_spec_flags = 0;
diff --git a/tools/aapt2/test/Builders.cpp b/tools/aapt2/test/Builders.cpp
index 5a62e9777065..ecec63f3cf31 100644
--- a/tools/aapt2/test/Builders.cpp
+++ b/tools/aapt2/test/Builders.cpp
@@ -78,21 +78,27 @@ ResourceTableBuilder& ResourceTableBuilder::AddString(const StringPiece& name, c
}
ResourceTableBuilder& ResourceTableBuilder::AddFileReference(const StringPiece& name,
- const StringPiece& path) {
- return AddFileReference(name, {}, path);
+ const StringPiece& path,
+ io::IFile* file) {
+ return AddFileReference(name, {}, path, file);
}
ResourceTableBuilder& ResourceTableBuilder::AddFileReference(const StringPiece& name,
const ResourceId& id,
- const StringPiece& path) {
- return AddValue(name, id, util::make_unique<FileReference>(table_->string_pool.MakeRef(path)));
+ const StringPiece& path,
+ io::IFile* file) {
+ auto file_ref = util::make_unique<FileReference>(table_->string_pool.MakeRef(path));
+ file_ref->file = file;
+ return AddValue(name, id, std::move(file_ref));
}
ResourceTableBuilder& ResourceTableBuilder::AddFileReference(const StringPiece& name,
const StringPiece& path,
- const ConfigDescription& config) {
- return AddValue(name, config, {},
- util::make_unique<FileReference>(table_->string_pool.MakeRef(path)));
+ const ConfigDescription& config,
+ io::IFile* file) {
+ auto file_ref = util::make_unique<FileReference>(table_->string_pool.MakeRef(path));
+ file_ref->file = file;
+ return AddValue(name, config, {}, std::move(file_ref));
}
ResourceTableBuilder& ResourceTableBuilder::AddValue(const StringPiece& name,
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 263fb5562b25..4cdfc33e92e3 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -52,12 +52,15 @@ class ResourceTableBuilder {
ResourceTableBuilder& AddString(const android::StringPiece& name, const ResourceId& id,
const ConfigDescription& config, const android::StringPiece& str);
ResourceTableBuilder& AddFileReference(const android::StringPiece& name,
- const android::StringPiece& path);
+ const android::StringPiece& path,
+ io::IFile* file = nullptr);
ResourceTableBuilder& AddFileReference(const android::StringPiece& name, const ResourceId& id,
- const android::StringPiece& path);
+ const android::StringPiece& path,
+ io::IFile* file = nullptr);
ResourceTableBuilder& AddFileReference(const android::StringPiece& name,
const android::StringPiece& path,
- const ConfigDescription& config);
+ const ConfigDescription& config,
+ io::IFile* file = nullptr);
ResourceTableBuilder& AddValue(const android::StringPiece& name, std::unique_ptr<Value> value);
ResourceTableBuilder& AddValue(const android::StringPiece& name, const ResourceId& id,
std::unique_ptr<Value> value);
diff --git a/tools/aapt2/text/Printer.cpp b/tools/aapt2/text/Printer.cpp
new file mode 100644
index 000000000000..38b3585f81f5
--- /dev/null
+++ b/tools/aapt2/text/Printer.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "text/Printer.h"
+
+#include <algorithm>
+
+#include "io/Util.h"
+
+using ::aapt::io::OutputStream;
+using ::android::StringPiece;
+
+namespace aapt {
+namespace text {
+
+void Printer::Println(const StringPiece& str) {
+ Print(str);
+ Print("\n");
+}
+
+void Printer::Println() {
+ Print("\n");
+}
+
+void Printer::Print(const StringPiece& str) {
+ if (error_) {
+ return;
+ }
+
+ auto remaining_str_begin = str.begin();
+ const auto remaining_str_end = str.end();
+ while (remaining_str_end != remaining_str_begin) {
+ // Find the next new-line.
+ const auto new_line_iter = std::find(remaining_str_begin, remaining_str_end, '\n');
+
+ // We will copy the string up until the next new-line (or end of string).
+ const StringPiece str_to_copy = str.substr(remaining_str_begin, new_line_iter);
+ if (!str_to_copy.empty()) {
+ if (needs_indent_) {
+ for (int i = 0; i < indent_level_; i++) {
+ if (!io::Copy(out_, " ")) {
+ error_ = true;
+ return;
+ }
+ }
+ needs_indent_ = false;
+ }
+
+ if (!io::Copy(out_, str_to_copy)) {
+ error_ = true;
+ return;
+ }
+ }
+
+ // If we found a new-line.
+ if (new_line_iter != remaining_str_end) {
+ if (!io::Copy(out_, "\n")) {
+ error_ = true;
+ return;
+ }
+ needs_indent_ = true;
+ // Ok to increment iterator here because we know that the '\n' character is one byte.
+ remaining_str_begin = new_line_iter + 1;
+ } else {
+ remaining_str_begin = new_line_iter;
+ }
+ }
+}
+
+void Printer::Indent() {
+ ++indent_level_;
+}
+
+void Printer::Undent() {
+ --indent_level_;
+}
+
+} // namespace text
+} // namespace aapt
diff --git a/tools/aapt2/text/Printer.h b/tools/aapt2/text/Printer.h
new file mode 100644
index 000000000000..94b3c0bf9449
--- /dev/null
+++ b/tools/aapt2/text/Printer.h
@@ -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.
+ */
+
+#ifndef AAPT_TEXT_PRINTER_H
+#define AAPT_TEXT_PRINTER_H
+
+#include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
+
+#include "io/Io.h"
+
+namespace aapt {
+namespace text {
+
+// An indenting Printer that helps write formatted text to the OutputStream.
+class Printer {
+ public:
+ explicit Printer(::aapt::io::OutputStream* out) : out_(out) {
+ }
+
+ void Print(const ::android::StringPiece& str);
+ void Println(const ::android::StringPiece& str);
+ void Println();
+
+ void Indent();
+ void Undent();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Printer);
+
+ ::aapt::io::OutputStream* out_;
+ int indent_level_ = 0;
+ bool needs_indent_ = false;
+ bool error_ = false;
+};
+
+} // namespace text
+} // namespace aapt
+
+#endif // AAPT_TEXT_PRINTER_H
diff --git a/tools/aapt2/text/Printer_test.cpp b/tools/aapt2/text/Printer_test.cpp
new file mode 100644
index 000000000000..58beae73c9f2
--- /dev/null
+++ b/tools/aapt2/text/Printer_test.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "text/Printer.h"
+
+#include "io/StringStream.h"
+#include "test/Test.h"
+
+using ::aapt::io::StringOutputStream;
+using ::android::StringPiece;
+using ::testing::StrEq;
+
+namespace aapt {
+namespace text {
+
+TEST(PrinterTest, PrintsToStreamWithIndents) {
+ std::string result;
+ StringOutputStream out(&result);
+ Printer printer(&out);
+
+ printer.Print("Hello");
+ out.Flush();
+ EXPECT_THAT(result, StrEq("Hello"));
+
+ printer.Println();
+ out.Flush();
+ EXPECT_THAT(result, StrEq("Hello\n"));
+
+ // This shouldn't print anything yet.
+ printer.Indent();
+ out.Flush();
+ EXPECT_THAT(result, StrEq("Hello\n"));
+
+ // Now we should see the indent.
+ printer.Print("world!");
+ out.Flush();
+ EXPECT_THAT(result, StrEq("Hello\n world!"));
+
+ printer.Println(" What a\nlovely day.");
+ out.Flush();
+ EXPECT_THAT(result, StrEq("Hello\n world! What a\n lovely day.\n"));
+
+ // This shouldn't print anything yet.
+ printer.Undent();
+ out.Flush();
+ EXPECT_THAT(result, StrEq("Hello\n world! What a\n lovely day.\n"));
+
+ printer.Println("Isn't it?");
+ out.Flush();
+ EXPECT_THAT(result, StrEq("Hello\n world! What a\n lovely day.\nIsn't it?\n"));
+}
+
+} // namespace text
+} // namespace aapt
diff --git a/tools/aapt2/text/Unicode.cpp b/tools/aapt2/text/Unicode.cpp
index 75eeb46c7f5e..3735b3e841e0 100644
--- a/tools/aapt2/text/Unicode.cpp
+++ b/tools/aapt2/text/Unicode.cpp
@@ -85,7 +85,8 @@ bool IsJavaIdentifier(const StringPiece& str) {
return false;
}
- if (!IsXidStart(iter.Next())) {
+ const char32_t first_codepoint = iter.Next();
+ if (!IsXidStart(first_codepoint) && first_codepoint != U'_' && first_codepoint != U'$') {
return false;
}
diff --git a/tools/aapt2/text/Unicode_test.cpp b/tools/aapt2/text/Unicode_test.cpp
index d47fb282bc0a..a8e797cf3d17 100644
--- a/tools/aapt2/text/Unicode_test.cpp
+++ b/tools/aapt2/text/Unicode_test.cpp
@@ -44,10 +44,11 @@ TEST(UnicodeTest, IsXidContinue) {
TEST(UnicodeTest, IsJavaIdentifier) {
EXPECT_TRUE(IsJavaIdentifier("FøøBar_12"));
EXPECT_TRUE(IsJavaIdentifier("Føø$Bar"));
+ EXPECT_TRUE(IsJavaIdentifier("_FøøBar"));
+ EXPECT_TRUE(IsJavaIdentifier("$Føø$Bar"));
EXPECT_FALSE(IsJavaIdentifier("12FøøBar"));
- EXPECT_FALSE(IsJavaIdentifier("_FøøBar"));
- EXPECT_FALSE(IsJavaIdentifier("$Føø$Bar"));
+ EXPECT_FALSE(IsJavaIdentifier(".Hello"));
}
TEST(UnicodeTest, IsValidResourceEntryName) {
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index bf8dc4d727f7..5a8ff0926483 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -34,7 +34,7 @@
#ifdef _WIN32
// Windows includes.
-#include <direct.h>
+#include <windows.h>
#endif
using ::android::FileMap;
@@ -46,21 +46,29 @@ using ::android::base::unique_fd;
namespace aapt {
namespace file {
-FileType GetFileType(const std::string& path) {
-// TODO(adamlesinski): I'd like to move this to ::android::base::utf8 but Windows does some macro
-// trickery with 'stat' and things don't override very well.
#ifdef _WIN32
+FileType GetFileType(const std::string& path) {
std::wstring path_utf16;
if (!::android::base::UTF8PathToWindowsLongPath(path.c_str(), &path_utf16)) {
return FileType::kNonexistant;
}
- struct _stat64 sb;
- int result = _wstat64(path_utf16.c_str(), &sb);
+ DWORD result = GetFileAttributesW(path_utf16.c_str());
+ if (result == INVALID_FILE_ATTRIBUTES) {
+ return FileType::kNonexistant;
+ }
+
+ if (result & FILE_ATTRIBUTE_DIRECTORY) {
+ return FileType::kDirectory;
+ }
+
+ // Too many types to consider, just let open fail later.
+ return FileType::kRegular;
+}
#else
+FileType GetFileType(const std::string& path) {
struct stat sb;
int result = stat(path.c_str(), &sb);
-#endif
if (result == -1) {
if (errno == ENOENT || errno == ENOTDIR) {
@@ -91,6 +99,7 @@ FileType GetFileType(const std::string& path) {
return FileType::kUnknown;
}
}
+#endif
bool mkdirs(const std::string& path) {
constexpr const mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP;
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index a9b49d9d9904..e42145dff47e 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -24,6 +24,7 @@
#include "androidfw/StringPiece.h"
#include "utils/Unicode.h"
+#include "text/Unicode.h"
#include "text/Utf8Iterator.h"
#include "util/BigBuffer.h"
#include "util/Maybe.h"
@@ -94,72 +95,55 @@ StringPiece TrimWhitespace(const StringPiece& str) {
return StringPiece(start, end - start);
}
-StringPiece::const_iterator FindNonAlphaNumericAndNotInSet(
- const StringPiece& str, const StringPiece& allowed_chars) {
- const auto end_iter = str.end();
- for (auto iter = str.begin(); iter != end_iter; ++iter) {
- char c = *iter;
- if ((c >= u'a' && c <= u'z') || (c >= u'A' && c <= u'Z') ||
- (c >= u'0' && c <= u'9')) {
- continue;
- }
-
- bool match = false;
- for (char i : allowed_chars) {
- if (c == i) {
- match = true;
- break;
- }
- }
-
- if (!match) {
- return iter;
+static int IsJavaNameImpl(const StringPiece& str) {
+ int pieces = 0;
+ for (const StringPiece& piece : Tokenize(str, '.')) {
+ pieces++;
+ if (!text::IsJavaIdentifier(piece)) {
+ return -1;
}
}
- return end_iter;
+ return pieces;
}
bool IsJavaClassName(const StringPiece& str) {
- size_t pieces = 0;
- for (const StringPiece& piece : Tokenize(str, '.')) {
- pieces++;
- if (piece.empty()) {
- return false;
- }
-
- // Can't have starting or trailing $ character.
- if (piece.data()[0] == '$' || piece.data()[piece.size() - 1] == '$') {
- return false;
- }
-
- if (FindNonAlphaNumericAndNotInSet(piece, "$_") != piece.end()) {
- return false;
- }
- }
- return pieces >= 2;
+ return IsJavaNameImpl(str) >= 2;
}
bool IsJavaPackageName(const StringPiece& str) {
- if (str.empty()) {
- return false;
- }
+ return IsJavaNameImpl(str) >= 1;
+}
- size_t pieces = 0;
+static int IsAndroidNameImpl(const StringPiece& str) {
+ int pieces = 0;
for (const StringPiece& piece : Tokenize(str, '.')) {
- pieces++;
if (piece.empty()) {
- return false;
+ return -1;
}
- if (piece.data()[0] == '_' || piece.data()[piece.size() - 1] == '_') {
- return false;
+ const char first_character = piece.data()[0];
+ if (!::isalpha(first_character)) {
+ return -1;
}
- if (FindNonAlphaNumericAndNotInSet(piece, "_") != piece.end()) {
- return false;
+ bool valid = std::all_of(piece.begin() + 1, piece.end(), [](const char c) -> bool {
+ return ::isalnum(c) || c == '_';
+ });
+
+ if (!valid) {
+ return -1;
}
+ pieces++;
}
- return pieces >= 1;
+ return pieces;
+}
+
+bool IsAndroidPackageName(const StringPiece& str) {
+ return IsAndroidNameImpl(str) > 1 || str == "android";
+}
+
+bool IsAndroidSplitName(const StringPiece& str) {
+ return IsAndroidNameImpl(str) > 0;
}
Maybe<std::string> GetFullyQualifiedClassName(const StringPiece& package,
@@ -176,7 +160,7 @@ Maybe<std::string> GetFullyQualifiedClassName(const StringPiece& package,
return {};
}
- std::string result(package.data(), package.size());
+ std::string result = package.to_string();
if (classname.data()[0] != '.') {
result += '.';
}
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index c928458786e4..7c949b90c10a 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -53,48 +53,40 @@ struct Range {
std::vector<std::string> Split(const android::StringPiece& str, char sep);
std::vector<std::string> SplitAndLowercase(const android::StringPiece& str, char sep);
-/**
- * Returns true if the string starts with prefix.
- */
+// Returns true if the string starts with prefix.
bool StartsWith(const android::StringPiece& str, const android::StringPiece& prefix);
-/**
- * Returns true if the string ends with suffix.
- */
+// Returns true if the string ends with suffix.
bool EndsWith(const android::StringPiece& str, const android::StringPiece& suffix);
-/**
- * Creates a new StringPiece16 that points to a substring
- * of the original string without leading or trailing whitespace.
- */
+// Creates a new StringPiece16 that points to a substring of the original string without leading or
+// trailing whitespace.
android::StringPiece TrimWhitespace(const android::StringPiece& str);
-/**
- * Returns an iterator to the first character that is not alpha-numeric and that
- * is not in the allowedChars set.
- */
-android::StringPiece::const_iterator FindNonAlphaNumericAndNotInSet(
- const android::StringPiece& str, const android::StringPiece& allowed_chars);
-
-/**
- * Tests that the string is a valid Java class name.
- */
+// Tests that the string is a valid Java class name.
bool IsJavaClassName(const android::StringPiece& str);
-/**
- * Tests that the string is a valid Java package name.
- */
+// Tests that the string is a valid Java package name.
bool IsJavaPackageName(const android::StringPiece& str);
-/**
- * Converts the class name to a fully qualified class name from the given
- * `package`. Ex:
- *
- * asdf --> package.asdf
- * .asdf --> package.asdf
- * .a.b --> package.a.b
- * asdf.adsf --> asdf.adsf
- */
+// Tests that the string is a valid Android package name. More strict than a Java package name.
+// - First character of each component (separated by '.') must be an ASCII letter.
+// - Subsequent characters of a component can be ASCII alphanumeric or an underscore.
+// - Package must contain at least two components, unless it is 'android'.
+bool IsAndroidPackageName(const android::StringPiece& str);
+
+// Tests that the string is a valid Android split name.
+// - First character of each component (separated by '.') must be an ASCII letter.
+// - Subsequent characters of a component can be ASCII alphanumeric or an underscore.
+bool IsAndroidSplitName(const android::StringPiece& str);
+
+// Converts the class name to a fully qualified class name from the given
+// `package`. Ex:
+//
+// asdf --> package.asdf
+// .asdf --> package.asdf
+// .a.b --> package.a.b
+// asdf.adsf --> asdf.adsf
Maybe<std::string> GetFullyQualifiedClassName(const android::StringPiece& package,
const android::StringPiece& class_name);
@@ -108,23 +100,17 @@ typename std::enable_if<std::is_arithmetic<T>::value, int>::type compare(const T
return 0;
}
-/**
- * Makes a std::unique_ptr<> with the template parameter inferred by the compiler.
- * This will be present in C++14 and can be removed then.
- */
+// Makes a std::unique_ptr<> with the template parameter inferred by the compiler.
+// This will be present in C++14 and can be removed then.
template <typename T, class... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
}
-/**
- * Writes a set of items to the std::ostream, joining the times with the
- * provided
- * separator.
- */
+// Writes a set of items to the std::ostream, joining the times with the provided separator.
template <typename Container>
-::std::function<::std::ostream&(::std::ostream&)> Joiner(
- const Container& container, const char* sep) {
+::std::function<::std::ostream&(::std::ostream&)> Joiner(const Container& container,
+ const char* sep) {
using std::begin;
using std::end;
const auto begin_iter = begin(container);
@@ -140,32 +126,19 @@ template <typename Container>
};
}
-/**
- * Helper method to extract a UTF-16 string from a StringPool. If the string is
- * stored as UTF-8,
- * the conversion to UTF-16 happens within ResStringPool.
- */
+// Helper method to extract a UTF-16 string from a StringPool. If the string is stored as UTF-8,
+// the conversion to UTF-16 happens within ResStringPool.
android::StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx);
-/**
- * Helper method to extract a UTF-8 string from a StringPool. If the string is
- * stored as UTF-16,
- * the conversion from UTF-16 to UTF-8 does not happen in ResStringPool and is
- * done by this method,
- * which maintains no state or cache. This means we must return an std::string
- * copy.
- */
+// Helper method to extract a UTF-8 string from a StringPool. If the string is stored as UTF-16,
+// the conversion from UTF-16 to UTF-8 does not happen in ResStringPool and is done by this method,
+// which maintains no state or cache. This means we must return an std::string copy.
std::string GetString(const android::ResStringPool& pool, size_t idx);
-/**
- * Checks that the Java string format contains no non-positional arguments
- * (arguments without
- * explicitly specifying an index) when there are more than one argument. This
- * is an error
- * because translations may rearrange the order of the arguments in the string,
- * which will
- * break the string interpolation.
- */
+// Checks that the Java string format contains no non-positional arguments (arguments without
+// explicitly specifying an index) when there are more than one argument. This is an error
+// because translations may rearrange the order of the arguments in the string, which will
+// break the string interpolation.
bool VerifyJavaStringFormat(const android::StringPiece& str);
class StringBuilder {
@@ -194,36 +167,38 @@ class StringBuilder {
std::string error_;
};
-inline const std::string& StringBuilder::ToString() const { return str_; }
+inline const std::string& StringBuilder::ToString() const {
+ return str_;
+}
-inline const std::string& StringBuilder::Error() const { return error_; }
+inline const std::string& StringBuilder::Error() const {
+ return error_;
+}
-inline bool StringBuilder::IsEmpty() const { return str_.empty(); }
+inline bool StringBuilder::IsEmpty() const {
+ return str_.empty();
+}
-inline size_t StringBuilder::Utf16Len() const { return utf16_len_; }
+inline size_t StringBuilder::Utf16Len() const {
+ return utf16_len_;
+}
-inline StringBuilder::operator bool() const { return error_.empty(); }
+inline StringBuilder::operator bool() const {
+ return error_.empty();
+}
-/**
- * Converts a UTF8 string to a UTF16 string.
- */
+// Converts a UTF8 string to a UTF16 string.
std::u16string Utf8ToUtf16(const android::StringPiece& utf8);
std::string Utf16ToUtf8(const android::StringPiece16& utf16);
-/**
- * Writes the entire BigBuffer to the output stream.
- */
+// Writes the entire BigBuffer to the output stream.
bool WriteAll(std::ostream& out, const BigBuffer& buffer);
-/*
- * Copies the entire BigBuffer into a single buffer.
- */
+// Copies the entire BigBuffer into a single buffer.
std::unique_ptr<uint8_t[]> Copy(const BigBuffer& buffer);
-/**
- * A Tokenizer implemented as an iterable collection. It does not allocate
- * any memory on the heap nor use standard containers.
- */
+// A Tokenizer implemented as an iterable collection. It does not allocate any memory on the heap
+// nor use standard containers.
class Tokenizer {
public:
class iterator {
@@ -269,38 +244,42 @@ class Tokenizer {
const iterator end_;
};
-inline Tokenizer Tokenize(const android::StringPiece& str, char sep) { return Tokenizer(str, sep); }
+inline Tokenizer Tokenize(const android::StringPiece& str, char sep) {
+ return Tokenizer(str, sep);
+}
-inline uint16_t HostToDevice16(uint16_t value) { return htods(value); }
+inline uint16_t HostToDevice16(uint16_t value) {
+ return htods(value);
+}
-inline uint32_t HostToDevice32(uint32_t value) { return htodl(value); }
+inline uint32_t HostToDevice32(uint32_t value) {
+ return htodl(value);
+}
-inline uint16_t DeviceToHost16(uint16_t value) { return dtohs(value); }
+inline uint16_t DeviceToHost16(uint16_t value) {
+ return dtohs(value);
+}
-inline uint32_t DeviceToHost32(uint32_t value) { return dtohl(value); }
+inline uint32_t DeviceToHost32(uint32_t value) {
+ return dtohl(value);
+}
-/**
- * Given a path like: res/xml-sw600dp/foo.xml
- *
- * Extracts "res/xml-sw600dp/" into outPrefix.
- * Extracts "foo" into outEntry.
- * Extracts ".xml" into outSuffix.
- *
- * Returns true if successful.
- */
+// Given a path like: res/xml-sw600dp/foo.xml
+//
+// Extracts "res/xml-sw600dp/" into outPrefix.
+// Extracts "foo" into outEntry.
+// Extracts ".xml" into outSuffix.
+//
+// Returns true if successful.
bool ExtractResFilePathParts(const android::StringPiece& path, android::StringPiece* out_prefix,
android::StringPiece* out_entry, android::StringPiece* out_suffix);
} // namespace util
-/**
- * Stream operator for functions. Calls the function with the stream as an
- * argument.
- * In the aapt namespace for lookup.
- */
-inline ::std::ostream& operator<<(
- ::std::ostream& out,
- const ::std::function<::std::ostream&(::std::ostream&)>& f) {
+// Stream operator for functions. Calls the function with the stream as an argument.
+// In the aapt namespace for lookup.
+inline ::std::ostream& operator<<(::std::ostream& out,
+ const ::std::function<::std::ostream&(::std::ostream&)>& f) {
return f(out);
}
diff --git a/tools/aapt2/util/Util_test.cpp b/tools/aapt2/util/Util_test.cpp
index adb52911ab82..2d1242ada949 100644
--- a/tools/aapt2/util/Util_test.cpp
+++ b/tools/aapt2/util/Util_test.cpp
@@ -117,24 +117,46 @@ TEST(UtilTest, IsJavaClassName) {
EXPECT_TRUE(util::IsJavaClassName("android.test.Class$Inner"));
EXPECT_TRUE(util::IsJavaClassName("android_test.test.Class"));
EXPECT_TRUE(util::IsJavaClassName("_android_.test._Class_"));
- EXPECT_FALSE(util::IsJavaClassName("android.test.$Inner"));
- EXPECT_FALSE(util::IsJavaClassName("android.test.Inner$"));
+ EXPECT_TRUE(util::IsJavaClassName("android.test.$Inner"));
+ EXPECT_TRUE(util::IsJavaClassName("android.test.Inner$"));
+ EXPECT_TRUE(util::IsJavaClassName("com.foo.FøøBar"));
+
EXPECT_FALSE(util::IsJavaClassName(".test.Class"));
EXPECT_FALSE(util::IsJavaClassName("android"));
+ EXPECT_FALSE(util::IsJavaClassName("FooBar"));
}
TEST(UtilTest, IsJavaPackageName) {
EXPECT_TRUE(util::IsJavaPackageName("android"));
EXPECT_TRUE(util::IsJavaPackageName("android.test"));
EXPECT_TRUE(util::IsJavaPackageName("android.test_thing"));
- EXPECT_FALSE(util::IsJavaPackageName("_android"));
- EXPECT_FALSE(util::IsJavaPackageName("android_"));
+ EXPECT_TRUE(util::IsJavaPackageName("_android"));
+ EXPECT_TRUE(util::IsJavaPackageName("android_"));
+ EXPECT_TRUE(util::IsJavaPackageName("android._test"));
+ EXPECT_TRUE(util::IsJavaPackageName("cøm.foo"));
+
EXPECT_FALSE(util::IsJavaPackageName("android."));
EXPECT_FALSE(util::IsJavaPackageName(".android"));
- EXPECT_FALSE(util::IsJavaPackageName("android._test"));
EXPECT_FALSE(util::IsJavaPackageName(".."));
}
+TEST(UtilTest, IsAndroidPackageName) {
+ EXPECT_TRUE(util::IsAndroidPackageName("android"));
+ EXPECT_TRUE(util::IsAndroidPackageName("android.test"));
+ EXPECT_TRUE(util::IsAndroidPackageName("com.foo"));
+ EXPECT_TRUE(util::IsAndroidPackageName("com.foo.test_thing"));
+ EXPECT_TRUE(util::IsAndroidPackageName("com.foo.testing_thing_"));
+ EXPECT_TRUE(util::IsAndroidPackageName("com.foo.test_99_"));
+
+ EXPECT_FALSE(util::IsAndroidPackageName("android._test"));
+ EXPECT_FALSE(util::IsAndroidPackageName("com"));
+ EXPECT_FALSE(util::IsAndroidPackageName("_android"));
+ EXPECT_FALSE(util::IsAndroidPackageName("android."));
+ EXPECT_FALSE(util::IsAndroidPackageName(".android"));
+ EXPECT_FALSE(util::IsAndroidPackageName(".."));
+ EXPECT_FALSE(util::IsAndroidPackageName("cøm.foo"));
+}
+
TEST(UtilTest, FullyQualifiedClassName) {
EXPECT_THAT(util::GetFullyQualifiedClassName("android", ".asdf"), Eq("android.asdf"));
EXPECT_THAT(util::GetFullyQualifiedClassName("android", ".a.b"), Eq("android.a.b"));
diff --git a/tools/aapt2/xml/XmlActionExecutor.cpp b/tools/aapt2/xml/XmlActionExecutor.cpp
index cc664a5de722..602a902bfc3e 100644
--- a/tools/aapt2/xml/XmlActionExecutor.cpp
+++ b/tools/aapt2/xml/XmlActionExecutor.cpp
@@ -16,6 +16,8 @@
#include "xml/XmlActionExecutor.h"
+using ::android::StringPiece;
+
namespace aapt {
namespace xml {
@@ -46,8 +48,8 @@ static void PrintElementToDiagMessage(const Element* el, DiagMessage* msg) {
*msg << el->name << ">";
}
-bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, SourcePathDiagnostics* diag,
- Element* el) const {
+bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, std::vector<StringPiece>* bread_crumb,
+ SourcePathDiagnostics* diag, Element* el) const {
bool error = false;
for (const ActionFuncWithDiag& action : actions_) {
error |= !action(el, diag);
@@ -57,15 +59,21 @@ bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, SourcePathDiagnostic
if (child_el->namespace_uri.empty()) {
std::map<std::string, XmlNodeAction>::const_iterator iter = map_.find(child_el->name);
if (iter != map_.end()) {
- error |= !iter->second.Execute(policy, diag, child_el);
+ // Use the iterator's copy of the element name, because the element may be modified.
+ bread_crumb->push_back(iter->first);
+ error |= !iter->second.Execute(policy, bread_crumb, diag, child_el);
+ bread_crumb->pop_back();
continue;
}
if (policy == XmlActionExecutorPolicy::kWhitelist) {
DiagMessage error_msg(child_el->line_number);
- error_msg << "unknown element ";
+ error_msg << "unexpected element ";
PrintElementToDiagMessage(child_el, &error_msg);
- error_msg << " found";
+ error_msg << " found in ";
+ for (const StringPiece& element : *bread_crumb) {
+ error_msg << "<" << element << ">";
+ }
diag->Error(error_msg);
error = true;
}
@@ -90,14 +98,15 @@ bool XmlActionExecutor::Execute(XmlActionExecutorPolicy policy, IDiagnostics* di
if (el->namespace_uri.empty()) {
std::map<std::string, XmlNodeAction>::const_iterator iter = map_.find(el->name);
if (iter != map_.end()) {
- return iter->second.Execute(policy, &source_diag, el);
+ std::vector<StringPiece> bread_crumb;
+ bread_crumb.push_back(iter->first);
+ return iter->second.Execute(policy, &bread_crumb, &source_diag, el);
}
if (policy == XmlActionExecutorPolicy::kWhitelist) {
DiagMessage error_msg(el->line_number);
- error_msg << "unknown element ";
+ error_msg << "unexpected root element ";
PrintElementToDiagMessage(el, &error_msg);
- error_msg << " found";
source_diag.Error(error_msg);
return false;
}
diff --git a/tools/aapt2/xml/XmlActionExecutor.h b/tools/aapt2/xml/XmlActionExecutor.h
index 1d70045b3023..df70100e882a 100644
--- a/tools/aapt2/xml/XmlActionExecutor.h
+++ b/tools/aapt2/xml/XmlActionExecutor.h
@@ -40,56 +40,46 @@ enum class XmlActionExecutorPolicy {
kWhitelist,
};
-/**
- * Contains the actions to perform at this XML node. This is a recursive data
- * structure that
- * holds XmlNodeActions for child XML nodes.
- */
+// Contains the actions to perform at this XML node. This is a recursive data structure that
+// holds XmlNodeActions for child XML nodes.
class XmlNodeAction {
public:
using ActionFuncWithDiag = std::function<bool(Element*, SourcePathDiagnostics*)>;
using ActionFunc = std::function<bool(Element*)>;
- /**
- * Find or create a child XmlNodeAction that will be performed for the child
- * element with the name `name`.
- */
- XmlNodeAction& operator[](const std::string& name) { return map_[name]; }
+ // Find or create a child XmlNodeAction that will be performed for the child element with the
+ // name `name`.
+ XmlNodeAction& operator[](const std::string& name) {
+ return map_[name];
+ }
- /**
- * Add an action to be performed at this XmlNodeAction.
- */
+ // Add an action to be performed at this XmlNodeAction.
void Action(ActionFunc f);
void Action(ActionFuncWithDiag);
private:
friend class XmlActionExecutor;
- bool Execute(XmlActionExecutorPolicy policy, SourcePathDiagnostics* diag, Element* el) const;
+ bool Execute(XmlActionExecutorPolicy policy, std::vector<::android::StringPiece>* bread_crumb,
+ SourcePathDiagnostics* diag, Element* el) const;
std::map<std::string, XmlNodeAction> map_;
std::vector<ActionFuncWithDiag> actions_;
};
-/**
- * Allows the definition of actions to execute at specific XML elements defined
- * by their
- * hierarchy.
- */
+// Allows the definition of actions to execute at specific XML elements defined by their hierarchy.
class XmlActionExecutor {
public:
XmlActionExecutor() = default;
- /**
- * Find or create a root XmlNodeAction that will be performed for the root XML
- * element with the name `name`.
- */
- XmlNodeAction& operator[](const std::string& name) { return map_[name]; }
+ // Find or create a root XmlNodeAction that will be performed for the root XML element with the
+ // name `name`.
+ XmlNodeAction& operator[](const std::string& name) {
+ return map_[name];
+ }
- /**
- * Execute the defined actions for this XmlResource.
- * Returns true if all actions return true, otherwise returns false.
- */
+ // Execute the defined actions for this XmlResource.
+ // Returns true if all actions return true, otherwise returns false.
bool Execute(XmlActionExecutorPolicy policy, IDiagnostics* diag, XmlResource* doc) const;
private:
diff --git a/tools/aapt2/xml/XmlActionExecutor_test.cpp b/tools/aapt2/xml/XmlActionExecutor_test.cpp
index 0fe7ab05ceb2..d39854e5fe4e 100644
--- a/tools/aapt2/xml/XmlActionExecutor_test.cpp
+++ b/tools/aapt2/xml/XmlActionExecutor_test.cpp
@@ -56,9 +56,13 @@ TEST(XmlActionExecutorTest, FailsWhenUndefinedHierarchyExists) {
XmlActionExecutor executor;
executor["manifest"]["application"];
- std::unique_ptr<XmlResource> doc =
- test::BuildXmlDom("<manifest><application /><activity /></manifest>");
+ std::unique_ptr<XmlResource> doc;
StdErrDiagnostics diag;
+
+ doc = test::BuildXmlDom("<manifest><application /><activity /></manifest>");
+ ASSERT_FALSE(executor.Execute(XmlActionExecutorPolicy::kWhitelist, &diag, doc.get()));
+
+ doc = test::BuildXmlDom("<manifest><application><activity /></application></manifest>");
ASSERT_FALSE(executor.Execute(XmlActionExecutorPolicy::kWhitelist, &diag, doc.get()));
}
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index 35225066633c..b0cf44accafa 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -258,8 +258,7 @@ static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPoo
}
}
-std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnostics* diag,
- const Source& source) {
+std::unique_ptr<XmlResource> Inflate(const void* data, size_t len, std::string* out_error) {
// We import the android namespace because on Windows NO_ERROR is a macro, not
// an enum, which causes errors when qualifying it with android::
using namespace android;
@@ -270,7 +269,10 @@ std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnos
std::unique_ptr<Element> pending_element;
ResXMLTree tree;
- if (tree.setTo(data, data_len) != NO_ERROR) {
+ if (tree.setTo(data, len) != NO_ERROR) {
+ if (out_error != nullptr) {
+ *out_error = "failed to initialize ResXMLTree";
+ }
return {};
}
@@ -361,6 +363,27 @@ std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnos
return util::make_unique<XmlResource>(ResourceFile{}, std::move(string_pool), std::move(root));
}
+std::unique_ptr<XmlResource> XmlResource::Clone() const {
+ std::unique_ptr<XmlResource> cloned = util::make_unique<XmlResource>(file);
+ if (root != nullptr) {
+ cloned->root = root->CloneElement([&](const xml::Element& src, xml::Element* dst) {
+ dst->attributes.reserve(src.attributes.size());
+ for (const xml::Attribute& attr : src.attributes) {
+ xml::Attribute cloned_attr;
+ cloned_attr.name = attr.name;
+ cloned_attr.namespace_uri = attr.namespace_uri;
+ cloned_attr.value = attr.value;
+ cloned_attr.compiled_attribute = attr.compiled_attribute;
+ if (attr.compiled_value != nullptr) {
+ cloned_attr.compiled_value.reset(attr.compiled_value->Clone(&cloned->string_pool));
+ }
+ dst->attributes.push_back(std::move(cloned_attr));
+ }
+ });
+ }
+ return cloned;
+}
+
Element* FindRootElement(Node* node) {
if (node == nullptr) {
return nullptr;
@@ -383,12 +406,7 @@ void Element::InsertChild(size_t index, std::unique_ptr<Node> child) {
}
Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) {
- for (auto& attr : attributes) {
- if (ns == attr.namespace_uri && name == attr.name) {
- return &attr;
- }
- }
- return nullptr;
+ return const_cast<Attribute*>(static_cast<const Element*>(this)->FindAttribute(ns, name));
}
const Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) const {
@@ -404,17 +422,29 @@ Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
return FindChildWithAttribute(ns, name, {}, {}, {});
}
+const Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) const {
+ return FindChildWithAttribute(ns, name, {}, {}, {});
+}
+
Element* Element::FindChildWithAttribute(const StringPiece& ns, const StringPiece& name,
const StringPiece& attr_ns, const StringPiece& attr_name,
const StringPiece& attr_value) {
- for (auto& child : children) {
- if (Element* el = NodeCast<Element>(child.get())) {
+ return const_cast<Element*>(static_cast<const Element*>(this)->FindChildWithAttribute(
+ ns, name, attr_ns, attr_name, attr_value));
+}
+
+const Element* Element::FindChildWithAttribute(const StringPiece& ns, const StringPiece& name,
+ const StringPiece& attr_ns,
+ const StringPiece& attr_name,
+ const StringPiece& attr_value) const {
+ for (const auto& child : children) {
+ if (const Element* el = NodeCast<Element>(child.get())) {
if (ns == el->namespace_uri && name == el->name) {
if (attr_ns.empty() && attr_name.empty()) {
return el;
}
- Attribute* attr = el->FindAttribute(attr_ns, attr_name);
+ const Attribute* attr = el->FindAttribute(attr_ns, attr_name);
if (attr && attr_value == attr->value) {
return el;
}
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index 063d7b9210c1..cf06ba5cc50e 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -100,11 +100,21 @@ class Element : public Node {
Attribute* FindAttribute(const android::StringPiece& ns, const android::StringPiece& name);
const Attribute* FindAttribute(const android::StringPiece& ns,
const android::StringPiece& name) const;
+
Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name);
+ const Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name) const;
+
Element* FindChildWithAttribute(const android::StringPiece& ns, const android::StringPiece& name,
const android::StringPiece& attr_ns,
const android::StringPiece& attr_name,
const android::StringPiece& attr_value);
+
+ const Element* FindChildWithAttribute(const android::StringPiece& ns,
+ const android::StringPiece& name,
+ const android::StringPiece& attr_ns,
+ const android::StringPiece& attr_name,
+ const android::StringPiece& attr_value) const;
+
std::vector<Element*> GetChildElements();
// Due to overriding of subtypes not working with unique_ptr, define a convenience Clone method
@@ -139,16 +149,16 @@ class XmlResource {
StringPool string_pool;
std::unique_ptr<xml::Element> root;
+
+ std::unique_ptr<XmlResource> Clone() const;
};
// Inflates an XML DOM from an InputStream, logging errors to the logger.
-// Returns the root node on success, or nullptr on failure.
std::unique_ptr<XmlResource> Inflate(io::InputStream* in, IDiagnostics* diag, const Source& source);
-// Inflates an XML DOM from a binary ResXMLTree, logging errors to the logger.
-// Returns the root node on success, or nullptr on failure.
-std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnostics* diag,
- const Source& source);
+// Inflates an XML DOM from a binary ResXMLTree.
+std::unique_ptr<XmlResource> Inflate(const void* data, size_t len,
+ std::string* out_error = nullptr);
Element* FindRootElement(Node* node);
diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp
index 34e6d3f54f56..e5012d67163d 100644
--- a/tools/aapt2/xml/XmlDom_test.cpp
+++ b/tools/aapt2/xml/XmlDom_test.cpp
@@ -70,8 +70,7 @@ TEST(XmlDomTest, BinaryInflate) {
ASSERT_TRUE(flattener.Consume(context.get(), doc.get()));
auto block = util::Copy(buffer);
- std::unique_ptr<XmlResource> new_doc =
- Inflate(block.get(), buffer.size(), context->GetDiagnostics(), Source("test.xml"));
+ std::unique_ptr<XmlResource> new_doc = Inflate(block.get(), buffer.size(), nullptr);
ASSERT_THAT(new_doc, NotNull());
EXPECT_THAT(new_doc->root->name, StrEq("Layout"));
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 2eab22e8ec14..c9f3199ef616 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -1371,7 +1371,9 @@ if __name__ == "__main__":
print
"""
- print "%s API style issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
- for f in sorted(cur_fail):
- print cur_fail[f]
- print
+ if len(cur_fail) != 0:
+ print "%s API style issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
+ for f in sorted(cur_fail):
+ print cur_fail[f]
+ print
+ sys.exit(77)
diff --git a/tools/apilint/apilint_sha.sh b/tools/apilint/apilint_sha.sh
new file mode 100755
index 000000000000..2a45b10392d7
--- /dev/null
+++ b/tools/apilint/apilint_sha.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+if git show --name-only --pretty=format: $1 | grep api/ > /dev/null; then
+ python tools/apilint/apilint.py <(git show $1:api/current.txt) <(git show $1^:api/current.txt)
+fi
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index a910c628a9e6..468864b49d3f 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -23,6 +23,10 @@ cc_binary_host {
"Collation.cpp",
"main.cpp",
],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
shared_libs: [
"libstats_proto_host",
@@ -90,6 +94,10 @@ cc_library_shared {
name: "libstatslog",
generated_sources: ["statslog.cpp"],
generated_headers: ["statslog.h"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
export_generated_headers: ["statslog.h"],
shared_libs: [
"liblog",
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 6350b725f09a..c54ab18717dd 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -2,7 +2,7 @@
#include "Collation.h"
-#include "frameworks/base/cmds/statsd/src/stats_events.pb.h"
+#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
#include <set>
#include <vector>
@@ -18,7 +18,7 @@ using namespace std;
namespace android {
namespace stats_log_api_gen {
-using android::os::statsd::StatsEvent;
+using android::os::statsd::Atom;
// TODO: Support WorkSources
@@ -96,8 +96,6 @@ java_type_name(java_type_t type)
static int
write_stats_log_cpp(FILE* out, const Atoms& atoms)
{
- int errorCount;
-
// Print prelude
fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n");
@@ -157,8 +155,6 @@ write_stats_log_cpp(FILE* out, const Atoms& atoms)
static int
write_stats_log_header(FILE* out, const Atoms& atoms)
{
- int errorCount;
-
// Print prelude
fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n");
@@ -229,8 +225,6 @@ write_stats_log_header(FILE* out, const Atoms& atoms)
static int
write_stats_log_java(FILE* out, const Atoms& atoms)
{
- int errorCount;
-
// Print prelude
fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n");
@@ -395,8 +389,6 @@ jni_function_signature(const vector<java_type_t>& signature)
static int
write_stats_log_jni(FILE* out, const Atoms& atoms)
{
- int errorCount;
-
// Print prelude
fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n");
@@ -582,7 +574,7 @@ run(int argc, char const*const* argv)
// Collate the parameters
Atoms atoms;
- int errorCount = collate_atoms(StatsEvent::descriptor(), &atoms);
+ int errorCount = collate_atoms(Atom::descriptor(), &atoms);
if (errorCount != 0) {
return 1;
}
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index 2311a1192c95..66861588a008 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -16,7 +16,7 @@
syntax = "proto2";
-import "frameworks/base/cmds/statsd/src/stats_events.proto";
+import "frameworks/base/cmds/statsd/src/atoms.proto";
package android.stats_log_api_gen;
diff --git a/tools/streaming_proto/cpp/main.cpp b/tools/streaming_proto/cpp/main.cpp
index 481698432711..477902065f99 100644
--- a/tools/streaming_proto/cpp/main.cpp
+++ b/tools/streaming_proto/cpp/main.cpp
@@ -18,6 +18,12 @@ make_filename(const FileDescriptorProto& file_descriptor)
return file_descriptor.name() + ".h";
}
+static inline bool
+should_generate_enums_mapping(const EnumDescriptorProto& enu)
+{
+ return enu.options().GetExtension(stream_enum).enable_enums_mapping();
+}
+
static void
write_enum(stringstream& text, const EnumDescriptorProto& enu, const string& indent)
{
@@ -25,10 +31,27 @@ write_enum(stringstream& text, const EnumDescriptorProto& enu, const string& ind
text << indent << "// enum " << enu.name() << endl;
for (int i=0; i<N; i++) {
const EnumValueDescriptorProto& value = enu.value(i);
- text << indent << "const uint32_t "
+ text << indent << "const int "
<< make_constant_name(value.name())
<< " = " << value.number() << ";" << endl;
}
+
+ if (should_generate_enums_mapping(enu)) {
+ string name = make_constant_name(enu.name());
+ string prefix = name + "_";
+ text << indent << "const int _ENUM_" << name << "_COUNT = " << N << ";" << endl;
+ text << indent << "const char* _ENUM_" << name << "_NAMES[" << N << "] = {" << endl;
+ for (int i=0; i<N; i++) {
+ text << indent << INDENT << "\"" << stripPrefix(enu.value(i).name(), prefix) << "\"," << endl;
+ }
+ text << indent << "};" << endl;
+ text << indent << "const int _ENUM_" << name << "_VALUES[" << N << "] = {" << endl;
+ for (int i=0; i<N; i++) {
+ text << indent << INDENT << make_constant_name(enu.value(i).name()) << "," << endl;
+ }
+ text << indent << "};" << endl;
+ }
+
text << endl;
}
@@ -59,7 +82,7 @@ write_field(stringstream& text, const FieldDescriptorProto& field, const string&
static inline bool
should_generate_fields_mapping(const DescriptorProto& message)
{
- return message.options().GetExtension(stream).enable_fields_mapping();
+ return message.options().GetExtension(stream_msg).enable_fields_mapping();
}
static void
diff --git a/tools/streaming_proto/stream.proto b/tools/streaming_proto/stream.proto
index 123506c03cfd..c08120986cc7 100644
--- a/tools/streaming_proto/stream.proto
+++ b/tools/streaming_proto/stream.proto
@@ -21,12 +21,22 @@ import "google/protobuf/descriptor.proto";
package android.stream_proto;
// This option tells streaming proto plugin to compile .proto files with extra features.
-message StreamFlags {
+message MessageOptions {
// creates a mapping of field names of the message to its field ids
optional bool enable_fields_mapping = 1;
}
extend google.protobuf.MessageOptions {
// Flags used by streaming proto plugins
- optional StreamFlags stream = 126856794;
+ optional MessageOptions stream_msg = 126856794;
+}
+
+message EnumOptions {
+ // creates a mapping of enum names to its values, strip its prefix enum type for each value
+ optional bool enable_enums_mapping = 1;
+}
+
+extend google.protobuf.EnumOptions {
+ // Flags used by streaming proto plugins
+ optional EnumOptions stream_enum = 126856794;
}
diff --git a/tools/streaming_proto/string_utils.cpp b/tools/streaming_proto/string_utils.cpp
index bd34ab7aa44d..607d820033ff 100644
--- a/tools/streaming_proto/string_utils.cpp
+++ b/tools/streaming_proto/string_utils.cpp
@@ -108,6 +108,17 @@ split(const string& str, const char delimiter)
return result;
}
+string
+stripPrefix(const string& str, const string& prefix)
+{
+ if (str.size() <= prefix.size()) return str;
+ size_t i = 0, len = prefix.size();
+ for (; i<len; i++) {
+ if (str[i] != prefix[i]) return str;
+ }
+ return str.substr(i);
+}
+
} // namespace stream_proto
} // namespace android
diff --git a/tools/streaming_proto/string_utils.h b/tools/streaming_proto/string_utils.h
index d6f195f67188..315b27531afd 100644
--- a/tools/streaming_proto/string_utils.h
+++ b/tools/streaming_proto/string_utils.h
@@ -26,15 +26,20 @@ string make_constant_name(const string& str);
string file_base_name(const string& str);
/**
- * Replace all occurances of 'replace' with 'with'.
+ * Replaces all occurances of 'replace' with 'with'.
*/
string replace_string(const string& str, const char replace, const char with);
/**
- * Split a string to parts by delimiter.
+ * Splits a string to parts by delimiter.
*/
vector<string> split(const string& str, const char delimiter);
+/**
+ * Returns the rest of str if it has prefix, otherwise return all.
+ */
+string stripPrefix(const string& str, const string& prefix);
+
} // namespace stream_proto
} // namespace android
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 551e4df1c816..c2f11d96b9f2 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -66,11 +66,11 @@ interface IWifiManager
List<OsuProvider> getMatchingOsuProviders(in ScanResult scanResult);
- int addOrUpdateNetwork(in WifiConfiguration config);
+ int addOrUpdateNetwork(in WifiConfiguration config, String packageName);
- boolean addOrUpdatePasspointConfiguration(in PasspointConfiguration config);
+ boolean addOrUpdatePasspointConfiguration(in PasspointConfiguration config, String packageName);
- boolean removePasspointConfiguration(in String fqdn);
+ boolean removePasspointConfiguration(in String fqdn, String packageName);
List<PasspointConfiguration> getPasspointConfigurations();
@@ -80,21 +80,21 @@ interface IWifiManager
void deauthenticateNetwork(long holdoff, boolean ess);
- boolean removeNetwork(int netId);
+ boolean removeNetwork(int netId, String packageName);
- boolean enableNetwork(int netId, boolean disableOthers);
+ boolean enableNetwork(int netId, boolean disableOthers, String packageName);
- boolean disableNetwork(int netId);
+ boolean disableNetwork(int netId, String packageName);
- void startScan(in ScanSettings requested, in WorkSource ws, in String packageName);
+ void startScan(in ScanSettings requested, in WorkSource ws, String packageName);
List<ScanResult> getScanResults(String callingPackage);
- void disconnect();
+ void disconnect(String packageName);
- void reconnect();
+ void reconnect(String packageName);
- void reassociate();
+ void reassociate(String packageName);
WifiInfo getConnectionInfo(String callingPackage);
@@ -102,13 +102,13 @@ interface IWifiManager
int getWifiEnabledState();
- void setCountryCode(String country, boolean persist);
+ void setCountryCode(String country);
String getCountryCode();
boolean isDualBandSupported();
- boolean saveConfiguration();
+ boolean saveConfiguration(String packageName);
DhcpInfo getDhcpInfo();
@@ -134,9 +134,9 @@ interface IWifiManager
boolean stopSoftAp();
- int startLocalOnlyHotspot(in Messenger messenger, in IBinder binder, in String packageName);
+ int startLocalOnlyHotspot(in Messenger messenger, in IBinder binder, String packageName);
- void stopLocalOnlyHotspot();
+ void stopLocalOnlyHotspot(String packageName);
void startWatchLocalOnlyHotspot(in Messenger messenger, in IBinder binder);
@@ -146,9 +146,9 @@ interface IWifiManager
WifiConfiguration getWifiApConfiguration();
- void setWifiApConfiguration(in WifiConfiguration wifiConfig);
+ void setWifiApConfiguration(in WifiConfiguration wifiConfig, String packageName);
- Messenger getWifiServiceMessenger();
+ Messenger getWifiServiceMessenger(String packageName);
void enableTdls(String remoteIPAddress, boolean enable);
@@ -166,16 +166,16 @@ interface IWifiManager
void setAllowScansWithTraffic(int enabled);
int getAllowScansWithTraffic();
- boolean setEnableAutoJoinWhenAssociated(boolean enabled);
+ boolean setEnableAutoJoinWhenAssociated(boolean enabled, String packageName);
boolean getEnableAutoJoinWhenAssociated();
void enableWifiConnectivityManager(boolean enabled);
WifiConnectionStatistics getConnectionStatistics();
- void disableEphemeralNetwork(String SSID);
+ void disableEphemeralNetwork(String SSID, String packageName);
- void factoryReset();
+ void factoryReset(String packageName);
Network getCurrentNetwork();
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index a367b2310721..bf8fed1c5f5c 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -348,6 +348,9 @@ public class WifiInfo implements Parcelable {
* quotation marks. Otherwise, it is returned as a string of hex digits. The
* SSID may be &lt;unknown ssid&gt; if there is no network currently connected,
* or if the caller has insufficient permissions to access the SSID.
+ *
+ * Prior to {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method
+ * always returned the SSID with no quotes around it.
* @return the SSID
*/
public String getSSID() {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index c2959d5e7ab7..66fabf33ddbb 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -16,6 +16,7 @@
package android.net.wifi;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
@@ -1127,7 +1128,7 @@ public class WifiManager {
*/
private int addOrUpdateNetwork(WifiConfiguration config) {
try {
- return mService.addOrUpdateNetwork(config);
+ return mService.addOrUpdateNetwork(config, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1148,7 +1149,7 @@ public class WifiManager {
*/
public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
try {
- if (!mService.addOrUpdatePasspointConfiguration(config)) {
+ if (!mService.addOrUpdatePasspointConfiguration(config, mContext.getOpPackageName())) {
throw new IllegalArgumentException();
}
} catch (RemoteException e) {
@@ -1165,7 +1166,7 @@ public class WifiManager {
*/
public void removePasspointConfiguration(String fqdn) {
try {
- if (!mService.removePasspointConfiguration(fqdn)) {
+ if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) {
throw new IllegalArgumentException();
}
} catch (RemoteException e) {
@@ -1251,7 +1252,7 @@ public class WifiManager {
*/
public boolean removeNetwork(int netId) {
try {
- return mService.removeNetwork(netId);
+ return mService.removeNetwork(netId, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1297,7 +1298,7 @@ public class WifiManager {
boolean success;
try {
- success = mService.enableNetwork(netId, attemptConnect);
+ success = mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1323,7 +1324,7 @@ public class WifiManager {
*/
public boolean disableNetwork(int netId) {
try {
- return mService.disableNetwork(netId);
+ return mService.disableNetwork(netId, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1336,7 +1337,7 @@ public class WifiManager {
*/
public boolean disconnect() {
try {
- mService.disconnect();
+ mService.disconnect(mContext.getOpPackageName());
return true;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1351,7 +1352,7 @@ public class WifiManager {
*/
public boolean reconnect() {
try {
- mService.reconnect();
+ mService.reconnect(mContext.getOpPackageName());
return true;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1366,7 +1367,7 @@ public class WifiManager {
*/
public boolean reassociate() {
try {
- mService.reassociate();
+ mService.reassociate(mContext.getOpPackageName());
return true;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1739,7 +1740,7 @@ public class WifiManager {
@Deprecated
public boolean saveConfiguration() {
try {
- return mService.saveConfiguration();
+ return mService.saveConfiguration(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1748,13 +1749,12 @@ public class WifiManager {
/**
* Set the country code.
* @param countryCode country code in ISO 3166 format.
- * @param persist {@code true} if this needs to be remembered
*
* @hide
*/
- public void setCountryCode(String country, boolean persist) {
+ public void setCountryCode(@NonNull String country) {
try {
- mService.setCountryCode(country, persist);
+ mService.setCountryCode(country);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1803,18 +1803,14 @@ public class WifiManager {
/**
* Enable or disable Wi-Fi.
- *
- * Note: This method will return false if wifi cannot be enabled (e.g., an incompatible mode
- * where the user has enabled tethering or Airplane Mode).
- *
- * Applications need to have the {@link android.Manifest.permission#CHANGE_WIFI_STATE}
- * permission to toggle wifi. Callers without the permissions will trigger a
- * {@link java.lang.SecurityException}.
+ * <p>
+ * Applications must have the {@link android.Manifest.permission#CHANGE_WIFI_STATE}
+ * permission to toggle wifi.
*
* @param enabled {@code true} to enable, {@code false} to disable.
- * @return {@code true} if the operation succeeds (or if the existing state
- * is the same as the requested state). False if wifi cannot be toggled on/off when the
- * request is made.
+ * @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is
+ * either already in the requested state, or in progress toward the requested state.
+ * @throws {@link java.lang.SecurityException} if the caller is missing required permissions.
*/
public boolean setWifiEnabled(boolean enabled) {
try {
@@ -2060,7 +2056,7 @@ public class WifiManager {
}
mLOHSCallbackProxy = null;
try {
- mService.stopLocalOnlyHotspot();
+ mService.stopLocalOnlyHotspot(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2179,7 +2175,7 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
try {
- mService.setWifiApConfiguration(wifiConfig);
+ mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
return true;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -2951,7 +2947,7 @@ public class WifiManager {
public void disableEphemeralNetwork(String SSID) {
if (SSID == null) throw new IllegalArgumentException("SSID cannot be null");
try {
- mService.disableEphemeralNetwork(SSID);
+ mService.disableEphemeralNetwork(SSID, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2990,7 +2986,7 @@ public class WifiManager {
*/
public Messenger getWifiServiceMessenger() {
try {
- return mService.getWifiServiceMessenger();
+ return mService.getWifiServiceMessenger(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3441,6 +3437,7 @@ public class WifiManager {
* Set wifi verbose log. Called from developer settings.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void enableVerboseLogging (int verbose) {
try {
mService.enableVerboseLogging(verbose);
@@ -3519,7 +3516,7 @@ public class WifiManager {
*/
public void factoryReset() {
try {
- mService.factoryReset();
+ mService.factoryReset(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3546,7 +3543,7 @@ public class WifiManager {
*/
public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
try {
- return mService.setEnableAutoJoinWhenAssociated(enabled);
+ return mService.setEnableAutoJoinWhenAssociated(enabled, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl b/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl
index e1ad78320611..3e37af06ab27 100644
--- a/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl
+++ b/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl
@@ -16,6 +16,8 @@
package android.net.wifi.rtt;
+import android.os.WorkSource;
+
import android.net.wifi.rtt.IRttCallback;
import android.net.wifi.rtt.RangingRequest;
@@ -25,6 +27,7 @@ import android.net.wifi.rtt.RangingRequest;
interface IWifiRttManager
{
boolean isAvailable();
- void startRanging(in IBinder binder, in String callingPackage, in RangingRequest request,
- in IRttCallback callback);
+ void startRanging(in IBinder binder, in String callingPackage, in WorkSource workSource,
+ in RangingRequest request, in IRttCallback callback);
+ void cancelRanging(in WorkSource workSource);
}
diff --git a/wifi/java/android/net/wifi/rtt/WifiRttManager.java b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
index c7c09239ce0d..128d6c91e7b6 100644
--- a/wifi/java/android/net/wifi/rtt/WifiRttManager.java
+++ b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
@@ -3,16 +3,19 @@ package android.net.wifi.rtt;
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_WIFI_STATE;
import static android.Manifest.permission.CHANGE_WIFI_STATE;
+import static android.Manifest.permission.LOCATION_HARDWARE;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.WorkSource;
import android.util.Log;
import java.util.List;
@@ -94,21 +97,63 @@ public class WifiRttManager {
@RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, CHANGE_WIFI_STATE, ACCESS_WIFI_STATE})
public void startRanging(RangingRequest request, RangingResultCallback callback,
@Nullable Handler handler) {
+ startRanging(null, request, callback, handler);
+ }
+
+ /**
+ * Initiate a request to range to a set of devices specified in the {@link RangingRequest}.
+ * Results will be returned in the {@link RangingResultCallback} set of callbacks.
+ *
+ * @param workSource A mechanism to specify an alternative work-source for the request.
+ * @param request A request specifying a set of devices whose distance measurements are
+ * requested.
+ * @param callback A callback for the result of the ranging request.
+ * @param handler The Handler on whose thread to execute the callbacks of the {@code
+ * callback} object. If a null is provided then the application's main thread
+ * will be used.
+ *
+ * @hide (@SystemApi)
+ */
+ @RequiresPermission(allOf = {LOCATION_HARDWARE, ACCESS_COARSE_LOCATION, CHANGE_WIFI_STATE,
+ ACCESS_WIFI_STATE})
+ public void startRanging(@Nullable WorkSource workSource, RangingRequest request,
+ RangingResultCallback callback, @Nullable Handler handler) {
if (VDBG) {
- Log.v(TAG, "startRanging: request=" + request + ", callback=" + callback + ", handler="
- + handler);
+ Log.v(TAG, "startRanging: workSource=" + workSource + ", request=" + request
+ + ", callback=" + callback + ", handler=" + handler);
}
Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
Binder binder = new Binder();
try {
- mService.startRanging(binder, mContext.getOpPackageName(), request,
+ mService.startRanging(binder, mContext.getOpPackageName(), workSource, request,
new RttCallbackProxy(looper, callback));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+ /**
+ * Cancel all ranging requests for the specified work sources. The requests have been requested
+ * using {@link #startRanging(WorkSource, RangingRequest, RangingResultCallback, Handler)}.
+ *
+ * @param workSource The work-sources of the requesters.
+ *
+ * @hide (@SystemApi)
+ */
+ @RequiresPermission(allOf = {LOCATION_HARDWARE})
+ public void cancelRanging(WorkSource workSource) {
+ if (VDBG) {
+ Log.v(TAG, "cancelRanging: workSource=" + workSource);
+ }
+
+ try {
+ mService.cancelRanging(workSource);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private static class RttCallbackProxy extends IRttCallback.Stub {
private final Handler mHandler;
private final RangingResultCallback mCallback;
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index ee6f12b775a8..3cad59053308 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -59,6 +59,7 @@ public class WifiManagerTest {
private static final int ERROR_NOT_SET = -1;
private static final int ERROR_TEST_REASON = 5;
private static final String TEST_PACKAGE_NAME = "TestPackage";
+ private static final String TEST_COUNTRY_CODE = "US";
@Mock Context mContext;
@Mock IWifiManager mWifiService;
@@ -136,7 +137,7 @@ public class WifiManagerTest {
assertEquals(mApConfig, callback.mRes.getWifiConfiguration());
callback.mRes.close();
- verify(mWifiService).stopLocalOnlyHotspot();
+ verify(mWifiService).stopLocalOnlyHotspot(TEST_PACKAGE_NAME);
}
/**
@@ -156,7 +157,7 @@ public class WifiManagerTest {
assertEquals(mApConfig, res.getWifiConfiguration());
}
- verify(mWifiService).stopLocalOnlyHotspot();
+ verify(mWifiService).stopLocalOnlyHotspot(TEST_PACKAGE_NAME);
}
/**
@@ -547,7 +548,7 @@ public class WifiManagerTest {
anyString())).thenReturn(REQUEST_REGISTERED);
mWifiManager.startLocalOnlyHotspot(callback, mHandler);
mWifiManager.cancelLocalOnlyHotspotRequest();
- verify(mWifiService).stopLocalOnlyHotspot();
+ verify(mWifiService).stopLocalOnlyHotspot(TEST_PACKAGE_NAME);
}
/**
@@ -569,7 +570,7 @@ public class WifiManagerTest {
anyString())).thenReturn(REQUEST_REGISTERED);
mWifiManager.startLocalOnlyHotspot(callback, mHandler);
mWifiManager.cancelLocalOnlyHotspotRequest();
- verify(mWifiService).stopLocalOnlyHotspot();
+ verify(mWifiService).stopLocalOnlyHotspot(TEST_PACKAGE_NAME);
mLooper.dispatchAll();
assertEquals(ERROR_NOT_SET, callback.mFailureReason);
assertFalse(callback.mOnStartedCalled);
@@ -593,7 +594,7 @@ public class WifiManagerTest {
assertFalse(callback.mOnStoppedCalled);
assertEquals(null, callback.mRes);
mWifiManager.cancelLocalOnlyHotspotRequest();
- verify(mWifiService, never()).stopLocalOnlyHotspot();
+ verify(mWifiService, never()).stopLocalOnlyHotspot(anyString());
}
/**
@@ -777,4 +778,23 @@ public class WifiManagerTest {
mWifiManager.unregisterLocalOnlyHotspotObserver();
verify(mWifiService).stopWatchLocalOnlyHotspot();
}
+
+ /**
+ * Verify that calls WifiServiceImpl to set country code when no exception happens.
+ */
+ @Test
+ public void testSetWifiCountryCode() throws Exception {
+ mWifiManager.setCountryCode(TEST_COUNTRY_CODE);
+ verify(mWifiService).setCountryCode(TEST_COUNTRY_CODE);
+ }
+
+ /**
+ * Verify that WifiManager.setCountryCode() rethrows exceptions if caller does not
+ * have necessary permissions.
+ */
+ @Test(expected = SecurityException.class)
+ public void testSetWifiCountryCodeFailedOnSecurityException() throws Exception {
+ doThrow(new SecurityException()).when(mWifiService).setCountryCode(anyString());
+ mWifiManager.setCountryCode(TEST_COUNTRY_CODE);
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
index 33bd9828fb1b..300d425e8062 100644
--- a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
@@ -85,8 +85,8 @@ public class WifiRttManagerTest {
// verify ranging request passed to service
mDut.startRanging(request, callbackMock, mMockLooperHandler);
- verify(mockRttService).startRanging(any(IBinder.class), eq(packageName), eq(request),
- callbackCaptor.capture());
+ verify(mockRttService).startRanging(any(IBinder.class), eq(packageName), eq(null),
+ eq(request), callbackCaptor.capture());
// service calls back with success
callbackCaptor.getValue().onRangingResults(results);
@@ -109,8 +109,8 @@ public class WifiRttManagerTest {
// verify ranging request passed to service
mDut.startRanging(request, callbackMock, mMockLooperHandler);
- verify(mockRttService).startRanging(any(IBinder.class), eq(packageName), eq(request),
- callbackCaptor.capture());
+ verify(mockRttService).startRanging(any(IBinder.class), eq(packageName), eq(null),
+ eq(request), callbackCaptor.capture());
// service calls back with failure code
callbackCaptor.getValue().onRangingFailure(failureCode);