summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk16
-rw-r--r--apct-tests/perftests/core/src/android/os/ParcelPerfTest.java55
-rw-r--r--apct-tests/perftests/multiuser/Android.mk3
-rw-r--r--apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResults.java77
-rw-r--r--apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResultsReporter.java74
-rw-r--r--apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java103
-rw-r--r--apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java83
-rw-r--r--api/current.txt117
-rw-r--r--api/system-current.txt122
-rw-r--r--api/test-current.txt117
-rw-r--r--cmds/vr/src/com/android/commands/vr/Vr.java24
-rw-r--r--core/java/android/app/Activity.java67
-rw-r--r--core/java/android/app/ActivityManager.java48
-rw-r--r--core/java/android/app/ActivityThread.java57
-rw-r--r--core/java/android/app/IActivityManager.aidl6
-rw-r--r--core/java/android/app/IApplicationThread.aidl2
-rw-r--r--core/java/android/app/KeyguardManager.java3
-rw-r--r--core/java/android/app/ProfilerInfo.java62
-rw-r--r--core/java/android/app/Vr2dDisplayProperties.java123
-rw-r--r--core/java/android/app/WallpaperManager.java22
-rw-r--r--core/java/android/app/timezone/DistroRulesVersion.java4
-rw-r--r--core/java/android/app/timezone/RulesUpdaterContract.java6
-rw-r--r--core/java/android/bluetooth/BluetoothHeadset.java55
-rw-r--r--core/java/android/content/pm/ActivityInfo.java17
-rw-r--r--core/java/android/content/pm/PackageParser.java9
-rw-r--r--core/java/android/content/res/Configuration.java54
-rw-r--r--core/java/android/database/sqlite/SQLiteConnection.java15
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java304
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java18
-rw-r--r--core/java/android/database/sqlite/SQLiteOpenHelper.java78
-rw-r--r--core/java/android/hardware/radio/RadioManager.java19
-rw-r--r--core/java/android/net/ConnectivityManager.java6
-rw-r--r--core/java/android/net/NetworkCapabilities.java26
-rw-r--r--core/java/android/net/NetworkInfo.java3
-rw-r--r--core/java/android/os/MemoryFile.java154
-rw-r--r--core/java/android/os/Parcel.java26
-rw-r--r--core/java/android/os/SharedMemory.aidl20
-rw-r--r--core/java/android/os/SharedMemory.java351
-rw-r--r--core/java/android/preference/Preference.java1
-rwxr-xr-xcore/java/android/provider/Settings.java27
-rw-r--r--core/java/android/service/autofill/CharSequenceTransformation.java202
-rw-r--r--core/java/android/service/autofill/CustomDescription.java218
-rw-r--r--core/java/android/service/autofill/ImageTransformation.java210
-rw-r--r--core/java/android/service/autofill/InternalTransformation.java36
-rw-r--r--core/java/android/service/autofill/InternalValidator.java33
-rw-r--r--core/java/android/service/autofill/LuhnChecksumValidator.java97
-rw-r--r--core/java/android/service/autofill/OptionalValidators.java96
-rw-r--r--core/java/android/service/autofill/RequiredValidators.java94
-rw-r--r--core/java/android/service/autofill/SaveInfo.java138
-rw-r--r--core/java/android/service/autofill/SimpleRegexValidator.java105
-rw-r--r--core/java/android/service/autofill/Transformation.java25
-rw-r--r--core/java/android/service/autofill/Validator.java24
-rw-r--r--core/java/android/service/autofill/Validators.java67
-rw-r--r--core/java/android/service/autofill/ValueFinder.java33
-rw-r--r--core/java/android/util/Log.java5
-rw-r--r--core/java/android/util/MergedConfiguration.java15
-rw-r--r--core/java/android/view/Display.java11
-rw-r--r--core/java/android/view/Surface.java8
-rw-r--r--core/java/android/view/View.java2
-rw-r--r--core/java/android/view/ViewGroup.java10
-rw-r--r--core/java/android/view/ViewRootImpl.java25
-rw-r--r--core/java/android/view/WindowManager.java38
-rw-r--r--core/java/android/view/WindowManagerImpl.java10
-rw-r--r--core/java/android/view/autofill/AutofillManager.java3
-rw-r--r--core/java/android/view/textservice/TextServicesManager.java42
-rw-r--r--core/java/android/webkit/WebView.java11
-rw-r--r--core/java/android/webkit/WebViewFactoryProvider.java6
-rw-r--r--core/java/android/widget/Editor.java37
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java9
-rw-r--r--core/java/com/android/internal/app/ResolverComparator.java4
-rw-r--r--core/java/com/android/internal/app/ResolverListController.java74
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java17
-rw-r--r--core/java/com/android/internal/policy/PipSnapAlgorithm.java110
-rw-r--r--core/java/com/android/internal/textservice/ITextServicesManager.aidl3
-rw-r--r--core/jni/Android.bp1
-rw-r--r--core/jni/AndroidRuntime.cpp34
-rw-r--r--core/jni/android_database_SQLiteConnection.cpp15
-rw-r--r--core/jni/android_os_HwBinder.cpp2
-rw-r--r--core/jni/android_os_MemoryFile.cpp98
-rw-r--r--core/jni/android_os_Parcel.cpp51
-rw-r--r--core/jni/android_os_SharedMemory.cpp105
-rw-r--r--core/res/AndroidManifest.xml9
-rw-r--r--core/res/res/anim/task_close_enter.xml2
-rw-r--r--core/res/res/anim/task_close_exit.xml2
-rw-r--r--core/res/res/layout/autofill_save.xml9
-rw-r--r--core/res/res/layout/shutdown_dialog.xml52
-rw-r--r--core/res/res/values-af/strings.xml2
-rw-r--r--core/res/res/values-am/strings.xml2
-rw-r--r--core/res/res/values-ar/strings.xml20
-rw-r--r--core/res/res/values-az/strings.xml2
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml4
-rw-r--r--core/res/res/values-be/strings.xml2
-rw-r--r--core/res/res/values-bg/strings.xml4
-rw-r--r--core/res/res/values-bn/strings.xml6
-rw-r--r--core/res/res/values-bs/strings.xml2
-rw-r--r--core/res/res/values-ca/strings.xml10
-rw-r--r--core/res/res/values-cs/strings.xml2
-rw-r--r--core/res/res/values-da/strings.xml2
-rw-r--r--core/res/res/values-de/strings.xml18
-rw-r--r--core/res/res/values-el/strings.xml4
-rw-r--r--core/res/res/values-en-rAU/strings.xml2
-rw-r--r--core/res/res/values-en-rGB/strings.xml2
-rw-r--r--core/res/res/values-en-rIN/strings.xml2
-rw-r--r--core/res/res/values-es-rUS/strings.xml4
-rw-r--r--core/res/res/values-es/strings.xml4
-rw-r--r--core/res/res/values-et/strings.xml2
-rw-r--r--core/res/res/values-eu/strings.xml2
-rw-r--r--core/res/res/values-fa/strings.xml2
-rw-r--r--core/res/res/values-fi/strings.xml2
-rw-r--r--core/res/res/values-fr-rCA/strings.xml4
-rw-r--r--core/res/res/values-fr/strings.xml2
-rw-r--r--core/res/res/values-gl/strings.xml2
-rw-r--r--core/res/res/values-gu/strings.xml2
-rw-r--r--core/res/res/values-hi/strings.xml4
-rw-r--r--core/res/res/values-hr/strings.xml2
-rw-r--r--core/res/res/values-hu/strings.xml2
-rw-r--r--core/res/res/values-hy/strings.xml2
-rw-r--r--core/res/res/values-in/strings.xml2
-rw-r--r--core/res/res/values-is/strings.xml2
-rw-r--r--core/res/res/values-it/strings.xml2
-rw-r--r--core/res/res/values-iw/strings.xml2
-rw-r--r--core/res/res/values-ja/strings.xml4
-rw-r--r--core/res/res/values-ka/strings.xml4
-rw-r--r--core/res/res/values-kk/strings.xml2
-rw-r--r--core/res/res/values-km/strings.xml4
-rw-r--r--core/res/res/values-kn/strings.xml2
-rw-r--r--core/res/res/values-ko/strings.xml2
-rw-r--r--core/res/res/values-ky/strings.xml2
-rw-r--r--core/res/res/values-lo/strings.xml2
-rw-r--r--core/res/res/values-lt/strings.xml2
-rw-r--r--core/res/res/values-lv/strings.xml2
-rw-r--r--core/res/res/values-mcc302-mnc370-bn/strings.xml26
-rw-r--r--core/res/res/values-mcc302-mnc370-gu/strings.xml26
-rw-r--r--core/res/res/values-mcc302-mnc370-kn/strings.xml26
-rw-r--r--core/res/res/values-mcc302-mnc370-ne/strings.xml26
-rw-r--r--core/res/res/values-mcc302-mnc370-pa/strings.xml26
-rw-r--r--core/res/res/values-mcc302-mnc370-ur/strings.xml26
-rw-r--r--core/res/res/values-mcc302-mnc720-bn/strings.xml26
-rw-r--r--core/res/res/values-mcc302-mnc720-gu/strings.xml26
-rw-r--r--core/res/res/values-mcc302-mnc720-kn/strings.xml26
-rw-r--r--core/res/res/values-mcc302-mnc720-ne/strings.xml26
-rw-r--r--core/res/res/values-mcc302-mnc720-pa/strings.xml26
-rw-r--r--core/res/res/values-mcc302-mnc720-ur/strings.xml26
-rw-r--r--core/res/res/values-mk/strings.xml2
-rw-r--r--core/res/res/values-ml/strings.xml2
-rw-r--r--core/res/res/values-mn/strings.xml2
-rw-r--r--core/res/res/values-mr/strings.xml2
-rw-r--r--core/res/res/values-ms/strings.xml2
-rw-r--r--core/res/res/values-my/strings.xml2
-rw-r--r--core/res/res/values-nb/strings.xml4
-rw-r--r--core/res/res/values-ne/strings.xml8
-rw-r--r--core/res/res/values-nl/strings.xml4
-rw-r--r--core/res/res/values-pa/strings.xml8
-rw-r--r--core/res/res/values-pl/strings.xml2
-rw-r--r--core/res/res/values-pt-rBR/strings.xml4
-rw-r--r--core/res/res/values-pt-rPT/strings.xml6
-rw-r--r--core/res/res/values-pt/strings.xml4
-rw-r--r--core/res/res/values-ro/strings.xml4
-rw-r--r--core/res/res/values-ru/strings.xml4
-rw-r--r--core/res/res/values-si/strings.xml2
-rw-r--r--core/res/res/values-sk/strings.xml4
-rw-r--r--core/res/res/values-sl/strings.xml2
-rw-r--r--core/res/res/values-sq/strings.xml2
-rw-r--r--core/res/res/values-sr/strings.xml4
-rw-r--r--core/res/res/values-sv/strings.xml4
-rw-r--r--core/res/res/values-sw/strings.xml2
-rw-r--r--core/res/res/values-ta/strings.xml2
-rw-r--r--core/res/res/values-te/strings.xml2
-rw-r--r--core/res/res/values-th/strings.xml6
-rw-r--r--core/res/res/values-tl/strings.xml2
-rw-r--r--core/res/res/values-tr/strings.xml4
-rw-r--r--core/res/res/values-uk/strings.xml6
-rw-r--r--core/res/res/values-ur/strings.xml6
-rw-r--r--core/res/res/values-uz/strings.xml2
-rw-r--r--core/res/res/values-vi/strings.xml4
-rw-r--r--core/res/res/values-zh-rCN/strings.xml6
-rw-r--r--core/res/res/values-zh-rHK/strings.xml4
-rw-r--r--core/res/res/values-zh-rTW/strings.xml4
-rw-r--r--core/res/res/values-zu/strings.xml2
-rw-r--r--core/res/res/values/attrs_manifest.xml33
-rw-r--r--core/res/res/values/config.xml21
-rw-r--r--core/res/res/values/dimens.xml3
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--core/res/res/values/symbols.xml5
-rw-r--r--core/tests/coretests/src/android/database/DatabaseGeneralTest.java54
-rw-r--r--core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java171
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java11
-rw-r--r--data/etc/privapp-permissions-platform.xml1
-rw-r--r--graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java5
-rw-r--r--graphics/java/android/graphics/drawable/TransitionDrawable.java12
-rw-r--r--legacy-test/Android.mk90
-rw-r--r--legacy-test/api/apicheck_msg_legacy_test.txt17
-rw-r--r--legacy-test/api/legacy-test-current.txt227
-rw-r--r--legacy-test/api/legacy-test-removed.txt0
-rw-r--r--libs/androidfw/ResourceTypes.cpp7
-rw-r--r--libs/hwui/GlopBuilder.cpp6
-rw-r--r--libs/hwui/GlopBuilder.h3
-rw-r--r--libs/hwui/OpenGLReadback.cpp8
-rw-r--r--location/java/android/location/GnssStatus.java13
-rw-r--r--location/java/android/location/LocationManager.java7
l---------native/android/include/android/multinetwork.h1
l---------native/android/include/multinetwork.h1
-rw-r--r--packages/CarrierDefaultApp/res/values-ca/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java6
-rw-r--r--packages/PrintSpooler/res/values-b+sr+Latn/strings.xml2
-rw-r--r--packages/PrintSpooler/res/values-sr/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml10
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml10
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml10
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml10
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml10
-rw-r--r--packages/SettingsLib/res/values-ka/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml10
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml10
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml8
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml20
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml8
-rw-r--r--packages/SettingsLib/res/values/strings.xml9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/TronUtils.java40
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java91
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java15
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java (renamed from packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java)21
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java89
-rw-r--r--packages/SettingsLib/tests/integ/AndroidManifest.xml1
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java69
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java80
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java61
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java8
-rw-r--r--packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_bottom.xml33
-rw-r--r--packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_top.xml33
-rw-r--r--packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_bottom.xml33
-rw-r--r--packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_top.xml33
-rw-r--r--packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_body.xml35
-rw-r--r--packages/SystemUI/res/anim/ic_landscape_to_rotate_arrows_animation.xml (renamed from packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device.xml)12
-rw-r--r--packages/SystemUI/res/anim/ic_landscape_to_rotate_bottom_merged_animation.xml (renamed from packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_bottom.xml)15
-rw-r--r--packages/SystemUI/res/anim/ic_landscape_to_rotate_landscape_animation.xml50
-rw-r--r--packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device_1.xml35
-rw-r--r--packages/SystemUI/res/anim/ic_portrait_to_rotate_arrows_0_animation.xml (renamed from packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrows.xml)31
-rw-r--r--packages/SystemUI/res/anim/ic_portrait_to_rotate_arrows_animation.xml (renamed from packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_device.xml)12
-rw-r--r--packages/SystemUI/res/anim/ic_portrait_to_rotate_bottom_merged_animation.xml (renamed from packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_bottom.xml)15
-rw-r--r--packages/SystemUI/res/anim/ic_portrait_to_rotate_device_0_animation.xml (renamed from packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_device.xml)10
-rw-r--r--packages/SystemUI/res/anim/ic_portrait_to_rotate_device_merged_animation.xml (renamed from packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_body.xml)11
-rw-r--r--packages/SystemUI/res/anim/ic_rotate_to_landscape_arrows_0_animation.xml (renamed from packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrows.xml)35
-rw-r--r--packages/SystemUI/res/anim/ic_rotate_to_landscape_arrows_animation.xml26
-rw-r--r--packages/SystemUI/res/anim/ic_rotate_to_landscape_bottom_merged_animation.xml (renamed from packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_top.xml)17
-rw-r--r--packages/SystemUI/res/anim/ic_rotate_to_landscape_landscape_animation.xml (renamed from packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrows.xml)46
-rw-r--r--packages/SystemUI/res/anim/ic_rotate_to_portrait_arrows_0_animation.xml (renamed from packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrows.xml)25
-rw-r--r--packages/SystemUI/res/anim/ic_rotate_to_portrait_arrows_animation.xml26
-rw-r--r--packages/SystemUI/res/anim/ic_rotate_to_portrait_bottom_merged_animation.xml (renamed from packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_top.xml)15
-rw-r--r--packages/SystemUI/res/anim/ic_rotate_to_portrait_device_0_animation.xml (renamed from packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device.xml)17
-rw-r--r--packages/SystemUI/res/anim/ic_rotate_to_portrait_device_merged_animation.xml (renamed from packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device_1.xml)7
-rw-r--r--packages/SystemUI/res/drawable/brightness_mirror_background.xml2
-rw-r--r--packages/SystemUI/res/drawable/car_qs_background_primary.xml20
-rw-r--r--packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate.xml61
-rw-r--r--packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate_animation.xml24
-rw-r--r--packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate.xml62
-rw-r--r--packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate_animation.xml23
-rw-r--r--packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate.xml57
-rw-r--r--packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate_animation.xml27
-rw-r--r--packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate.xml61
-rw-r--r--packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate_animation.xml27
-rw-r--r--packages/SystemUI/res/drawable/recents_dismiss_dark.xml19
-rw-r--r--packages/SystemUI/res/drawable/recents_dismiss_light.xml19
-rw-r--r--packages/SystemUI/res/interpolator/ic_landscape_to_rotate_animation_interpolator_0.xml (renamed from packages/SystemUI/res/interpolator/ic_landscape_to_auto_rotate_arrows_rotation_interpolator.xml)7
-rw-r--r--packages/SystemUI/res/interpolator/ic_rotate_to_landscape_animation_interpolator_0.xml (renamed from packages/SystemUI/res/interpolator/ic_landscape_from_auto_rotate_arrows_rotation_interpolator.xml)7
-rw-r--r--packages/SystemUI/res/interpolator/ic_rotate_to_portrait_animation_interpolator_0.xml19
-rw-r--r--packages/SystemUI/res/layout/car_qs_footer.xml63
-rw-r--r--packages/SystemUI/res/layout/car_qs_panel.xml27
-rw-r--r--packages/SystemUI/res/layout/car_status_bar_header.xml44
-rw-r--r--packages/SystemUI/res/layout/qs_footer_impl.xml (renamed from packages/SystemUI/res/layout/qs_footer.xml)8
-rw-r--r--packages/SystemUI/res/layout/qs_panel.xml3
-rw-r--r--packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml42
-rw-r--r--packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml58
-rw-r--r--packages/SystemUI/res/layout/rounded_corners.xml3
-rw-r--r--packages/SystemUI/res/values-af/strings.xml2
-rw-r--r--packages/SystemUI/res/values-am/strings.xml2
-rw-r--r--packages/SystemUI/res/values-am/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml26
-rw-r--r--packages/SystemUI/res/values-az/strings.xml2
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-be/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml6
-rw-r--r--packages/SystemUI/res/values-bg/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml2
-rw-r--r--packages/SystemUI/res/values-car/dimens.xml22
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml6
-rw-r--r--packages/SystemUI/res/values-cs/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-da/strings.xml2
-rw-r--r--packages/SystemUI/res/values-da/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-de/strings.xml4
-rw-r--r--packages/SystemUI/res/values-el/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml2
-rw-r--r--packages/SystemUI/res/values-es/strings.xml2
-rw-r--r--packages/SystemUI/res/values-et/strings.xml2
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml6
-rw-r--r--packages/SystemUI/res/values-eu/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml4
-rw-r--r--packages/SystemUI/res/values-hi/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml2
-rw-r--r--packages/SystemUI/res/values-in/strings.xml6
-rw-r--r--packages/SystemUI/res/values-in/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-is/strings.xml2
-rw-r--r--packages/SystemUI/res/values-it/strings.xml6
-rw-r--r--packages/SystemUI/res/values-it/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ja/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml2
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-kk/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-km/strings.xml6
-rw-r--r--packages/SystemUI/res/values-km/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml6
-rw-r--r--packages/SystemUI/res/values-mn/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml2
-rw-r--r--packages/SystemUI/res/values-my/strings.xml4
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ne/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml6
-rw-r--r--packages/SystemUI/res/values-nl/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml6
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml2
-rw-r--r--packages/SystemUI/res/values-si/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml4
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ta/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-te/strings.xml2
-rw-r--r--packages/SystemUI/res/values-th/strings.xml2
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-tr/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml2
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml2
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml4
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml2
-rw-r--r--packages/SystemUI/res/values/config.xml25
-rw-r--r--packages/SystemUI/res/values/dimens.xml20
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/res/values/styles.xml12
-rw-r--r--packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java93
-rw-r--r--packages/SystemUI/src/com/android/systemui/Prefs.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/RoundedCorners.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozePauser.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java92
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenStatePreventingAdapter.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeService.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapter.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeUi.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java98
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooter.java468
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java414
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java113
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java164
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java54
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/AlarmTimeout.java93
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/RoundedCornersTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java48
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java162
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java98
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java100
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java)10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/car/CarQsFragmentTest.java83
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java71
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java5
-rw-r--r--packages/VpnDialogs/res/values-ar/strings.xml2
-rw-r--r--packages/overlays/SysuiDarkThemeOverlay/res/values/styles.xml10
-rw-r--r--proto/src/metrics_constants.proto12
-rw-r--r--services/Android.mk3
-rw-r--r--services/autofill/java/com/android/server/autofill/RemoteFillService.java2
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java64
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java8
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/OverlayControl.java9
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/SaveUi.java31
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java2
-rw-r--r--services/core/Android.mk14
-rw-r--r--services/core/java/com/android/server/AppOpsService.java107
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java36
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java49
-rw-r--r--services/core/java/com/android/server/GestureLauncherService.java2
-rw-r--r--services/core/java/com/android/server/TextServicesManagerService.java71
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerDebugConfig.java1
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java179
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java20
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java107
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java144
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java462
-rw-r--r--services/core/java/com/android/server/am/KeyguardController.java8
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkMonitor.java52
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java385
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/OffloadController.java14
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java45
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java76
-rw-r--r--services/core/java/com/android/server/content/ContentService.java28
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java16
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java48
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java10
-rw-r--r--services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java3
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java11
-rw-r--r--services/core/java/com/android/server/power/ShutdownThread.java75
-rw-r--r--services/core/java/com/android/server/timezone/PackageStatusStorage.java5
-rw-r--r--services/core/java/com/android/server/timezone/PackageTracker.java20
-rw-r--r--services/core/java/com/android/server/timezone/PermissionHelper.java4
-rw-r--r--services/core/java/com/android/server/timezone/RulesManagerService.java140
-rw-r--r--services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java16
-rw-r--r--services/core/java/com/android/server/updates/TzDataInstallReceiver.java2
-rw-r--r--services/core/java/com/android/server/vr/Vr2dDisplay.java99
-rw-r--r--services/core/java/com/android/server/vr/VrManagerService.java2
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java53
-rw-r--r--services/core/java/com/android/server/wm/AppWindowContainerController.java19
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java17
-rw-r--r--services/core/java/com/android/server/wm/DimLayer.java6
-rw-r--r--services/core/java/com/android/server/wm/DimLayerController.java3
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java2
-rw-r--r--services/core/java/com/android/server/wm/Session.java4
-rw-r--r--services/core/java/com/android/server/wm/Task.java15
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotSurface.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java65
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java82
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfaceController.java4
-rw-r--r--services/core/jni/Android.mk1
-rw-r--r--services/core/jni/com_android_server_GraphicsStatsService.cpp3
-rw-r--r--services/core/jni/com_android_server_UsbDescriptorParser.cpp62
-rw-r--r--services/core/jni/com_android_server_VibratorService.cpp156
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java26
-rw-r--r--services/net/java/android/net/ip/IpManager.java18
-rw-r--r--services/net/java/android/net/ip/IpReachabilityMonitor.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java21
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java26
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java135
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java38
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java86
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java507
-rw-r--r--services/tests/servicestests/src/com/android/server/timezone/PackageStatusStorageTest.java25
-rw-r--r--services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java98
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java3
-rw-r--r--services/usb/java/com/android/server/usb/UsbAlsaManager.java37
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java5
-rw-r--r--services/usb/java/com/android/server/usb/UsbHostManager.java10
-rw-r--r--services/usb/java/com/android/server/usb/UsbPortManager.java7
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/ByteStream.java189
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java72
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java39
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java71
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.java76
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACHeader.java78
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACInputTerminal.java64
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java190
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java52
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java100
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACOutputTerminal.java49
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java65
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java54
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbASFormat.java64
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbASFormatI.java77
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbASFormatII.java72
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbASGeneral.java58
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbBinaryParser.java72
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java75
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.java223
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java376
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java109
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java117
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbHIDDescriptor.java70
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbInterfaceAssoc.java73
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java78
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.java36
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.java36
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.java36
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java93
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbUnknown.java28
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/report/HTMLReporter.java572
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/report/Reporter.java40
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/report/Reporting.java27
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java312
-rw-r--r--telecomm/java/android/telecom/PhoneAccount.java2
-rw-r--r--telephony/java/android/telephony/MbmsDownloadManager.java121
-rw-r--r--telephony/java/android/telephony/MbmsStreamingManager.java31
-rw-r--r--telephony/java/android/telephony/mbms/DownloadRequest.java48
-rw-r--r--telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java49
-rw-r--r--telephony/java/android/telephony/mbms/MbmsException.java2
-rw-r--r--telephony/java/android/telephony/mbms/ServiceInfo.java23
-rw-r--r--telephony/java/android/telephony/mbms/StreamingService.java11
-rwxr-xr-xtelephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl32
-rwxr-xr-xtelephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl24
-rw-r--r--telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java80
-rw-r--r--telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java41
-rw-r--r--test-runner/Android.mk176
-rw-r--r--test-runner/api/android-test-mock-current.txt413
-rw-r--r--test-runner/api/android-test-mock-removed.txt9
-rw-r--r--test-runner/api/android-test-runner-current.txt336
-rw-r--r--test-runner/api/android-test-runner-removed.txt0
-rw-r--r--test-runner/api/apicheck_msg_android_test_mock.txt17
-rw-r--r--test-runner/api/apicheck_msg_android_test_runner.txt17
-rw-r--r--tests/ShowWhenLockedApp/Android.mk10
-rw-r--r--tests/ShowWhenLockedApp/AndroidManifest.xml31
-rw-r--r--tests/ShowWhenLockedApp/src/com/android/showwhenlocked/ShowWhenLockedActivity.java164
-rw-r--r--tests/net/java/android/net/nsd/NsdManagerTest.java1
-rw-r--r--tests/net/java/android/net/util/SharedLogTest.java6
-rw-r--r--tests/net/java/com/android/internal/util/TestUtils.java54
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java230
-rw-r--r--tests/net/java/com/android/server/connectivity/TetheringTest.java50
-rw-r--r--tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java126
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsObserversTest.java29
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsServiceTest.java59
-rw-r--r--tools/aapt2/ConfigDescription.cpp4
-rw-r--r--tools/aapt2/ConfigDescription.h90
-rw-r--r--tools/aapt2/cmd/Link.cpp86
-rw-r--r--tools/aapt2/integration-tests/AppOne/res/drawable/adaptive-icon.xml20
-rw-r--r--tools/aapt2/link/AutoVersioner.cpp33
-rw-r--r--tools/aapt2/link/AutoVersioner_test.cpp2
-rw-r--r--tools/aapt2/link/Linkers.h15
-rw-r--r--tools/aapt2/readme.md1
-rw-r--r--tools/aapt2/util/TypeTraits.h1
-rw-r--r--tools/aapt2/util/Util.h5
-rw-r--r--tools/aapt2/xml/XmlUtil.cpp60
-rw-r--r--tools/aapt2/xml/XmlUtil.h28
674 files changed, 17551 insertions, 4562 deletions
diff --git a/Android.mk b/Android.mk
index 6fb5aec2eccc..7fda1dde463a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -729,6 +729,7 @@ aidl_files := \
frameworks/base/core/java/android/os/DropBoxManager.aidl \
frameworks/base/core/java/android/os/Bundle.aidl \
frameworks/base/core/java/android/os/Debug.aidl \
+ frameworks/base/core/java/android/os/SharedMemory.aidl \
frameworks/base/core/java/android/os/StrictMode.aidl \
frameworks/base/core/java/android/accessibilityservice/AccessibilityServiceInfo.aidl \
frameworks/base/core/java/android/net/Network.aidl \
@@ -873,7 +874,6 @@ packages_to_document := \
# The result will be relative to frameworks/base.
fwbase_dirs_to_document := \
legacy-test/src \
- test-runner/src \
$(patsubst $(LOCAL_PATH)/%,%, \
$(wildcard \
$(foreach dir, $(FRAMEWORKS_BASE_JAVA_SRC_DIRS), \
@@ -891,6 +891,12 @@ non_base_dirs := \
../opt/net/voip/src/java/android/net/rtp \
../opt/net/voip/src/java/android/net/sip
+framework_base_android_test_mock_src_files := \
+ $(call all-java-files-under, test-runner/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))
+
# These are relative to frameworks/base
dirs_to_check_apis := \
$(fwbase_dirs_to_document) \
@@ -910,6 +916,7 @@ endef
# FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk
dirs_to_document := \
$(dirs_to_check_apis) \
+ test-runner/src \
$(addprefix ../../, $(FRAMEWORKS_DATA_BINDING_JAVA_SRC_DIRS))
patterns_to_not_document := \
@@ -932,7 +939,9 @@ framework_docs_LOCAL_SRC_FILES := \
# These are relative to frameworks/base
framework_docs_LOCAL_API_CHECK_SRC_FILES := \
- $(call find-other-java-files, $(dirs_to_check_apis)) \
+ $(framework_base_android_test_mock_src_files) \
+ $(framework_base_android_test_runner_excluding_mock_src_files) \
+ $(call all-java-files-under, $(dirs_to_check_apis)) \
$(common_src_files)
# This is used by ide.mk as the list of source files that are
@@ -956,7 +965,8 @@ framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES := \
ext \
icu4j \
framework \
- voip-common
+ voip-common \
+ android.test.mock \
# Platform docs can refer to Support Library APIs, but we don't actually build
# them as part of the docs target, so we need to include them on the classpath.
diff --git a/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java b/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java
index 8cd45f7f92bd..a92597f131c3 100644
--- a/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java
@@ -57,6 +57,46 @@ public class ParcelPerfTest {
}
@Test
+ public void timeGetDataPosition() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mParcel.dataPosition();
+ }
+ }
+
+ @Test
+ public void timeSetDataSize() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mParcel.setDataSize(0);
+ }
+ }
+
+ @Test
+ public void timeGetDataSize() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mParcel.dataSize();
+ }
+ }
+
+ @Test
+ public void timeSetDataCapacity() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mParcel.setDataCapacity(0);
+ }
+ }
+
+ @Test
+ public void timeGetDataCapacity() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mParcel.dataCapacity();
+ }
+ }
+
+ @Test
public void timeWriteByte() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final byte val = 0xF;
@@ -112,4 +152,19 @@ public class ParcelPerfTest {
mParcel.readLong();
}
}
+
+ @Test
+ public void timeObtainRecycle() {
+ // Use up the pooled instances.
+ // A lot bigger than the actual size but in case someone increased it.
+ final int POOL_SIZE = 100;
+ for (int i = 0; i < POOL_SIZE; i++) {
+ Parcel.obtain();
+ }
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ Parcel.obtain().recycle();
+ }
+ }
}
diff --git a/apct-tests/perftests/multiuser/Android.mk b/apct-tests/perftests/multiuser/Android.mk
index f67004358ee6..e3f7775383bd 100644
--- a/apct-tests/perftests/multiuser/Android.mk
+++ b/apct-tests/perftests/multiuser/Android.mk
@@ -20,8 +20,7 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-test \
- apct-perftests-utils
+ android-support-test
LOCAL_PACKAGE_NAME := MultiUserPerfTests
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResults.java b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResults.java
new file mode 100644
index 000000000000..0d764ce29c74
--- /dev/null
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResults.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.multiuser;
+
+import android.os.Bundle;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.concurrent.TimeUnit;
+
+public class BenchmarkResults {
+ private final ArrayList<Long> mResults = new ArrayList<>();
+
+ public void addDuration(long duration) {
+ mResults.add(TimeUnit.NANOSECONDS.toMillis(duration));
+ }
+
+ public Bundle getStats() {
+ final Bundle stats = new Bundle();
+ stats.putDouble("Mean (ms)", mean());
+ stats.putDouble("Median (ms)", median());
+ stats.putDouble("Sigma (ms)", standardDeviation());
+ return stats;
+ }
+
+ public ArrayList<Long> getAllDurations() {
+ return mResults;
+ }
+
+ private double mean() {
+ final int size = mResults.size();
+ long sum = 0;
+ for (int i = 0; i < size; ++i) {
+ sum += mResults.get(i);
+ }
+ return (double) sum / size;
+ }
+
+ private double median() {
+ final int size = mResults.size();
+ if (size == 0) {
+ return 0f;
+ }
+ Collections.sort(mResults);
+ final int idx = size / 2;
+ return size % 2 == 0
+ ? (double) (mResults.get(idx) + mResults.get(idx - 1)) / 2
+ : mResults.get(idx);
+ }
+
+ private double standardDeviation() {
+ final int size = mResults.size();
+ if (size == 0) {
+ return 0f;
+ }
+ final double mean = mean();
+ double sd = 0;
+ for (int i = 0; i < size; ++i) {
+ double diff = mResults.get(i) - mean;
+ sd += diff * diff;
+ }
+ return Math.sqrt(sd / size);
+ }
+}
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResultsReporter.java b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResultsReporter.java
new file mode 100644
index 000000000000..7472865e9a5a
--- /dev/null
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResultsReporter.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.multiuser;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.os.Bundle;
+import android.support.test.InstrumentationRegistry;
+import android.util.Log;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.util.ArrayList;
+
+public class BenchmarkResultsReporter implements TestRule {
+ private final BenchmarkRunner mRunner;
+
+ public BenchmarkResultsReporter(BenchmarkRunner benchmarkRunner) {
+ mRunner = benchmarkRunner;
+ }
+
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ base.evaluate();
+ final Bundle stats = mRunner.getStats();
+ final String summary = getSummaryString(description.getMethodName(), stats);
+ logSummary(description.getTestClass().getSimpleName(), summary, mRunner.getAllDurations());
+ stats.putString(Instrumentation.REPORT_KEY_STREAMRESULT, summary);
+ InstrumentationRegistry.getInstrumentation().sendStatus(
+ Activity.RESULT_OK, stats);
+ }
+ };
+ }
+
+ private void logSummary(String tag, String summary, ArrayList<Long> durations) {
+ final StringBuilder sb = new StringBuilder(summary);
+ final int size = durations.size();
+ for (int i = 0; i < size; ++i) {
+ sb.append("\n").append(i).append("->").append(durations.get(i));
+ }
+ Log.d(tag, sb.toString());
+ }
+
+ private String getSummaryString(String testName, Bundle stats) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("\n\n").append(getKey(testName));
+ for (String key : stats.keySet()) {
+ sb.append("\n").append(key).append(": ").append(stats.get(key));
+ }
+ return sb.toString();
+ }
+
+ private String getKey(String testName) {
+ return testName.replaceAll("Perf$", "");
+ }
+}
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
new file mode 100644
index 000000000000..ccadc9a8f6a9
--- /dev/null
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.multiuser;
+
+import android.os.Bundle;
+import android.os.SystemClock;
+
+import java.util.ArrayList;
+
+// Based on //platform/frameworks/base/apct-tests/perftests/utils/BenchmarkState.java
+public class BenchmarkRunner {
+
+ private static long COOL_OFF_PERIOD_MS = 2000;
+
+ private static final int NUM_ITERATIONS = 4;
+
+ private static final int NOT_STARTED = 0; // The benchmark has not started yet.
+ private static final int RUNNING = 1; // The benchmark is running.
+ private static final int PAUSED = 2; // The benchmark is paused
+ private static final int FINISHED = 3; // The benchmark has stopped.
+
+ private final BenchmarkResults mResults = new BenchmarkResults();
+ private int mState = NOT_STARTED; // Current benchmark state.
+ private int mIteration;
+
+ public long mStartTimeNs;
+ public long mPausedDurationNs;
+ public long mPausedTimeNs;
+
+ public boolean keepRunning() {
+ switch (mState) {
+ case NOT_STARTED:
+ mState = RUNNING;
+ prepareForNextRun();
+ return true;
+ case RUNNING:
+ mIteration++;
+ return startNextTestRun();
+ case PAUSED:
+ throw new IllegalStateException("Benchmarking is in paused state");
+ case FINISHED:
+ throw new IllegalStateException("Benchmarking is finished");
+ default:
+ throw new IllegalStateException("BenchmarkRunner is in unknown state");
+ }
+ }
+
+ private boolean startNextTestRun() {
+ mResults.addDuration(System.nanoTime() - mStartTimeNs - mPausedDurationNs);
+ if (mIteration == NUM_ITERATIONS) {
+ mState = FINISHED;
+ return false;
+ } else {
+ prepareForNextRun();
+ return true;
+ }
+ }
+
+ private void prepareForNextRun() {
+ // TODO: Once http://b/63115387 is fixed, look into using "am wait-for-broadcast-idle"
+ // command instead of waiting for a fixed amount of time.
+ SystemClock.sleep(COOL_OFF_PERIOD_MS);
+ mStartTimeNs = System.nanoTime();
+ mPausedDurationNs = 0;
+ }
+
+ public void pauseTiming() {
+ if (mState != RUNNING) {
+ throw new IllegalStateException("Unable to pause the runner: not running currently");
+ }
+ mPausedTimeNs = System.nanoTime();
+ mState = PAUSED;
+ }
+
+ public void resumeTiming() {
+ if (mState != PAUSED) {
+ throw new IllegalStateException("Unable to resume the runner: already running");
+ }
+ mPausedDurationNs += System.nanoTime() - mPausedTimeNs;
+ mState = RUNNING;
+ }
+
+ public Bundle getStats() {
+ return mResults.getStats();
+ }
+
+ public ArrayList<Long> getAllDurations() {
+ return mResults.getAllDurations();
+ }
+} \ No newline at end of file
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
index e89157b52108..f114ef47007b 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
@@ -27,8 +27,6 @@ import android.content.pm.UserInfo;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
@@ -47,26 +45,34 @@ import java.util.concurrent.TimeUnit;
* Perf tests for user life cycle events.
*
* Running the tests:
+ *
* make MultiUserPerfTests &&
* adb install -r \
* ${ANDROID_PRODUCT_OUT}/data/app/MultiUserPerfTests/MultiUserPerfTests.apk &&
* adb shell am instrument -e class android.multiuser.UserLifecycleTest \
* -w com.android.perftests.multiuser/android.support.test.runner.AndroidJUnitRunner
+ *
+ * or
+ *
+ * bit MultiUserPerfTests:android.multiuser.UserLifecycleTest
+ *
+ * Note: If you use bit for running the tests, benchmark results won't be printed on the host side.
+ * But in either case, results can be checked on the device side 'adb logcat -s UserLifecycleTest'
*/
@LargeTest
@RunWith(AndroidJUnit4.class)
public class UserLifecycleTest {
- private final int TIMEOUT_IN_SECOND = 10;
+ private final int TIMEOUT_IN_SECOND = 30;
private final int CHECK_USER_REMOVED_INTERVAL_MS = 200;
private UserManager mUm;
private ActivityManager mAm;
private IActivityManager mIam;
- private BenchmarkState mState;
private ArrayList<Integer> mUsersToRemove;
+ private final BenchmarkRunner mRunner = new BenchmarkRunner();
@Rule
- public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ public BenchmarkResultsReporter mReporter = new BenchmarkResultsReporter(mRunner);
@Before
public void setUp() {
@@ -74,7 +80,6 @@ public class UserLifecycleTest {
mUm = UserManager.get(context);
mAm = context.getSystemService(ActivityManager.class);
mIam = ActivityManager.getService();
- mState = mPerfStatusReporter.getBenchmarkState();
mUsersToRemove = new ArrayList<>();
}
@@ -91,7 +96,7 @@ public class UserLifecycleTest {
@Test
public void createAndStartUserPerf() throws Exception {
- while (mState.keepRunning()) {
+ while (mRunner.keepRunning()) {
final UserInfo userInfo = mUm.createUser("TestUser", 0);
final CountDownLatch latch = new CountDownLatch(1);
@@ -99,91 +104,91 @@ public class UserLifecycleTest {
mIam.startUserInBackground(userInfo.id);
latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
- mState.pauseTiming();
+ mRunner.pauseTiming();
removeUser(userInfo.id);
- mState.resumeTiming();
+ mRunner.resumeTiming();
}
}
@Test
public void switchUserPerf() throws Exception {
- while (mState.keepRunning()) {
- mState.pauseTiming();
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
final int startUser = mAm.getCurrentUser();
final UserInfo userInfo = mUm.createUser("TestUser", 0);
- mState.resumeTiming();
+ mRunner.resumeTiming();
switchUser(userInfo.id);
- mState.pauseTiming();
+ mRunner.pauseTiming();
switchUser(startUser);
removeUser(userInfo.id);
- mState.resumeTiming();
+ mRunner.resumeTiming();
}
}
@Test
public void stopUserPerf() throws Exception {
- while (mState.keepRunning()) {
- mState.pauseTiming();
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
final UserInfo userInfo = mUm.createUser("TestUser", 0);
final CountDownLatch latch = new CountDownLatch(1);
registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userInfo.id);
mIam.startUserInBackground(userInfo.id);
latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
- mState.resumeTiming();
+ mRunner.resumeTiming();
stopUser(userInfo.id, false);
- mState.pauseTiming();
+ mRunner.pauseTiming();
removeUser(userInfo.id);
- mState.resumeTiming();
+ mRunner.resumeTiming();
}
}
@Test
public void lockedBootCompletedPerf() throws Exception {
- while (mState.keepRunning()) {
- mState.pauseTiming();
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
final int startUser = mAm.getCurrentUser();
final UserInfo userInfo = mUm.createUser("TestUser", 0);
final CountDownLatch latch = new CountDownLatch(1);
registerUserSwitchObserver(null, latch, userInfo.id);
- mState.resumeTiming();
+ mRunner.resumeTiming();
mAm.switchUser(userInfo.id);
latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
- mState.pauseTiming();
+ mRunner.pauseTiming();
switchUser(startUser);
removeUser(userInfo.id);
- mState.resumeTiming();
+ mRunner.resumeTiming();
}
}
@Test
public void managedProfileUnlockPerf() throws Exception {
- while (mState.keepRunning()) {
- mState.pauseTiming();
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
final UserInfo userInfo = mUm.createProfileForUser("TestUser",
UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser());
final CountDownLatch latch = new CountDownLatch(1);
registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, userInfo.id);
- mState.resumeTiming();
+ mRunner.resumeTiming();
mIam.startUserInBackground(userInfo.id);
latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
- mState.pauseTiming();
+ mRunner.pauseTiming();
removeUser(userInfo.id);
- mState.resumeTiming();
+ mRunner.resumeTiming();
}
}
@Test
public void ephemeralUserStoppedPerf() throws Exception {
- while (mState.keepRunning()) {
- mState.pauseTiming();
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
final int startUser = mAm.getCurrentUser();
final UserInfo userInfo = mUm.createUser("TestUser",
UserInfo.FLAG_EPHEMERAL | UserInfo.FLAG_DEMO);
@@ -200,35 +205,35 @@ public class UserLifecycleTest {
}, new IntentFilter(Intent.ACTION_USER_STOPPED));
final CountDownLatch switchLatch = new CountDownLatch(1);
registerUserSwitchObserver(switchLatch, null, startUser);
- mState.resumeTiming();
+ mRunner.resumeTiming();
mAm.switchUser(startUser);
latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
- mState.pauseTiming();
+ mRunner.pauseTiming();
switchLatch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
removeUser(userInfo.id);
- mState.resumeTiming();
+ mRunner.resumeTiming();
}
}
@Test
public void managedProfileStoppedPerf() throws Exception {
- while (mState.keepRunning()) {
- mState.pauseTiming();
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
final UserInfo userInfo = mUm.createProfileForUser("TestUser",
UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser());
final CountDownLatch latch = new CountDownLatch(1);
registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, userInfo.id);
mIam.startUserInBackground(userInfo.id);
latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
- mState.resumeTiming();
+ mRunner.resumeTiming();
stopUser(userInfo.id, true);
- mState.pauseTiming();
+ mRunner.pauseTiming();
removeUser(userInfo.id);
- mState.resumeTiming();
+ mRunner.resumeTiming();
}
}
diff --git a/api/current.txt b/api/current.txt
index 0eab1fd802ca..02c313cd4926 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1180,6 +1180,7 @@ package android {
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showText = 16843949; // 0x10104ad
field public static final deprecated int showWeekNumber = 16843582; // 0x101033e
+ field public static final int showWhenLocked = 16844137; // 0x1010569
field public static final deprecated int shownWeekCount = 16843585; // 0x1010341
field public static final int shrinkColumns = 16843082; // 0x101014a
field public static final deprecated int singleLine = 16843101; // 0x101015d
@@ -1438,6 +1439,7 @@ package android {
field public static final int trimPathOffset = 16843786; // 0x101040a
field public static final int trimPathStart = 16843784; // 0x1010408
field public static final int tunerCount = 16844061; // 0x101051d
+ field public static final int turnScreenOn = 16844138; // 0x101056a
field public static final int type = 16843169; // 0x10101a1
field public static final int typeface = 16842902; // 0x1010096
field public static final int uiOptions = 16843672; // 0x1010398
@@ -3764,10 +3766,12 @@ package android.app {
method public final void setResult(int);
method public final void setResult(int, android.content.Intent);
method public final deprecated void setSecondaryProgress(int);
+ method public void setShowWhenLocked(boolean);
method public void setTaskDescription(android.app.ActivityManager.TaskDescription);
method public void setTitle(java.lang.CharSequence);
method public void setTitle(int);
method public deprecated void setTitleColor(int);
+ method public void setTurnScreenOn(boolean);
method public void setVisible(boolean);
method public final void setVolumeControlStream(int);
method public void setVrModeEnabled(boolean, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -11868,6 +11872,7 @@ package android.database.sqlite {
method public void beginTransactionWithListenerNonExclusive(android.database.sqlite.SQLiteTransactionListener);
method public android.database.sqlite.SQLiteStatement compileStatement(java.lang.String) throws android.database.SQLException;
method public static android.database.sqlite.SQLiteDatabase create(android.database.sqlite.SQLiteDatabase.CursorFactory);
+ method public static android.database.sqlite.SQLiteDatabase createInMemory(android.database.sqlite.SQLiteDatabase.OpenParams);
method public int delete(java.lang.String, java.lang.String, java.lang.String[]);
method public static boolean deleteDatabase(java.io.File);
method public void disableWriteAheadLogging();
@@ -11897,6 +11902,7 @@ package android.database.sqlite {
method public boolean needUpgrade(int);
method protected void onAllReferencesReleased();
method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
+ method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.OpenParams);
method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.io.File, android.database.sqlite.SQLiteDatabase.CursorFactory);
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -11947,6 +11953,26 @@ package android.database.sqlite {
method public abstract android.database.Cursor newCursor(android.database.sqlite.SQLiteDatabase, android.database.sqlite.SQLiteCursorDriver, java.lang.String, android.database.sqlite.SQLiteQuery);
}
+ public static final class SQLiteDatabase.OpenParams {
+ method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
+ method public android.database.DatabaseErrorHandler getErrorHandler();
+ method public int getLookasideSlotCount();
+ method public int getLookasideSlotSize();
+ method public int getOpenFlags();
+ }
+
+ public static final class SQLiteDatabase.OpenParams.Builder {
+ ctor public SQLiteDatabase.OpenParams.Builder();
+ ctor public SQLiteDatabase.OpenParams.Builder(android.database.sqlite.SQLiteDatabase.OpenParams);
+ method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder addOpenFlags(int);
+ method public android.database.sqlite.SQLiteDatabase.OpenParams build();
+ method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder removeOpenFlags(int);
+ 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 setLookasideConfig(int, int);
+ method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
+ }
+
public class SQLiteDatabaseCorruptException extends android.database.sqlite.SQLiteException {
ctor public SQLiteDatabaseCorruptException();
ctor public SQLiteDatabaseCorruptException(java.lang.String);
@@ -12000,6 +12026,7 @@ package android.database.sqlite {
method public void onDowngrade(android.database.sqlite.SQLiteDatabase, int, int);
method public void onOpen(android.database.sqlite.SQLiteDatabase);
method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int);
+ method public void setLookasideConfig(int, int);
method public void setWriteAheadLoggingEnabled(boolean);
}
@@ -31023,12 +31050,12 @@ package android.os {
public class MemoryFile {
ctor public MemoryFile(java.lang.String, int) throws java.io.IOException;
- method public synchronized boolean allowPurging(boolean) throws java.io.IOException;
+ method public deprecated synchronized boolean allowPurging(boolean) throws java.io.IOException;
method public void close();
- method protected void finalize();
+ method public java.io.FileDescriptor getFileDescriptor() throws java.io.IOException;
method public java.io.InputStream getInputStream();
method public java.io.OutputStream getOutputStream();
- method public boolean isPurgingAllowed();
+ method public deprecated boolean isPurgingAllowed();
method public int length();
method public int readBytes(byte[], int, int, int) throws java.io.IOException;
method public void writeBytes(byte[], int, int, int) throws java.io.IOException;
@@ -31453,6 +31480,22 @@ package android.os {
field public static final android.os.Parcelable.Creator<android.os.ResultReceiver> CREATOR;
}
+ public final class SharedMemory implements java.io.Closeable android.os.Parcelable {
+ method public void close();
+ method public static android.os.SharedMemory create(java.lang.String, int) throws android.system.ErrnoException;
+ method public int describeContents();
+ method public int getFd();
+ method public java.io.FileDescriptor getFileDescriptor();
+ method public int getSize();
+ method public java.nio.ByteBuffer map(int, int, int) throws android.system.ErrnoException;
+ method public java.nio.ByteBuffer mapReadOnly() throws android.system.ErrnoException;
+ method public java.nio.ByteBuffer mapReadWrite() throws android.system.ErrnoException;
+ method public boolean setProtect(int);
+ method public static void unmap(java.nio.ByteBuffer);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.os.SharedMemory> CREATOR;
+ }
+
public class StatFs {
ctor public StatFs(java.lang.String);
method public deprecated int getAvailableBlocks();
@@ -36908,6 +36951,30 @@ package android.service.autofill {
field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
}
+ public final class CharSequenceTransformation implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.CharSequenceTransformation> CREATOR;
+ }
+
+ public static class CharSequenceTransformation.Builder {
+ ctor public CharSequenceTransformation.Builder();
+ method public android.service.autofill.CharSequenceTransformation.Builder addField(android.view.autofill.AutofillId, java.lang.String, java.lang.String);
+ method public android.service.autofill.CharSequenceTransformation build();
+ }
+
+ public final class CustomDescription implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.CustomDescription> CREATOR;
+ }
+
+ public static class CustomDescription.Builder {
+ ctor public CustomDescription.Builder(android.widget.RemoteViews);
+ method public android.service.autofill.CustomDescription.Builder addChild(int, android.service.autofill.Transformation);
+ method public android.service.autofill.CustomDescription build();
+ }
+
public final class Dataset implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -36981,6 +37048,25 @@ package android.service.autofill {
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
+ public final class ImageTransformation implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.ImageTransformation> CREATOR;
+ }
+
+ public static class ImageTransformation.Builder {
+ ctor public ImageTransformation.Builder(android.view.autofill.AutofillId);
+ method public android.service.autofill.ImageTransformation.Builder addOption(java.lang.String, int);
+ method public android.service.autofill.ImageTransformation build();
+ }
+
+ public final class LuhnChecksumValidator implements android.os.Parcelable {
+ ctor public LuhnChecksumValidator(android.view.autofill.AutofillId...);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.LuhnChecksumValidator> CREATOR;
+ }
+
public final class SaveCallback {
method public void onFailure(java.lang.CharSequence);
method public void onSuccess();
@@ -37004,10 +37090,12 @@ package android.service.autofill {
public static final class SaveInfo.Builder {
ctor public SaveInfo.Builder(int, android.view.autofill.AutofillId[]);
method public android.service.autofill.SaveInfo build();
+ method public android.service.autofill.SaveInfo.Builder setCustomDescription(android.service.autofill.CustomDescription);
method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence);
method public android.service.autofill.SaveInfo.Builder setFlags(int);
method public android.service.autofill.SaveInfo.Builder setNegativeAction(int, android.content.IntentSender);
method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]);
+ method public android.service.autofill.SaveInfo.Builder setValidator(android.service.autofill.Validator);
}
public final class SaveRequest implements android.os.Parcelable {
@@ -37018,6 +37106,24 @@ package android.service.autofill {
field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
}
+ public final class SimpleRegexValidator implements android.os.Parcelable {
+ ctor public SimpleRegexValidator(android.view.autofill.AutofillId, 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.SimpleRegexValidator> CREATOR;
+ }
+
+ public abstract interface Transformation {
+ }
+
+ public abstract interface Validator {
+ }
+
+ public final class Validators {
+ method public static android.service.autofill.Validator and(android.service.autofill.Validator...);
+ method public static android.service.autofill.Validator or(android.service.autofill.Validator...);
+ }
+
}
package android.service.carrier {
@@ -46890,12 +46996,12 @@ package android.view {
field public static final int FLAG_SCALED = 16384; // 0x4000
field public static final int FLAG_SECURE = 8192; // 0x2000
field public static final int FLAG_SHOW_WALLPAPER = 1048576; // 0x100000
- field public static final int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000
+ field public static final deprecated int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000
field public static final int FLAG_SPLIT_TOUCH = 8388608; // 0x800000
field public static final deprecated int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40
field public static final int FLAG_TRANSLUCENT_NAVIGATION = 134217728; // 0x8000000
field public static final int FLAG_TRANSLUCENT_STATUS = 67108864; // 0x4000000
- field public static final int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000
+ field public static final deprecated int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000
field public static final int FLAG_WATCH_OUTSIDE_TOUCH = 262144; // 0x40000
field public static final int FORMAT_CHANGED = 8; // 0x8
field public static final int LAST_APPLICATION_WINDOW = 99; // 0x63
@@ -48951,6 +49057,7 @@ package android.webkit {
method public void setNetworkAvailable(boolean);
method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
method public void setRendererPriorityPolicy(int, boolean);
+ method public static void setSafeBrowsingWhiteList(java.lang.String[]);
method public deprecated void setVerticalScrollbarOverlay(boolean);
method public void setWebChromeClient(android.webkit.WebChromeClient);
method public static void setWebContentsDebuggingEnabled(boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index 81f3aec09d8b..b9a8b20230c5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -120,6 +120,7 @@ package android {
field public static final java.lang.String GRANT_RUNTIME_PERMISSIONS = "android.permission.GRANT_RUNTIME_PERMISSIONS";
field public static final java.lang.String HARDWARE_TEST = "android.permission.HARDWARE_TEST";
field public static final java.lang.String HDMI_CEC = "android.permission.HDMI_CEC";
+ field public static final java.lang.String HIDE_NON_SYSTEM_OVERLAY_WINDOWS = "android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS";
field public static final java.lang.String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
field public static final java.lang.String INSTALL_GRANT_RUNTIME_PERMISSIONS = "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS";
field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
@@ -1308,6 +1309,7 @@ package android {
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showText = 16843949; // 0x10104ad
field public static final deprecated int showWeekNumber = 16843582; // 0x101033e
+ field public static final int showWhenLocked = 16844137; // 0x1010569
field public static final deprecated int shownWeekCount = 16843585; // 0x1010341
field public static final int shrinkColumns = 16843082; // 0x101014a
field public static final deprecated int singleLine = 16843101; // 0x101015d
@@ -1566,6 +1568,7 @@ package android {
field public static final int trimPathOffset = 16843786; // 0x101040a
field public static final int trimPathStart = 16843784; // 0x1010408
field public static final int tunerCount = 16844061; // 0x101051d
+ field public static final int turnScreenOn = 16844138; // 0x101056a
field public static final int type = 16843169; // 0x10101a1
field public static final int typeface = 16842902; // 0x1010096
field public static final int uiOptions = 16843672; // 0x1010398
@@ -3901,10 +3904,12 @@ package android.app {
method public final void setResult(int);
method public final void setResult(int, android.content.Intent);
method public final deprecated void setSecondaryProgress(int);
+ method public void setShowWhenLocked(boolean);
method public void setTaskDescription(android.app.ActivityManager.TaskDescription);
method public void setTitle(java.lang.CharSequence);
method public void setTitle(int);
method public deprecated void setTitleColor(int);
+ method public void setTurnScreenOn(boolean);
method public void setVisible(boolean);
method public final void setVolumeControlStream(int);
method public void setVrModeEnabled(boolean, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -12656,6 +12661,7 @@ package android.database.sqlite {
method public void beginTransactionWithListenerNonExclusive(android.database.sqlite.SQLiteTransactionListener);
method public android.database.sqlite.SQLiteStatement compileStatement(java.lang.String) throws android.database.SQLException;
method public static android.database.sqlite.SQLiteDatabase create(android.database.sqlite.SQLiteDatabase.CursorFactory);
+ method public static android.database.sqlite.SQLiteDatabase createInMemory(android.database.sqlite.SQLiteDatabase.OpenParams);
method public int delete(java.lang.String, java.lang.String, java.lang.String[]);
method public static boolean deleteDatabase(java.io.File);
method public void disableWriteAheadLogging();
@@ -12685,6 +12691,7 @@ package android.database.sqlite {
method public boolean needUpgrade(int);
method protected void onAllReferencesReleased();
method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
+ method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.OpenParams);
method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.io.File, android.database.sqlite.SQLiteDatabase.CursorFactory);
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -12735,6 +12742,26 @@ package android.database.sqlite {
method public abstract android.database.Cursor newCursor(android.database.sqlite.SQLiteDatabase, android.database.sqlite.SQLiteCursorDriver, java.lang.String, android.database.sqlite.SQLiteQuery);
}
+ public static final class SQLiteDatabase.OpenParams {
+ method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
+ method public android.database.DatabaseErrorHandler getErrorHandler();
+ method public int getLookasideSlotCount();
+ method public int getLookasideSlotSize();
+ method public int getOpenFlags();
+ }
+
+ public static final class SQLiteDatabase.OpenParams.Builder {
+ ctor public SQLiteDatabase.OpenParams.Builder();
+ ctor public SQLiteDatabase.OpenParams.Builder(android.database.sqlite.SQLiteDatabase.OpenParams);
+ method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder addOpenFlags(int);
+ method public android.database.sqlite.SQLiteDatabase.OpenParams build();
+ method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder removeOpenFlags(int);
+ 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 setLookasideConfig(int, int);
+ method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
+ }
+
public class SQLiteDatabaseCorruptException extends android.database.sqlite.SQLiteException {
ctor public SQLiteDatabaseCorruptException();
ctor public SQLiteDatabaseCorruptException(java.lang.String);
@@ -12788,6 +12815,7 @@ package android.database.sqlite {
method public void onDowngrade(android.database.sqlite.SQLiteDatabase, int, int);
method public void onOpen(android.database.sqlite.SQLiteDatabase);
method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int);
+ method public void setLookasideConfig(int, int);
method public void setWriteAheadLoggingEnabled(boolean);
}
@@ -17243,6 +17271,8 @@ package android.hardware.radio {
method public int getSpacing();
method public int getType();
method public int getUpperLimit();
+ method public boolean isAmBand();
+ method public boolean isFmBand();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.radio.RadioManager.BandDescriptor> CREATOR;
}
@@ -33774,12 +33804,12 @@ package android.os {
public class MemoryFile {
ctor public MemoryFile(java.lang.String, int) throws java.io.IOException;
- method public synchronized boolean allowPurging(boolean) throws java.io.IOException;
+ method public deprecated synchronized boolean allowPurging(boolean) throws java.io.IOException;
method public void close();
- method protected void finalize();
+ method public java.io.FileDescriptor getFileDescriptor() throws java.io.IOException;
method public java.io.InputStream getInputStream();
method public java.io.OutputStream getOutputStream();
- method public boolean isPurgingAllowed();
+ method public deprecated boolean isPurgingAllowed();
method public int length();
method public int readBytes(byte[], int, int, int) throws java.io.IOException;
method public void writeBytes(byte[], int, int, int) throws java.io.IOException;
@@ -34233,6 +34263,22 @@ package android.os {
field public static final android.os.Parcelable.Creator<android.os.ResultReceiver> CREATOR;
}
+ public final class SharedMemory implements java.io.Closeable android.os.Parcelable {
+ method public void close();
+ method public static android.os.SharedMemory create(java.lang.String, int) throws android.system.ErrnoException;
+ method public int describeContents();
+ method public int getFd();
+ method public java.io.FileDescriptor getFileDescriptor();
+ method public int getSize();
+ method public java.nio.ByteBuffer map(int, int, int) throws android.system.ErrnoException;
+ method public java.nio.ByteBuffer mapReadOnly() throws android.system.ErrnoException;
+ method public java.nio.ByteBuffer mapReadWrite() throws android.system.ErrnoException;
+ method public boolean setProtect(int);
+ method public static void unmap(java.nio.ByteBuffer);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.os.SharedMemory> CREATOR;
+ }
+
public class StatFs {
ctor public StatFs(java.lang.String);
method public deprecated int getAvailableBlocks();
@@ -39986,6 +40032,30 @@ package android.service.autofill {
field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
}
+ public final class CharSequenceTransformation implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.CharSequenceTransformation> CREATOR;
+ }
+
+ public static class CharSequenceTransformation.Builder {
+ ctor public CharSequenceTransformation.Builder();
+ method public android.service.autofill.CharSequenceTransformation.Builder addField(android.view.autofill.AutofillId, java.lang.String, java.lang.String);
+ method public android.service.autofill.CharSequenceTransformation build();
+ }
+
+ public final class CustomDescription implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.CustomDescription> CREATOR;
+ }
+
+ public static class CustomDescription.Builder {
+ ctor public CustomDescription.Builder(android.widget.RemoteViews);
+ method public android.service.autofill.CustomDescription.Builder addChild(int, android.service.autofill.Transformation);
+ method public android.service.autofill.CustomDescription build();
+ }
+
public final class Dataset implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -40059,6 +40129,25 @@ package android.service.autofill {
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
+ public final class ImageTransformation implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.ImageTransformation> CREATOR;
+ }
+
+ public static class ImageTransformation.Builder {
+ ctor public ImageTransformation.Builder(android.view.autofill.AutofillId);
+ method public android.service.autofill.ImageTransformation.Builder addOption(java.lang.String, int);
+ method public android.service.autofill.ImageTransformation build();
+ }
+
+ public final class LuhnChecksumValidator implements android.os.Parcelable {
+ ctor public LuhnChecksumValidator(android.view.autofill.AutofillId...);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.LuhnChecksumValidator> CREATOR;
+ }
+
public final class SaveCallback {
method public void onFailure(java.lang.CharSequence);
method public void onSuccess();
@@ -40082,10 +40171,12 @@ package android.service.autofill {
public static final class SaveInfo.Builder {
ctor public SaveInfo.Builder(int, android.view.autofill.AutofillId[]);
method public android.service.autofill.SaveInfo build();
+ method public android.service.autofill.SaveInfo.Builder setCustomDescription(android.service.autofill.CustomDescription);
method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence);
method public android.service.autofill.SaveInfo.Builder setFlags(int);
method public android.service.autofill.SaveInfo.Builder setNegativeAction(int, android.content.IntentSender);
method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]);
+ method public android.service.autofill.SaveInfo.Builder setValidator(android.service.autofill.Validator);
}
public final class SaveRequest implements android.os.Parcelable {
@@ -40096,6 +40187,24 @@ package android.service.autofill {
field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
}
+ public final class SimpleRegexValidator implements android.os.Parcelable {
+ ctor public SimpleRegexValidator(android.view.autofill.AutofillId, 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.SimpleRegexValidator> CREATOR;
+ }
+
+ public abstract interface Transformation {
+ }
+
+ public abstract interface Validator {
+ }
+
+ public final class Validators {
+ method public static android.service.autofill.Validator and(android.service.autofill.Validator...);
+ method public static android.service.autofill.Validator or(android.service.autofill.Validator...);
+ }
+
}
package android.service.carrier {
@@ -50374,6 +50483,7 @@ package android.view {
}
public abstract interface WindowManager implements android.view.ViewManager {
+ method public abstract android.graphics.Region getCurrentImeTouchRegion();
method public abstract android.view.Display getDefaultDisplay();
method public abstract void removeViewImmediate(android.view.View);
}
@@ -50442,12 +50552,12 @@ package android.view {
field public static final int FLAG_SCALED = 16384; // 0x4000
field public static final int FLAG_SECURE = 8192; // 0x2000
field public static final int FLAG_SHOW_WALLPAPER = 1048576; // 0x100000
- field public static final int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000
+ field public static final deprecated int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000
field public static final int FLAG_SPLIT_TOUCH = 8388608; // 0x800000
field public static final deprecated int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40
field public static final int FLAG_TRANSLUCENT_NAVIGATION = 134217728; // 0x8000000
field public static final int FLAG_TRANSLUCENT_STATUS = 67108864; // 0x4000000
- field public static final int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000
+ field public static final deprecated int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000
field public static final int FLAG_WATCH_OUTSIDE_TOUCH = 262144; // 0x40000
field public static final int FORMAT_CHANGED = 8; // 0x8
field public static final int LAST_APPLICATION_WINDOW = 99; // 0x63
@@ -52598,6 +52708,7 @@ package android.webkit {
method public void setNetworkAvailable(boolean);
method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
method public void setRendererPriorityPolicy(int, boolean);
+ method public static void setSafeBrowsingWhiteList(java.lang.String[]);
method public deprecated void setVerticalScrollbarOverlay(boolean);
method public void setWebChromeClient(android.webkit.WebChromeClient);
method public static void setWebContentsDebuggingEnabled(boolean);
@@ -52802,6 +52913,7 @@ package android.webkit {
method public abstract java.lang.String getDefaultUserAgent(android.content.Context);
method public abstract void initSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean>);
method public abstract android.net.Uri[] parseFileChooserResult(int, android.content.Intent);
+ method public abstract void setSafeBrowsingWhiteList(java.lang.String[]);
method public abstract void setWebContentsDebuggingEnabled(boolean);
method public abstract void shutdownSafeBrowsing();
}
diff --git a/api/test-current.txt b/api/test-current.txt
index e6c22ae979f0..08084b9a61f2 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1180,6 +1180,7 @@ package android {
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showText = 16843949; // 0x10104ad
field public static final deprecated int showWeekNumber = 16843582; // 0x101033e
+ field public static final int showWhenLocked = 16844137; // 0x1010569
field public static final deprecated int shownWeekCount = 16843585; // 0x1010341
field public static final int shrinkColumns = 16843082; // 0x101014a
field public static final deprecated int singleLine = 16843101; // 0x101015d
@@ -1438,6 +1439,7 @@ package android {
field public static final int trimPathOffset = 16843786; // 0x101040a
field public static final int trimPathStart = 16843784; // 0x1010408
field public static final int tunerCount = 16844061; // 0x101051d
+ field public static final int turnScreenOn = 16844138; // 0x101056a
field public static final int type = 16843169; // 0x10101a1
field public static final int typeface = 16842902; // 0x1010096
field public static final int uiOptions = 16843672; // 0x1010398
@@ -3766,10 +3768,12 @@ package android.app {
method public final void setResult(int);
method public final void setResult(int, android.content.Intent);
method public final deprecated void setSecondaryProgress(int);
+ method public void setShowWhenLocked(boolean);
method public void setTaskDescription(android.app.ActivityManager.TaskDescription);
method public void setTitle(java.lang.CharSequence);
method public void setTitle(int);
method public deprecated void setTitleColor(int);
+ method public void setTurnScreenOn(boolean);
method public void setVisible(boolean);
method public final void setVolumeControlStream(int);
method public void setVrModeEnabled(boolean, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -11911,6 +11915,7 @@ package android.database.sqlite {
method public void beginTransactionWithListenerNonExclusive(android.database.sqlite.SQLiteTransactionListener);
method public android.database.sqlite.SQLiteStatement compileStatement(java.lang.String) throws android.database.SQLException;
method public static android.database.sqlite.SQLiteDatabase create(android.database.sqlite.SQLiteDatabase.CursorFactory);
+ method public static android.database.sqlite.SQLiteDatabase createInMemory(android.database.sqlite.SQLiteDatabase.OpenParams);
method public int delete(java.lang.String, java.lang.String, java.lang.String[]);
method public static boolean deleteDatabase(java.io.File);
method public void disableWriteAheadLogging();
@@ -11940,6 +11945,7 @@ package android.database.sqlite {
method public boolean needUpgrade(int);
method protected void onAllReferencesReleased();
method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int);
+ method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.OpenParams);
method public static android.database.sqlite.SQLiteDatabase openDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, android.database.DatabaseErrorHandler);
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.io.File, android.database.sqlite.SQLiteDatabase.CursorFactory);
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -11990,6 +11996,26 @@ package android.database.sqlite {
method public abstract android.database.Cursor newCursor(android.database.sqlite.SQLiteDatabase, android.database.sqlite.SQLiteCursorDriver, java.lang.String, android.database.sqlite.SQLiteQuery);
}
+ public static final class SQLiteDatabase.OpenParams {
+ method public android.database.sqlite.SQLiteDatabase.CursorFactory getCursorFactory();
+ method public android.database.DatabaseErrorHandler getErrorHandler();
+ method public int getLookasideSlotCount();
+ method public int getLookasideSlotSize();
+ method public int getOpenFlags();
+ }
+
+ public static final class SQLiteDatabase.OpenParams.Builder {
+ ctor public SQLiteDatabase.OpenParams.Builder();
+ ctor public SQLiteDatabase.OpenParams.Builder(android.database.sqlite.SQLiteDatabase.OpenParams);
+ method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder addOpenFlags(int);
+ method public android.database.sqlite.SQLiteDatabase.OpenParams build();
+ method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder removeOpenFlags(int);
+ 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 setLookasideConfig(int, int);
+ method public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setOpenFlags(int);
+ }
+
public class SQLiteDatabaseCorruptException extends android.database.sqlite.SQLiteException {
ctor public SQLiteDatabaseCorruptException();
ctor public SQLiteDatabaseCorruptException(java.lang.String);
@@ -12043,6 +12069,7 @@ package android.database.sqlite {
method public void onDowngrade(android.database.sqlite.SQLiteDatabase, int, int);
method public void onOpen(android.database.sqlite.SQLiteDatabase);
method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int);
+ method public void setLookasideConfig(int, int);
method public void setWriteAheadLoggingEnabled(boolean);
}
@@ -31154,12 +31181,12 @@ package android.os {
public class MemoryFile {
ctor public MemoryFile(java.lang.String, int) throws java.io.IOException;
- method public synchronized boolean allowPurging(boolean) throws java.io.IOException;
+ method public deprecated synchronized boolean allowPurging(boolean) throws java.io.IOException;
method public void close();
- method protected void finalize();
+ method public java.io.FileDescriptor getFileDescriptor() throws java.io.IOException;
method public java.io.InputStream getInputStream();
method public java.io.OutputStream getOutputStream();
- method public boolean isPurgingAllowed();
+ method public deprecated boolean isPurgingAllowed();
method public int length();
method public int readBytes(byte[], int, int, int) throws java.io.IOException;
method public void writeBytes(byte[], int, int, int) throws java.io.IOException;
@@ -31585,6 +31612,22 @@ package android.os {
field public static final android.os.Parcelable.Creator<android.os.ResultReceiver> CREATOR;
}
+ public final class SharedMemory implements java.io.Closeable android.os.Parcelable {
+ method public void close();
+ method public static android.os.SharedMemory create(java.lang.String, int) throws android.system.ErrnoException;
+ method public int describeContents();
+ method public int getFd();
+ method public java.io.FileDescriptor getFileDescriptor();
+ method public int getSize();
+ method public java.nio.ByteBuffer map(int, int, int) throws android.system.ErrnoException;
+ method public java.nio.ByteBuffer mapReadOnly() throws android.system.ErrnoException;
+ method public java.nio.ByteBuffer mapReadWrite() throws android.system.ErrnoException;
+ method public boolean setProtect(int);
+ method public static void unmap(java.nio.ByteBuffer);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.os.SharedMemory> CREATOR;
+ }
+
public class StatFs {
ctor public StatFs(java.lang.String);
method public deprecated int getAvailableBlocks();
@@ -37080,6 +37123,30 @@ package android.service.autofill {
field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
}
+ public final class CharSequenceTransformation implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.CharSequenceTransformation> CREATOR;
+ }
+
+ public static class CharSequenceTransformation.Builder {
+ ctor public CharSequenceTransformation.Builder();
+ method public android.service.autofill.CharSequenceTransformation.Builder addField(android.view.autofill.AutofillId, java.lang.String, java.lang.String);
+ method public android.service.autofill.CharSequenceTransformation build();
+ }
+
+ public final class CustomDescription implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.CustomDescription> CREATOR;
+ }
+
+ public static class CustomDescription.Builder {
+ ctor public CustomDescription.Builder(android.widget.RemoteViews);
+ method public android.service.autofill.CustomDescription.Builder addChild(int, android.service.autofill.Transformation);
+ method public android.service.autofill.CustomDescription build();
+ }
+
public final class Dataset implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -37153,6 +37220,25 @@ package android.service.autofill {
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
+ public final class ImageTransformation implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.ImageTransformation> CREATOR;
+ }
+
+ public static class ImageTransformation.Builder {
+ ctor public ImageTransformation.Builder(android.view.autofill.AutofillId);
+ method public android.service.autofill.ImageTransformation.Builder addOption(java.lang.String, int);
+ method public android.service.autofill.ImageTransformation build();
+ }
+
+ public final class LuhnChecksumValidator implements android.os.Parcelable {
+ ctor public LuhnChecksumValidator(android.view.autofill.AutofillId...);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.LuhnChecksumValidator> CREATOR;
+ }
+
public final class SaveCallback {
method public void onFailure(java.lang.CharSequence);
method public void onSuccess();
@@ -37176,10 +37262,12 @@ package android.service.autofill {
public static final class SaveInfo.Builder {
ctor public SaveInfo.Builder(int, android.view.autofill.AutofillId[]);
method public android.service.autofill.SaveInfo build();
+ method public android.service.autofill.SaveInfo.Builder setCustomDescription(android.service.autofill.CustomDescription);
method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence);
method public android.service.autofill.SaveInfo.Builder setFlags(int);
method public android.service.autofill.SaveInfo.Builder setNegativeAction(int, android.content.IntentSender);
method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]);
+ method public android.service.autofill.SaveInfo.Builder setValidator(android.service.autofill.Validator);
}
public final class SaveRequest implements android.os.Parcelable {
@@ -37190,6 +37278,24 @@ package android.service.autofill {
field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
}
+ public final class SimpleRegexValidator implements android.os.Parcelable {
+ ctor public SimpleRegexValidator(android.view.autofill.AutofillId, 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.SimpleRegexValidator> CREATOR;
+ }
+
+ public abstract interface Transformation {
+ }
+
+ public abstract interface Validator {
+ }
+
+ public final class Validators {
+ method public static android.service.autofill.Validator and(android.service.autofill.Validator...);
+ method public static android.service.autofill.Validator or(android.service.autofill.Validator...);
+ }
+
}
package android.service.carrier {
@@ -47306,12 +47412,12 @@ package android.view {
field public static final int FLAG_SCALED = 16384; // 0x4000
field public static final int FLAG_SECURE = 8192; // 0x2000
field public static final int FLAG_SHOW_WALLPAPER = 1048576; // 0x100000
- field public static final int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000
+ field public static final deprecated int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000
field public static final int FLAG_SPLIT_TOUCH = 8388608; // 0x800000
field public static final deprecated int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40
field public static final int FLAG_TRANSLUCENT_NAVIGATION = 134217728; // 0x8000000
field public static final int FLAG_TRANSLUCENT_STATUS = 67108864; // 0x4000000
- field public static final int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000
+ field public static final deprecated int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000
field public static final int FLAG_WATCH_OUTSIDE_TOUCH = 262144; // 0x40000
field public static final int FORMAT_CHANGED = 8; // 0x8
field public static final int LAST_APPLICATION_WINDOW = 99; // 0x63
@@ -49372,6 +49478,7 @@ package android.webkit {
method public void setNetworkAvailable(boolean);
method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
method public void setRendererPriorityPolicy(int, boolean);
+ method public static void setSafeBrowsingWhiteList(java.lang.String[]);
method public deprecated void setVerticalScrollbarOverlay(boolean);
method public void setWebChromeClient(android.webkit.WebChromeClient);
method public static void setWebContentsDebuggingEnabled(boolean);
diff --git a/cmds/vr/src/com/android/commands/vr/Vr.java b/cmds/vr/src/com/android/commands/vr/Vr.java
index b765866faef9..8fb1b7b80618 100644
--- a/cmds/vr/src/com/android/commands/vr/Vr.java
+++ b/cmds/vr/src/com/android/commands/vr/Vr.java
@@ -41,6 +41,7 @@ public final class Vr extends BaseCommand {
"set-persistent-vr-mode-enabled";
private static final String COMMAND_SET_VR2D_DISPLAY_PROPERTIES =
"set-display-props";
+ private static final String COMMAND_ENABLE_VD = "enable-virtual-display";
private IVrManager mVrService;
@@ -49,7 +50,8 @@ public final class Vr extends BaseCommand {
out.println(
"usage: vr [subcommand]\n" +
"usage: vr set-persistent-vr-mode-enabled [true|false]\n" +
- "usage: vr set-display-props [width] [height] [dpi]\n"
+ "usage: vr set-display-props [width] [height] [dpi]\n" +
+ "usage: vr enable-virtual-display [true|false]\n"
);
}
@@ -69,6 +71,9 @@ public final class Vr extends BaseCommand {
case COMMAND_SET_PERSISTENT_VR_MODE_ENABLED:
runSetPersistentVrModeEnabled();
break;
+ case COMMAND_ENABLE_VD:
+ runEnableVd();
+ break;
default:
throw new IllegalArgumentException ("unknown command '" + command + "'");
}
@@ -94,6 +99,23 @@ public final class Vr extends BaseCommand {
}
}
+ private void runEnableVd() throws RemoteException {
+ Vr2dDisplayProperties.Builder builder = new Vr2dDisplayProperties.Builder();
+
+ String value = nextArgRequired();
+ if ("true".equals(value)) {
+ builder.setEnabled(true);
+ } else if ("false".equals(value)) {
+ builder.setEnabled(false);
+ } // Don't do anything if not exactly true/false
+
+ try {
+ mVrService.setVr2dDisplayProperties(builder.build());
+ } catch (RemoteException re) {
+ System.err.println("Error: Can't enable (" + value +") virtual display" + re);
+ }
+ }
+
private void runSetPersistentVrModeEnabled() throws RemoteException {
String enableStr = nextArg();
boolean enabled = Boolean.parseBoolean(enableStr);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index bc6e9cd0ab7e..adb3152d4ae7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -801,10 +801,6 @@ public class Activity extends ContextThemeWrapper
final Handler mHandler = new Handler();
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
- // Most recent call to requestVisibleBehind().
- @Deprecated
- boolean mVisibleBehind;
-
private static final class ManagedCursor {
ManagedCursor(Cursor cursor) {
mCursor = cursor;
@@ -6416,17 +6412,7 @@ public class Activity extends ContextThemeWrapper
*/
@Deprecated
public boolean requestVisibleBehind(boolean visible) {
- if (!mResumed) {
- // Do not permit paused or stopped activities to do this.
- visible = false;
- }
- try {
- mVisibleBehind = ActivityManager.getService()
- .requestVisibleBehind(mToken, visible) && visible;
- } catch (RemoteException e) {
- mVisibleBehind = false;
- }
- return mVisibleBehind;
+ return false;
}
/**
@@ -6469,10 +6455,6 @@ public class Activity extends ContextThemeWrapper
@Deprecated
@SystemApi
public boolean isBackgroundVisibleBehind() {
- try {
- return ActivityManager.getService().isBackgroundVisibleBehind(mToken);
- } catch (RemoteException e) {
- }
return false;
}
@@ -7566,6 +7548,53 @@ public class Activity extends ContextThemeWrapper
}
}
+ /**
+ * Specifies whether an {@link Activity} should be shown on top of the the lock screen whenever
+ * the lockscreen is up and the activity is resumed. Normally an activity will be transitioned
+ * to the stopped state if it is started while the lockscreen is up, but with this flag set the
+ * activity will remain in the resumed state visible on-top of the lock screen. This value can
+ * be set as a manifest attribute using {@link android.R.attr#showWhenLocked}.
+ *
+ * @param showWhenLocked {@code true} to show the {@link Activity} on top of the lock screen;
+ * {@code false} otherwise.
+ * @see #setTurnScreenOn(boolean)
+ * @see android.R.attr#turnScreenOn
+ * @see android.R.attr#showWhenLocked
+ */
+ public void setShowWhenLocked(boolean showWhenLocked) {
+ try {
+ ActivityManager.getService().setShowWhenLocked(mToken, showWhenLocked);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to call setShowWhenLocked", e);
+ }
+ }
+
+ /**
+ * Specifies whether the screen should be turned on when the {@link Activity} is resumed.
+ * Normally an activity will be transitioned to the stopped state if it is started while the
+ * screen if off, but with this flag set the activity will cause the screen to turn on if the
+ * activity will be visible and resumed due to the screen coming on. The screen will not be
+ * turned on if the activity won't be visible after the screen is turned on. This flag is
+ * normally used in conjunction with the {@link android.R.attr#showWhenLocked} flag to make sure
+ * the activity is visible after the screen is turned on when the lockscreen is up. In addition,
+ * if this flag is set and the activity calls {@link
+ * KeyguardManager#requestDismissKeyguard(Activity, KeyguardManager.KeyguardDismissCallback)}
+ * the screen will turn on.
+ *
+ * @param turnScreenOn {@code true} to turn on the screen; {@code false} otherwise.
+ *
+ * @see #setShowWhenLocked(boolean)
+ * @see android.R.attr#turnScreenOn
+ * @see android.R.attr#showWhenLocked
+ */
+ public void setTurnScreenOn(boolean turnScreenOn) {
+ try {
+ ActivityManager.getService().setTurnScreenOn(mToken, turnScreenOn);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to call setTurnScreenOn", e);
+ }
+ }
+
class HostCallbacks extends FragmentHostCallback<Activity> {
public HostCallbacks() {
super(Activity.this /*activity*/);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 06dbe8218450..20a4ba159ef9 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -24,42 +24,35 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.graphics.Canvas;
-import android.graphics.GraphicBuffer;
-import android.graphics.Matrix;
-import android.graphics.Point;
-import android.os.BatteryStats;
-import android.os.Build;
-import android.os.Build.VERSION_CODES;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-
-import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.os.RoSystemProperties;
-import com.android.internal.os.TransferPipe;
-import com.android.internal.util.FastPrintWriter;
-import com.android.server.LocalServices;
-
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.UriPermission;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.GraphicBuffer;
+import android.graphics.Matrix;
+import android.graphics.Point;
import android.graphics.Rect;
+import android.os.BatteryStats;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
@@ -72,6 +65,12 @@ import android.util.DisplayMetrics;
import android.util.Singleton;
import android.util.Size;
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.os.RoSystemProperties;
+import com.android.internal.os.TransferPipe;
+import com.android.internal.util.FastPrintWriter;
+import com.android.server.LocalServices;
+
import org.xmlpull.v1.XmlSerializer;
import java.io.FileDescriptor;
@@ -904,19 +903,6 @@ public class ActivityManager {
}
/**
- * Returns true if activities contained in this stack can request visible behind by
- * calling {@link Activity#requestVisibleBehind}.
- *
- * @deprecated This method's functionality is no longer supported as of
- * {@link android.os.Build.VERSION_CODES#O} and will be removed in a future release.
- */
- @Deprecated
- public static boolean activitiesCanRequestVisibleBehind(int stackId) {
- return stackId == FULLSCREEN_WORKSPACE_STACK_ID ||
- stackId == ASSISTANT_STACK_ID;
- }
-
- /**
* Returns true if this stack may be scaled without resizing, and windows within may need
* to be configured as such.
*/
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4a01fe68f0fd..074cdefc52b0 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -445,7 +445,6 @@ public final class ActivityThread {
sb.append(", startedActivity=").append(activity.mStartedActivity);
sb.append(", temporaryPause=").append(activity.mTemporaryPause);
sb.append(", changingConfigurations=").append(activity.mChangingConfigurations);
- sb.append(", visibleBehind=").append(activity.mVisibleBehind);
sb.append("}");
}
sb.append("}");
@@ -1384,16 +1383,6 @@ public final class ActivityThread {
}
@Override
- public void scheduleCancelVisibleBehind(IBinder token) {
- sendMessage(H.CANCEL_VISIBLE_BEHIND, token);
- }
-
- @Override
- public void scheduleBackgroundVisibleBehindChanged(IBinder token, boolean visible) {
- sendMessage(H.BACKGROUND_VISIBLE_BEHIND_CHANGED, token, visible ? 1 : 0);
- }
-
- @Override
public void scheduleEnterAnimationComplete(IBinder token) {
sendMessage(H.ENTER_ANIMATION_COMPLETE, token);
}
@@ -1509,8 +1498,6 @@ public final class ActivityThread {
public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144;
public static final int INSTALL_PROVIDER = 145;
public static final int ON_NEW_ACTIVITY_OPTIONS = 146;
- public static final int CANCEL_VISIBLE_BEHIND = 147;
- public static final int BACKGROUND_VISIBLE_BEHIND_CHANGED = 148;
public static final int ENTER_ANIMATION_COMPLETE = 149;
public static final int START_BINDER_TRACKING = 150;
public static final int STOP_BINDER_TRACKING_AND_DUMP = 151;
@@ -1571,8 +1558,6 @@ public final class ActivityThread {
case TRANSLUCENT_CONVERSION_COMPLETE: return "TRANSLUCENT_CONVERSION_COMPLETE";
case INSTALL_PROVIDER: return "INSTALL_PROVIDER";
case ON_NEW_ACTIVITY_OPTIONS: return "ON_NEW_ACTIVITY_OPTIONS";
- case CANCEL_VISIBLE_BEHIND: return "CANCEL_VISIBLE_BEHIND";
- case BACKGROUND_VISIBLE_BEHIND_CHANGED: return "BACKGROUND_VISIBLE_BEHIND_CHANGED";
case ENTER_ANIMATION_COMPLETE: return "ENTER_ANIMATION_COMPLETE";
case MULTI_WINDOW_MODE_CHANGED: return "MULTI_WINDOW_MODE_CHANGED";
case PICTURE_IN_PICTURE_MODE_CHANGED: return "PICTURE_IN_PICTURE_MODE_CHANGED";
@@ -1815,12 +1800,6 @@ public final class ActivityThread {
Pair<IBinder, ActivityOptions> pair = (Pair<IBinder, ActivityOptions>) msg.obj;
onNewActivityOptions(pair.first, pair.second);
break;
- case CANCEL_VISIBLE_BEHIND:
- handleCancelVisibleBehind((IBinder) msg.obj);
- break;
- case BACKGROUND_VISIBLE_BEHIND_CHANGED:
- handleOnBackgroundVisibleBehindChanged((IBinder) msg.obj, msg.arg1 > 0);
- break;
case ENTER_ANIMATION_COMPLETE:
handleEnterAnimationComplete((IBinder) msg.obj);
break;
@@ -3070,36 +3049,6 @@ public final class ActivityThread {
}
}
- public void handleCancelVisibleBehind(IBinder token) {
- ActivityClientRecord r = mActivities.get(token);
- if (r != null) {
- mSomeActivitiesChanged = true;
- final Activity activity = r.activity;
- if (activity.mVisibleBehind) {
- activity.mCalled = false;
- activity.onVisibleBehindCanceled();
- // Tick, tick, tick. The activity has 500 msec to return or it will be destroyed.
- if (!activity.mCalled) {
- throw new SuperNotCalledException("Activity " + activity.getLocalClassName() +
- " did not call through to super.onVisibleBehindCanceled()");
- }
- activity.mVisibleBehind = false;
- }
- }
- try {
- ActivityManager.getService().backgroundResourcesReleased(token);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- public void handleOnBackgroundVisibleBehindChanged(IBinder token, boolean visible) {
- ActivityClientRecord r = mActivities.get(token);
- if (r != null) {
- r.activity.onBackgroundVisibleBehindChanged(visible);
- }
- }
-
public void handleInstallProvider(ProviderInfo info) {
final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
try {
@@ -5189,11 +5138,7 @@ public final class ActivityThread {
Slog.w(TAG, "Profiling failed on path " + profilerInfo.profileFile
+ " -- can the process access this path?");
} finally {
- try {
- profilerInfo.profileFd.close();
- } catch (IOException e) {
- Slog.w(TAG, "Failure closing profile fd", e);
- }
+ profilerInfo.closeFd();
}
} else {
switch (profileType) {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 3ac026d70a6f..b27e224251d3 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -412,9 +412,6 @@ interface IActivityManager {
void stopSystemLockTaskMode();
void finishVoiceTask(in IVoiceInteractionSession session);
boolean isTopOfTask(in IBinder token);
- boolean requestVisibleBehind(in IBinder token, boolean visible);
- boolean isBackgroundVisibleBehind(in IBinder token);
- void backgroundResourcesReleased(in IBinder token);
void notifyLaunchTaskBehindComplete(in IBinder token);
int startActivityFromRecents(int taskId, in Bundle options);
void notifyEnterAnimationComplete(in IBinder token);
@@ -636,4 +633,7 @@ interface IActivityManager {
// side. If so, make sure they are using the correct transaction ids and arguments.
// If a transaction which will also be used on the native side is being inserted, add it
// alongside with other transactions of this kind at the top of this file.
+
+ void setShowWhenLocked(in IBinder token, boolean showWhenLocked);
+ void setTurnScreenOn(in IBinder token, boolean turnScreenOn);
}
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index b3521c06ae96..bd8c5c92a502 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -140,8 +140,6 @@ oneway interface IApplicationThread {
void setProcessState(int state);
void scheduleInstallProvider(in ProviderInfo provider);
void updateTimePrefs(int timeFormatPreference);
- void scheduleCancelVisibleBehind(IBinder token);
- void scheduleBackgroundVisibleBehindChanged(IBinder token, boolean enabled);
void scheduleEnterAnimationComplete(IBinder token);
void notifyCleartextNetwork(in byte[] firstPacket);
void startBinderTracking();
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 16b21f15353e..c0381d69d681 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -461,6 +461,9 @@ public class KeyguardManager {
* <p>
* If the Keyguard is secure and the device is not in a trusted state, this will bring up the
* UI so the user can enter their credentials.
+ * <p>
+ * If the value set for the {@link Activity} attr {@link android.R.attr#turnScreenOn} is true,
+ * the screen will turn on when the keyguard is dismissed.
*
* @param activity The activity requesting the dismissal. The activity must be either visible
* by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in
diff --git a/core/java/android/app/ProfilerInfo.java b/core/java/android/app/ProfilerInfo.java
index f3fe6778375b..fad4798e3a3e 100644
--- a/core/java/android/app/ProfilerInfo.java
+++ b/core/java/android/app/ProfilerInfo.java
@@ -17,8 +17,11 @@
package android.app;
import android.os.Parcel;
-import android.os.Parcelable;
import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+import android.util.Slog;
+
+import java.io.IOException;
/**
* System private API for passing profiler settings.
@@ -27,6 +30,8 @@ import android.os.ParcelFileDescriptor;
*/
public class ProfilerInfo implements Parcelable {
+ private static final String TAG = "ProfilerInfo";
+
/* Name of profile output file. */
public final String profileFile;
@@ -39,18 +44,50 @@ public class ProfilerInfo implements Parcelable {
/* Automatically stop the profiler when the app goes idle. */
public final boolean autoStopProfiler;
- /* Indicates whether to stream the profiling info to the out file continuously. */
+ /*
+ * Indicates whether to stream the profiling info to the out file continuously.
+ */
public final boolean streamingOutput;
+ /**
+ * Denotes an agent (and its parameters) to attach for profiling.
+ */
+ public final String agent;
+
public ProfilerInfo(String filename, ParcelFileDescriptor fd, int interval, boolean autoStop,
- boolean streaming) {
+ boolean streaming, String agent) {
profileFile = filename;
profileFd = fd;
samplingInterval = interval;
autoStopProfiler = autoStop;
streamingOutput = streaming;
+ this.agent = agent;
+ }
+
+ public ProfilerInfo(ProfilerInfo in) {
+ profileFile = in.profileFile;
+ profileFd = in.profileFd;
+ samplingInterval = in.samplingInterval;
+ autoStopProfiler = in.autoStopProfiler;
+ streamingOutput = in.streamingOutput;
+ agent = in.agent;
}
+ /**
+ * Close profileFd, if it is open. The field will be null after a call to this function.
+ */
+ public void closeFd() {
+ if (profileFd != null) {
+ try {
+ profileFd.close();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failure closing profile fd", e);
+ }
+ profileFd = null;
+ }
+ }
+
+ @Override
public int describeContents() {
if (profileFd != null) {
return profileFd.describeContents();
@@ -59,6 +96,7 @@ public class ProfilerInfo implements Parcelable {
}
}
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(profileFile);
if (profileFd != null) {
@@ -70,18 +108,21 @@ public class ProfilerInfo implements Parcelable {
out.writeInt(samplingInterval);
out.writeInt(autoStopProfiler ? 1 : 0);
out.writeInt(streamingOutput ? 1 : 0);
+ out.writeString(agent);
}
public static final Parcelable.Creator<ProfilerInfo> CREATOR =
new Parcelable.Creator<ProfilerInfo>() {
- public ProfilerInfo createFromParcel(Parcel in) {
- return new ProfilerInfo(in);
- }
+ @Override
+ public ProfilerInfo createFromParcel(Parcel in) {
+ return new ProfilerInfo(in);
+ }
- public ProfilerInfo[] newArray(int size) {
- return new ProfilerInfo[size];
- }
- };
+ @Override
+ public ProfilerInfo[] newArray(int size) {
+ return new ProfilerInfo[size];
+ }
+ };
private ProfilerInfo(Parcel in) {
profileFile = in.readString();
@@ -89,5 +130,6 @@ public class ProfilerInfo implements Parcelable {
samplingInterval = in.readInt();
autoStopProfiler = in.readInt() != 0;
streamingOutput = in.readInt() != 0;
+ agent = in.readString();
}
}
diff --git a/core/java/android/app/Vr2dDisplayProperties.java b/core/java/android/app/Vr2dDisplayProperties.java
index a608bb08836f..0eb2af361ae9 100644
--- a/core/java/android/app/Vr2dDisplayProperties.java
+++ b/core/java/android/app/Vr2dDisplayProperties.java
@@ -16,7 +16,6 @@
package android.app;
-import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
@@ -27,19 +26,31 @@ import java.io.PrintWriter;
*
* @hide
*/
-public class Vr2dDisplayProperties implements Parcelable {
+public final class Vr2dDisplayProperties implements Parcelable {
- /**
- * The actual width, height and dpi.
- */
+ public static final int FLAG_VIRTUAL_DISPLAY_ENABLED = 1;
+
+ /**
+ * The actual width, height and dpi.
+ */
private final int mWidth;
private final int mHeight;
private final int mDpi;
+ // Flags describing the virtual display behavior.
+ private final int mAddedFlags;
+ private final int mRemovedFlags;
+
public Vr2dDisplayProperties(int width, int height, int dpi) {
+ this(width, height, dpi, 0, 0);
+ }
+
+ private Vr2dDisplayProperties(int width, int height, int dpi, int flags, int removedFlags) {
mWidth = width;
mHeight = height;
mDpi = dpi;
+ mAddedFlags = flags;
+ mRemovedFlags = removedFlags;
}
@Override
@@ -52,11 +63,13 @@ public class Vr2dDisplayProperties implements Parcelable {
@Override
public String toString() {
- return "Vr2dDisplayProperties{" +
- "mWidth=" + mWidth +
- ", mHeight=" + mHeight +
- ", mDpi=" + mDpi +
- "}";
+ return "Vr2dDisplayProperties{"
+ + "mWidth=" + mWidth
+ + ", mHeight=" + mHeight
+ + ", mDpi=" + mDpi
+ + ", flags=" + toReadableFlags(mAddedFlags)
+ + ", removed_flags=" + toReadableFlags(mRemovedFlags)
+ + "}";
}
@Override
@@ -66,6 +79,8 @@ public class Vr2dDisplayProperties implements Parcelable {
Vr2dDisplayProperties that = (Vr2dDisplayProperties) o;
+ if (getFlags() != that.getFlags()) return false;
+ if (getRemovedFlags() != that.getRemovedFlags()) return false;
if (getWidth() != that.getWidth()) return false;
if (getHeight() != that.getHeight()) return false;
return getDpi() == that.getDpi();
@@ -81,6 +96,8 @@ public class Vr2dDisplayProperties implements Parcelable {
dest.writeInt(mWidth);
dest.writeInt(mHeight);
dest.writeInt(mDpi);
+ dest.writeInt(mAddedFlags);
+ dest.writeInt(mRemovedFlags);
}
public static final Parcelable.Creator<Vr2dDisplayProperties> CREATOR
@@ -100,13 +117,12 @@ public class Vr2dDisplayProperties implements Parcelable {
mWidth = source.readInt();
mHeight = source.readInt();
mDpi = source.readInt();
+ mAddedFlags = source.readInt();
+ mRemovedFlags = source.readInt();
}
public void dump(PrintWriter pw, String prefix) {
- pw.println(prefix + "Vr2dDisplayProperties:");
- pw.println(prefix + " width=" + mWidth);
- pw.println(prefix + " height=" + mHeight);
- pw.println(prefix + " dpi=" + mDpi);
+ pw.println(prefix + toString());
}
public int getWidth() {
@@ -120,4 +136,83 @@ public class Vr2dDisplayProperties implements Parcelable {
public int getDpi() {
return mDpi;
}
+
+ public int getFlags() {
+ return mAddedFlags;
+ }
+
+ public int getRemovedFlags() {
+ return mRemovedFlags;
+ }
+
+ private static String toReadableFlags(int flags) {
+ String retval = "{";
+ if ((flags & FLAG_VIRTUAL_DISPLAY_ENABLED) == FLAG_VIRTUAL_DISPLAY_ENABLED) {
+ retval += "enabled";
+ }
+ return retval + "}";
+ }
+
+ /**
+ * Convenience class for creating Vr2dDisplayProperties.
+ */
+ public static class Builder {
+ private int mAddedFlags = 0;
+ private int mRemovedFlags = 0;
+
+ // Negative values are translated as an "ignore" to VrManagerService.
+ private int mWidth = -1;
+ private int mHeight = -1;
+ private int mDpi = -1;
+
+ public Builder() {
+ }
+
+ /**
+ * Sets the dimensions to use for the virtual display.
+ */
+ public Builder setDimensions(int width, int height, int dpi) {
+ mWidth = width;
+ mHeight = height;
+ mDpi = dpi;
+ return this;
+ }
+
+ /**
+ * Toggles the virtual display functionality for 2D activities in VR.
+ */
+ public Builder setEnabled(boolean enabled) {
+ if (enabled) {
+ addFlags(FLAG_VIRTUAL_DISPLAY_ENABLED);
+ } else {
+ removeFlags(FLAG_VIRTUAL_DISPLAY_ENABLED);
+ }
+ return this;
+ }
+
+ /**
+ * Adds property flags.
+ */
+ public Builder addFlags(int flags) {
+ mAddedFlags |= flags;
+ mRemovedFlags &= ~flags;
+ return this;
+ }
+
+ /**
+ * Removes property flags.
+ */
+ public Builder removeFlags(int flags) {
+ mRemovedFlags |= flags;
+ mAddedFlags &= ~flags;
+ return this;
+ }
+
+ /**
+ * Builds the Vr2dDisplayProperty instance.
+ */
+ public Vr2dDisplayProperties build() {
+ return new Vr2dDisplayProperties(mWidth, mHeight, mDpi, mAddedFlags, mRemovedFlags);
+ }
+ }
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index dfcbfc4f8e09..0b8b689ce4e6 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -22,9 +22,9 @@ import android.annotation.Nullable;
import android.annotation.RawRes;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.annotation.SystemService;
-import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -74,7 +74,6 @@ import java.io.InputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -369,18 +368,17 @@ public class WallpaperManager {
}
WallpaperColors getWallpaperColors(int which) {
- synchronized (this) {
- if (which != FLAG_LOCK && which != FLAG_SYSTEM)
- throw new IllegalArgumentException(
- "which should be either FLAG_LOCK or FLAG_SYSTEM");
+ if (which != FLAG_LOCK && which != FLAG_SYSTEM) {
+ throw new IllegalArgumentException(
+ "Must request colors for exactly one kind of wallpaper");
+ }
- try {
- return mService.getWallpaperColors(which);
- } catch (RemoteException e) {
- // Can't get colors, connection lost.
- }
- return null;
+ try {
+ return mService.getWallpaperColors(which);
+ } catch (RemoteException e) {
+ // Can't get colors, connection lost.
}
+ return null;
}
public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault,
diff --git a/core/java/android/app/timezone/DistroRulesVersion.java b/core/java/android/app/timezone/DistroRulesVersion.java
index 5503ce1cf973..1eb9f45f48f1 100644
--- a/core/java/android/app/timezone/DistroRulesVersion.java
+++ b/core/java/android/app/timezone/DistroRulesVersion.java
@@ -125,4 +125,8 @@ public final class DistroRulesVersion implements Parcelable {
+ ", mRevision='" + mRevision + '\''
+ '}';
}
+
+ public String toDumpString() {
+ return mRulesVersion + "," + mRevision;
+ }
}
diff --git a/core/java/android/app/timezone/RulesUpdaterContract.java b/core/java/android/app/timezone/RulesUpdaterContract.java
index 4e7781866aae..07b2f33ef5e0 100644
--- a/core/java/android/app/timezone/RulesUpdaterContract.java
+++ b/core/java/android/app/timezone/RulesUpdaterContract.java
@@ -19,6 +19,7 @@ package android.app.timezone;
import android.content.Context;
import android.content.Intent;
import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
/**
* Constants related to the contract between the Android system and the privileged time zone updater
@@ -82,6 +83,9 @@ public final class RulesUpdaterContract {
byte[] checkTokenBytes) {
Intent intent = createUpdaterIntent(updaterAppPackageName);
intent.putExtra(EXTRA_CHECK_TOKEN, checkTokenBytes);
- context.sendBroadcast(intent, RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION);
+ context.sendBroadcastAsUser(
+ intent,
+ UserHandle.of(UserHandle.myUserId()),
+ RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION);
}
}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 5b8d81d81efb..c84643fc46b3 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -200,6 +200,37 @@ public final class BluetoothHeadset implements BluetoothProfile {
public static final String VENDOR_RESULT_CODE_COMMAND_ANDROID = "+ANDROID";
/**
+ * A vendor-specific AT command
+ * @hide
+ */
+ public static final String VENDOR_SPECIFIC_HEADSET_EVENT_XAPL = "+XAPL";
+
+ /**
+ * A vendor-specific AT command
+ * @hide
+ */
+ public static final String VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV = "+IPHONEACCEV";
+
+ /**
+ * Battery level indicator associated with
+ * {@link #VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV}
+ * @hide
+ */
+ public static final int VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV_BATTERY_LEVEL = 1;
+
+ /**
+ * A vendor-specific AT command
+ * @hide
+ */
+ public static final String VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT = "+XEVENT";
+
+ /**
+ * Battery level indicator associated with {@link #VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT}
+ * @hide
+ */
+ public static final String VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT_BATTERY_LEVEL = "BATTERY";
+
+ /**
* Headset state when SCO audio is not connected.
* This state can be one of
* {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
@@ -229,31 +260,31 @@ public final class BluetoothHeadset implements BluetoothProfile {
* <ul>
* <li> {@link #EXTRA_HF_INDICATORS_IND_ID} - The Assigned number of headset Indicator which
* is supported by the headset ( as indicated by AT+BIND command in the SLC
- * sequence).or whose value is changed (indicated by AT+BIEV command) </li>
- * <li> {@link #EXTRA_HF_INDICATORS_IND_VALUE}- The updated value of headset indicator. </li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * sequence) or whose value is changed (indicated by AT+BIEV command) </li>
+ * <li> {@link #EXTRA_HF_INDICATORS_IND_VALUE} - Updated value of headset indicator. </li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - Remote device. </li>
* </ul>
- * <p>{@link #EXTRA_HF_INDICATORS_IND_ID} is defined by Bluetooth SIG and each of the indicators are
- * given an assigned number. Below shows the assigned number of Indicator added so far
- * - Enhanced Safety - 1
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
+ * <p>{@link #EXTRA_HF_INDICATORS_IND_ID} is defined by Bluetooth SIG and each of the indicators
+ * are given an assigned number. Below shows the assigned number of Indicator added so far
+ * - Enhanced Safety - 1, Valid Values: 0 - Disabled, 1 - Enabled
+ * - Battery Level - 2, Valid Values: 0~100 - Remaining level of Battery
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to receive.
* @hide
*/
public static final String ACTION_HF_INDICATORS_VALUE_CHANGED =
"android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED";
/**
- * A String extra field in {@link #ACTION_HF_INDICATORS_VALUE_CHANGED}
- * intents that contains the UUID of the headset indicator (as defined by Bluetooth SIG)
- * that is being sent.
+ * A int extra field in {@link #ACTION_HF_INDICATORS_VALUE_CHANGED}
+ * intents that contains the assigned number of the headset indicator as defined by
+ * Bluetooth SIG that is being sent. Value range is 0-65535 as defined in HFP 1.7
* @hide
*/
public static final String EXTRA_HF_INDICATORS_IND_ID =
"android.bluetooth.headset.extra.HF_INDICATORS_IND_ID";
/**
- * A int extra field in {@link #ACTION_HF_INDICATORS_VALUE_CHANGED}
+ * A int extra field in {@link #ACTION_HF_INDICATORS_VALUE_CHANGED}
* intents that contains the value of the Headset indicator that is being sent.
* @hide
*/
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 9a014766c206..b75c39c0d350 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -441,6 +441,22 @@ public class ActivityInfo extends ComponentInfo
* @hide
*/
public static final int FLAG_SUPPORTS_PICTURE_IN_PICTURE = 0x400000;
+
+ /**
+ * Bit in {@link #flags} indicating if the activity should be shown when locked.
+ * See {@link android.R.attr#showWhenLocked}
+ * @hide
+ */
+ public static final int FLAG_SHOW_WHEN_LOCKED = 0x800000;
+
+ /**
+ * Bit in {@link #flags} indicating if the screen should turn on when starting the activity.
+ * See {@link android.R.attr#turnScreenOn}
+ * @hide
+ */
+ public static final int FLAG_TURN_SCREEN_ON = 0x1000000;
+
+
/**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the system user. Only works with broadcast receivers. Set from the
@@ -462,6 +478,7 @@ public class ActivityInfo extends ComponentInfo
* thrown. Set from the {@link android.R.attr#allowEmbedded} attribute.
*/
public static final int FLAG_ALLOW_EMBEDDED = 0x80000000;
+
/**
* Options that have been set in the activity declaration in the
* manifest.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 1b88ce7c3a04..e4f2fc1c5035 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -4292,6 +4292,15 @@ public class PackageParser {
a.info.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode,
ActivityInfo.COLOR_MODE_DEFAULT);
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_showWhenLocked, false)) {
+ a.info.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_turnScreenOn, false)) {
+ a.info.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON;
+ }
+
} else {
a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
a.info.configChanges = 0;
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 6834ba816910..be31d1b0b5e5 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -42,6 +42,9 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Locale;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_UNDEFINED;
+
/**
* This class describes all device configuration information that can
* impact the resources the application retrieves. This includes both
@@ -597,6 +600,13 @@ public final class Configuration implements Parcelable, Comparable<Configuration
*/
public int orientation;
+ /**
+ * The mRotation used at the time orientation was determined.
+ * TODO(b/36812336): Move mRotation out of {@link Configuration}.
+ * {@hide}
+ */
+ private int mRotation;
+
/** Constant for {@link #uiMode}: bits that encode the mode type. */
public static final int UI_MODE_TYPE_MASK = 0x0f;
/** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
@@ -884,6 +894,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
navigation = o.navigation;
navigationHidden = o.navigationHidden;
orientation = o.orientation;
+ mRotation = o.mRotation;
screenLayout = o.screenLayout;
colorMode = o.colorMode;
uiMode = o.uiMode;
@@ -1074,6 +1085,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
navigation = NAVIGATION_UNDEFINED;
navigationHidden = NAVIGATIONHIDDEN_UNDEFINED;
orientation = ORIENTATION_UNDEFINED;
+ mRotation = ROTATION_UNDEFINED;
screenLayout = SCREENLAYOUT_UNDEFINED;
colorMode = COLOR_MODE_UNDEFINED;
uiMode = UI_MODE_TYPE_UNDEFINED;
@@ -1182,6 +1194,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration
changed |= ActivityInfo.CONFIG_ORIENTATION;
orientation = delta.orientation;
}
+ if (delta.mRotation != ROTATION_UNDEFINED
+ && mRotation != delta.mRotation) {
+ changed |= ActivityInfo.CONFIG_ORIENTATION;
+ mRotation = delta.mRotation;
+ }
if (((delta.screenLayout & SCREENLAYOUT_SIZE_MASK) != SCREENLAYOUT_SIZE_UNDEFINED)
&& (delta.screenLayout & SCREENLAYOUT_SIZE_MASK)
@@ -1376,6 +1393,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration
&& orientation != delta.orientation) {
changed |= ActivityInfo.CONFIG_ORIENTATION;
}
+ if ((compareUndefined || delta.mRotation != ROTATION_UNDEFINED)
+ && mRotation != delta.mRotation) {
+ changed |= ActivityInfo.CONFIG_ORIENTATION;
+ }
if ((compareUndefined || getScreenLayoutNoDirection(delta.screenLayout) !=
(SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED))
&& getScreenLayoutNoDirection(screenLayout) !=
@@ -1512,6 +1533,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
dest.writeInt(navigation);
dest.writeInt(navigationHidden);
dest.writeInt(orientation);
+ dest.writeInt(mRotation);
dest.writeInt(screenLayout);
dest.writeInt(colorMode);
dest.writeInt(uiMode);
@@ -1548,6 +1570,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
navigation = source.readInt();
navigationHidden = source.readInt();
orientation = source.readInt();
+ mRotation = source.readInt();
screenLayout = source.readInt();
colorMode = source.readInt();
uiMode = source.readInt();
@@ -1632,6 +1655,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if (n != 0) return n;
n = this.orientation - that.orientation;
if (n != 0) return n;
+ n = this.mRotation - that.mRotation;
+ if (n != 0) return n;
n = this.colorMode - that.colorMode;
if (n != 0) return n;
n = this.screenLayout - that.screenLayout;
@@ -1763,6 +1788,24 @@ public final class Configuration implements Parcelable, Comparable<Configuration
/**
* @hide
*
+ * Setter for orientation converts from {@link Surface} values to internal representation.
+ */
+ public void setRotation(int rotation) {
+ this.mRotation = rotation;
+ }
+
+ /**
+ * @hide
+ *
+ * Getter for orientation. Converts from internal representation to {@link Surface} values.
+ */
+ public int getRotation() {
+ return mRotation != ROTATION_UNDEFINED ? mRotation : ROTATION_0;
+ }
+
+ /**
+ * @hide
+ *
* Clears the locale without changing layout direction.
*/
public void clearLocales() {
@@ -2193,6 +2236,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration
delta.orientation = change.orientation;
}
+ if (base.mRotation != change.mRotation) {
+ base.mRotation = change.mRotation;
+ }
+
if ((base.screenLayout & SCREENLAYOUT_SIZE_MASK) !=
(change.screenLayout & SCREENLAYOUT_SIZE_MASK)) {
delta.screenLayout |= change.screenLayout & SCREENLAYOUT_SIZE_MASK;
@@ -2264,6 +2311,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
private static final String XML_ATTR_NAVIGATION = "nav";
private static final String XML_ATTR_NAVIGATION_HIDDEN = "navHid";
private static final String XML_ATTR_ORIENTATION = "ori";
+ private static final String XML_ATTR_ROTATION = "rot";
private static final String XML_ATTR_SCREEN_LAYOUT = "scrLay";
private static final String XML_ATTR_COLOR_MODE = "clrMod";
private static final String XML_ATTR_UI_MODE = "ui";
@@ -2323,6 +2371,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
DENSITY_DPI_UNDEFINED);
configOut.appBounds =
Rect.unflattenFromString(XmlUtils.readStringAttribute(parser, XML_ATTR_APP_BOUNDS));
+ configOut.mRotation = XmlUtils.readIntAttribute(parser, XML_ATTR_ROTATION,
+ ROTATION_UNDEFINED);
// For persistence, we don't care about assetsSeq, so do not read it out.
}
@@ -2399,6 +2449,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration
config.appBounds.flattenToString());
}
+ if (config.mRotation != ROTATION_UNDEFINED) {
+ XmlUtils.writeIntAttribute(xml, XML_ATTR_ROTATION, config.mRotation);
+ }
+
// For persistence, we do not care about assetsSeq, so do not write it out.
}
}
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 34a9523fc104..f894f0536b52 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -16,9 +16,6 @@
package android.database.sqlite;
-import dalvik.system.BlockGuard;
-import dalvik.system.CloseGuard;
-
import android.database.Cursor;
import android.database.CursorWindow;
import android.database.DatabaseUtils;
@@ -32,11 +29,14 @@ import android.util.Log;
import android.util.LruCache;
import android.util.Printer;
+import dalvik.system.BlockGuard;
+import dalvik.system.CloseGuard;
+
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;
-import java.util.regex.Pattern;
+
/**
* Represents a SQLite database connection.
@@ -118,7 +118,8 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
private int mCancellationSignalAttachCount;
private static native long nativeOpen(String path, int openFlags, String label,
- boolean enableTrace, boolean enableProfile);
+ boolean enableTrace, boolean enableProfile, int lookasideSlotSize,
+ int lookasideSlotCount);
private static native void nativeClose(long connectionPtr);
private static native void nativeRegisterCustomFunction(long connectionPtr,
SQLiteCustomFunction function);
@@ -208,8 +209,8 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
private void open() {
mConnectionPtr = nativeOpen(mConfiguration.path, mConfiguration.openFlags,
mConfiguration.label,
- SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME);
-
+ SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME,
+ mConfiguration.lookasideSlotSize, mConfiguration.lookasideSlotCount);
setPageSize();
setForeignKeyModeFromConfiguration();
setWalModeFromConfiguration();
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index fe849b8a99cf..7406b3fd1f28 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -16,6 +16,8 @@
package android.database.sqlite;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentValues;
@@ -34,10 +36,14 @@ import android.util.Log;
import android.util.Pair;
import android.util.Printer;
+import com.android.internal.util.Preconditions;
+
import dalvik.system.CloseGuard;
import java.io.File;
import java.io.FileFilter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -253,11 +259,14 @@ public final class SQLiteDatabase extends SQLiteClosable {
*/
public static final int MAX_SQL_CACHE_SIZE = 100;
- private SQLiteDatabase(String path, int openFlags, CursorFactory cursorFactory,
- DatabaseErrorHandler errorHandler) {
+ private SQLiteDatabase(final String path, final int openFlags,
+ CursorFactory cursorFactory, DatabaseErrorHandler errorHandler,
+ int lookasideSlotSize, int lookasideSlotCount) {
mCursorFactory = cursorFactory;
mErrorHandler = errorHandler != null ? errorHandler : new DefaultDatabaseErrorHandler();
mConfigurationLocked = new SQLiteDatabaseConfiguration(path, openFlags);
+ mConfigurationLocked.lookasideSlotSize = lookasideSlotSize;
+ mConfigurationLocked.lookasideSlotCount = lookasideSlotCount;
}
@Override
@@ -667,11 +676,30 @@ public final class SQLiteDatabase extends SQLiteClosable {
* @return the newly opened database
* @throws SQLiteException if the database cannot be opened
*/
- public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
+ public static SQLiteDatabase openDatabase(@NonNull String path, @Nullable CursorFactory factory,
+ @DatabaseOpenFlags int flags) {
return openDatabase(path, factory, flags, null);
}
/**
+ * Open the database according to the specified {@link OpenParams parameters}
+ *
+ * @param path to database file to open and/or create
+ * @param openParams configuration parameters that are used for opening {@link SQLiteDatabase}
+ * @return the newly opened database
+ * @throws SQLiteException if the database cannot be opened
+ */
+ public static SQLiteDatabase openDatabase(@NonNull String path,
+ @NonNull OpenParams openParams) {
+ Preconditions.checkArgument(openParams != null, "OpenParams cannot be null");
+ SQLiteDatabase db = new SQLiteDatabase(path, openParams.mOpenFlags,
+ openParams.mCursorFactory, openParams.mErrorHandler,
+ openParams.mLookasideSlotSize, openParams.mLookasideSlotCount);
+ db.open();
+ return db;
+ }
+
+ /**
* Open the database according to the flags {@link #OPEN_READWRITE}
* {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.
*
@@ -690,9 +718,9 @@ public final class SQLiteDatabase extends SQLiteClosable {
* @return the newly opened database
* @throws SQLiteException if the database cannot be opened
*/
- public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,
- DatabaseErrorHandler errorHandler) {
- SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler);
+ 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);
db.open();
return db;
}
@@ -700,22 +728,24 @@ public final class SQLiteDatabase extends SQLiteClosable {
/**
* Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).
*/
- public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) {
+ public static SQLiteDatabase openOrCreateDatabase(@NonNull File file,
+ @Nullable CursorFactory factory) {
return openOrCreateDatabase(file.getPath(), factory);
}
/**
* Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY).
*/
- public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) {
+ public static SQLiteDatabase openOrCreateDatabase(@NonNull String path,
+ @Nullable CursorFactory factory) {
return openDatabase(path, factory, CREATE_IF_NECESSARY, null);
}
/**
* Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler).
*/
- public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory,
- DatabaseErrorHandler errorHandler) {
+ public static SQLiteDatabase openOrCreateDatabase(@NonNull String path,
+ @Nullable CursorFactory factory, @Nullable DatabaseErrorHandler errorHandler) {
return openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler);
}
@@ -726,7 +756,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
* @param file The database file path.
* @return True if the database was successfully deleted.
*/
- public static boolean deleteDatabase(File file) {
+ public static boolean deleteDatabase(@NonNull File file) {
if (file == null) {
throw new IllegalArgumentException("file must not be null");
}
@@ -825,13 +855,29 @@ public final class SQLiteDatabase extends SQLiteClosable {
* cursor when query is called
* @return a SQLiteDatabase object, or null if the database can't be created
*/
- public static SQLiteDatabase create(CursorFactory factory) {
+ @NonNull
+ public static SQLiteDatabase create(@Nullable CursorFactory factory) {
// This is a magic string with special meaning for SQLite.
return openDatabase(SQLiteDatabaseConfiguration.MEMORY_DB_PATH,
factory, CREATE_IF_NECESSARY);
}
/**
+ * Create a memory backed SQLite database. Its contents will be destroyed
+ * when the database is closed.
+ *
+ * <p>Sets the locale of the database to the the system's current locale.
+ * Call {@link #setLocale} if you would like something else.</p>
+ * @param openParams configuration parameters that are used for opening SQLiteDatabase
+ * @return a SQLiteDatabase object, or null if the database can't be created
+ */
+ @NonNull
+ public static SQLiteDatabase createInMemory(@NonNull OpenParams openParams) {
+ return openDatabase(SQLiteDatabaseConfiguration.MEMORY_DB_PATH,
+ openParams.toBuilder().addOpenFlags(CREATE_IF_NECESSARY).build());
+ }
+
+ /**
* Registers a CustomFunction callback as a function that can be called from
* SQLite database triggers.
*
@@ -2210,4 +2256,238 @@ public final class SQLiteDatabase extends SQLiteClosable {
public interface CustomFunction {
public void callback(String[] args);
}
+
+ /**
+ * Wrapper for configuration parameters that are used for opening {@link SQLiteDatabase}
+ */
+ public static final class OpenParams {
+ private final int mOpenFlags;
+ private final CursorFactory mCursorFactory;
+ private final DatabaseErrorHandler mErrorHandler;
+ private final int mLookasideSlotSize;
+ private final int mLookasideSlotCount;
+
+ private OpenParams(int openFlags, CursorFactory cursorFactory,
+ DatabaseErrorHandler errorHandler, int lookasideSlotSize, int lookasideSlotCount) {
+ mOpenFlags = openFlags;
+ mCursorFactory = cursorFactory;
+ mErrorHandler = errorHandler;
+ mLookasideSlotSize = lookasideSlotSize;
+ mLookasideSlotCount = lookasideSlotCount;
+ }
+
+ /**
+ * Returns size in bytes of each lookaside slot or -1 if not set.
+ *
+ * @see Builder#setLookasideConfig(int, int)
+ */
+ @IntRange(from = -1)
+ public int getLookasideSlotSize() {
+ return mLookasideSlotSize;
+ }
+
+ /**
+ * Returns total number of lookaside memory slots per database connection or -1 if not
+ * set.
+ *
+ * @see Builder#setLookasideConfig(int, int)
+ */
+ @IntRange(from = -1)
+ public int getLookasideSlotCount() {
+ return mLookasideSlotCount;
+ }
+
+ /**
+ * Returns flags to control database access mode
+ *
+ * @see Builder#setOpenFlags(int)
+ */
+ @DatabaseOpenFlags
+ public int getOpenFlags() {
+ return mOpenFlags;
+ }
+
+ /**
+ * Returns an optional factory class that is called to instantiate a cursor when query
+ * is called
+ *
+ * @see Builder#setCursorFactory(CursorFactory)
+ */
+ @Nullable
+ public CursorFactory getCursorFactory() {
+ return mCursorFactory;
+ }
+
+ /**
+ * Returns handler for database corruption errors
+ *
+ * @see Builder#setErrorHandler(DatabaseErrorHandler)
+ */
+ @Nullable
+ public DatabaseErrorHandler getErrorHandler() {
+ return mErrorHandler;
+ }
+
+ /**
+ * Creates a new instance of builder {@link Builder#Builder(OpenParams) initialized} with
+ * {@code this} parameters.
+ * @hide
+ */
+ @NonNull
+ public Builder toBuilder() {
+ return new Builder(this);
+ }
+
+ /**
+ * Builder for {@link OpenParams}.
+ */
+ public static final class Builder {
+ private int mLookasideSlotSize = -1;
+ private int mLookasideSlotCount = -1;
+ private int mOpenFlags;
+ private CursorFactory mCursorFactory;
+ private DatabaseErrorHandler mErrorHandler;
+
+ public Builder() {
+ }
+
+ public Builder(OpenParams params) {
+ mLookasideSlotSize = params.mLookasideSlotSize;
+ mLookasideSlotCount = params.mLookasideSlotCount;
+ mOpenFlags = params.mOpenFlags;
+ mCursorFactory = params.mCursorFactory;
+ mErrorHandler = params.mErrorHandler;
+ }
+
+ /**
+ * Configures
+ * <a href="https://sqlite.org/malloc.html#lookaside">lookaside memory allocator</a>
+ *
+ * <p>SQLite default settings will be used, if this method isn't called.
+ * Use {@code setLookasideConfig(0,0)} to disable lookaside
+ *
+ * @param slotSize The size in bytes of each lookaside slot.
+ * @param slotCount The total number of lookaside memory slots per database connection.
+ */
+ public Builder setLookasideConfig(@IntRange(from = 0) final int slotSize,
+ @IntRange(from = 0) final int slotCount) {
+ Preconditions.checkArgument(slotSize >= 0,
+ "lookasideSlotCount cannot be negative");
+ Preconditions.checkArgument(slotCount >= 0,
+ "lookasideSlotSize cannot be negative");
+ Preconditions.checkArgument(
+ (slotSize > 0 && slotCount > 0) || (slotCount == 0 && slotSize == 0),
+ "Invalid configuration: " + slotSize + ", " + slotCount);
+
+ mLookasideSlotSize = slotSize;
+ mLookasideSlotCount = slotCount;
+ return this;
+ }
+
+ /**
+ * Returns true if {@link #ENABLE_WRITE_AHEAD_LOGGING} flag is set
+ * @hide
+ */
+ public boolean isWriteAheadLoggingEnabled() {
+ return (mOpenFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0;
+ }
+
+ /**
+ * Sets flags to control database access mode
+ * @param openFlags The new flags to set
+ * @see #OPEN_READWRITE
+ * @see #OPEN_READONLY
+ * @see #CREATE_IF_NECESSARY
+ * @see #NO_LOCALIZED_COLLATORS
+ * @see #ENABLE_WRITE_AHEAD_LOGGING
+ * @return same builder instance for chaining multiple calls into a single statement
+ */
+ @NonNull
+ public Builder setOpenFlags(@DatabaseOpenFlags int openFlags) {
+ mOpenFlags = openFlags;
+ return this;
+ }
+
+ /**
+ * Adds flags to control database access mode
+ *
+ * @param openFlags The new flags to add
+ * @return same builder instance for chaining multiple calls into a single statement
+ */
+ @NonNull
+ public Builder addOpenFlags(@DatabaseOpenFlags int openFlags) {
+ mOpenFlags |= openFlags;
+ return this;
+ }
+
+ /**
+ * Removes database access mode flags
+ *
+ * @param openFlags Flags to remove
+ * @return same builder instance for chaining multiple calls into a single statement
+ */
+ @NonNull
+ public Builder removeOpenFlags(@DatabaseOpenFlags int openFlags) {
+ mOpenFlags &= ~openFlags;
+ return this;
+ }
+
+ /**
+ * Sets {@link #ENABLE_WRITE_AHEAD_LOGGING} flag if {@code enabled} is {@code true},
+ * unsets otherwise
+ * @hide
+ */
+ public void setWriteAheadLoggingEnabled(boolean enabled) {
+ if (enabled) {
+ addOpenFlags(ENABLE_WRITE_AHEAD_LOGGING);
+ } else {
+ removeOpenFlags(ENABLE_WRITE_AHEAD_LOGGING);
+ }
+ }
+
+ /**
+ * Set an optional factory class that is called to instantiate a cursor when query
+ * is called.
+ *
+ * @param cursorFactory instance
+ * @return same builder instance for chaining multiple calls into a single statement
+ */
+ @NonNull
+ public Builder setCursorFactory(@Nullable CursorFactory cursorFactory) {
+ mCursorFactory = cursorFactory;
+ return this;
+ }
+
+
+ /**
+ * Sets {@link DatabaseErrorHandler} object to handle db corruption errors
+ */
+ @NonNull
+ public Builder setErrorHandler(@Nullable DatabaseErrorHandler errorHandler) {
+ mErrorHandler = errorHandler;
+ return this;
+ }
+
+ /**
+ * Creates an instance of {@link OpenParams} with the options that were previously set
+ * on this builder
+ */
+ @NonNull
+ public OpenParams build() {
+ return new OpenParams(mOpenFlags, mCursorFactory, mErrorHandler, mLookasideSlotSize,
+ mLookasideSlotCount);
+ }
+ }
+ }
+
+ /** @hide */
+ @IntDef(flag = true, prefix = {"OPEN_", "CREATE_", "NO_", "ENABLE_"}, value = {
+ OPEN_READWRITE,
+ OPEN_READONLY,
+ CREATE_IF_NECESSARY,
+ NO_LOCALIZED_COLLATORS,
+ ENABLE_WRITE_AHEAD_LOGGING
+ })
+ @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 549ab902fdd1..1435c83c53dc 100644
--- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
+++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
@@ -90,6 +90,20 @@ public final class SQLiteDatabaseConfiguration {
new ArrayList<SQLiteCustomFunction>();
/**
+ * The size in bytes of each lookaside slot
+ *
+ * <p>If negative, the default lookaside configuration will be used
+ */
+ public int lookasideSlotSize;
+
+ /**
+ * The total number of lookaside memory slots per database connection
+ *
+ * <p>If negative, the default lookaside configuration will be used
+ */
+ public int lookasideSlotCount;
+
+ /**
* Creates a database configuration with the required parameters for opening a
* database and default values for all other parameters.
*
@@ -108,6 +122,8 @@ public final class SQLiteDatabaseConfiguration {
// Set default values for optional parameters.
maxSqlCacheSize = 25;
locale = Locale.getDefault();
+ lookasideSlotSize = -1;
+ lookasideSlotCount = -1;
}
/**
@@ -146,6 +162,8 @@ public final class SQLiteDatabaseConfiguration {
foreignKeyConstraintsEnabled = other.foreignKeyConstraintsEnabled;
customFunctions.clear();
customFunctions.addAll(other.customFunctions);
+ lookasideSlotSize = other.lookasideSlotSize;
+ lookasideSlotCount = other.lookasideSlotCount;
}
/**
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index bb8d9ffa679b..44a72ddd1f7a 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -16,10 +16,14 @@
package android.database.sqlite;
+import android.annotation.IntRange;
import android.content.Context;
import android.database.DatabaseErrorHandler;
+import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
+import android.os.FileUtils;
import android.util.Log;
+
import java.io.File;
/**
@@ -43,24 +47,14 @@ import java.io.File;
public abstract class SQLiteOpenHelper {
private static final String TAG = SQLiteOpenHelper.class.getSimpleName();
- // When true, getReadableDatabase returns a read-only database if it is just being opened.
- // The database handle is reopened in read/write mode when getWritableDatabase is called.
- // We leave this behavior disabled in production because it is inefficient and breaks
- // many applications. For debugging purposes it can be useful to turn on strict
- // read-only semantics to catch applications that call getReadableDatabase when they really
- // wanted getWritableDatabase.
- private static final boolean DEBUG_STRICT_READONLY = false;
-
private final Context mContext;
private final String mName;
- private final CursorFactory mFactory;
private final int mNewVersion;
private final int mMinimumSupportedVersion;
private SQLiteDatabase mDatabase;
private boolean mIsInitializing;
- private boolean mEnableWriteAheadLogging;
- private final DatabaseErrorHandler mErrorHandler;
+ private final SQLiteDatabase.OpenParams.Builder mOpenParamsBuilder;
/**
* Create a helper object to create, open, and/or manage a database.
@@ -130,10 +124,12 @@ public abstract class SQLiteOpenHelper {
mContext = context;
mName = name;
- mFactory = factory;
mNewVersion = version;
- mErrorHandler = errorHandler;
mMinimumSupportedVersion = Math.max(0, minimumSupportedVersion);
+ mOpenParamsBuilder = new SQLiteDatabase.OpenParams.Builder();
+ mOpenParamsBuilder.setCursorFactory(factory);
+ mOpenParamsBuilder.setErrorHandler(errorHandler);
+ mOpenParamsBuilder.addOpenFlags(SQLiteDatabase.CREATE_IF_NECESSARY);
}
/**
@@ -157,7 +153,7 @@ public abstract class SQLiteOpenHelper {
*/
public void setWriteAheadLoggingEnabled(boolean enabled) {
synchronized (this) {
- if (mEnableWriteAheadLogging != enabled) {
+ if (mOpenParamsBuilder.isWriteAheadLoggingEnabled() != enabled) {
if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) {
if (enabled) {
mDatabase.enableWriteAheadLogging();
@@ -165,8 +161,32 @@ public abstract class SQLiteOpenHelper {
mDatabase.disableWriteAheadLogging();
}
}
- mEnableWriteAheadLogging = enabled;
+ mOpenParamsBuilder.setWriteAheadLoggingEnabled(enabled);
+ }
+ }
+ }
+
+ /**
+ * Configures <a href="https://sqlite.org/malloc.html#lookaside">lookaside memory allocator</a>
+ *
+ * <p>This method should be called from the constructor of the subclass,
+ * before opening the database, since lookaside memory configuration can only be changed
+ * when no connection is using it
+ *
+ * <p>SQLite default settings will be used, if this method isn't called.
+ * Use {@code setLookasideConfig(0,0)} to disable lookaside
+ *
+ * @param slotSize The size in bytes of each lookaside slot.
+ * @param slotCount The total number of lookaside memory slots per database connection.
+ */
+ public void setLookasideConfig(@IntRange(from = 0) final int slotSize,
+ @IntRange(from = 0) final int slotCount) {
+ synchronized (this) {
+ if (mDatabase != null && mDatabase.isOpen()) {
+ throw new IllegalStateException(
+ "Lookaside memory config cannot be changed after opening the database");
}
+ mOpenParamsBuilder.setLookasideConfig(slotSize, slotCount);
}
}
@@ -243,27 +263,22 @@ public abstract class SQLiteOpenHelper {
db.reopenReadWrite();
}
} else if (mName == null) {
- db = SQLiteDatabase.create(null);
+ db = SQLiteDatabase.createInMemory(mOpenParamsBuilder.build());
} else {
+ final String path = mContext.getDatabasePath(mName).getPath();
+ SQLiteDatabase.OpenParams params = mOpenParamsBuilder.build();
try {
- if (DEBUG_STRICT_READONLY && !writable) {
- final String path = mContext.getDatabasePath(mName).getPath();
- db = SQLiteDatabase.openDatabase(path, mFactory,
- SQLiteDatabase.OPEN_READONLY, mErrorHandler);
- } else {
- db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
- Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
- mFactory, mErrorHandler);
- }
- } catch (SQLiteException ex) {
+ db = SQLiteDatabase.openDatabase(path, params);
+ // Keep pre-O-MR1 behavior by resetting file permissions to 660
+ setFilePermissionsForDb(path);
+ } catch (SQLException ex) {
if (writable) {
throw ex;
}
Log.e(TAG, "Couldn't open " + mName
+ " for writing (will try read-only):", ex);
- final String path = mContext.getDatabasePath(mName).getPath();
- db = SQLiteDatabase.openDatabase(path, mFactory,
- SQLiteDatabase.OPEN_READONLY, mErrorHandler);
+ params = params.toBuilder().addOpenFlags(SQLiteDatabase.OPEN_READONLY).build();
+ db = SQLiteDatabase.openDatabase(path, params);
}
}
@@ -323,6 +338,11 @@ public abstract class SQLiteOpenHelper {
}
}
+ private static void setFilePermissionsForDb(String dbPath) {
+ int perms = FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IWGRP;
+ FileUtils.setPermissions(dbPath, perms, -1, -1);
+ }
+
/**
* Close any open database object.
*/
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index b6eaa5c7cd10..f697b89f6fdd 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -431,6 +431,25 @@ public class RadioManager {
public int getType() {
return mType;
}
+
+ /**
+ * Checks if the band is either AM or AM_HD.
+ *
+ * @return {@code true}, if band is AM or AM_HD.
+ */
+ public boolean isAmBand() {
+ return mType == BAND_AM || mType == BAND_AM_HD;
+ }
+
+ /**
+ * Checks if the band is either FM or FM_HD.
+ *
+ * @return {@code true}, if band is FM or FM_HD.
+ */
+ public boolean isFmBand() {
+ return mType == BAND_FM || mType == BAND_FM_HD;
+ }
+
/** Lower band limit expressed in units according to band type.
* Currently all defined band types express channels as frequency in kHz
* @return the lower band limit.
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 5e9b02ac043f..2979cd8a5dba 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -582,6 +582,8 @@ public class ConnectivityManager {
/** {@hide} */
public static final int MAX_NETWORK_TYPE = TYPE_VPN;
+ private static final int MIN_NETWORK_TYPE = TYPE_MOBILE;
+
/**
* If you want to set the default network preference,you can directly
* change the networkAttributes array in framework's config.xml.
@@ -640,7 +642,7 @@ public class ConnectivityManager {
*/
@Deprecated
public static boolean isNetworkTypeValid(int networkType) {
- return networkType >= 0 && networkType <= MAX_NETWORK_TYPE;
+ return MIN_NETWORK_TYPE <= networkType && networkType <= MAX_NETWORK_TYPE;
}
/**
@@ -653,6 +655,8 @@ public class ConnectivityManager {
*/
public static String getNetworkTypeName(int type) {
switch (type) {
+ case TYPE_NONE:
+ return "NONE";
case TYPE_MOBILE:
return "MOBILE";
case TYPE_WIFI:
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 2dd7f757aea3..76646b8939c4 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -21,6 +21,7 @@ import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.BitUtils;
+import com.android.internal.util.Preconditions;
import java.util.Objects;
@@ -429,6 +430,11 @@ public final class NetworkCapabilities implements Parcelable {
/** @hide */
public static final int MAX_TRANSPORT = TRANSPORT_LOWPAN;
+ /** @hide */
+ public static boolean isValidTransport(int transportType) {
+ return (MIN_TRANSPORT <= transportType) && (transportType <= MAX_TRANSPORT);
+ }
+
private static final String[] TRANSPORT_NAMES = {
"CELLULAR",
"WIFI",
@@ -453,9 +459,7 @@ public final class NetworkCapabilities implements Parcelable {
* @hide
*/
public NetworkCapabilities addTransportType(int transportType) {
- if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
- throw new IllegalArgumentException("TransportType out of range");
- }
+ checkValidTransportType(transportType);
mTransportTypes |= 1 << transportType;
setNetworkSpecifier(mNetworkSpecifier); // used for exception checking
return this;
@@ -469,9 +473,7 @@ public final class NetworkCapabilities implements Parcelable {
* @hide
*/
public NetworkCapabilities removeTransportType(int transportType) {
- if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
- throw new IllegalArgumentException("TransportType out of range");
- }
+ checkValidTransportType(transportType);
mTransportTypes &= ~(1 << transportType);
setNetworkSpecifier(mNetworkSpecifier); // used for exception checking
return this;
@@ -495,10 +497,7 @@ public final class NetworkCapabilities implements Parcelable {
* @return {@code true} if set on this instance.
*/
public boolean hasTransport(int transportType) {
- if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
- return false;
- }
- return ((mTransportTypes & (1 << transportType)) != 0);
+ return isValidTransport(transportType) && ((mTransportTypes & (1 << transportType)) != 0);
}
private void combineTransportTypes(NetworkCapabilities nc) {
@@ -906,9 +905,14 @@ public final class NetworkCapabilities implements Parcelable {
* @hide
*/
public static String transportNameOf(int transport) {
- if (transport < 0 || TRANSPORT_NAMES.length <= transport) {
+ if (!isValidTransport(transport)) {
return "UNKNOWN";
}
return TRANSPORT_NAMES[transport];
}
+
+ private static void checkValidTransportType(int transport) {
+ Preconditions.checkArgument(
+ isValidTransport(transport), "Invalid TransportType " + transport);
+ }
}
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 42f5feb58339..84c32bec8ef7 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -127,7 +127,8 @@ public class NetworkInfo implements Parcelable {
* @hide
*/
public NetworkInfo(int type, int subtype, String typeName, String subtypeName) {
- if (!ConnectivityManager.isNetworkTypeValid(type)) {
+ if (!ConnectivityManager.isNetworkTypeValid(type)
+ && type != ConnectivityManager.TYPE_NONE) {
throw new IllegalArgumentException("Invalid network type: " + type);
}
mNetworkType = type;
diff --git a/core/java/android/os/MemoryFile.java b/core/java/android/os/MemoryFile.java
index 6cec55a4a09e..9294c449e4d6 100644
--- a/core/java/android/os/MemoryFile.java
+++ b/core/java/android/os/MemoryFile.java
@@ -16,68 +16,50 @@
package android.os;
-import android.util.Log;
+import android.system.ErrnoException;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.ByteBuffer;
/**
- * MemoryFile is a wrapper for the Linux ashmem driver.
- * MemoryFiles are backed by shared memory, which can be optionally
- * set to be purgeable.
+ * MemoryFile is a wrapper for {@link SharedMemory} which can optionally be set to purgeable.
+ *
+ * Applications should generally prefer to use {@link SharedMemory} which offers more flexible
+ * access & control over the shared memory region than MemoryFile does.
+ *
* Purgeable files may have their contents reclaimed by the kernel
* in low memory conditions (only if allowPurging is set to true).
* After a file is purged, attempts to read or write the file will
* cause an IOException to be thrown.
*/
-public class MemoryFile
-{
+public class MemoryFile {
private static String TAG = "MemoryFile";
- // mmap(2) protection flags from <sys/mman.h>
- private static final int PROT_READ = 0x1;
- private static final int PROT_WRITE = 0x2;
-
- private static native FileDescriptor native_open(String name, int length) throws IOException;
- // returns memory address for ashmem region
- private static native long native_mmap(FileDescriptor fd, int length, int mode)
- throws IOException;
- private static native void native_munmap(long addr, int length) throws IOException;
- private static native void native_close(FileDescriptor fd);
- private static native int native_read(FileDescriptor fd, long address, byte[] buffer,
- int srcOffset, int destOffset, int count, boolean isUnpinned) throws IOException;
- private static native void native_write(FileDescriptor fd, long address, byte[] buffer,
- int srcOffset, int destOffset, int count, boolean isUnpinned) throws IOException;
- private static native void native_pin(FileDescriptor fd, boolean pin) throws IOException;
+ // Returns 'true' if purged, 'false' otherwise
+ private static native boolean native_pin(FileDescriptor fd, boolean pin) throws IOException;
private static native int native_get_size(FileDescriptor fd) throws IOException;
- private FileDescriptor mFD; // ashmem file descriptor
- private long mAddress; // address of ashmem memory
- private int mLength; // total length of our ashmem region
+ private SharedMemory mSharedMemory;
+ private ByteBuffer mMapping;
private boolean mAllowPurging = false; // true if our ashmem region is unpinned
/**
* Allocates a new ashmem region. The region is initially not purgable.
*
* @param name optional name for the file (can be null).
- * @param length of the memory file in bytes, must be non-negative.
+ * @param length of the memory file in bytes, must be positive.
* @throws IOException if the memory file could not be created.
*/
public MemoryFile(String name, int length) throws IOException {
- mLength = length;
- if (length >= 0) {
- mFD = native_open(name, length);
- } else {
- throw new IOException("Invalid length: " + length);
- }
-
- if (length > 0) {
- mAddress = native_mmap(mFD, length, PROT_READ | PROT_WRITE);
- } else {
- mAddress = 0;
+ try {
+ mSharedMemory = SharedMemory.create(name, length);
+ mMapping = mSharedMemory.mapReadWrite();
+ } catch (ErrnoException ex) {
+ ex.rethrowAsIOException();
}
}
@@ -87,9 +69,7 @@ public class MemoryFile
*/
public void close() {
deactivate();
- if (!isClosed()) {
- native_close(mFD);
- }
+ mSharedMemory.close();
}
/**
@@ -100,35 +80,30 @@ public class MemoryFile
* @hide
*/
void deactivate() {
- if (!isDeactivated()) {
- try {
- native_munmap(mAddress, mLength);
- mAddress = 0;
- } catch (IOException ex) {
- Log.e(TAG, ex.toString());
- }
+ if (mMapping != null) {
+ SharedMemory.unmap(mMapping);
+ mMapping = null;
}
}
- /**
- * Checks whether the memory file has been deactivated.
- */
- private boolean isDeactivated() {
- return mAddress == 0;
+ private void checkActive() throws IOException {
+ if (mMapping == null) {
+ throw new IOException("MemoryFile has been deactivated");
+ }
}
- /**
- * Checks whether the memory file has been closed.
- */
- private boolean isClosed() {
- return !mFD.valid();
+ private void beginAccess() throws IOException {
+ checkActive();
+ if (mAllowPurging) {
+ if (native_pin(mSharedMemory.getFileDescriptor(), true)) {
+ throw new IOException("MemoryFile has been purged");
+ }
+ }
}
- @Override
- protected void finalize() {
- if (!isClosed()) {
- Log.e(TAG, "MemoryFile.finalize() called while ashmem still open");
- close();
+ private void endAccess() throws IOException {
+ if (mAllowPurging) {
+ native_pin(mSharedMemory.getFileDescriptor(), false);
}
}
@@ -138,14 +113,19 @@ public class MemoryFile
* @return file length.
*/
public int length() {
- return mLength;
+ return mSharedMemory.getSize();
}
/**
* Is memory file purging enabled?
*
* @return true if the file may be purged.
+ *
+ * @deprecated Purgable is considered generally fragile and hard to use safely. Applications
+ * are recommend to instead use {@link android.content.ComponentCallbacks2#onTrimMemory(int)}
+ * to react to memory events and release shared memory regions as appropriate.
*/
+ @Deprecated
public boolean isPurgingAllowed() {
return mAllowPurging;
}
@@ -156,11 +136,16 @@ public class MemoryFile
* @param allowPurging true if the operating system can purge the contents
* of the file in low memory situations
* @return previous value of allowPurging
+ *
+ * @deprecated Purgable is considered generally fragile and hard to use safely. Applications
+ * are recommend to instead use {@link android.content.ComponentCallbacks2#onTrimMemory(int)}
+ * to react to memory events and release shared memory regions as appropriate.
*/
+ @Deprecated
synchronized public boolean allowPurging(boolean allowPurging) throws IOException {
boolean oldValue = mAllowPurging;
if (oldValue != allowPurging) {
- native_pin(mFD, !allowPurging);
+ native_pin(mSharedMemory.getFileDescriptor(), !allowPurging);
mAllowPurging = allowPurging;
}
return oldValue;
@@ -197,16 +182,14 @@ public class MemoryFile
*/
public int readBytes(byte[] buffer, int srcOffset, int destOffset, int count)
throws IOException {
- if (isDeactivated()) {
- throw new IOException("Can't read from deactivated memory file.");
+ beginAccess();
+ try {
+ mMapping.position(srcOffset);
+ mMapping.get(buffer, destOffset, count);
+ } finally {
+ endAccess();
}
- if (destOffset < 0 || destOffset > buffer.length || count < 0
- || count > buffer.length - destOffset
- || srcOffset < 0 || srcOffset > mLength
- || count > mLength - srcOffset) {
- throw new IndexOutOfBoundsException();
- }
- return native_read(mFD, mAddress, buffer, srcOffset, destOffset, count, mAllowPurging);
+ return count;
}
/**
@@ -221,16 +204,13 @@ public class MemoryFile
*/
public void writeBytes(byte[] buffer, int srcOffset, int destOffset, int count)
throws IOException {
- if (isDeactivated()) {
- throw new IOException("Can't write to deactivated memory file.");
- }
- if (srcOffset < 0 || srcOffset > buffer.length || count < 0
- || count > buffer.length - srcOffset
- || destOffset < 0 || destOffset > mLength
- || count > mLength - destOffset) {
- throw new IndexOutOfBoundsException();
+ beginAccess();
+ try {
+ mMapping.position(destOffset);
+ mMapping.put(buffer, srcOffset, count);
+ } finally {
+ endAccess();
}
- native_write(mFD, mAddress, buffer, srcOffset, destOffset, count, mAllowPurging);
}
/**
@@ -239,11 +219,9 @@ public class MemoryFile
* The returned file descriptor is not duplicated.
*
* @throws IOException If the memory file has been closed.
- *
- * @hide
*/
public FileDescriptor getFileDescriptor() throws IOException {
- return mFD;
+ return mSharedMemory.getFileDescriptor();
}
/**
@@ -266,10 +244,10 @@ public class MemoryFile
@Override
public int available() throws IOException {
- if (mOffset >= mLength) {
+ if (mOffset >= mSharedMemory.getSize()) {
return 0;
}
- return mLength - mOffset;
+ return mSharedMemory.getSize() - mOffset;
}
@Override
@@ -319,8 +297,8 @@ public class MemoryFile
@Override
public long skip(long n) throws IOException {
- if (mOffset + n > mLength) {
- n = mLength - mOffset;
+ if (mOffset + n > mSharedMemory.getSize()) {
+ n = mSharedMemory.getSize() - mOffset;
}
mOffset += n;
return n;
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 68a81ca341a7..801c002fb568 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -27,6 +27,7 @@ import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
+import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
import dalvik.system.VMRuntime;
@@ -260,24 +261,24 @@ public final class Parcel {
// see libbinder's binder/Status.h
private static final int EX_TRANSACTION_FAILED = -129;
- @FastNative
+ @CriticalNative
private static native int nativeDataSize(long nativePtr);
- @FastNative
+ @CriticalNative
private static native int nativeDataAvail(long nativePtr);
- @FastNative
+ @CriticalNative
private static native int nativeDataPosition(long nativePtr);
- @FastNative
+ @CriticalNative
private static native int nativeDataCapacity(long nativePtr);
@FastNative
private static native long nativeSetDataSize(long nativePtr, int size);
- @FastNative
+ @CriticalNative
private static native void nativeSetDataPosition(long nativePtr, int pos);
@FastNative
private static native void nativeSetDataCapacity(long nativePtr, int size);
- @FastNative
+ @CriticalNative
private static native boolean nativePushAllowFds(long nativePtr, boolean allowFds);
- @FastNative
+ @CriticalNative
private static native void nativeRestoreAllowFds(long nativePtr, boolean lastValue);
private static native void nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len);
@@ -297,13 +298,13 @@ public final class Parcel {
private static native byte[] nativeCreateByteArray(long nativePtr);
private static native boolean nativeReadByteArray(long nativePtr, byte[] dest, int destLen);
private static native byte[] nativeReadBlob(long nativePtr);
- @FastNative
+ @CriticalNative
private static native int nativeReadInt(long nativePtr);
- @FastNative
+ @CriticalNative
private static native long nativeReadLong(long nativePtr);
- @FastNative
+ @CriticalNative
private static native float nativeReadFloat(long nativePtr);
- @FastNative
+ @CriticalNative
private static native double nativeReadDouble(long nativePtr);
private static native String nativeReadString(long nativePtr);
private static native IBinder nativeReadStrongBinder(long nativePtr);
@@ -319,11 +320,12 @@ public final class Parcel {
private static native int nativeCompareData(long thisNativePtr, long otherNativePtr);
private static native long nativeAppendFrom(
long thisNativePtr, long otherNativePtr, int offset, int length);
- @FastNative
+ @CriticalNative
private static native boolean nativeHasFileDescriptors(long nativePtr);
private static native void nativeWriteInterfaceToken(long nativePtr, String interfaceName);
private static native void nativeEnforceInterface(long nativePtr, String interfaceName);
+ @CriticalNative
private static native long nativeGetBlobAshmemSize(long nativePtr);
public final static Parcelable.Creator<String> STRING_CREATOR
diff --git a/core/java/android/os/SharedMemory.aidl b/core/java/android/os/SharedMemory.aidl
new file mode 100644
index 000000000000..b7c695e5f15c
--- /dev/null
+++ b/core/java/android/os/SharedMemory.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/os/SharedMemory.aidl
+**
+** 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;
+
+parcelable SharedMemory; \ No newline at end of file
diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java
new file mode 100644
index 000000000000..712bbaa101aa
--- /dev/null
+++ b/core/java/android/os/SharedMemory.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.os;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+
+import dalvik.system.VMRuntime;
+
+import java.io.Closeable;
+import java.io.FileDescriptor;
+import java.nio.ByteBuffer;
+import java.nio.DirectByteBuffer;
+
+import sun.misc.Cleaner;
+
+/**
+ * SharedMemory enables the creation, mapping, and protection control over anonymous shared memory.
+ */
+public final class SharedMemory implements Parcelable, Closeable {
+
+ private final FileDescriptor mFileDescriptor;
+ private final int mSize;
+ private final MemoryRegistration mMemoryRegistration;
+ private Cleaner mCleaner;
+
+ private SharedMemory(FileDescriptor fd) {
+ // This constructor is only used internally so it should be impossible to hit any of the
+ // exceptions unless something goes horribly wrong.
+ if (fd == null) {
+ throw new IllegalArgumentException(
+ "Unable to create SharedMemory from a null FileDescriptor");
+ }
+ if (!fd.valid()) {
+ throw new IllegalArgumentException(
+ "Unable to create SharedMemory from closed FileDescriptor");
+ }
+ mFileDescriptor = fd;
+ mSize = nGetSize(mFileDescriptor);
+ if (mSize <= 0) {
+ throw new IllegalArgumentException("FileDescriptor is not a valid ashmem fd");
+ }
+
+ mMemoryRegistration = new MemoryRegistration(mSize);
+ mCleaner = Cleaner.create(this, new Closer(mFileDescriptor, mMemoryRegistration));
+ }
+
+ /**
+ * Creates an anonymous SharedMemory instance with the provided debug name and size. The name
+ * is only used for debugging purposes and can help identify what the shared memory is used
+ * for when inspecting memory maps for the processes that have mapped this SharedMemory
+ * instance.
+ *
+ * @param name The debug name to use for this SharedMemory instance. This can be null, however
+ * a debug name is recommended to help identify memory usage when using tools
+ * such as lsof or examining /proc/[pid]/maps
+ * @param size The size of the shared memory to create. Must be greater than 0.
+ * @return A SharedMemory instance of the requested size
+ * @throws ErrnoException if the requested allocation fails.
+ */
+ public static @NonNull SharedMemory create(@Nullable String name, int size)
+ throws ErrnoException {
+ if (size <= 0) {
+ throw new IllegalArgumentException("Size must be greater than zero");
+ }
+ return new SharedMemory(nCreate(name, size));
+ }
+
+ private void checkOpen() {
+ if (!mFileDescriptor.valid()) {
+ throw new IllegalStateException("SharedMemory is closed");
+ }
+ }
+
+ private static final int PROT_MASK = OsConstants.PROT_READ | OsConstants.PROT_WRITE
+ | OsConstants.PROT_EXEC | OsConstants.PROT_NONE;
+
+ private static void validateProt(int prot) {
+ if ((prot & ~PROT_MASK) != 0) {
+ throw new IllegalArgumentException("Invalid prot value");
+ }
+ }
+
+ /**
+ * Sets the protection on the shared memory to the combination specified in prot, which
+ * is either a bitwise-or'd combination of {@link android.system.OsConstants#PROT_READ},
+ * {@link android.system.OsConstants#PROT_WRITE}, {@link android.system.OsConstants#PROT_EXEC}
+ * from {@link android.system.OsConstants}, or {@link android.system.OsConstants#PROT_NONE},
+ * to remove all further access.
+ *
+ * Note that protection can only ever be removed, not added. By default shared memory
+ * is created with protection set to PROT_READ | PROT_WRITE | PROT_EXEC. The protection
+ * passed here also only applies to any mappings created after calling this method. Existing
+ * mmaps of the shared memory retain whatever protection they had when they were created.
+ *
+ * A common usage of this is to share a read-only copy of the data with something else. To do
+ * that first create the read/write mapping with PROT_READ | PROT_WRITE,
+ * then call setProtect(PROT_READ) to remove write capability, then send the SharedMemory
+ * to another process. That process will only be able to mmap with PROT_READ.
+ *
+ * @param prot Any bitwise-or'ed combination of
+ * {@link android.system.OsConstants#PROT_READ},
+ * {@link android.system.OsConstants#PROT_WRITE}, and
+ * {@link android.system.OsConstants#PROT_EXEC}; or
+ * {@link android.system.OsConstants#PROT_NONE}
+ * @return Whether or not the requested protection was applied. Returns true on success,
+ * false if the requested protection was broader than the existing protection.
+ */
+ public boolean setProtect(int prot) {
+ checkOpen();
+ validateProt(prot);
+ int errno = nSetProt(mFileDescriptor, prot);
+ return errno == 0;
+ }
+
+ /**
+ * Returns the backing {@link FileDescriptor} for this SharedMemory object. The SharedMemory
+ * instance retains ownership of the FileDescriptor.
+ *
+ * This FileDescriptor is interoperable with the ASharedMemory NDK APIs.
+ *
+ * @return Returns the FileDescriptor associated with this object.
+ */
+ public @NonNull FileDescriptor getFileDescriptor() {
+ return mFileDescriptor;
+ }
+
+ /**
+ * Returns the backing native fd int for this SharedMemory object. The SharedMemory
+ * instance retains ownership of the fd.
+ *
+ * This fd is interoperable with the ASharedMemory NDK APIs.
+ *
+ * @return Returns the native fd associated with this object, or -1 if it is already closed.
+ */
+ public int getFd() {
+ return mFileDescriptor.getInt$();
+ }
+
+ /**
+ * @return The size of the SharedMemory region.
+ */
+ public int getSize() {
+ checkOpen();
+ return mSize;
+ }
+
+ /**
+ * Creates a read/write mapping of the entire shared memory region. This requires the the
+ * protection level of the shared memory is at least PROT_READ|PROT_WRITE or the map will fail.
+ *
+ * Use {@link #map(int, int, int)} to have more control over the mapping if desired.
+ * This is equivalent to map(OsConstants.PROT_READ | OsConstants.PROT_WRITE, 0, getSize())
+ *
+ * @return A ByteBuffer mapping
+ * @throws ErrnoException if the mmap call failed.
+ */
+ public @NonNull ByteBuffer mapReadWrite() throws ErrnoException {
+ return map(OsConstants.PROT_READ | OsConstants.PROT_WRITE, 0, mSize);
+ }
+
+ /**
+ * Creates a read-only mapping of the entire shared memory region. This requires the the
+ * protection level of the shared memory is at least PROT_READ or the map will fail.
+ *
+ * Use {@link #map(int, int, int)} to have more control over the mapping if desired.
+ * This is equivalent to map(OsConstants.PROT_READ, 0, getSize())
+ *
+ * @return A ByteBuffer mapping
+ * @throws ErrnoException if the mmap call failed.
+ */
+ public @NonNull ByteBuffer mapReadOnly() throws ErrnoException {
+ return map(OsConstants.PROT_READ, 0, mSize);
+ }
+
+ /**
+ * Creates an mmap of the SharedMemory with the specified prot, offset, and length.
+ *
+ * @param prot A bitwise-or'd combination of PROT_READ, PROT_WRITE, PROT_EXEC, or PROT_NONE.
+ * @param offset The offset into the shared memory to begin mapping
+ * @param length The length of the region to map
+ * @return A ByteBuffer mapping.
+ * @throws ErrnoException if the mmap call failed.
+ */
+ public @NonNull ByteBuffer map(int prot, int offset, int length) throws ErrnoException {
+ checkOpen();
+ validateProt(prot);
+ if (offset < 0) {
+ throw new IllegalArgumentException("Offset must be > 0");
+ }
+ if (length <= 0) {
+ throw new IllegalArgumentException("Length must be > 0");
+ }
+ if (offset + length > mSize) {
+ throw new IllegalArgumentException("offset + length must not exceed getSize()");
+ }
+ long address = Os.mmap(0, length, prot, OsConstants.MAP_SHARED, mFileDescriptor, offset);
+ boolean readOnly = (prot & OsConstants.PROT_WRITE) == 0;
+ Runnable unmapper = new Unmapper(address, length, mMemoryRegistration.acquire());
+ return new DirectByteBuffer(length, address, mFileDescriptor, unmapper, readOnly);
+ }
+
+ /**
+ * Unmaps a buffer previously returned by {@link #map(int, int, int)}
+ * @param buffer The buffer to unmap
+ */
+ public static void unmap(@NonNull ByteBuffer buffer) {
+ if (buffer instanceof DirectByteBuffer) {
+ Cleaner cleaner = ((DirectByteBuffer) buffer).cleaner();
+ if (cleaner != null) {
+ cleaner.clean();
+ }
+ } else {
+ throw new IllegalArgumentException(
+ "ByteBuffer wasn't created by #map(int, int, int); can't unmap");
+ }
+ }
+
+ /**
+ * Close the backing {@link FileDescriptor} of this SharedMemory instance. Note that all
+ * open mappings of the shared memory will remain valid and may continue to be used. The
+ * shared memory will not be freed until all file descriptor handles are closed and all
+ * memory mappings are unmapped.
+ */
+ @Override
+ public void close() {
+ if (mCleaner != null) {
+ mCleaner.clean();
+ mCleaner = null;
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return CONTENTS_FILE_DESCRIPTOR;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ checkOpen();
+ dest.writeFileDescriptor(mFileDescriptor);
+ }
+
+ public static final Parcelable.Creator<SharedMemory> CREATOR =
+ new Parcelable.Creator<SharedMemory>() {
+ @Override
+ public SharedMemory createFromParcel(Parcel source) {
+ FileDescriptor descriptor = source.readRawFileDescriptor();
+ return new SharedMemory(descriptor);
+ }
+
+ @Override
+ public SharedMemory[] newArray(int size) {
+ return new SharedMemory[size];
+ }
+ };
+
+ /**
+ * Cleaner that closes the FD
+ */
+ private static final class Closer implements Runnable {
+ private FileDescriptor mFd;
+ private MemoryRegistration mMemoryReference;
+
+ private Closer(FileDescriptor fd, MemoryRegistration memoryReference) {
+ mFd = fd;
+ mMemoryReference = memoryReference;
+ }
+
+ @Override
+ public void run() {
+ try {
+ Os.close(mFd);
+ } catch (ErrnoException e) { /* swallow error */ }
+ mMemoryReference.release();
+ mMemoryReference = null;
+ }
+ }
+
+ /**
+ * Cleaner that munmap regions
+ */
+ private static final class Unmapper implements Runnable {
+ private long mAddress;
+ private int mSize;
+ private MemoryRegistration mMemoryReference;
+
+ private Unmapper(long address, int size, MemoryRegistration memoryReference) {
+ mAddress = address;
+ mSize = size;
+ mMemoryReference = memoryReference;
+ }
+
+ @Override
+ public void run() {
+ try {
+ Os.munmap(mAddress, mSize);
+ } catch (ErrnoException e) { /* swallow exception */ }
+ mMemoryReference.release();
+ mMemoryReference = null;
+ }
+ }
+
+ /**
+ * Helper class that ensures that the native allocation pressure against the VM heap stays
+ * active until the FD is closed as well as all mappings from that FD are closed.
+ */
+ private static final class MemoryRegistration {
+ private int mSize;
+ private int mReferenceCount;
+
+ private MemoryRegistration(int size) {
+ mSize = size;
+ mReferenceCount = 1;
+ VMRuntime.getRuntime().registerNativeAllocation(mSize);
+ }
+
+ public synchronized MemoryRegistration acquire() {
+ mReferenceCount++;
+ return this;
+ }
+
+ public synchronized void release() {
+ mReferenceCount--;
+ if (mReferenceCount == 0) {
+ VMRuntime.getRuntime().registerNativeFree(mSize);
+ }
+ }
+ }
+
+ private static native FileDescriptor nCreate(String name, int size) throws ErrnoException;
+ private static native int nGetSize(FileDescriptor fd);
+ private static native int nSetProt(FileDescriptor fd, int prot);
+}
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 2179bd45e303..4306bc47f2b5 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -934,6 +934,7 @@ public class Preference implements Comparable<Preference> {
* @param singleLineTitle set {@code true} if the title should be constrained to one line
*/
public void setSingleLineTitle(boolean singleLineTitle) {
+ mHasSingleLineTitleAttr = true;
mSingleLineTitle = singleLineTitle;
notifyChanged();
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bc0534a353b3..b710cf1846be 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -195,6 +195,24 @@ public final class Settings {
"android.settings.AIRPLANE_MODE_SETTINGS";
/**
+ * Activity Action: Show mobile data usage list.
+ * <p>
+ * Input: {@link EXTRA_NETWORK_TEMPLATE} and {@link EXTRA_SUB_ID} should be included to specify
+ * how and what mobile data statistics should be collected.
+ * <p>
+ * Output: Nothing
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MOBILE_DATA_USAGE =
+ "android.settings.MOBILE_DATA_USAGE";
+
+ /** @hide */
+ public static final String EXTRA_NETWORK_TEMPLATE = "network_template";
+ /** @hide */
+ public static final String EXTRA_SUB_ID = "sub_id";
+
+ /**
* Activity Action: Modify Airplane mode settings using a voice command.
* <p>
* In some cases, a matching Activity may not exist, so ensure you safeguard against this.
@@ -7060,6 +7078,12 @@ public final class Settings {
public static final String NOTIFICATION_BADGING = "notification_badging";
/**
+ * Comma separated list of QS tiles that have been auto-added already.
+ * @hide
+ */
+ public static final String QS_AUTO_ADDED_TILES = "qs_auto_tiles";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -7155,7 +7179,8 @@ public final class Settings {
ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
ASSIST_GESTURE_WAKE_ENABLED,
VR_DISPLAY_MODE,
- NOTIFICATION_BADGING
+ NOTIFICATION_BADGING,
+ QS_AUTO_ADDED_TILES,
};
/** @hide */
diff --git a/core/java/android/service/autofill/CharSequenceTransformation.java b/core/java/android/service/autofill/CharSequenceTransformation.java
new file mode 100644
index 000000000000..7472aba99c21
--- /dev/null
+++ b/core/java/android/service/autofill/CharSequenceTransformation.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import static android.view.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Pair;
+import android.view.autofill.AutofillId;
+import android.widget.RemoteViews;
+import android.widget.TextView;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Replaces a {@link TextView} child of a {@link CustomDescription} with the contents of one or
+ * more regular expressions (regexs).
+ *
+ * <p>When it contains more than one field, the fields that match their regex are added to the
+ * overall transformation result.
+ *
+ * <p>For example, a transformation to mask a credit card number contained in just one field would
+ * be:
+ *
+ * <pre class="prettyprint">
+ * new CharSequenceTransformation.Builder()
+ * .addField(ccNumberId, "^.*(\\d\\d\\d\\d)$", "...$1")
+ * .build();
+ * </pre>
+ *
+ * <p>But a tranformation that generates a {@code Exp: MM / YYYY} credit expiration date from two
+ * fields (month and year) would be:
+ *
+ * <pre class="prettyprint">
+ * new CharSequenceTransformation.Builder()
+ * .addField(ccExpMonthId, "^(\\d\\d)$", "Exp: $1")
+ * .addField(ccExpYearId, "^(\\d\\d\\d\\d)$", " / $1");
+ * </pre>
+ */
+//TODO(b/62534917): add unit tests
+public final class CharSequenceTransformation extends InternalTransformation implements Parcelable {
+ private static final String TAG = "CharSequenceTransformation";
+ private final ArrayMap<AutofillId, Pair<String, String>> mFields;
+
+ private CharSequenceTransformation(Builder builder) {
+ mFields = builder.mFields;
+ }
+
+ /** @hide */
+ @Override
+ public void apply(@NonNull ValueFinder finder, @NonNull RemoteViews parentTemplate,
+ int childViewId) {
+ final StringBuilder converted = new StringBuilder();
+ final int size = mFields.size();
+ if (sDebug) Log.d(TAG, size + " multiple fields on id " + childViewId);
+ for (int i = 0; i < size; i++) {
+ final AutofillId id = mFields.keyAt(i);
+ final Pair<String, String> regex = mFields.valueAt(i);
+ final String value = finder.findByAutofillId(id);
+ if (value == null) {
+ Log.w(TAG, "No value for id " + id);
+ return;
+ }
+ final String convertedValue = value.replaceAll(regex.first, regex.second);
+ converted.append(convertedValue);
+ }
+ parentTemplate.setCharSequence(childViewId, "setText", converted);
+ }
+
+ /**
+ * Builder for {@link CharSequenceTransformation} objects.
+ */
+ public static class Builder {
+ private ArrayMap<AutofillId, Pair<String, String>> mFields;
+ private boolean mDestroyed;
+
+ //TODO(b/62534917): add constructor that takes a field so we force it to have at least one
+ // (and then remove the check for empty from build())
+
+ /**
+ * Adds the transformed contents of a field to the overall result of this transformation.
+ *
+ * @param id id of the screen field.
+ * @param regex regular expression with groups (delimited by {@code (} and {@code (}) that
+ * are used to substitute parts of the value.
+ * @param subst the string that substitutes the matched regex, using {@code $} for
+ * group substitution ({@code $1} for 1st group match, {@code $2} for 2nd, etc).
+ *
+ * @return this builder.
+ */
+ public Builder addField(@NonNull AutofillId id, @NonNull String regex,
+ @NonNull String subst) {
+ //TODO(b/62534917): throw exception if regex /subts are invalid
+ throwIfDestroyed();
+ Preconditions.checkNotNull(id);
+ Preconditions.checkNotNull(regex);
+ Preconditions.checkNotNull(subst);
+ if (mFields == null) {
+ mFields = new ArrayMap<>();
+ }
+ mFields.put(id, new Pair<>(regex, subst));
+ return this;
+ }
+
+ /**
+ * Creates a new {@link CharSequenceTransformation} instance.
+ *
+ * @throws IllegalStateException if no call to {@link #addField(AutofillId, String, String)}
+ * was made.
+ */
+ public CharSequenceTransformation build() {
+ throwIfDestroyed();
+ Preconditions.checkState(mFields != null && !mFields.isEmpty(),
+ "Must add at least one field");
+ mDestroyed = true;
+ return new CharSequenceTransformation(this);
+ }
+
+ private void throwIfDestroyed() {
+ Preconditions.checkState(!mDestroyed, "Already called build()");
+ }
+ }
+
+ /////////////////////////////////////
+ // Object "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public String toString() {
+ if (!sDebug) return super.toString();
+
+ return "MultipleViewsCharSequenceTransformation: [fields=" + mFields + "]";
+ }
+
+ /////////////////////////////////////
+ // Parcelable "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ final int size = mFields.size();
+ final AutofillId[] ids = new AutofillId[size];
+ final String[] regexs = new String[size];
+ final String[] substs = new String[size];
+ Pair<String, String> pair;
+ for (int i = 0; i < size; i++) {
+ ids[i] = mFields.keyAt(i);
+ pair = mFields.valueAt(i);
+ regexs[i] = pair.first;
+ substs[i] = pair.second;
+ }
+ parcel.writeParcelableArray(ids, flags);
+ parcel.writeStringArray(regexs);
+ parcel.writeStringArray(substs);
+ }
+
+ public static final Parcelable.Creator<CharSequenceTransformation> CREATOR =
+ new Parcelable.Creator<CharSequenceTransformation>() {
+ @Override
+ public CharSequenceTransformation createFromParcel(Parcel parcel) {
+ // Always go through the builder to ensure the data ingested by
+ // the system obeys the contract of the builder to avoid attacks
+ // using specially crafted parcels.
+ final CharSequenceTransformation.Builder builder =
+ new CharSequenceTransformation.Builder();
+ final AutofillId[] ids = parcel.readParcelableArray(null, AutofillId.class);
+ final String[] regexs = parcel.createStringArray();
+ final String[] substs = parcel.createStringArray();
+ final int size = ids.length;
+ for (int i = 0; i < size; i++) {
+ builder.addField(ids[i], regexs[i], substs[i]);
+ }
+ return builder.build();
+ }
+
+ @Override
+ public CharSequenceTransformation[] newArray(int size) {
+ return new CharSequenceTransformation[size];
+ }
+ };
+}
diff --git a/core/java/android/service/autofill/CustomDescription.java b/core/java/android/service/autofill/CustomDescription.java
new file mode 100644
index 000000000000..51530d61c9f5
--- /dev/null
+++ b/core/java/android/service/autofill/CustomDescription.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import static android.view.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import android.util.SparseArray;
+import android.widget.RemoteViews;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Defines a custom description for the Save UI affordance.
+ *
+ * <p>This is useful when the autofill service needs to show a detailed view of what would be saved;
+ * for example, when the screen contains a credit card, it could display a logo of the credit card
+ * bank, the last for digits of the credit card number, and its expiration number.
+ *
+ * <p>A custom description is made of 2 parts:
+ * <ul>
+ * <li>A {@link RemoteViews presentation template} containing children views.
+ * <li>{@link Transformation Transformations} to populate the children views.
+ * </ul>
+ *
+ * <p>For the credit card example mentioned above, the (simplified) template would be:
+ *
+ * <pre class="prettyprint">
+ * &lt;LinearLayout&gt;
+ * &lt;ImageView android:id="@+id/templateccLogo"/&gt;
+ * &lt;TextView android:id="@+id/templateCcNumber"/&gt;
+ * &lt;TextView android:id="@+id/templateExpDate"/&gt;
+ * &lt;/LinearLayout&gt;
+ * </pre>
+ *
+ * <p>Which in code translates to:
+ *
+ * <pre class="prettyprint">
+ * CustomDescription.Builder buider = new Builder(new RemoteViews(pgkName, R.layout.cc_template);
+ * </pre>
+ *
+ * <p>Then the value of each of the 3 children would be changed at runtime based on the the value of
+ * the screen fields and the {@link Transformation Transformations}:
+ *
+ * <pre class="prettyprint">
+ * // Image child - different logo for each bank, based on credit card prefix
+ * builder.addChild(R.id.templateccLogo,
+ * new ImageTransformation.Builder(ccNumberId)
+ * .addOption("^4815.*$", R.drawable.ic_credit_card_logo1)
+ * .addOption("^1623.*$", R.drawable.ic_credit_card_logo2)
+ * .addOption("^42.*$", R.drawable.ic_credit_card_logo3);
+ * // Masked credit card number (as .....LAST_4_DIGITS)
+ * builder.addChild(R.id.templateCcNumber, new CharSequenceTransformation.Builder()
+ * .addField(ccNumberId, "^.*(\\d\\d\\d\\d)$", "...$1")
+ * // Expiration date as MM / YYYY:
+ * builder.addChild(R.id.templateExpDate, new CharSequenceTransformation.Builder()
+ * .addField(ccExpMonthId, "^(\\d\\d)$", "Exp: $1")
+ * .addField(ccExpYearId, "^(\\d\\d)$", "/$1");
+ * </pre>
+ *
+ * <p>See {@link ImageTransformation}, {@link CharSequenceTransformation} for more info about these
+ * transformations.
+ */
+// TODO(b/62534917): add integration tests
+public final class CustomDescription implements Parcelable {
+
+ private static final String TAG = "CustomDescription";
+
+ private final RemoteViews mPresentation;
+ private final SparseArray<InternalTransformation> mTransformations;
+
+ private CustomDescription(Builder builder) {
+ mPresentation = builder.mPresentation;
+ mTransformations = builder.mTransformations;
+ }
+
+ /** @hide */
+ public RemoteViews getPresentation(ValueFinder finder) {
+ // TODO(b/62534917): need to handler errors, like not finding the ID
+ if (mTransformations != null) {
+ final int size = mTransformations.size();
+ if (sDebug) Log.d(TAG, "getPresentation(): applying " + size + " transformations");
+ for (int i = 0; i < size; i++) {
+ final int id = mTransformations.keyAt(i);
+ final InternalTransformation transformation = mTransformations.valueAt(i);
+ if (sDebug) Log.d(TAG, "#" + i + ": " + transformation);
+ transformation.apply(finder, mPresentation, id);
+ }
+ }
+ return mPresentation;
+ }
+
+ /**
+ * Builder for {@link CustomDescription} objects.
+ */
+ public static class Builder {
+ private final RemoteViews mPresentation;
+
+ private SparseArray<InternalTransformation> mTransformations;
+
+ /**
+ * Default constructor.
+ *
+ * @param parentPresentation template presentation with (optional) children views.
+ */
+ public Builder(RemoteViews parentPresentation) {
+ mPresentation = parentPresentation;
+ }
+
+ /**
+ * Adds a transformation to replace the value of a child view with the fields in the
+ * screen.
+ *
+ * @param id view id of the children view.
+ * @param transformation an implementation provided by the Android System.
+ * @return this builder.
+ * @throws IllegalArgumentException if {@code transformation} is not a class provided
+ * by the Android System.
+ */
+ public Builder addChild(int id, @NonNull Transformation transformation) {
+ Preconditions.checkArgument((transformation instanceof InternalTransformation),
+ "not provided by Android System: " + transformation);
+ if (mTransformations == null) {
+ mTransformations = new SparseArray<>();
+ }
+ mTransformations.put(id, (InternalTransformation) transformation);
+ return this;
+ }
+
+ /**
+ * Creates a new {@link CustomDescription} instance.
+ */
+ public CustomDescription build() {
+ return new CustomDescription(this);
+ }
+ }
+
+ /////////////////////////////////////
+ // Object "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public String toString() {
+ if (!sDebug) return super.toString();
+
+ return new StringBuilder("CustomDescription: [presentation=")
+ .append(mPresentation)
+ .append(", transformations=").append(mTransformations)
+ .append("]").toString();
+ }
+
+ /////////////////////////////////////
+ // Parcelable "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mPresentation, flags);
+ if (mTransformations == null) {
+ dest.writeIntArray(null);
+ } else {
+ final int size = mTransformations.size();
+ final int[] ids = new int[size];
+ final InternalTransformation[] values = new InternalTransformation[size];
+ for (int i = 0; i < size; i++) {
+ ids[i] = mTransformations.keyAt(i);
+ values[i] = mTransformations.valueAt(i);
+ }
+ dest.writeIntArray(ids);
+ dest.writeParcelableArray(values, flags);
+ }
+ }
+ public static final Parcelable.Creator<CustomDescription> CREATOR =
+ new Parcelable.Creator<CustomDescription>() {
+ @Override
+ public CustomDescription createFromParcel(Parcel parcel) {
+ // Always go through the builder to ensure the data ingested by
+ // the system obeys the contract of the builder to avoid attacks
+ // using specially crafted parcels.
+ final Builder builder = new Builder(parcel.readParcelable(null));
+ final int[] ids = parcel.createIntArray();
+ if (ids != null) {
+ final InternalTransformation[] values =
+ parcel.readParcelableArray(null, InternalTransformation.class);
+ final int size = ids.length;
+ for (int i = 0; i < size; i++) {
+ builder.addChild(ids[i], values[i]);
+ }
+ }
+ return builder.build();
+ }
+
+ @Override
+ public CustomDescription[] newArray(int size) {
+ return new CustomDescription[size];
+ }
+ };
+}
diff --git a/core/java/android/service/autofill/ImageTransformation.java b/core/java/android/service/autofill/ImageTransformation.java
new file mode 100644
index 000000000000..9f6eedc8b3a2
--- /dev/null
+++ b/core/java/android/service/autofill/ImageTransformation.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import static android.view.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.view.autofill.AutofillId;
+import android.widget.ImageView;
+import android.widget.RemoteViews;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Replaces the content of a child {@link ImageView} of a
+ * {@link RemoteViews presentation template} with the first image that matches a regular expression
+ * (regex).
+ *
+ * <p>Typically used to display credit card logos. Example:
+ *
+ * <pre class="prettyprint">
+ * new ImageTransformation.Builder(ccNumberId)
+ * .addOption("^4815.*$", R.drawable.ic_credit_card_logo1)
+ * .addOption("^1623.*$", R.drawable.ic_credit_card_logo2)
+ * .addOption("^42.*$", R.drawable.ic_credit_card_logo3)
+ * .build();
+ * </pre>
+ *
+ * <p>There is no imposed limit in the number of options, but keep in mind that regexs are
+ * expensive to evaluate, so try to:
+ * <ul>
+ * <li>Use the minimum number of regex per image.
+ * <li>Add the most common images first.
+ * </ul>
+ */
+//TODO(b/62534917): add unit tests
+public final class ImageTransformation extends InternalTransformation implements Parcelable {
+ private static final String TAG = "ImageTransformation";
+
+ private final AutofillId mId;
+ private final ArrayMap<String, Integer> mOptions;
+
+ private ImageTransformation(Builder builder) {
+ mId = builder.mId;
+ mOptions = builder.mOptions;
+ }
+
+ /** @hide */
+ @Override
+ public void apply(@NonNull ValueFinder finder, @NonNull RemoteViews parentTemplate,
+ int childViewId) {
+ final String value = finder.findByAutofillId(mId);
+ if (value == null) {
+ Log.w(TAG, "No view for id " + mId);
+ return;
+ }
+ final int size = mOptions.size();
+ if (sDebug) {
+ Log.d(TAG, size + " multiple options on id " + childViewId + " to compare against "
+ + value);
+ }
+
+ for (int i = 0; i < size; i++) {
+ final String regex = mOptions.keyAt(i);
+ if (value.matches(regex)) {
+ Log.d(TAG, "Found match at " + i + ": " + regex);
+ parentTemplate.setImageViewResource(childViewId, mOptions.valueAt(i));
+ return;
+ }
+ }
+ Log.w(TAG, "No match for " + value);
+ }
+
+ /**
+ * Builder for {@link ImageTransformation} objects.
+ */
+ public static class Builder {
+ private final AutofillId mId;
+ private ArrayMap<String, Integer> mOptions;
+ private boolean mDestroyed;
+
+ /**
+ * Default constructor.
+ *
+ * @param id id of the screen field that will be used to evaluate whether the image should
+ * be used.
+ */
+ //TODO(b/62534917): add a regex/resid so we force it to have at least one
+ // (and then remove the check for empty from build())
+ public Builder(@NonNull AutofillId id) {
+ mId = Preconditions.checkNotNull(id);
+ }
+
+ /**
+ * Adds an option to replace the child view with a different image when the regex matches.
+ *
+ * @param regex regular expression defining what should be matched to use this image.
+ * @param resId resource id of the image (in the autofill service's package). The
+ * {@link RemoteViews presentation} must contain a {@link ImageView} child with that id.
+ *
+ * @return this build
+ */
+ public Builder addOption(String regex, int resId) {
+ //TODO(b/62534917): throw exception if regex / resId are invalid
+ throwIfDestroyed();
+ if (mOptions == null) {
+ mOptions = new ArrayMap<>();
+ }
+ mOptions.put(regex, resId);
+ return this;
+ }
+
+ /**
+ * Creates a new {@link ImageTransformation} instance.
+ *
+ * @throws IllegalStateException if no call to {@link #addOption(String, int)} was made.
+ */
+ public ImageTransformation build() {
+ throwIfDestroyed();
+ Preconditions.checkState(mOptions != null && !mOptions.isEmpty(),
+ "Must add at least one option");
+ mDestroyed = true;
+ return new ImageTransformation(this);
+ }
+
+ private void throwIfDestroyed() {
+ Preconditions.checkState(!mDestroyed, "Already called build()");
+ }
+ }
+
+ /////////////////////////////////////
+ // Object "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public String toString() {
+ if (!sDebug) return super.toString();
+
+ return "ImageTransformation: [id=" + mId + ", options=" + mOptions + "]";
+ }
+
+ /////////////////////////////////////
+ // Parcelable "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeParcelable(mId, flags);
+ if (mOptions == null) {
+ parcel.writeStringArray(null);
+ return;
+ }
+ final int size = mOptions.size();
+ final String[] regexs = new String[size];
+ final int[] resIds = new int[size];
+ for (int i = 0; i < size; i++) {
+ regexs[i] = mOptions.keyAt(i);
+ resIds[i] = mOptions.valueAt(i);
+ }
+ parcel.writeStringArray(regexs);
+ parcel.writeIntArray(resIds);
+ }
+
+ public static final Parcelable.Creator<ImageTransformation> CREATOR =
+ new Parcelable.Creator<ImageTransformation>() {
+ @Override
+ public ImageTransformation createFromParcel(Parcel parcel) {
+ // Always go through the builder to ensure the data ingested by
+ // the system obeys the contract of the builder to avoid attacks
+ // using specially crafted parcels.
+ final ImageTransformation.Builder builder =
+ new ImageTransformation.Builder(parcel.readParcelable(null));
+ final String[] regexs = parcel.createStringArray();
+ if (regexs != null) {
+ final int[] resIds = parcel.createIntArray();
+ final int size = regexs.length;
+ for (int i = 0; i < size; i++) {
+ builder.addOption(regexs[i], resIds[i]);
+ }
+ }
+ return builder.build();
+ }
+
+ @Override
+ public ImageTransformation[] newArray(int size) {
+ return new ImageTransformation[size];
+ }
+ };
+}
diff --git a/core/java/android/service/autofill/InternalTransformation.java b/core/java/android/service/autofill/InternalTransformation.java
new file mode 100644
index 000000000000..3e51f87c7280
--- /dev/null
+++ b/core/java/android/service/autofill/InternalTransformation.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.service.autofill;
+
+import android.annotation.NonNull;
+import android.os.Parcelable;
+import android.widget.RemoteViews;
+
+/** @hide */
+abstract class InternalTransformation implements Transformation, Parcelable {
+
+ /**
+ * Applies this transformation to a child view of a {@link RemoteViews presentation template}.
+ *
+ * @param finder object used to find the value of a field in the screen.
+ * @param template the {@link RemoteViews presentation template}.
+ * @param childViewId resource id of the child view inside the template.
+ *
+ * @hide
+ */
+ abstract void apply(@NonNull ValueFinder finder, @NonNull RemoteViews template,
+ int childViewId);
+}
diff --git a/core/java/android/service/autofill/InternalValidator.java b/core/java/android/service/autofill/InternalValidator.java
new file mode 100644
index 000000000000..37ef96fd82ea
--- /dev/null
+++ b/core/java/android/service/autofill/InternalValidator.java
@@ -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.
+ */
+package android.service.autofill;
+
+import android.annotation.NonNull;
+import android.os.Parcelable;
+
+/** @hide */
+public abstract class InternalValidator implements Validator, Parcelable {
+
+ /**
+ * Decides whether the contents of the screen are valid.
+ *
+ * @param finder object used to find the value of a field in the screen.
+ * @return {@code true} if the contents are valid, {@code false} otherwise.
+ *
+ * @hide
+ */
+ public abstract boolean isValid(@NonNull ValueFinder finder);
+}
diff --git a/core/java/android/service/autofill/LuhnChecksumValidator.java b/core/java/android/service/autofill/LuhnChecksumValidator.java
new file mode 100644
index 000000000000..713f0f9a963e
--- /dev/null
+++ b/core/java/android/service/autofill/LuhnChecksumValidator.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import static android.view.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.autofill.AutofillId;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Validator that returns {@code true} if the number created by concatenating all given fields
+ * pass a Luhn algorithm checksum.
+ *
+ * <p>See {@link SaveInfo.Builder#setValidator(Validator)} for examples.
+ */
+public final class LuhnChecksumValidator extends InternalValidator implements Parcelable {
+ private static final String TAG = "LuhnChecksumValidator";
+
+ private final AutofillId[] mIds;
+
+ /**
+ * Default constructor.
+ *
+ * @param ids id of fields that comprises the number to be checked.
+ */
+ public LuhnChecksumValidator(@NonNull AutofillId... ids) {
+ mIds = Preconditions.checkArrayElementsNotNull(ids, "ids");
+ }
+
+ /** @hide */
+ @Override
+ public boolean isValid(@NonNull ValueFinder finder) {
+ if (mIds == null || mIds.length == 0) return false;
+
+ final StringBuilder number = new StringBuilder();
+ for (AutofillId id : mIds) {
+ final String partialNumber = finder.findByAutofillId(id);
+ if (partialNumber == null) {
+ if (sDebug) Log.d(TAG, "No partial number for id " + id);
+ return false;
+ }
+ number.append(partialNumber);
+ }
+ final boolean isValid = TextUtils.isDigitsOnly(number.toString());
+ if (sDebug) Log.d(TAG, "Is valid: " + isValid);
+ // TODO(b/62534917): proper implementation - copy & paste code from:
+ // PaymentUtils.java
+ // PaymentUtilsTest.java
+ return isValid;
+ }
+
+ /////////////////////////////////////
+ // Parcelable "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeParcelableArray(mIds, flags);
+ }
+
+ public static final Parcelable.Creator<LuhnChecksumValidator> CREATOR =
+ new Parcelable.Creator<LuhnChecksumValidator>() {
+ @Override
+ public LuhnChecksumValidator createFromParcel(Parcel parcel) {
+ return new LuhnChecksumValidator(parcel.readParcelableArray(null, AutofillId.class));
+ }
+
+ @Override
+ public LuhnChecksumValidator[] newArray(int size) {
+ return new LuhnChecksumValidator[size];
+ }
+ };
+}
diff --git a/core/java/android/service/autofill/OptionalValidators.java b/core/java/android/service/autofill/OptionalValidators.java
new file mode 100644
index 000000000000..c9dd1d40e0aa
--- /dev/null
+++ b/core/java/android/service/autofill/OptionalValidators.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import static android.view.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Compound validator that returns {@code true} on {@link #isValid(ValueFinder)} if any
+ * of its subvalidators returns {@code true} as well.
+ *
+ * <p>Used to implement an {@code OR} logical operation.
+ *
+ * @hide
+ */
+final class OptionalValidators extends InternalValidator {
+
+ private final InternalValidator[] mValidators;
+
+ OptionalValidators(@NonNull InternalValidator[] validators) {
+ mValidators = Preconditions.checkArrayElementsNotNull(validators, "validators");
+ }
+
+ @Override
+ public boolean isValid(@NonNull ValueFinder finder) {
+ if (mValidators == null) {
+ return true;
+ }
+ // TODO(b/62534917): handle errors, like not finding the ID
+
+ for (InternalValidator validator : mValidators) {
+ final boolean valid = validator.isValid(finder);
+ if (valid) return true;
+ }
+
+ return false;
+ }
+
+ /////////////////////////////////////
+ // Object "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public String toString() {
+ if (!sDebug) return super.toString();
+
+ return new StringBuilder("OptionalValidators: [validators=").append(mValidators)
+ .append("]")
+ .toString();
+ }
+
+ /////////////////////////////////////
+ // Parcelable "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelableArray(mValidators, flags);
+ }
+
+ public static final Parcelable.Creator<OptionalValidators> CREATOR =
+ new Parcelable.Creator<OptionalValidators>() {
+ @Override
+ public OptionalValidators createFromParcel(Parcel parcel) {
+ return new OptionalValidators(parcel
+ .readParcelableArray(null, InternalValidator.class));
+ }
+
+ @Override
+ public OptionalValidators[] newArray(int size) {
+ return new OptionalValidators[size];
+ }
+ };
+}
diff --git a/core/java/android/service/autofill/RequiredValidators.java b/core/java/android/service/autofill/RequiredValidators.java
new file mode 100644
index 000000000000..f2b7db8af7a8
--- /dev/null
+++ b/core/java/android/service/autofill/RequiredValidators.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import static android.view.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Compound validator that only returns {@code true} on {@link #isValid(ValueFinder)} if all
+ * of its subvalidators return {@code true} as well.
+ *
+ * <p>Used to implement an {@code AND} logical operation.
+ *
+ * @hide
+ */
+final class RequiredValidators extends InternalValidator {
+
+ private final InternalValidator[] mValidators;
+
+ RequiredValidators(@NonNull InternalValidator[] validators) {
+ mValidators = Preconditions.checkArrayElementsNotNull(validators, "validators");
+ }
+
+ @Override
+ public boolean isValid(@NonNull ValueFinder finder) {
+ if (mValidators == null) {
+ return true;
+ }
+ // TODO(b/62534917): handle errors, like not finding the ID
+ for (InternalValidator validator : mValidators) {
+ final boolean valid = validator.isValid(finder);
+ if (!valid) return false;
+ }
+ return true;
+ }
+
+ /////////////////////////////////////
+ // Object "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public String toString() {
+ if (!sDebug) return super.toString();
+
+ return new StringBuilder("RequiredValidators: [validators=").append(mValidators)
+ .append("]")
+ .toString();
+ }
+
+ /////////////////////////////////////
+ // Parcelable "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelableArray(mValidators, flags);
+ }
+
+ public static final Parcelable.Creator<RequiredValidators> CREATOR =
+ new Parcelable.Creator<RequiredValidators>() {
+ @Override
+ public RequiredValidators createFromParcel(Parcel parcel) {
+ return new RequiredValidators(parcel
+ .readParcelableArray(null, InternalValidator.class));
+ }
+
+ @Override
+ public RequiredValidators[] newArray(int size) {
+ return new RequiredValidators[size];
+ }
+ };
+}
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 95d393b0234c..41491735df66 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -122,9 +122,13 @@ import java.util.Arrays;
*
* <p>The service can also customize some aspects of the save UI affordance:
* <ul>
- * <li>Add a subtitle by calling {@link Builder#setDescription(CharSequence)}.
+ * <li>Add a simple subtitle by calling {@link Builder#setDescription(CharSequence)}.
+ * <li>Add a customized subtitle by calling
+ * {@link Builder#setCustomDescription(CustomDescription)}.
* <li>Customize the button used to reject the save request by calling
* {@link Builder#setNegativeAction(int, IntentSender)}.
+ * <li>Decide whether the UI should be shown based on the user input validation by calling
+ * {@link Builder#setValidator(Validator)}.
* </ul>
*/
public final class SaveInfo implements Parcelable {
@@ -222,6 +226,8 @@ public final class SaveInfo implements Parcelable {
private final AutofillId[] mOptionalIds;
private final CharSequence mDescription;
private final int mFlags;
+ private final CustomDescription mCustomDescription;
+ private final InternalValidator mValidator;
private SaveInfo(Builder builder) {
mType = builder.mType;
@@ -231,6 +237,8 @@ public final class SaveInfo implements Parcelable {
mOptionalIds = builder.mOptionalIds;
mDescription = builder.mDescription;
mFlags = builder.mFlags;
+ mCustomDescription = builder.mCustomDescription;
+ mValidator = builder.mValidator;
}
/** @hide */
@@ -268,6 +276,18 @@ public final class SaveInfo implements Parcelable {
return mDescription;
}
+ /** @hide */
+ @Nullable
+ public CustomDescription getCustomDescription() {
+ return mCustomDescription;
+ }
+
+ /** @hide */
+ @Nullable
+ public InternalValidator getValidator() {
+ return mValidator;
+ }
+
/**
* A builder for {@link SaveInfo} objects.
*/
@@ -281,12 +301,14 @@ public final class SaveInfo implements Parcelable {
private CharSequence mDescription;
private boolean mDestroyed;
private int mFlags;
+ private CustomDescription mCustomDescription;
+ private InternalValidator mValidator;
/**
* Creates a new builder.
*
- * @param type the type of information the associated {@link FillResponse} represents, can
- * be any combination of {@link SaveInfo#SAVE_DATA_TYPE_GENERIC},
+ * @param type the type of information the associated {@link FillResponse} represents. It
+ * can be any combination of {@link SaveInfo#SAVE_DATA_TYPE_GENERIC},
* {@link SaveInfo#SAVE_DATA_TYPE_PASSWORD},
* {@link SaveInfo#SAVE_DATA_TYPE_ADDRESS}, {@link SaveInfo#SAVE_DATA_TYPE_CREDIT_CARD},
* {@link SaveInfo#SAVE_DATA_TYPE_USERNAME}, or
@@ -354,21 +376,46 @@ public final class SaveInfo implements Parcelable {
*
* @param description a succint description.
* @return This Builder.
+ *
+ * @throws IllegalStateException if this call was made after calling
+ * {@link #setCustomDescription(CustomDescription)}.
*/
public @NonNull Builder setDescription(@Nullable CharSequence description) {
throwIfDestroyed();
+ Preconditions.checkState(mCustomDescription == null,
+ "Can call setDescription() or setCustomDescription(), but not both");
mDescription = description;
return this;
}
/**
+ * Sets a custom description to be shown in the UI when the user is asked to save.
+ *
+ * <p>Typically used when the service must show more info about the object being saved,
+ * like a credit card logo, masked number, and expiration date.
+ *
+ * @param customDescription the custom description.
+ * @return This Builder.
+ *
+ * @throws IllegalStateException if this call was made after calling
+ * {@link #setDescription(CharSequence)}.
+ */
+ public @NonNull Builder setCustomDescription(@NonNull CustomDescription customDescription) {
+ throwIfDestroyed();
+ Preconditions.checkState(mDescription == null,
+ "Can call setDescription() or setCustomDescription(), but not both");
+ mCustomDescription = customDescription;
+ return this;
+ }
+
+ /**
* Sets the style and listener for the negative save action.
*
- * <p>This allows a fill-provider to customize the style and be
+ * <p>This allows an autofill service to customize the style and be
* notified when the user selects the negative action in the save
* UI. Note that selecting the negative action regardless of its style
* and listener being customized would dismiss the save UI and if a
- * custom listener intent is provided then this intent will be
+ * custom listener intent is provided then this intent is
* started. The default style is {@link #NEGATIVE_BUTTON_STYLE_CANCEL}</p>
*
* @param style The action style.
@@ -393,6 +440,74 @@ public final class SaveInfo implements Parcelable {
}
/**
+ * Sets an object used to validate the user input - if the input is not valid, the Save UI
+ * affordance is not shown.
+ *
+ * <p>Typically used to validate credit card numbers. Examples:
+ *
+ * <p>Validator for a credit number that must have exactly 16 digits:
+ *
+ * <pre class="prettyprint">
+ * Validator validator = new SimpleRegexValidator(ccNumberId, "^\\d{16}$")
+ * </pre>
+ *
+ * <p>Validator for a credit number that must pass a Luhn checksum and either have
+ * 16 digits, or 15 digits starting with 108:
+ *
+ * <pre class="prettyprint">
+ * import android.service.autofill.Validators;
+ *
+ * Validator validator =
+ * and(
+ * new LuhnChecksumValidator(ccNumberId),
+ * or(
+ * new SimpleRegexValidator(ccNumberId, "^\\d{16}$"),
+ * new SimpleRegexValidator(ccNumberId, "^108\\d{12}$")
+ * )
+ * );
+ * </pre>
+ *
+ * <p><b>NOTE: </b>the example above is just for illustrative purposes; the same validator
+ * could be created using a single regex for the {@code OR} part:
+ *
+ * <pre class="prettyprint">
+ * Validator validator =
+ * and(
+ * new LuhnChecksumValidator(ccNumberId),
+ * new SimpleRegexValidator(ccNumberId, "^(\\d{16}|108\\d{12})$")
+ * );
+ * </pre>
+ *
+ * <p>Validator for a credit number contained in just 4 fields and that must have exactly
+ * 4 digits on each field:
+ *
+ * <pre class="prettyprint">
+ * import android.service.autofill.Validators;
+ *
+ * Validator validator =
+ * and(
+ * new SimpleRegexValidator.(ccNumberId1, "^\\d{4}$"),
+ * new SimpleRegexValidator.(ccNumberId2, "^\\d{4}$"),
+ * new SimpleRegexValidator.(ccNumberId3, "^\\d{4}$"),
+ * new SimpleRegexValidator.(ccNumberId4, "^\\d{4}$")
+ * );
+ * </pre>
+ *
+ * @param validator an implementation provided by the Android System.
+ * @return this builder.
+ *
+ * @throws IllegalArgumentException if {@code validator} is not a class provided
+ * by the Android System.
+ */
+ public @NonNull Builder setValidator(@NonNull Validator validator) {
+ throwIfDestroyed();
+ Preconditions.checkArgument((validator instanceof InternalValidator),
+ "not provided by Android System: " + validator);
+ mValidator = (InternalValidator) validator;
+ return this;
+ }
+
+ /**
* Builds a new {@link SaveInfo} instance.
*/
public SaveInfo build() {
@@ -406,7 +521,6 @@ public final class SaveInfo implements Parcelable {
throw new IllegalStateException("Already called #build()");
}
}
-
}
/////////////////////////////////////
@@ -424,6 +538,8 @@ public final class SaveInfo implements Parcelable {
.append(DebugUtils.flagsToString(SaveInfo.class, "NEGATIVE_BUTTON_STYLE_",
mNegativeButtonStyle))
.append(", mFlags=").append(mFlags)
+ .append(", mCustomDescription=").append(mCustomDescription)
+ .append(", validation=").append(mValidator)
.append("]").toString();
}
@@ -444,6 +560,8 @@ public final class SaveInfo implements Parcelable {
parcel.writeParcelable(mNegativeActionListener, flags);
parcel.writeParcelableArray(mOptionalIds, flags);
parcel.writeCharSequence(mDescription);
+ parcel.writeParcelable(mCustomDescription, flags);
+ parcel.writeParcelable(mValidator, flags);
parcel.writeInt(mFlags);
}
@@ -461,6 +579,14 @@ public final class SaveInfo implements Parcelable {
builder.setOptionalIds(optionalIds);
}
builder.setDescription(parcel.readCharSequence());
+ final CustomDescription customDescripton = parcel.readParcelable(null);
+ if (customDescripton != null) {
+ builder.setCustomDescription(customDescripton);
+ }
+ final InternalValidator validator = parcel.readParcelable(null);
+ if (validator != null) {
+ builder.setValidator(validator);
+ }
builder.setFlags(parcel.readInt());
return builder.build();
}
diff --git a/core/java/android/service/autofill/SimpleRegexValidator.java b/core/java/android/service/autofill/SimpleRegexValidator.java
new file mode 100644
index 000000000000..ffe0076dfb34
--- /dev/null
+++ b/core/java/android/service/autofill/SimpleRegexValidator.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.service.autofill;
+
+import static android.view.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import android.view.autofill.AutofillId;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Defines if a field is valid based on a regular expression (regex).
+ *
+ * <p>See {@link SaveInfo.Builder#setValidator(Validator)} for examples.
+ */
+public final class SimpleRegexValidator extends InternalValidator implements Parcelable {
+
+ private static final String TAG = "SimpleRegexValidator";
+
+ private final AutofillId mId;
+ private final String mRegex;
+
+ /**
+ * Default constructor.
+ *
+ * @param id id of the field whose regex is applied to.
+ * @param regex regular expression that defines the result
+ * of the validator: if the regex matches the contents of
+ * the field identified by {@code id}, it returns {@code true}; otherwise, it
+ * returns {@code false}.
+ */
+ public SimpleRegexValidator(@NonNull AutofillId id, @NonNull String regex) {
+ mId = Preconditions.checkNotNull(id);
+ //TODO(b/62534917): throw exception if regex is invalid
+ mRegex = Preconditions.checkNotNull(regex);
+ }
+
+ /** @hide */
+ @Override
+ public boolean isValid(@NonNull ValueFinder finder) {
+ final String value = finder.findByAutofillId(mId);
+ if (value == null) {
+ Log.w(TAG, "No view for id " + mId);
+ return false;
+ }
+ final boolean valid = value.matches(mRegex);
+ if (sDebug) Log.d(TAG, "isValid(): " + valid);
+ return valid;
+ }
+
+ /////////////////////////////////////
+ // Object "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public String toString() {
+ if (!sDebug) return super.toString();
+
+ return "SimpleRegexValidator: [id=" + mId + ", regex=" + mRegex + "]";
+ }
+
+ /////////////////////////////////////
+ // Parcelable "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeParcelable(mId, flags);
+ parcel.writeString(mRegex);
+ }
+
+ public static final Parcelable.Creator<SimpleRegexValidator> CREATOR =
+ new Parcelable.Creator<SimpleRegexValidator>() {
+ @Override
+ public SimpleRegexValidator createFromParcel(Parcel parcel) {
+ return new SimpleRegexValidator(parcel.readParcelable(null), parcel.readString());
+ }
+
+ @Override
+ public SimpleRegexValidator[] newArray(int size) {
+ return new SimpleRegexValidator[size];
+ }
+ };
+}
diff --git a/core/java/android/service/autofill/Transformation.java b/core/java/android/service/autofill/Transformation.java
new file mode 100644
index 000000000000..63b679d87259
--- /dev/null
+++ b/core/java/android/service/autofill/Transformation.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.service.autofill;
+
+/**
+ * Helper class used to change a child view of a {@link RemoteViews presentation template} at
+ * runtime, using the values of fields contained in the screen.
+ *
+ * <p>Typically used by {@link CustomDescription} to provide a customized Save UI affordance.
+ */
+public interface Transformation {
+}
diff --git a/core/java/android/service/autofill/Validator.java b/core/java/android/service/autofill/Validator.java
new file mode 100644
index 000000000000..854aa1e69db7
--- /dev/null
+++ b/core/java/android/service/autofill/Validator.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.service.autofill;
+
+/**
+ * Helper class used to define whether the contents of a screen are valid.
+ *
+ * <p>Typically used to avoid displaying the Save UI affordance when the user input is invalid.
+ */
+public interface Validator {
+}
diff --git a/core/java/android/service/autofill/Validators.java b/core/java/android/service/autofill/Validators.java
new file mode 100644
index 000000000000..51b503c21690
--- /dev/null
+++ b/core/java/android/service/autofill/Validators.java
@@ -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.
+ */
+package android.service.autofill;
+
+import android.annotation.NonNull;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Factory for {@link Validator} operations.
+ *
+ * <p>See {@link SaveInfo.Builder#setValidator(Validator)} for examples.
+ */
+public final class Validators {
+
+ private Validators() {
+ throw new UnsupportedOperationException("contains static methods only");
+ }
+
+ /**
+ * Creates a validator that is only valid if all {@code validators} are valid.
+ *
+ * @throws IllegalArgumentException if any element of {@code validators} is an instance of a
+ * class that is not provided by the Android System.
+ */
+ @NonNull
+ public static Validator and(@NonNull Validator...validators) {
+ return new RequiredValidators(getInternalValidators(validators));
+ }
+
+ /**
+ * Creates a validator that is valid if any of the {@code validators} is valid.
+ *
+ * @throws IllegalArgumentException if any element of {@code validators} is an instance of a
+ * class that is not provided by the Android System.
+ */
+ @NonNull
+ public static Validator or(@NonNull Validator...validators) {
+ return new OptionalValidators(getInternalValidators(validators));
+ }
+
+ private static InternalValidator[] getInternalValidators(Validator[] validators) {
+ Preconditions.checkArrayElementsNotNull(validators, "validators");
+
+ final InternalValidator[] internals = new InternalValidator[validators.length];
+
+ for (int i = 0; i < validators.length; i++) {
+ Preconditions.checkArgument((validators[i] instanceof InternalValidator),
+ "element " + i + " not provided by Android System: " + validators[i]);
+ internals[i] = (InternalValidator) validators[i];
+ }
+ return internals;
+ }
+}
diff --git a/core/java/android/service/autofill/ValueFinder.java b/core/java/android/service/autofill/ValueFinder.java
new file mode 100644
index 000000000000..d02a35890545
--- /dev/null
+++ b/core/java/android/service/autofill/ValueFinder.java
@@ -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.
+ */
+package android.service.autofill;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.view.autofill.AutofillId;
+
+/**
+ * Helper object used to obtain the value of a field in the screen being autofilled.
+ *
+ * @hide
+ */
+public interface ValueFinder {
+
+ /**
+ * Gets the value of a field, or {@code null} when not found.
+ */
+ @Nullable String findByAutofillId(@NonNull AutofillId id);
+}
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 951aa8df9ea3..8691136dfedc 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -30,8 +30,9 @@ import java.net.UnknownHostException;
/**
* API for sending log output.
*
- * <p>Generally, use the Log.v() Log.d() Log.i() Log.w() and Log.e()
- * methods.
+ * <p>Generally, you should use the {@link #v Log.v()}, {@link #d Log.d()},
+ * {@link #i Log.i()}, {@link #w Log.w()}, and {@link #e Log.e()} methods to write logs.
+ * You can then <a href="{@docRoot}studio/debug/am-logcat.html">view the logs in logcat</a>.
*
* <p>The order in terms of verbosity, from least to most is
* ERROR, WARN, INFO, DEBUG, VERBOSE. Verbose should never be compiled
diff --git a/core/java/android/util/MergedConfiguration.java b/core/java/android/util/MergedConfiguration.java
index 68d0309cfc9e..ae6605043b2e 100644
--- a/core/java/android/util/MergedConfiguration.java
+++ b/core/java/android/util/MergedConfiguration.java
@@ -161,6 +161,21 @@ public class MergedConfiguration implements Parcelable {
return "{mGlobalConfig=" + mGlobalConfig + " mOverrideConfig=" + mOverrideConfig + "}";
}
+ @Override
+ public int hashCode() {
+ return mMergedConfig.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object that) {
+ if (!(that instanceof MergedConfiguration)) {
+ return false;
+ }
+
+ if (that == this) return true;
+ return mMergedConfig.equals(((MergedConfiguration) that).mMergedConfig);
+ }
+
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "mGlobalConfig=" + mGlobalConfig);
pw.println(prefix + "mOverrideConfig=" + mOverrideConfig);
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index cdb9b8229314..7346a215ed8e 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -726,6 +726,17 @@ public final class Display {
}
/**
+ * Returns the rotation associated with this display as used during layout. This is currently
+ * derived from the {@link Configuration}.
+ *
+ * @hide
+ */
+ @Surface.Rotation
+ public int getLayoutRotation() {
+ return mResources.getConfiguration().getRotation();
+ }
+
+ /**
* @deprecated use {@link #getRotation}
* @return orientation of this display.
*/
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 4f9dbd5ad7a0..1b702326cc28 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -131,11 +131,17 @@ public class Surface implements Parcelable {
public static final int SCALING_MODE_NO_SCALE_CROP = 3;
/** @hide */
- @IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
+ @IntDef({ROTATION_UNDEFINED, ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
@Retention(RetentionPolicy.SOURCE)
public @interface Rotation {}
/**
+ * Rotation constant: undefined
+ * @hide
+ */
+ public static final int ROTATION_UNDEFINED = -1;
+
+ /**
* Rotation constant: 0 degree rotation (natural orientation)
*/
public static final int ROTATION_0 = 0;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 371277622740..63fe300a7927 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -724,6 +724,8 @@ import java.util.function.Predicate;
* @attr ref android.R.styleable#View_nextFocusUp
* @attr ref android.R.styleable#View_onClick
* @attr ref android.R.styleable#View_padding
+ * @attr ref android.R.styleable#View_paddingHorizontal
+ * @attr ref android.R.styleable#View_paddingVertical
* @attr ref android.R.styleable#View_paddingBottom
* @attr ref android.R.styleable#View_paddingLeft
* @attr ref android.R.styleable#View_paddingRight
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index cb92a4ca3ad4..ecdfa3fc3336 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -7609,6 +7609,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* See
* {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
* for a list of all child view attributes that this class supports.
+ *
+ * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_margin
+ * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginHorizontal
+ * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginVertical
+ * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
+ * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
+ * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
+ * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
+ * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
+ * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
*/
public static class MarginLayoutParams extends ViewGroup.LayoutParams {
/**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e27eab92319b..e38a55f76b7d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1904,14 +1904,16 @@ public final class ViewRootImpl implements ViewParent,
+ " outsets=" + mPendingOutsets.toShortString()
+ " surface=" + mSurface);
- final Configuration pendingMergedConfig =
- mPendingMergedConfiguration.getMergedConfiguration();
- if (pendingMergedConfig.seq != 0) {
+ // If the pending {@link MergedConfiguration} handed back from
+ // {@link #relayoutWindow} does not match the one last reported,
+ // WindowManagerService has reported back a frame from a configuration not yet
+ // handled by the client. In this case, we need to accept the configuration so we
+ // do not lay out and draw with the wrong configuration.
+ if (!mPendingMergedConfiguration.equals(mLastReportedMergedConfiguration)) {
if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
- + pendingMergedConfig);
+ + mPendingMergedConfiguration.getMergedConfiguration());
performConfigurationChange(mPendingMergedConfiguration, !mFirst,
INVALID_DISPLAY /* same display */);
- pendingMergedConfig.seq = 0;
updatedConfiguration = true;
}
@@ -3596,6 +3598,13 @@ public final class ViewRootImpl implements ViewParent,
mView.setLayoutDirection(currentLayoutDirection);
}
mView.dispatchConfigurationChanged(config);
+
+ // We could have gotten this {@link Configuration} update after we called
+ // {@link #performTraversals} with an older {@link Configuration}. As a result, our
+ // window frame may be stale. We must ensure the next pass of {@link #performTraversals}
+ // catches this.
+ mForceNextWindowRelayout = true;
+ requestLayout();
}
}
@@ -3757,10 +3766,10 @@ public final class ViewRootImpl implements ViewParent,
SomeArgs args = (SomeArgs) msg.obj;
final int displayId = args.argi3;
- final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg4;
+ MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg4;
final boolean displayChanged = mDisplay.getDisplayId() != displayId;
- if (mergedConfiguration != null) {
+ if (!mLastReportedMergedConfiguration.equals(mergedConfiguration)) {
// If configuration changed - notify about that and, maybe, about move to
// display.
performConfigurationChange(mergedConfiguration, false /* force */,
@@ -6094,7 +6103,7 @@ public final class ViewRootImpl implements ViewParent,
if (params != null) {
if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
}
- mPendingMergedConfiguration.getMergedConfiguration().seq = 0;
+
//Log.d(mTag, ">>>>>> CALLING relayout");
if (params != null && mOrigWindowType != params.type) {
// For compatibility with old apps, don't crash here.
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 4c0a1902d6a4..050aa4d66c14 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -18,6 +18,7 @@ package android.view;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
@@ -27,6 +28,7 @@ import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -169,6 +171,18 @@ public interface WindowManager extends ViewManager {
*/
public void requestAppKeyboardShortcuts(final KeyboardShortcutsReceiver receiver, int deviceId);
+ /**
+ * Return the touch region for the current IME window, or an empty region if there is none.
+ *
+ * @return The region of the IME that is accepting touch inputs, or null if there is no IME, no
+ * region or there was an error.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
+ public Region getCurrentImeTouchRegion();
+
public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
/**
* X position for this window. With the default gravity it is ignored.
@@ -941,7 +955,11 @@ public interface WindowManager extends ViewManager {
* {@link #FLAG_DISMISS_KEYGUARD} to automatically fully dismisss
* non-secure keyguards. This flag only applies to the top-most
* full-screen window.
+ * @deprecated Use {@link android.R.attr#showWhenLocked} or
+ * {@link android.app.Activity#setShowWhenLocked(boolean)} instead to prevent an
+ * unintentional double life-cycle event.
*/
+ @Deprecated
public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
/** Window flag: ask that the system wallpaper be shown behind
@@ -966,7 +984,12 @@ public interface WindowManager extends ViewManager {
/** Window flag: when set as a window is being added or made
* visible, once the window has been shown then the system will
* poke the power manager's user activity (as if the user had woken
- * up the device) to turn the screen on. */
+ * up the device) to turn the screen on.
+ * @deprecated Use {@link android.R.attr#turnScreenOn} or
+ * {@link android.app.Activity#setTurnScreenOn(boolean)} instead to prevent an
+ * unintentional double life-cycle event.
+ */
+ @Deprecated
public static final int FLAG_TURN_SCREEN_ON = 0x00200000;
/** Window flag: when set the window will cause the keyguard to
@@ -1380,15 +1403,14 @@ public interface WindowManager extends ViewManager {
public static final int PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE = 0x00040000;
/**
- * Flag to indicate that this window is used as a task snapshot window. A task snapshot
- * window is a starting window that gets shown with a screenshot from the previous state
- * that is active until the app has drawn its first frame.
- *
- * <p>If this flag is set, SystemUI flags are ignored such that the real window behind can
- * set the SystemUI flags.
+ * Flag to indicate that any window added by an application process that is of type
+ * {@link #TYPE_TOAST} or that requires
+ * {@link android.app.AppOpsManager#OP_SYSTEM_ALERT_WINDOW} permission should be hidden when
+ * this window is visible.
* @hide
*/
- public static final int PRIVATE_FLAG_TASK_SNAPSHOT = 0x00080000;
+ @RequiresPermission(android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS)
+ public static final int PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 0x00080000;
/**
* Flag to indicate that this window should be ignored when determining what parts of the
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index c1b8f04a6865..a8722f101ef4 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -18,6 +18,7 @@ package android.view;
import android.annotation.NonNull;
import android.content.Context;
+import android.graphics.Region;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -145,4 +146,13 @@ public final class WindowManagerImpl implements WindowManager {
public Display getDefaultDisplay() {
return mContext.getDisplay();
}
+
+ @Override
+ public Region getCurrentImeTouchRegion() {
+ try {
+ return WindowManagerGlobal.getWindowManagerService().getCurrentImeTouchRegion();
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 5b04f41c7ee2..e1e8317d8ccb 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -741,7 +741,8 @@ public final class AutofillManager {
}
/**
- * Returns {@code true} if Autofill is supported for this user.
+ * Returns {@code true} if autofill is supported by the current device and
+ * is supported for this user.
*
* <p>Autofill is typically supported, but it could be unsupported in cases like:
* <ol>
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index d9bfade33539..f368c74a17b5 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -213,20 +213,6 @@ public final class TextServicesManager {
/**
* @hide
*/
- public void setCurrentSpellChecker(SpellCheckerInfo sci) {
- try {
- if (sci == null) {
- throw new NullPointerException("SpellCheckerInfo is null.");
- }
- mService.setCurrentSpellChecker(null, sci.getId());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * @hide
- */
public SpellCheckerSubtype getCurrentSpellCheckerSubtype(
boolean allowImplicitlySelectedSubtype) {
try {
@@ -240,34 +226,6 @@ public final class TextServicesManager {
/**
* @hide
*/
- public void setSpellCheckerSubtype(SpellCheckerSubtype subtype) {
- try {
- final int hashCode;
- if (subtype == null) {
- hashCode = 0;
- } else {
- hashCode = subtype.hashCode();
- }
- mService.setCurrentSpellCheckerSubtype(null, hashCode);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * @hide
- */
- public void setSpellCheckerEnabled(boolean enabled) {
- try {
- mService.setSpellCheckerEnabled(enabled);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * @hide
- */
public boolean isSpellCheckerEnabled() {
try {
return mService.isSpellCheckerEnabled();
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index ec2b302d35ca..5fed925dd956 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1638,6 +1638,17 @@ public class WebView extends AbsoluteLayout
}
/**
+ * Sets the list of domains that are exempt from SafeBrowsing checks. The list is
+ * global for all the WebViews.
+ * TODO: Add documentation for the format of the urls.
+ *
+ * @param urls the list of URLs
+ */
+ public static void setSafeBrowsingWhiteList(@Nullable String[] urls) {
+ getFactory().getStatics().setSafeBrowsingWhiteList(urls);
+ }
+
+ /**
* Gets the WebBackForwardList for this WebView. This contains the
* back/forward list for use in querying each item in the history stack.
* This is a copy of the private WebBackForwardList so it contains only a
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index 5cf48b585b16..7c938ae5bb70 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -86,6 +86,12 @@ public interface WebViewFactoryProvider {
* {@link android.webkit.WebView#shutdownSafeBrowsing()}
*/
void shutdownSafeBrowsing();
+
+ /**
+ * Implement the API method
+ * {@link android.webkit.WebView#setSafeBrowsingWhiteList(String[])}
+ */
+ void setSafeBrowsingWhiteList(String[] urls);
}
Statics getStatics();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 1f2e3d02144a..f21545fe8636 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3914,25 +3914,30 @@ public class Editor {
menu.removeItem(TextView.ID_ASSIST);
final TextClassification textClassification =
getSelectionActionModeHelper().getTextClassification();
- if (textClassification != null) {
- final Drawable icon = textClassification.getIcon();
- final CharSequence label = textClassification.getLabel();
- final OnClickListener onClickListener =
- textClassification.getOnClickListener();
- final Intent intent = textClassification.getIntent();
- if ((icon != null || !TextUtils.isEmpty(label))
- && (onClickListener != null || intent != null)) {
- menu.add(TextView.ID_ASSIST, TextView.ID_ASSIST, MENU_ITEM_ORDER_ASSIST, label)
- .setIcon(icon)
- .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
- mMetricsLogger.write(
- new LogMaker(MetricsEvent.TEXT_SELECTION_MENU_ITEM_ASSIST)
- .setType(MetricsEvent.TYPE_OPEN)
- .setSubtype(textClassification.getLogType()));
- }
+ if (canAssist()) {
+ menu.add(TextView.ID_ASSIST, TextView.ID_ASSIST, MENU_ITEM_ORDER_ASSIST,
+ textClassification.getLabel())
+ .setIcon(textClassification.getIcon())
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ mMetricsLogger.write(
+ new LogMaker(MetricsEvent.TEXT_SELECTION_MENU_ITEM_ASSIST)
+ .setType(MetricsEvent.TYPE_OPEN)
+ .setSubtype(textClassification.getLogType()));
}
}
+ private boolean canAssist() {
+ final TextClassification textClassification =
+ getSelectionActionModeHelper().getTextClassification();
+ return mTextView.isDeviceProvisioned()
+ && textClassification != null
+ && (textClassification.getIcon() != null
+ || !TextUtils.isEmpty(textClassification.getLabel()))
+ && (textClassification.getOnClickListener() != null
+ || (textClassification.getIntent() != null
+ && mTextView.getContext().canStartActivityForResult()));
+ }
+
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
getSelectionActionModeHelper().onSelectionAction();
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 9c6f1d0536e1..5c1bafdbca3f 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1681,7 +1681,14 @@ public class ResolverActivity extends Activity {
// We assume that at this point we've already filtered out the only intent for a different
// targetUserId which we're going to use.
private void addResolveInfo(DisplayResolveInfo dri) {
- if (dri.mResolveInfo.targetUserId == UserHandle.USER_CURRENT) {
+ if (dri != null && dri.mResolveInfo != null
+ && dri.mResolveInfo.targetUserId == UserHandle.USER_CURRENT) {
+ // Checks if this info is already listed in display.
+ for (DisplayResolveInfo existingInfo : mDisplayList) {
+ if (resolveInfoMatch(dri.mResolveInfo, existingInfo.mResolveInfo)) {
+ return;
+ }
+ }
mDisplayList.add(dri);
}
}
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
index 54b9cd869f2d..a0f58a99f625 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -553,7 +553,9 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> {
Log.e(TAG, "Error in Predict: " + e);
}
}
- mAfterCompute.afterCompute();
+ if (mAfterCompute != null) {
+ mAfterCompute.afterCompute();
+ }
}
// adds select prob as the default values, according to a pre-trained Logistic Regression model.
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 5ab17e449ba6..2ab2d20ed20d 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -30,6 +30,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.lang.InterruptedException;
@@ -55,7 +56,11 @@ public class ResolverListController {
private static final String TAG = "ResolverListController";
private static final boolean DEBUG = false;
+ Object mLock = new Object();
+
+ @GuardedBy("mLock")
private ResolverComparator mResolverComparator;
+ private boolean isComputed = false;
public ResolverListController(
Context context,
@@ -68,6 +73,10 @@ public class ResolverListController {
mLaunchedFromUid = launchedFromUid;
mTargetIntent = targetIntent;
mReferrerPackage = referrerPackage;
+ synchronized (mLock) {
+ mResolverComparator =
+ new ResolverComparator(mContext, mTargetIntent, mReferrerPackage, null);
+ }
}
@VisibleForTesting
@@ -232,25 +241,29 @@ public class ResolverListController {
@VisibleForTesting
@WorkerThread
public void sort(List<ResolverActivity.ResolvedComponentInfo> inputList) {
- final CountDownLatch finishComputeSignal = new CountDownLatch(1);
- ComputeCallback callback = new ComputeCallback(finishComputeSignal);
- if (mResolverComparator == null) {
- mResolverComparator =
- new ResolverComparator(mContext, mTargetIntent, mReferrerPackage, callback);
- } else {
+ synchronized (mLock) {
+ if (mResolverComparator == null) {
+ Log.d(TAG, "Comparator has already been destroyed; skipped.");
+ return;
+ }
+ final CountDownLatch finishComputeSignal = new CountDownLatch(1);
+ ComputeCallback callback = new ComputeCallback(finishComputeSignal);
mResolverComparator.setCallBack(callback);
- }
- try {
- long beforeRank = System.currentTimeMillis();
- mResolverComparator.compute(inputList);
- finishComputeSignal.await();
- Collections.sort(inputList, mResolverComparator);
- long afterRank = System.currentTimeMillis();
- if (DEBUG) {
- Log.d(TAG, "Time Cost: " + Long.toString(afterRank - beforeRank));
+ try {
+ long beforeRank = System.currentTimeMillis();
+ if (!isComputed) {
+ mResolverComparator.compute(inputList);
+ finishComputeSignal.await();
+ isComputed = true;
+ }
+ Collections.sort(inputList, mResolverComparator);
+ long afterRank = System.currentTimeMillis();
+ if (DEBUG) {
+ Log.d(TAG, "Time Cost: " + Long.toString(afterRank - beforeRank));
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Compute & Sort was interrupted: " + e);
}
- } catch (InterruptedException e) {
- Log.e(TAG, "Compute & Sort was interrupted: " + e);
}
}
@@ -271,27 +284,36 @@ public class ResolverListController {
@VisibleForTesting
public float getScore(ResolverActivity.DisplayResolveInfo target) {
- if (mResolverComparator == null) {
- return 0.0f;
+ synchronized (mLock) {
+ if (mResolverComparator == null) {
+ return 0.0f;
+ }
+ return mResolverComparator.getScore(target.getResolvedComponentName());
}
- return mResolverComparator.getScore(target.getResolvedComponentName());
}
public void updateModel(ComponentName componentName) {
- if (mResolverComparator != null) {
- mResolverComparator.updateModel(componentName);
+ synchronized (mLock) {
+ if (mResolverComparator != null) {
+ mResolverComparator.updateModel(componentName);
+ }
}
}
public void updateChooserCounts(String packageName, int userId, String action) {
- if (mResolverComparator != null) {
- mResolverComparator.updateChooserCounts(packageName, userId, action);
+ synchronized (mLock) {
+ if (mResolverComparator != null) {
+ mResolverComparator.updateChooserCounts(packageName, userId, action);
+ }
}
}
public void destroy() {
- if (mResolverComparator != null) {
- mResolverComparator.destroy();
+ synchronized (mLock) {
+ if (mResolverComparator != null) {
+ mResolverComparator.destroy();
+ }
+ mResolverComparator = null;
}
}
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 8fe9100d2011..544afd993b37 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -3103,12 +3103,29 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
/**
+ * Check if Setup or Post-Setup update is completed on TV
+ * @return true if completed
+ */
+ private boolean isTvUserSetupComplete() {
+ boolean isTvSetupComplete = Settings.Secure.getInt(getContext().getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0) != 0;
+ isTvSetupComplete &= Settings.Secure.getInt(getContext().getContentResolver(),
+ Settings.Secure.TV_USER_SETUP_COMPLETE, 0) != 0;
+ return isTvSetupComplete;
+ }
+
+ /**
* Helper method for adding launch-search to most applications. Opens the
* search window using default settings.
*
* @return true if search window opened
*/
private boolean launchDefaultSearch(KeyEvent event) {
+ if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)
+ && !isTvUserSetupComplete()) {
+ // If we are in Setup or Post-Setup update mode on TV, consume the search key
+ return false;
+ }
boolean result;
final Callback cb = getCallback();
if (cb == null || isDestroyed()) {
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
index 95d714f1c3c7..749d00c136ec 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
@@ -49,9 +49,6 @@ public class PipSnapAlgorithm {
// Allows snapping on the long edge in each orientation and magnets towards corners
private static final int SNAP_MODE_LONG_EDGE_MAGNET_CORNERS = 4;
- // The friction multiplier to control how slippery the PIP is when flung
- private static final float SCROLL_FRICTION_MULTIPLIER = 8f;
-
// Threshold to magnet to a corner
private static final float CORNER_MAGNET_THRESHOLD = 0.3f;
@@ -64,8 +61,8 @@ public class PipSnapAlgorithm {
private final float mDefaultSizePercent;
private final float mMinAspectRatioForMinSize;
private final float mMaxAspectRatioForMinSize;
+ private final int mFlingDeceleration;
- private Scroller mScroller;
private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
private final int mMinimizedVisibleSize;
@@ -81,6 +78,8 @@ public class PipSnapAlgorithm {
mMaxAspectRatioForMinSize = res.getFloat(
com.android.internal.R.dimen.config_pictureInPictureAspectRatioLimitForMinSize);
mMinAspectRatioForMinSize = 1f / mMaxAspectRatioForMinSize;
+ mFlingDeceleration = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.pip_fling_deceleration);
onConfigurationChanged();
}
@@ -107,20 +106,97 @@ public class PipSnapAlgorithm {
* those for the given {@param stackBounds}.
*/
public Rect findClosestSnapBounds(Rect movementBounds, Rect stackBounds, float velocityX,
- float velocityY) {
- final Rect finalStackBounds = new Rect(stackBounds);
- if (mScroller == null) {
- final ViewConfiguration viewConfig = ViewConfiguration.get(mContext);
- mScroller = new Scroller(mContext);
- mScroller.setFriction(viewConfig.getScrollFriction() * SCROLL_FRICTION_MULTIPLIER);
+ float velocityY, Point dragStartPosition) {
+ final Rect intersectStackBounds = new Rect(stackBounds);
+ final Point intersect = getEdgeIntersect(stackBounds, movementBounds, velocityX, velocityY,
+ dragStartPosition);
+ intersectStackBounds.offsetTo(intersect.x, intersect.y);
+ return findClosestSnapBounds(movementBounds, intersectStackBounds);
+ }
+
+ /**
+ * @return The point along the {@param movementBounds} that the PIP would intersect with based
+ * on the provided {@param velX}, {@param velY} along with the position of the PIP when
+ * the gesture started, {@param dragStartPosition}.
+ */
+ public Point getEdgeIntersect(Rect stackBounds, Rect movementBounds, float velX, float velY,
+ Point dragStartPosition) {
+ final boolean isLandscape = mOrientation == Configuration.ORIENTATION_LANDSCAPE;
+ final int x = stackBounds.left;
+ final int y = stackBounds.top;
+
+ // Find the line of movement the PIP is on. Line defined by: y = slope * x + yIntercept
+ final float slope = velY / velX; // slope = rise / run
+ final float yIntercept = y - slope * x; // rearrange line equation for yIntercept
+ // The PIP can have two intercept points:
+ // 1) Where the line intersects with one of the edges of the screen (vertical line)
+ Point vertPoint = new Point();
+ // 2) Where the line intersects with the top or bottom of the screen (horizontal line)
+ Point horizPoint = new Point();
+
+ // Find the vertical line intersection, x will be one of the edges
+ vertPoint.x = velX > 0 ? movementBounds.right : movementBounds.left;
+ // Sub in x in our line equation to determine y position
+ vertPoint.y = findY(slope, yIntercept, vertPoint.x);
+
+ // Find the horizontal line intersection, y will be the top or bottom of the screen
+ horizPoint.y = velY > 0 ? movementBounds.bottom : movementBounds.top;
+ // Sub in y in our line equation to determine x position
+ horizPoint.x = findX(slope, yIntercept, horizPoint.y);
+
+ // Now pick one of these points -- first determine if we're flinging along the current edge.
+ // Only fling along current edge if it's a direction with space for the PIP to move to
+ int maxDistance;
+ if (isLandscape) {
+ maxDistance = velX > 0
+ ? movementBounds.right - stackBounds.left
+ : stackBounds.left - movementBounds.left;
+ } else {
+ maxDistance = velY > 0
+ ? movementBounds.bottom - stackBounds.top
+ : stackBounds.top - movementBounds.top;
}
- mScroller.fling(stackBounds.left, stackBounds.top,
- (int) velocityX, (int) velocityY,
- movementBounds.left, movementBounds.right,
- movementBounds.top, movementBounds.bottom);
- finalStackBounds.offsetTo(mScroller.getFinalX(), mScroller.getFinalY());
- mScroller.abortAnimation();
- return findClosestSnapBounds(movementBounds, finalStackBounds);
+ if (maxDistance > 0) {
+ // Only fling along the current edge if the start and end point are on the same side
+ final int startPoint = isLandscape ? dragStartPosition.y : dragStartPosition.x;
+ final int endPoint = isLandscape ? horizPoint.y : horizPoint.x;
+ final int center = movementBounds.centerX();
+ if ((startPoint < center && endPoint < center)
+ || (startPoint > center && endPoint > center)) {
+ // We are flinging along the current edge, figure out how far it should travel
+ // based on velocity and assumed deceleration.
+ int distance = (int) (0 - Math.pow(isLandscape ? velX : velY, 2))
+ / (2 * mFlingDeceleration);
+ distance = Math.min(distance, maxDistance);
+ // Adjust the point for the distance
+ if (isLandscape) {
+ horizPoint.x = stackBounds.left + (velX > 0 ? distance : -distance);
+ } else {
+ horizPoint.y = stackBounds.top + (velY > 0 ? distance : -distance);
+ }
+ return horizPoint;
+ }
+ }
+ // If we're not flinging along the current edge, find the closest point instead.
+ final double distanceVert = Math.hypot(vertPoint.x - x, vertPoint.y - y);
+ final double distanceHoriz = Math.hypot(horizPoint.x - x, horizPoint.y - y);
+ // Ensure that we're actually going somewhere
+ if (distanceVert == 0) {
+ return horizPoint;
+ }
+ if (distanceHoriz == 0) {
+ return vertPoint;
+ }
+ // Otherwise use the closest point
+ return Math.abs(distanceVert) > Math.abs(distanceHoriz) ? horizPoint : vertPoint;
+ }
+
+ private int findY(float slope, float yIntercept, float x) {
+ return (int) ((slope * x) + yIntercept);
+ }
+
+ private int findX(float slope, float yIntercept, float y) {
+ return (int) ((y - yIntercept) / slope);
}
/**
diff --git a/core/java/com/android/internal/textservice/ITextServicesManager.aidl b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
index 4882a127f24b..c5940ba4dde2 100644
--- a/core/java/com/android/internal/textservice/ITextServicesManager.aidl
+++ b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
@@ -36,9 +36,6 @@ interface ITextServicesManager {
in ITextServicesSessionListener tsListener,
in ISpellCheckerSessionListener scListener, in Bundle bundle);
oneway void finishSpellCheckerService(in ISpellCheckerSessionListener listener);
- oneway void setCurrentSpellChecker(String locale, String sciId);
- oneway void setCurrentSpellCheckerSubtype(String locale, int hashCode);
- oneway void setSpellCheckerEnabled(boolean enabled);
boolean isSpellCheckerEnabled();
SpellCheckerInfo[] getEnabledSpellCheckers();
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 51851690c08d..c4533c36d0f2 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -90,6 +90,7 @@ cc_library_shared {
"android_os_Parcel.cpp",
"android_os_SELinux.cpp",
"android_os_seccomp.cpp",
+ "android_os_SharedMemory.cpp",
"android_os_SystemClock.cpp",
"android_os_SystemProperties.cpp",
"android_os_Trace.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 92bc16055931..89e137b7c399 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -167,6 +167,7 @@ extern int register_android_os_Trace(JNIEnv* env);
extern int register_android_os_FileObserver(JNIEnv *env);
extern int register_android_os_UEventObserver(JNIEnv* env);
extern int register_android_os_MemoryFile(JNIEnv* env);
+extern int register_android_os_SharedMemory(JNIEnv* env);
extern int register_android_net_LocalSocketImpl(JNIEnv* env);
extern int register_android_net_NetworkUtils(JNIEnv* env);
extern int register_android_net_TrafficStats(JNIEnv* env);
@@ -791,19 +792,27 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
"--compiler-filter=", "-Ximage-compiler-option");
}
- // Make sure there is a preloaded-classes file.
- if (!hasFile("/system/etc/preloaded-classes")) {
- ALOGE("Missing preloaded-classes file, /system/etc/preloaded-classes not found: %s\n",
- strerror(errno));
- return -1;
- }
- addOption("-Ximage-compiler-option");
- addOption("--image-classes=/system/etc/preloaded-classes");
-
- // If there is a compiled-classes file, push it.
- if (hasFile("/system/etc/compiled-classes")) {
+ // If there is a boot profile, it takes precedence over the image and preloaded classes.
+ if (hasFile("/system/etc/boot-image.prof")) {
+ addOption("-Ximage-compiler-option");
+ addOption("--profile-file=/system/etc/boot-image.prof");
+ addOption("-Ximage-compiler-option");
+ addOption("--compiler-filter=speed-profile");
+ } else {
+ // Make sure there is a preloaded-classes file.
+ if (!hasFile("/system/etc/preloaded-classes")) {
+ ALOGE("Missing preloaded-classes file, /system/etc/preloaded-classes not found: %s\n",
+ strerror(errno));
+ return -1;
+ }
addOption("-Ximage-compiler-option");
- addOption("--compiled-classes=/system/etc/compiled-classes");
+ addOption("--image-classes=/system/etc/preloaded-classes");
+
+ // If there is a compiled-classes file, push it.
+ if (hasFile("/system/etc/compiled-classes")) {
+ addOption("-Ximage-compiler-option");
+ addOption("--compiled-classes=/system/etc/compiled-classes");
+ }
}
property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
@@ -1392,6 +1401,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_net_NetworkUtils),
REG_JNI(register_android_net_TrafficStats),
REG_JNI(register_android_os_MemoryFile),
+ REG_JNI(register_android_os_SharedMemory),
REG_JNI(register_com_android_internal_os_PathClassLoaderFactory),
REG_JNI(register_com_android_internal_os_Zygote),
REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp
index bcc3bb09b69d..62240ea87807 100644
--- a/core/jni/android_database_SQLiteConnection.cpp
+++ b/core/jni/android_database_SQLiteConnection.cpp
@@ -112,7 +112,8 @@ static int sqliteProgressHandlerCallback(void* data) {
static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFlags,
- jstring labelStr, jboolean enableTrace, jboolean enableProfile) {
+ jstring labelStr, jboolean enableTrace, jboolean enableProfile, jint lookasideSz,
+ jint lookasideCnt) {
int sqliteFlags;
if (openFlags & SQLiteConnection::CREATE_IF_NECESSARY) {
sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
@@ -137,6 +138,16 @@ static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFla
return 0;
}
+ if (lookasideSz >= 0 && lookasideCnt >= 0) {
+ int err = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, NULL, lookasideSz, lookasideCnt);
+ if (err != SQLITE_OK) {
+ ALOGE("sqlite3_db_config(..., %d, %d) failed: %d", lookasideSz, lookasideCnt, err);
+ throw_sqlite3_exception(env, db, "Cannot set lookaside");
+ sqlite3_close(db);
+ return 0;
+ }
+ }
+
// Check that the database is really read/write when that is what we asked for.
if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(db, NULL)) {
throw_sqlite3_exception(env, db, "Could not open the database in read/write mode.");
@@ -789,7 +800,7 @@ static void nativeResetCancel(JNIEnv* env, jobject clazz, jlong connectionPtr,
static const JNINativeMethod sMethods[] =
{
/* name, signature, funcPtr */
- { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZ)J",
+ { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZII)J",
(void*)nativeOpen },
{ "nativeClose", "(J)V",
(void*)nativeClose },
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index cdd3c094e009..6c6fa66c422e 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -370,7 +370,7 @@ static jobject JHwBinder_native_getService(
if (transport != IServiceManager::Transport::HWBINDER && !vintfLegacy) {
LOG(ERROR) << "service " << ifaceName << " declares transport method "
<< toString(transport) << " but framework expects hwbinder.";
- signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
+ signalExceptionForError(env, NAME_NOT_FOUND, true /* canThrowRemoteException */);
return NULL;
}
diff --git a/core/jni/android_os_MemoryFile.cpp b/core/jni/android_os_MemoryFile.cpp
index c198a733103d..fdc9f9dc7464 100644
--- a/core/jni/android_os_MemoryFile.cpp
+++ b/core/jni/android_os_MemoryFile.cpp
@@ -26,95 +26,14 @@
namespace android {
-static jobject android_os_MemoryFile_open(JNIEnv* env, jobject clazz, jstring name, jint length)
-{
- const char* namestr = (name ? env->GetStringUTFChars(name, NULL) : NULL);
-
- int result = ashmem_create_region(namestr, length);
-
- if (name)
- env->ReleaseStringUTFChars(name, namestr);
-
- if (result < 0) {
- jniThrowException(env, "java/io/IOException", "ashmem_create_region failed");
- return NULL;
- }
-
- return jniCreateFileDescriptor(env, result);
-}
-
-static jlong android_os_MemoryFile_mmap(JNIEnv* env, jobject clazz, jobject fileDescriptor,
- jint length, jint prot)
-{
- int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- void* result = mmap(NULL, length, prot, MAP_SHARED, fd, 0);
- if (result == MAP_FAILED) {
- jniThrowException(env, "java/io/IOException", "mmap failed");
- }
- return reinterpret_cast<jlong>(result);
-}
-
-static void android_os_MemoryFile_munmap(JNIEnv* env, jobject clazz, jlong addr, jint length)
-{
- int result = munmap(reinterpret_cast<void *>(addr), length);
- if (result < 0)
- jniThrowException(env, "java/io/IOException", "munmap failed");
-}
-
-static void android_os_MemoryFile_close(JNIEnv* env, jobject clazz, jobject fileDescriptor)
-{
- int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (fd >= 0) {
- jniSetFileDescriptorOfFD(env, fileDescriptor, -1);
- close(fd);
- }
-}
-
-static jint android_os_MemoryFile_read(JNIEnv* env, jobject clazz,
- jobject fileDescriptor, jlong address, jbyteArray buffer, jint srcOffset, jint destOffset,
- jint count, jboolean unpinned)
-{
- int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (unpinned && ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) {
- ashmem_unpin_region(fd, 0, 0);
- jniThrowException(env, "java/io/IOException", "ashmem region was purged");
- return -1;
- }
-
- env->SetByteArrayRegion(buffer, destOffset, count, (const jbyte *)address + srcOffset);
-
- if (unpinned) {
- ashmem_unpin_region(fd, 0, 0);
- }
- return count;
-}
-
-static jint android_os_MemoryFile_write(JNIEnv* env, jobject clazz,
- jobject fileDescriptor, jlong address, jbyteArray buffer, jint srcOffset, jint destOffset,
- jint count, jboolean unpinned)
-{
- int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (unpinned && ashmem_pin_region(fd, 0, 0) == ASHMEM_WAS_PURGED) {
- ashmem_unpin_region(fd, 0, 0);
- jniThrowException(env, "java/io/IOException", "ashmem region was purged");
- return -1;
- }
-
- env->GetByteArrayRegion(buffer, srcOffset, count, (jbyte *)address + destOffset);
-
- if (unpinned) {
- ashmem_unpin_region(fd, 0, 0);
- }
- return count;
-}
-
-static void android_os_MemoryFile_pin(JNIEnv* env, jobject clazz, jobject fileDescriptor, jboolean pin)
-{
+static jboolean android_os_MemoryFile_pin(JNIEnv* env, jobject clazz, jobject fileDescriptor,
+ jboolean pin) {
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
int result = (pin ? ashmem_pin_region(fd, 0, 0) : ashmem_unpin_region(fd, 0, 0));
if (result < 0) {
jniThrowException(env, "java/io/IOException", NULL);
}
+ return result == ASHMEM_WAS_PURGED;
}
static jint android_os_MemoryFile_get_size(JNIEnv* env, jobject clazz,
@@ -138,19 +57,12 @@ static jint android_os_MemoryFile_get_size(JNIEnv* env, jobject clazz,
}
static const JNINativeMethod methods[] = {
- {"native_open", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_MemoryFile_open},
- {"native_mmap", "(Ljava/io/FileDescriptor;II)J", (void*)android_os_MemoryFile_mmap},
- {"native_munmap", "(JI)V", (void*)android_os_MemoryFile_munmap},
- {"native_close", "(Ljava/io/FileDescriptor;)V", (void*)android_os_MemoryFile_close},
- {"native_read", "(Ljava/io/FileDescriptor;J[BIIIZ)I", (void*)android_os_MemoryFile_read},
- {"native_write", "(Ljava/io/FileDescriptor;J[BIIIZ)V", (void*)android_os_MemoryFile_write},
- {"native_pin", "(Ljava/io/FileDescriptor;Z)V", (void*)android_os_MemoryFile_pin},
+ {"native_pin", "(Ljava/io/FileDescriptor;Z)Z", (void*)android_os_MemoryFile_pin},
{"native_get_size", "(Ljava/io/FileDescriptor;)I",
(void*)android_os_MemoryFile_get_size}
};
-int register_android_os_MemoryFile(JNIEnv* env)
-{
+int register_android_os_MemoryFile(JNIEnv* env) {
return RegisterMethodsOrDie(env, "android/os/MemoryFile", methods, NELEM(methods));
}
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index cd7aae7d29dd..d35ddd0a87a8 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -90,25 +90,25 @@ void recycleJavaParcelObject(JNIEnv* env, jobject parcelObj)
env->CallVoidMethod(parcelObj, gParcelOffsets.recycle);
}
-static jint android_os_Parcel_dataSize(JNIEnv* env, jclass clazz, jlong nativePtr)
+static jint android_os_Parcel_dataSize(jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
return parcel ? parcel->dataSize() : 0;
}
-static jint android_os_Parcel_dataAvail(JNIEnv* env, jclass clazz, jlong nativePtr)
+static jint android_os_Parcel_dataAvail(jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
return parcel ? parcel->dataAvail() : 0;
}
-static jint android_os_Parcel_dataPosition(JNIEnv* env, jclass clazz, jlong nativePtr)
+static jint android_os_Parcel_dataPosition(jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
return parcel ? parcel->dataPosition() : 0;
}
-static jint android_os_Parcel_dataCapacity(JNIEnv* env, jclass clazz, jlong nativePtr)
+static jint android_os_Parcel_dataCapacity(jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
return parcel ? parcel->dataCapacity() : 0;
@@ -127,7 +127,7 @@ static jlong android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jlong nati
return 0;
}
-static void android_os_Parcel_setDataPosition(JNIEnv* env, jclass clazz, jlong nativePtr, jint pos)
+static void android_os_Parcel_setDataPosition(jlong nativePtr, jint pos)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
@@ -146,7 +146,7 @@ static void android_os_Parcel_setDataCapacity(JNIEnv* env, jclass clazz, jlong n
}
}
-static jboolean android_os_Parcel_pushAllowFds(JNIEnv* env, jclass clazz, jlong nativePtr, jboolean allowFds)
+static jboolean android_os_Parcel_pushAllowFds(jlong nativePtr, jboolean allowFds)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
jboolean ret = JNI_TRUE;
@@ -156,7 +156,7 @@ static jboolean android_os_Parcel_pushAllowFds(JNIEnv* env, jclass clazz, jlong
return ret;
}
-static void android_os_Parcel_restoreAllowFds(JNIEnv* env, jclass clazz, jlong nativePtr, jboolean lastValue)
+static void android_os_Parcel_restoreAllowFds(jlong nativePtr, jboolean lastValue)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
@@ -398,7 +398,7 @@ static jbyteArray android_os_Parcel_readBlob(JNIEnv* env, jclass clazz, jlong na
return ret;
}
-static jint android_os_Parcel_readInt(JNIEnv* env, jclass clazz, jlong nativePtr)
+static jint android_os_Parcel_readInt(jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
@@ -407,7 +407,7 @@ static jint android_os_Parcel_readInt(JNIEnv* env, jclass clazz, jlong nativePtr
return 0;
}
-static jlong android_os_Parcel_readLong(JNIEnv* env, jclass clazz, jlong nativePtr)
+static jlong android_os_Parcel_readLong(jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
@@ -416,7 +416,7 @@ static jlong android_os_Parcel_readLong(JNIEnv* env, jclass clazz, jlong nativeP
return 0;
}
-static jfloat android_os_Parcel_readFloat(JNIEnv* env, jclass clazz, jlong nativePtr)
+static jfloat android_os_Parcel_readFloat(jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
@@ -425,7 +425,7 @@ static jfloat android_os_Parcel_readFloat(JNIEnv* env, jclass clazz, jlong nativ
return 0;
}
-static jdouble android_os_Parcel_readDouble(JNIEnv* env, jclass clazz, jlong nativePtr)
+static jdouble android_os_Parcel_readDouble(jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
@@ -673,7 +673,7 @@ static jlong android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisN
return thisParcel->getOpenAshmemSize();
}
-static jboolean android_os_Parcel_hasFileDescriptors(JNIEnv* env, jclass clazz, jlong nativePtr)
+static jboolean android_os_Parcel_hasFileDescriptors(jlong nativePtr)
{
jboolean ret = JNI_FALSE;
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
@@ -747,7 +747,7 @@ static jlong android_os_Parcel_getGlobalAllocCount(JNIEnv* env, jclass clazz)
return Parcel::getGlobalAllocCount();
}
-static jlong android_os_Parcel_getBlobAshmemSize(JNIEnv* env, jclass clazz, jlong nativePtr)
+static jlong android_os_Parcel_getBlobAshmemSize(jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
@@ -759,24 +759,24 @@ static jlong android_os_Parcel_getBlobAshmemSize(JNIEnv* env, jclass clazz, jlon
// ----------------------------------------------------------------------------
static const JNINativeMethod gParcelMethods[] = {
- // @FastNative
+ // @CriticalNative
{"nativeDataSize", "(J)I", (void*)android_os_Parcel_dataSize},
- // @FastNative
+ // @CriticalNative
{"nativeDataAvail", "(J)I", (void*)android_os_Parcel_dataAvail},
- // @FastNative
+ // @CriticalNative
{"nativeDataPosition", "(J)I", (void*)android_os_Parcel_dataPosition},
- // @FastNative
+ // @CriticalNative
{"nativeDataCapacity", "(J)I", (void*)android_os_Parcel_dataCapacity},
// @FastNative
{"nativeSetDataSize", "(JI)J", (void*)android_os_Parcel_setDataSize},
- // @FastNative
+ // @CriticalNative
{"nativeSetDataPosition", "(JI)V", (void*)android_os_Parcel_setDataPosition},
// @FastNative
{"nativeSetDataCapacity", "(JI)V", (void*)android_os_Parcel_setDataCapacity},
- // @FastNative
+ // @CriticalNative
{"nativePushAllowFds", "(JZ)Z", (void*)android_os_Parcel_pushAllowFds},
- // @FastNative
+ // @CriticalNative
{"nativeRestoreAllowFds", "(JZ)V", (void*)android_os_Parcel_restoreAllowFds},
{"nativeWriteByteArray", "(J[BII)V", (void*)android_os_Parcel_writeByteArray},
@@ -796,13 +796,13 @@ static const JNINativeMethod gParcelMethods[] = {
{"nativeCreateByteArray", "(J)[B", (void*)android_os_Parcel_createByteArray},
{"nativeReadByteArray", "(J[BI)Z", (void*)android_os_Parcel_readByteArray},
{"nativeReadBlob", "(J)[B", (void*)android_os_Parcel_readBlob},
- // @FastNative
+ // @CriticalNative
{"nativeReadInt", "(J)I", (void*)android_os_Parcel_readInt},
- // @FastNative
+ // @CriticalNative
{"nativeReadLong", "(J)J", (void*)android_os_Parcel_readLong},
- // @FastNative
+ // @CriticalNative
{"nativeReadFloat", "(J)F", (void*)android_os_Parcel_readFloat},
- // @FastNative
+ // @CriticalNative
{"nativeReadDouble", "(J)D", (void*)android_os_Parcel_readDouble},
{"nativeReadString", "(J)Ljava/lang/String;", (void*)android_os_Parcel_readString},
{"nativeReadStrongBinder", "(J)Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},
@@ -821,7 +821,7 @@ static const JNINativeMethod gParcelMethods[] = {
{"nativeUnmarshall", "(J[BII)J", (void*)android_os_Parcel_unmarshall},
{"nativeCompareData", "(JJ)I", (void*)android_os_Parcel_compareData},
{"nativeAppendFrom", "(JJII)J", (void*)android_os_Parcel_appendFrom},
- // @FastNative
+ // @CriticalNative
{"nativeHasFileDescriptors", "(J)Z", (void*)android_os_Parcel_hasFileDescriptors},
{"nativeWriteInterfaceToken", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
{"nativeEnforceInterface", "(JLjava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},
@@ -829,6 +829,7 @@ static const JNINativeMethod gParcelMethods[] = {
{"getGlobalAllocSize", "()J", (void*)android_os_Parcel_getGlobalAllocSize},
{"getGlobalAllocCount", "()J", (void*)android_os_Parcel_getGlobalAllocCount},
+ // @CriticalNative
{"nativeGetBlobAshmemSize", "(J)J", (void*)android_os_Parcel_getBlobAshmemSize},
};
diff --git a/core/jni/android_os_SharedMemory.cpp b/core/jni/android_os_SharedMemory.cpp
new file mode 100644
index 000000000000..24d08112275e
--- /dev/null
+++ b/core/jni/android_os_SharedMemory.cpp
@@ -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.
+ */
+
+#define LOG_TAG "SharedMemory"
+
+#include "core_jni_helpers.h"
+
+#include <cutils/ashmem.h>
+#include <utils/Log.h>
+#include "JNIHelp.h"
+#include "JniConstants.h"
+#include "ScopedLocalRef.h"
+
+#include <algorithm>
+#include <errno.h>
+#include <limits>
+#include <unistd.h>
+
+namespace {
+
+static void throwErrnoException(JNIEnv* env, const char* functionName, int error) {
+ static jmethodID ctor = env->GetMethodID(JniConstants::errnoExceptionClass,
+ "<init>", "(Ljava/lang/String;I)V");
+
+ ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
+ if (detailMessage.get() == NULL) {
+ // Not really much we can do here. We're probably dead in the water,
+ // but let's try to stumble on...
+ env->ExceptionClear();
+ }
+
+ jobject exception = env->NewObject(JniConstants::errnoExceptionClass, ctor,
+ detailMessage.get(), error);
+ env->Throw(reinterpret_cast<jthrowable>(exception));
+}
+
+static jobject SharedMemory_create(JNIEnv* env, jobject, jstring jname, jint size) {
+
+ // Name is optional so we can't use ScopedUtfChars for this as it throws NPE on null
+ const char* name = jname ? env->GetStringUTFChars(jname, nullptr) : nullptr;
+
+ int fd = ashmem_create_region(name, size);
+
+ // Capture the error, if there is one, before calling ReleaseStringUTFChars
+ int err = fd < 0 ? errno : 0;
+
+ if (name) {
+ env->ReleaseStringUTFChars(jname, name);
+ }
+
+ if (fd < 0) {
+ throwErrnoException(env, "SharedMemory_create", err);
+ return nullptr;
+ }
+
+ return jniCreateFileDescriptor(env, fd);
+}
+
+static jint SharedMemory_getSize(JNIEnv* env, jobject, jobject fileDescriptor) {
+ int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (!ashmem_valid(fd)) {
+ return -1;
+ }
+ size_t size = ashmem_get_size_region(fd);
+ return static_cast<jint>(std::min(size, static_cast<size_t>(std::numeric_limits<jint>::max())));
+}
+
+static jint SharedMemory_setProt(JNIEnv* env, jobject, jobject fileDescriptor, jint prot) {
+ int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ int err = 0;
+ if (ashmem_set_prot_region(fd, prot)) {
+ err = errno;
+ }
+ return err;
+}
+
+static const JNINativeMethod methods[] = {
+ {"nCreate", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)SharedMemory_create},
+ {"nGetSize", "(Ljava/io/FileDescriptor;)I", (void*)SharedMemory_getSize},
+ {"nSetProt", "(Ljava/io/FileDescriptor;I)I", (void*)SharedMemory_setProt},
+};
+
+} // anonymous namespace
+
+namespace android {
+
+int register_android_os_SharedMemory(JNIEnv* env)
+{
+ return RegisterMethodsOrDie(env, "android/os/SharedMemory", methods, NELEM(methods));
+}
+
+} // namespace android
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a3ee66f4e317..7555cabb9ae9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2394,6 +2394,15 @@
<permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"
android:protectionLevel="signature" />
+ <!-- @SystemApi Allows an application to use
+ {@link android.view.WindowManager.LayoutsParams#PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS}
+ to hide non-system-overlay windows.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"
+ android:protectionLevel="signature|installer" />
+
<!-- @SystemApi Allows an application to manage (create, destroy,
Z-order) application tokens in the window manager.
<p>Not for use by third-party applications.
diff --git a/core/res/res/anim/task_close_enter.xml b/core/res/res/anim/task_close_enter.xml
index b07f470dd5f5..bea0ee51d593 100644
--- a/core/res/res/anim/task_close_enter.xml
+++ b/core/res/res/anim/task_close_enter.xml
@@ -18,7 +18,7 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+ android:shareInterpolator="false" android:zAdjustment="normal">
<alpha android:fromAlpha="0.6" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml
index d23c74ffc160..b6a08070c3ce 100644
--- a/core/res/res/anim/task_close_exit.xml
+++ b/core/res/res/anim/task_close_exit.xml
@@ -18,7 +18,7 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
+ android:shareInterpolator="false" android:zAdjustment="top">
<alpha android:fromAlpha="1.0" android:toAlpha="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml
index 90b74acf9459..7b8d92285c5a 100644
--- a/core/res/res/layout/autofill_save.xml
+++ b/core/res/res/layout/autofill_save.xml
@@ -65,6 +65,15 @@
</LinearLayout>
+ <!-- TODO(b/62534917) wrap content to fit exactly what was provided in the remote views ?-->
+ <LinearLayout
+ android:id="@+id/autofill_save_custom_subtitle"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginTop="4dp"
+ android:visibility="gone"/>
+
<TextView
android:id="@+id/autofill_save_subtitle"
android:layout_width="fill_parent"
diff --git a/core/res/res/layout/shutdown_dialog.xml b/core/res/res/layout/shutdown_dialog.xml
new file mode 100644
index 000000000000..398bfb1824c7
--- /dev/null
+++ b/core/res/res/layout/shutdown_dialog.xml
@@ -0,0 +1,52 @@
+<?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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="center_horizontal" >
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="6" />
+
+ <TextView
+ android:id="@id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="32dp"
+ android:text="@string/shutdown_progress"
+ android:textDirection="locale"
+ android:textSize="24sp"
+ android:textAppearance="?attr/textAppearanceLarge"
+ android:gravity="center"
+ android:layout_marginBottom="24dp"
+ android:fontFamily="@string/config_headlineFontFamily"/>
+
+ <ProgressBar
+ android:id="@id/progress"
+ android:layout_width="30dp"
+ android:layout_height="30dp"
+ style="?attr/progressBarStyleLarge" />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="10" />
+
+</LinearLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 907f895cbaf7..0e7b5c03226d 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Ontruim kusgebiede en riviergebiede dadelik en gaan na \'n veiliger plek, soos \'n hoogliggende omgewing."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Bly kalm en soek skuiling naby."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Noodboodskappetoets"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM word nie toegelaat nie"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM is nie opgestel nie"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 27ce84d16515..8356efa748b2 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"ወዲያውኑ ከባህር ዳርቻ አካባቢዎች እና የወንዝ ዳርቻ አካባቢዎች ይውጡና እንደ ከፍ ያለ መሬት ያሉ ከአደጋ የተሻለ ደህንነት ወዳቸው ቦታዎች ይሂዱ።"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"ረጋ ይበሉና በአቅራቢያ ያለ መጠለያ ይፈልጉ።"</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"የአስቸኳይ አደጋ መልእክቶች ሙከራ"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"ሲም አይፈቀድም"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"ሲም አልቀረበም"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index d038a42ad2b9..26e43ca1cf41 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -248,7 +248,7 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"المحتويات مخفية"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"تم إخفاء المحتويات بواسطة السياسة"</string>
- <string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"لوحة المفاتيح الظاهرية"</string>
+ <string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"لوحة المفاتيح الافتراضية"</string>
<string name="notification_channel_physical_keyboard" msgid="7297661826966861459">"لوحة المفاتيح الفعلية"</string>
<string name="notification_channel_security" msgid="7345516133431326347">"الأمان"</string>
<string name="notification_channel_car_mode" msgid="3553380307619874564">"وضع السيارة"</string>
@@ -258,7 +258,7 @@
<string name="notification_channel_network_status" msgid="5025648583129035447">"حالة الشبكة"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"تنبيهات الشبكة"</string>
<string name="notification_channel_network_available" msgid="4531717914138179517">"الشبكة متوفرة"</string>
- <string name="notification_channel_vpn" msgid="8330103431055860618">"حالة الشبكة الظاهرية الخاصة"</string>
+ <string name="notification_channel_vpn" msgid="8330103431055860618">"حالة الشبكة الافتراضية الخاصة"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"إدارة الجهاز"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"التنبيهات"</string>
<string name="notification_channel_retail_mode" msgid="6088920674914038779">"عرض توضيحي لبائع التجزئة"</string>
@@ -1203,7 +1203,7 @@
<item msgid="75483255295529161">"Wi-Fi"</item>
<item msgid="6862614801537202646">"بلوتوث"</item>
<item msgid="5447331121797802871">"إيثرنت"</item>
- <item msgid="8257233890381651999">"‏شبكة ظاهرية خاصة (VPN)"</item>
+ <item msgid="8257233890381651999">"‏شبكة افتراضية خاصة (VPN)"</item>
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"نوع شبكة غير معروف"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏تعذر الاتصال بـ Wi-Fi"</string>
@@ -1281,7 +1281,7 @@
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"رفض"</string>
<string name="select_input_method" msgid="8547250819326693584">"تغيير لوحة المفاتيح"</string>
<string name="show_ime" msgid="2506087537466597099">"استمرار عرضها على الشاشة أثناء نشاط لوحة المفاتيح الفعلية"</string>
- <string name="hardware" msgid="194658061510127999">"إظهار لوحة المفاتيح الظاهرية"</string>
+ <string name="hardware" msgid="194658061510127999">"إظهار لوحة المفاتيح الافتراضية"</string>
<string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"تهيئة لوحة المفاتيح الفعلية"</string>
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"انقر لاختيار لغة وتنسيق"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
@@ -1369,14 +1369,14 @@
<string name="vr_listener_binding_label" msgid="4316591939343607306">"مستمع واقع افتراضي"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"موفر الحالة"</string>
<string name="notification_ranker_binding_label" msgid="774540592299064747">"خدمة ترتيب أهمية الإشعارات"</string>
- <string name="vpn_title" msgid="19615213552042827">"‏تم تنشيط الشبكة الظاهرية الخاصة (VPN)"</string>
+ <string name="vpn_title" msgid="19615213552042827">"‏تم تنشيط الشبكة الافتراضية الخاصة (VPN)"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"‏تم تنشيط VPN بواسطة <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"انقر لإدارة الشبكة."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"تم الاتصال بـ <xliff:g id="SESSION">%s</xliff:g>. انقر لإدارة الشبكة."</string>
- <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"‏جارٍ الاتصال بشبكة ظاهرية خاصة (VPN) دائمة التشغيل..."</string>
- <string name="vpn_lockdown_connected" msgid="8202679674819213931">"‏تم الاتصال بشبكة ظاهرية خاصة (VPN) دائمة التشغيل"</string>
- <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"‏تم فصل الشبكة الظاهرية الخاصة (VPN) دائمة التشغيل"</string>
- <string name="vpn_lockdown_error" msgid="6009249814034708175">"‏خطأ بشبكة ظاهرية خاصة (VPN) دائمة التشغيل"</string>
+ <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"‏جارٍ الاتصال بشبكة افتراضية خاصة (VPN) دائمة التشغيل..."</string>
+ <string name="vpn_lockdown_connected" msgid="8202679674819213931">"‏تم الاتصال بشبكة افتراضية خاصة (VPN) دائمة التشغيل"</string>
+ <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"‏تم فصل الشبكة الافتراضية الخاصة (VPN) دائمة التشغيل"</string>
+ <string name="vpn_lockdown_error" msgid="6009249814034708175">"‏خطأ بشبكة افتراضية خاصة (VPN) دائمة التشغيل"</string>
<string name="vpn_lockdown_config" msgid="5099330695245008680">"انقر للإعداد."</string>
<string name="upload_file" msgid="2897957172366730416">"اختيار ملف"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"لم يتم اختيار أي ملف"</string>
@@ -1905,6 +1905,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"يُرجى النزوح في الحال من المناطق الساحلية وضفاف النهر إلى مكان أكثر أمانًا مثل الأراضي المرتفعة."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"يُرجى الثبات والبحث عن ملاذ بالجوار."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"اختبار رسائل الطوارئ"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"‏غير مسموح باستخدام SIM"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"‏لم يتم تقديم SIM"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 76f7e2c61de6..10198de5daec 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Dərhal sahil bölgələrindən və çay kənarı ərazilərdən daha təhlükəsiz yüksək yerlərə evakuasiya edin."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Sakit qalın və yaxınlıqda sığınacaq axtarın."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Təcili mesaj testi"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-ə icazə verilmir"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM təmin edilməyib"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 1b67cf796f03..58495367d5f3 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1204,7 +1204,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Dodirnite za još opcija."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Dodatna oprema za audio sadržaj nije podržana"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Dodirnite za više informacija"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"Otklanjanje grešaka sa USB-a je uspostavljeno"</string>
+ <string name="adb_active_notification_title" msgid="6729044778949189918">"Otklanjanje grešaka sa USB-a je omogućeno"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Dodirnite da biste onemogućili otklanjanje grešaka sa USB-a."</string>
<string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Izaberite da biste onemogućili otklanjanja grešaka sa USB-a."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Izveštaj o grešci se generiše…"</string>
@@ -1803,6 +1803,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Odmah se sklonite iz priobalnih regiona i oblasti pored reka na neko bezbednije mesto, na primer, na neko uzvišenje."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Ostanite mirni i potražite sklonište u okolini."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Testiranje poruka u hitnim slučajevima"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM kartica nije dozvoljena"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM kartica nije podešena"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 6ad22f629fe4..316ee495f91c 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1837,6 +1837,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Неадкладна эвакуіруйцеся з прыбярэжных раёнаў у больш бяспечнае месца, напрыклад на ўзвышша."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Заставайцеся спакойнымі і пашукайце прытулак паблізу."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Праверка экстранных паведамленняў"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-карта не дапускаецца"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-карты няма"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index c9ed0cad7be5..83ae33899b00 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -268,7 +268,7 @@
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"има достъп до календара ви"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
<string name="permgroupdesc_sms" msgid="4656988620100940350">"да изпраща и преглежда SMS съобщения"</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Съхранение"</string>
+ <string name="permgrouplab_storage" msgid="1971118770546336966">"Хранилище"</string>
<string name="permgroupdesc_storage" msgid="637758554581589203">"да има достъп до снимките, мултимедията и файловете на устройството ви"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Микрофон"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"записва звук"</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Евакуирайте се незабавно от крайбрежните и крайречните региони на по-безопасно място – например такова с по-високо надморско равнище."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Запазете спокойствие и потърсете убежище в района."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Тест за спешни съобщения"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM картата не е разрешена"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM картата не е обезпечена"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 86ff9972c7d5..3e487b94ade1 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -118,7 +118,9 @@
<string name="roamingText12" msgid="1189071119992726320">"রোমিং ব্যানার বন্ধ আছে"</string>
<string name="roamingTextSearching" msgid="8360141885972279963">"পরিষেবা অনুসন্ধান করা হচ্ছে"</string>
<string name="wfcRegErrorTitle" msgid="2301376280632110664">"ওয়াই-ফাই কলিং"</string>
- <!-- no translation found for wfcOperatorErrorAlertMessages:0 (3910386316304772394) -->
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item msgid="3910386316304772394">"ওয়াই-ফাই এর মাধ্যমে কল করতে ও মেসেজ পাঠাতে, প্রথমে আপনার পরিষেবা প্রদানকারীকে এই পরিষেবার সেট-আপ করতে বলুন। তারপর আবার সেটিংস থেকে ওয়াই-ফাই কলিং চালু করুন। (ত্রুটি কোড: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ </string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="6177300162212449033">"আপনার পরিষেবা প্রদানকারীকে নথিভুক্ত করুন"</item>
</string-array>
@@ -1768,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"উপকূলবর্তী এবং নদীর পাশের অঞ্চল থেকে অবিলম্বে উঁচু কোনো জায়গার দিকে যান।"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"শান্ত থাকুন, আশেপাশে আশ্রয় খুঁজুন।"</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"বিপদকালীন বার্তাগুলির পরীক্ষা"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"সিম অনুমোদিত নয়"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"সিম প্রস্তুত নয়"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index f1ec56f4473a..4539121ed267 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1809,6 +1809,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Odmah se evakuirajte iz priobalnih područja i područja oko rijeka na sigurnije mjesto kao što su viši predjeli."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Ostanite smireni i potražite sklonište u blizini."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test poruka za hitne slučajeve"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM kartica nije dozvoljena"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM kartica nije dodijeljena"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index dc769e680d9b..7036603881b7 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -81,9 +81,9 @@
<string name="RestrictedOnEmergencyTitle" msgid="3646729271176394091">"No es poden fer trucades d\'emergència"</string>
<string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Sense servei de veu"</string>
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Sense servei de veu/emergència"</string>
- <string name="RestrictedStateContent" msgid="4278821484643362350">"La xarxa de telefonia mòbil de la teva ubicació temporalment no ofereix aquest servei"</string>
+ <string name="RestrictedStateContent" msgid="4278821484643362350">"La xarxa mòbil de la teva ubicació temporalment no ofereix aquest servei"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"No es pot accedir a la xarxa"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Per millorar la recepció, prova de canviar el tipus de xarxa a Configuració &gt; Xarxa i Internet &gt; Xarxes de telefonia mòbil &gt; Tipus de xarxa preferit."</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"Per millorar la recepció, prova de canviar el tipus de xarxa a Configuració &gt; Xarxa i Internet &gt; Xarxes mòbils &gt; Tipus de xarxa preferit."</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"Alertes"</string>
<string name="notification_channel_call_forward" msgid="2419697808481833249">"Desviació de trucades"</string>
<string name="notification_channel_emergency_callback" msgid="6686166232265733921">"Mode de devolució de trucada d\'emergència"</string>
@@ -1154,10 +1154,10 @@
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Permet sempre"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"No permetis mai"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Extracció de la targeta SIM"</string>
- <string name="sim_removed_message" msgid="2333164559970958645">"La xarxa de telefonia mòbil no estarà disponible fins que no reiniciïs amb una targeta SIM vàlida inserida."</string>
+ <string name="sim_removed_message" msgid="2333164559970958645">"La xarxa mòbil no estarà disponible fins que no reiniciïs amb una targeta SIM vàlida inserida."</string>
<string name="sim_done_button" msgid="827949989369963775">"Fet"</string>
<string name="sim_added_title" msgid="3719670512889674693">"Addició de la targeta SIM"</string>
- <string name="sim_added_message" msgid="6599945301141050216">"Reinicia el dispositiu per accedir a la xarxa de telefonia mòbil."</string>
+ <string name="sim_added_message" msgid="6599945301141050216">"Reinicia el dispositiu per accedir a la xarxa mòbil."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Reinicia"</string>
<string name="carrier_app_dialog_message" msgid="7066156088266319533">"Perquè la nova SIM funcioni, has d\'instal·lar i obrir una aplicació del teu operador de telefonia mòbil."</string>
<string name="carrier_app_dialog_button" msgid="7900235513678617329">"BAIXA L\'APLICACIÓ"</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Abandona immediatament les regions costaneres i riberenques, i cerca un lloc més segur, com ara un terreny elevat."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Mantén la calma i busca refugi a prop."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Prova de missatges d\'emergència"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM no compatible"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM no proporcionada"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index f11798254fb8..04190d598ed2 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1837,6 +1837,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Z pobřežních oblastí a okolí řek se co nejrychleji přesuňte do většího bezpečí (například na výše položené místo)."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Zachovejte klid a přesuňte se na bezpečné místo v okolí."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test nouzových zpráv"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM karta není povolena"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM karta není poskytována"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index e7db8d5615cd..3834d7cc5437 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Forlad omgående kyst- og flodområder, og søg mod et mere sikkert sted, f.eks. et højere terræn."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Bevar roen, og søg ly i nærheden."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test af nødbeskeder"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-kortet har ikke adgangstilladelse"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-kortet er ikke aktiveret"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 7ff623b4907e..27bd4a91ec03 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -437,7 +437,7 @@
<string name="permlab_accessWifiState" msgid="5202012949247040011">"WLAN-Verbindungen abrufen"</string>
<string name="permdesc_accessWifiState" msgid="5002798077387803726">"Ermöglicht der App, Informationen zu WLAN-Netzwerken abzurufen, etwa ob ein WLAN aktiviert ist, und den Namen verbundener WLAN-Geräte."</string>
<string name="permlab_changeWifiState" msgid="6550641188749128035">"WLAN-Verbindungen herstellen und trennen"</string>
- <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Ermöglicht der App, eine Verbindung zu WLAN-Zugangspunkten herzustellen und solche zu trennen und Änderungen an der Gerätekonfiguration für WLAN-Netzwerke vorzunehmen."</string>
+ <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Ermöglicht der App, eine Verbindung zu WLAN-Zugangspunkten herzustellen und solche zu trennen und Änderungen an der Gerätekonfiguration für WLANs vorzunehmen."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"WLAN-Multicast-Empfang zulassen"</string>
<string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Ermöglicht der App, Pakete zu empfangen, die mithilfe von Multicast-Adressen an sämtliche Geräte in einem WLAN versendet wurden, nicht nur an dein Tablet. Dies nicht mehr Leistung in Anspruch als der Nicht-Multicast-Modus."</string>
<string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Ermöglicht der App, Pakete zu empfangen, die mithilfe von Multicast-Adressen an sämtliche Geräte in einem WLAN gesendet wurden, nicht nur an deinen Fernseher. Dies nimmt mehr Leistung in Anspruch als der Nicht-Multicast-Modus."</string>
@@ -1087,12 +1087,12 @@
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Benachrichtigungstöne"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Unbekannt"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
- <item quantity="other">WLAN-Netzwerke verfügbar</item>
- <item quantity="one">WLAN-Netzwerk verfügbar</item>
+ <item quantity="other">WLANe verfügbar</item>
+ <item quantity="one">WLAN verfügbar</item>
</plurals>
<plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
- <item quantity="other">Verfügbare WLAN-Netzwerke öffnen</item>
- <item quantity="one">Verfügbares WLAN-Netzwerk öffnen</item>
+ <item quantity="other">Verfügbare WLANe öffnen</item>
+ <item quantity="one">Verfügbares WLAN öffnen</item>
</plurals>
<string name="wifi_available_title" msgid="3817100557900599505">"Mit offenem WLAN verbinden"</string>
<string name="wifi_available_title_connecting" msgid="1557292688310330032">"Verbindung mit offenem WLAN wird hergestellt"</string>
@@ -1101,7 +1101,7 @@
<string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Tippen, um alle Netzwerke zu sehen"</string>
<string name="wifi_available_action_connect" msgid="2635699628459488788">"Verbinden"</string>
<string name="wifi_available_action_all_networks" msgid="1100098935861622985">"Alle Netzwerke"</string>
- <string name="wifi_available_sign_in" msgid="9157196203958866662">"In WLAN-Netzwerk anmelden"</string>
+ <string name="wifi_available_sign_in" msgid="9157196203958866662">"In WLAN anmelden"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Im Netzwerk anmelden"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
@@ -1121,7 +1121,7 @@
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Es konnte keine WLAN-Verbindung hergestellt werden."</string>
<string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" hat eine schlechte Internetverbindung."</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"Verbindung zulassen?"</string>
- <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Die App \"%1$s\" möchte eine Verbindung zum WLAN-Netzwerk %2$s herstellen."</string>
+ <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Die App \"%1$s\" möchte eine Verbindung zum WLAN %2$s herstellen."</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"Eine App"</string>
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct-Betrieb starten. Hierdurch wird der WLAN-Client-/-Hotspot-Betrieb deaktiviert."</string>
@@ -1183,7 +1183,7 @@
<string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Audiozubehör wird nicht unterstützt"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Tippen, um weitere Informationen zu erhalten"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-Debugging aktiviert"</string>
- <string name="adb_active_notification_message" msgid="4948470599328424059">"Zum Deaktivieren von USB-Debugging tippen."</string>
+ <string name="adb_active_notification_message" msgid="4948470599328424059">"Zum Deaktivieren von USB-Debugging tippen"</string>
<string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB-Debugging deaktivieren: auswählen"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Fehlerbericht wird abgerufen…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Fehlerbericht teilen?"</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Verlasse so schnell wie möglich Flussufer und Küstengebiete und suche in einer höher gelegenen Umgebung Schutz."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Bleibe ruhig und suche in der Nähe Schutz."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test der Notfallwarnungen"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-Karte nicht zulässig"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM nicht eingerichtet"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index def96a88286a..24217973956a 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1364,7 +1364,7 @@
<string name="action_menu_overflow_description" msgid="2295659037509008453">"Περισσότερες επιλογές"</string>
<string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
- <string name="storage_internal" msgid="3570990907910199483">"Εσωτερικός κοινόχρηστος αποθηκευτικός χώρος"</string>
+ <string name="storage_internal" msgid="3570990907910199483">"Εσωτ. κοινόχρ. αποθ. χώρος"</string>
<string name="storage_sd_card" msgid="3282948861378286745">"Κάρτα SD"</string>
<string name="storage_sd_card_label" msgid="6347111320774379257">"Κάρτα SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb_drive" msgid="6261899683292244209">"Μονάδα USB"</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Εκκενώστε αμέσως τις παράκτιες περιοχές και τις περιοχές δίπλα σε ποτάμια και μετακινηθείτε σε ένα ασφαλέστερο μέρος, όπως περιοχές με υψόμετρο."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Μείνετε ψύχραιμοι και αναζητήστε κάποιο κοντινό καταφύγιο."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Δοκιμαστικό μήνυμα έκτακτης ανάγκης"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Η κάρτα SIM δεν επιτρέπεται"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Δεν παρέχεται κάρτα SIM"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 5db79b869c6d..f54625648c61 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Evacuate immediately from coastal regions and riverside areas to a safer place such as high ground."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Stay calm and seek shelter nearby."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Emergency messages test"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<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>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 5db79b869c6d..f54625648c61 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Evacuate immediately from coastal regions and riverside areas to a safer place such as high ground."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Stay calm and seek shelter nearby."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Emergency messages test"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<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>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 5db79b869c6d..f54625648c61 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Evacuate immediately from coastal regions and riverside areas to a safer place such as high ground."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Stay calm and seek shelter nearby."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Emergency messages test"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<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>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 2a828f7a65f4..68fb34b6cf0b 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1173,7 +1173,7 @@
<string name="no_permissions" msgid="7283357728219338112">"No se requieren permisos"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"esto puede costarte dinero"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
- <string name="usb_charging_notification_title" msgid="6895185153353640787">"Este dispositivo se está cargando mediante USB"</string>
+ <string name="usb_charging_notification_title" msgid="6895185153353640787">"Cargando este dispositivo por USB"</string>
<string name="usb_supplying_notification_title" msgid="5310642257296510271">"El dispositivo conectado se está cargando mediante USB"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB para transferir archivos"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB para transferir fotos"</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Evacúa inmediatamente las regiones costeras y ribereñas en busca de un lugar seguro, como un terreno elevado."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Mantén la calma y busca un refugio cercano."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Prueba de mensajes de emergencia"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM no permitida"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM no provista"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 9323e1f0ce6e..95f0dffb0bee 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1183,7 +1183,7 @@
<string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Accesorio de audio no compatible"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Toca para obtener más información"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración USB habilitada"</string>
- <string name="adb_active_notification_message" msgid="4948470599328424059">"Toca para inhabilitar la depuración USB."</string>
+ <string name="adb_active_notification_message" msgid="4948470599328424059">"Toca para inhabilitar la depuración USB"</string>
<string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleccionar para inhabilitar la depuración USB"</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Creando informe de errores…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"¿Compartir informe de errores?"</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Aléjate inmediatamente de las zonas costeras y situadas junto a un río para dirigirte hacia un lugar más seguro, por ejemplo, un terreno elevado."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Mantén la calma y busca refugio en algún lugar cercano."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Prueba de mensajes de emergencia"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM no compatible"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM no proporcionada"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 4ff5a6b2bbd6..bd05d6420d93 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Evakueeruge ranniku ja jõekallaste piirkondadest viivitamatult ohutusse kohta, näiteks kõrgematesse kohtadesse."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Jääge rahulikuks ja otsige lähedusest peavarju."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Hädaabisõnumite test"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-kaart pole lubatud"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-kaart on ettevalmistamata"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index ca369c434ede..36922d985056 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1770,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Ebakuatu kostaldeak eta ibaialdeak berehala eta joan toki seguru batera, adibidez, toki garai batera."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Ez larritu eta bilatu babesleku bat inguruan."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Larrialdi-mezuen proba"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Ez da onartzen SIM txartela"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Ez dago SIM txartelik"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 9d4cb6df4b40..46788fbb817f 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"فوراً مناطق ساحلی و محدوده رودخانه را ترک کنید و به جایی امن، مثل ارتفاعات بروید."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"آرام باشید و پناهگاهی در این اطراف پیدا کنید."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"آزمایش پیام‌های اضطراری"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"سیم‌کارت مجاز نیست"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"سیم‌کارت مجوز لازم را ندارد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index ffa6d67dca15..3459e3916886 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Siirry heti rannikkoalueilta ja jokien varsilta korkeampiin tai muuten turvallisempiin paikkoihin."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Pysy rauhallisena ja hakeudu lähimpään suojapaikkaan."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Hätäilmoitustesti"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-kortti estetty"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-kortti ei käyttäjien hallinnassa"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index d4bac7c02627..a39bc3ff5b4e 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1182,7 +1182,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Touchez pour afficher plus d\'options."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Accessoire audio non pris en charge"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Touchez l\'écran pour obtenir plus d\'information"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB connecté"</string>
+ <string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB activé"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Touchez pour désactiver le débogage USB."</string>
<string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Sélectionnez cette option pour désactiver le débogage USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Création d\'un rapport de bogue en cours..."</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Évacuez immédiatement les zones côtières et les rives des fleuves, et réfugiez-vous dans un endroit plus sécuritaire, comme un terrain surélevé."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Restez calme et cherchez un abri à proximité."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test de messages d\'urgence"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Carte SIM non autorisée"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Carte SIM non configurée"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index f1e693d02a33..7d27a5b2bc4c 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Évacuez immédiatement les zones côtières et les berges des fleuves, et réfugiez-vous dans un endroit plus sûr, comme un terrain surélevé."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Restez calme et cherchez un abri à proximité."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test de messages d\'urgence"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Carte SIM non autorisée"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Carte SIM non configurée"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index c45b7a97905c..09104db004e4 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1770,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Abandona de inmediato rexións costeiras e situadas na beira de ríos para dirixirte a un lugar máis seguro, como un terreo elevado."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Mantén a calma e busca refuxio cerca."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Proba de mensaxes de emerxencia"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Non se admite a tarxeta SIM"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Non se introduciu ningunha tarxeta SIM"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index bd4789ad0e43..4352845d1d0d 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1770,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"દરિયાકિનારાના પ્રદેશો તથા નદીકાંઠાના વિસ્તારો ખાલી કરીને તાત્કાલિક સુરક્ષિત ઊંચા સ્થાન પર જાઓ."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"શાંત રહો અને નજીકમાં આશ્રય લો."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"કટોકટી સંદેશાઓનું પરીક્ષણ"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM મંજૂર નથી"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIMની જોગવાઈ કરી નથી"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 7baa83baf214..391ad9f1df97 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -119,7 +119,7 @@
<string name="roamingTextSearching" msgid="8360141885972279963">"सेवा खोज रहा है"</string>
<string name="wfcRegErrorTitle" msgid="2301376280632110664">"वाई-फ़ाई कॉलिंग"</string>
<string-array name="wfcOperatorErrorAlertMessages">
- <item msgid="3910386316304772394">"वाई-फ़ाई से कॉल करने और संदेश भेजने के लिए, सबसे पहले अपने वाहक से इस सेवा को सेट करने के लिए कहें. उसके बाद सेटिंग से वाई-फ़ाई कॉलिंग को दोबारा चालू करें. (गड़बड़ी कोड: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ <item msgid="3910386316304772394">"वाई-फ़ाई से कॉल करने और संदेश भेजने के लिए, सबसे पहले अपने वाहक से इस सेवा को सेट अप करने के लिए कहें. उसके बाद सेटिंग से वाई-फ़ाई कॉलिंग को दोबारा चालू करें. (गड़बड़ी कोड: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="6177300162212449033">"अपने वाहक के साथ पंजीकृत करें"</item>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"तटीय क्षेत्रों और नदी के किनारे वाले क्षेत्रों को जल्द से जल्द खाली करके किसी सुरक्षित ऊंची जगह पर चले जाएं."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"शांत रहें और आस-पास आश्रय खोजें."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"आपातकालीन संदेश परीक्षण"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM की अनुमति नहीं है"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM का प्रावधान नहीं किया गया है"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 92d4651a8ec0..f43c600cba62 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1803,6 +1803,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Odmah se evakuirajte s obalnih područja i područja uz rijeku na sigurnije mjesto, primjerice povišeno područje."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Ostanite mirni i potražite sklonište u blizini."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test hitnih poruka"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM nije dopušten"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Ne pruža se usluga za SIM"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 107581c50849..285babebd8dc 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Azonnal meneküljön biztonságosabb helyre a tengerparti, illetve folyóparti területekről, például valamilyen magaslatra."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Őrizze meg nyugalmát, és keressen menedéket a közelben."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Vészhelyzetben küldött üzenetek tesztelése"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"A SIM-kártya nem engedélyezett"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Nem engedélyezett SIM-kártya"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 9c5b1e090d8b..02da2cc74471 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Ափամերձ և գետափնյա տարածքներից անմիջապես էվակուացվեք դեպի ավելի ապահով վայրեր (օրինակ՝ բարձրադիր գոտիներ):"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Պահպանեք հանգստությունը և մոտակայքում ապաստարան փնտրեք:"</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Արտակարգ իրավիճակների հաղորդագրությունների թեստ"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM քարտի օգտագործումն արգելված է"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM քարտը նախապատրաստված չէ"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index f6fcef7c6e66..15ea8d28fde8 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Evakuasi segera dari daerah pesisir dan area tepi sungai ke tempat yang lebih aman seperti dataran tinggi."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Tetap tenang dan cari tempat berlindung terdekat."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Tes pesan darurat"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM tidak diizinkan"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM tidak di-provisioning"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 2c0fb3b60414..2e0fa2e9a7cb 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1770,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Fólk sem statt er á strandsvæðum eða við ár á tafarlaust að leita öryggis á svæðum sem eru í meiri hæð yfir sjávarmáli."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Sýndu stillingu og leitaðu skjóls."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Prófun neyðarskilaboða"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-kort er ekki leyft"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-korti ekki úthlutað"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index f14b65b28a5e..5dcd3aafb878 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Evacuare immediatamente le zone costiere e in riva ai fiumi e recarsi in un luogo più sicuro, ad esempio un\'altura."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Mantieni la calma e cerca riparo nelle vicinanze."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Testo messaggi di emergenza"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Scheda SIM non consentita"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Scheda SIM non predisposta"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 5a3de37b73f4..938b03aac6fd 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1837,6 +1837,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"יש להתפנות מיידית מאזורים הסמוכים לחופים ולנהרות למקום בטוח יותר, כגון שטח גבוה יותר."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"הישאר רגוע וחפש מחסה בקרבת מקום."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"בדיקה של הודעות חירום"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"‏כרטיס ה-SIM לא מורשה"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"‏כרטיס ה-SIM לא מזוהה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index b2374390e610..c34e09e5de92 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -119,7 +119,7 @@
<string name="roamingTextSearching" msgid="8360141885972279963">"サービスを検索中"</string>
<string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi通話"</string>
<string-array name="wfcOperatorErrorAlertMessages">
- <item msgid="3910386316304772394">"Wi-Fi 経由で音声通話の発信やメッセージの送信を行うには、携帯通信会社に Wi-Fi サービスを申し込んだ上で、設定画面で Wi-Fi 発信を再度 ON にしてください(エラーコード: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ <item msgid="3910386316304772394">"Wi-Fi 経由で音声通話の発信やメッセージの送信を行うには、携帯通信会社に Wi-Fi サービスを申し込んだ上で、設定画面で Wi-Fi 通話を再度 ON にしてください(エラーコード: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="6177300162212449033">"携帯通信会社に登録してください"</item>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"沿岸部の方はただちに高台へ避難してください"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"強い揺れと津波に注意してください"</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"テスト用緊急速報メール"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM 使用不可"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM には対応していません"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index af653bd9aff5..6bd2ce1970dc 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -119,7 +119,7 @@
<string name="roamingTextSearching" msgid="8360141885972279963">"სერვისის ძიება"</string>
<string name="wfcRegErrorTitle" msgid="2301376280632110664">"დარეკვა Wi-Fi-ს მეშვეობით"</string>
<string-array name="wfcOperatorErrorAlertMessages">
- <item msgid="3910386316304772394">"Wi-Fi-ს მეშვეობით ზარების განსახორციელებლად ან შეტყობინებების გასაგზავნად, პირველ რიგში, ამ სერვისის გააქტიურება თქვენს ოპერატორს უნდა თხოვოთ. შემდეგ კი ხელახლა ჩართეთ Wi-Fi დარეკვა პარამეტრებიდან.. (შეცდომის კოდი: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ <item msgid="3910386316304772394">"Wi-Fi-ს მეშვეობით ზარების განსახორციელებლად ან შეტყობინებების გასაგზავნად, პირველ რიგში, ამ სერვისის გააქტიურება თქვენს ოპერატორს უნდა თხოვოთ. შემდეგ კი ხელახლა ჩართეთ Wi-Fi დარეკვა პარამეტრებიდან. (შეცდომის კოდი: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="6177300162212449033">"დაარეგისტრირეთ თქვენი ოპერატორი"</item>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"დაუყოვნებლივ გადაინაცვლეთ სანაპირო რეგიონებიდან და მდინარისპირა ტერიტორიებიდან უსაფრთხო ადგილზე (მაგალითად, შემაღლებულ ადგილზე)."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"შეინარჩუნეთ სიმშვიდე და იპოვეთ ახლომდებარე თავშესაფარი."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"სატესტო საგანგებო შეტყობინება"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM ბარათი დაუშვებელია"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM ბარათი უზრუნველყოფილი არ არის"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index e185552de2d2..70801fa1c3ff 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1770,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Жағалау аймақтан биіктеу қауіпсіз жерге дереу көшіңіз."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Сабыр сақтап, жақын жерден баспана іздеңіз."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Төтенше хабарлар сынағы"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM картасына рұқсат етілмеген"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM картасы белсендірілмеген"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 3843daa7c90b..76f06028803f 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -119,7 +119,7 @@
<string name="roamingTextSearching" msgid="8360141885972279963">"​ស្វែង​រក​សេវាកម្ម"</string>
<string name="wfcRegErrorTitle" msgid="2301376280632110664">"ការហៅតាម Wi-Fi"</string>
<string-array name="wfcOperatorErrorAlertMessages">
- <item msgid="3910386316304772394">"ដើម្បីធ្វើការហៅ និងផ្ញើសារតាម Wi-Fi អ្នកត្រូវស្នើឲ្យក្រុមហ៊ុនបម្រើសេវាទូរសព្ទរបស់អ្នកដំឡើងសេវាកម្មនេះជាមុនសិន។ បន្ទាប់មកបើកការហៅតាម Wi-Fi ម្តងទៀតនៅក្នុងការកំណត់។ (លេខកូដបញ្ហា៖ <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ <item msgid="3910386316304772394">"ដើម្បីហៅទូរសព្ទ និងផ្ញើសារតាម Wi-Fi អ្នកត្រូវស្នើឲ្យក្រុមហ៊ុនបម្រើសេវាទូរសព្ទរបស់អ្នកដំឡើងសេវាកម្មនេះជាមុនសិន។ បន្ទាប់មកបើកការហៅតាម Wi-Fi ម្តងទៀតនៅក្នុងការកំណត់។ (លេខកូដបញ្ហា៖ <xliff:g id="CODE">%1$s</xliff:g>)"</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="6177300162212449033">"ចុះឈ្មោះជាមួយក្រុមហ៊ុនរបស់អ្នក"</item>
@@ -1771,6 +1771,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"ភៀសខ្លួនជាបន្ទាន់ពីតំបន់ឆ្នេរ និងតំបន់តាមមាត់ទន្លេទៅកាន់កន្លែងដែលមានសុវត្ថិភាពជាងនេះ ដូចជាទីទួលណាមួយ។"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"សូមរក្សាភាពស្ងប់ស្ងាត់ ហើយស្វែងរកជម្រកសុវត្ថិភាពដែលនៅជិត។"</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"សារសាកល្បងពេលមានអាសន្ន"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"មិន​អនុញ្ញាត​សីុមកាត​ទេ"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"សីុម​មិន​ត្រូវបាន​ផ្តល់ជូន​ទេ"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 8d3db2098240..fad951ee5bb0 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1770,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"ಕರಾವಳಿ ಪ್ರದೇಶಗಳು ಮತ್ತು ನದಿ ತೀರಗಳಿಂದ ತಕ್ಷಣವೇ ಎತ್ತರದ ಪ್ರದೇಶಗಳಂತಹ ಸುರಕ್ಷಿತ ಸ್ಥಳಕ್ಕೆ ಹೋಗಿ."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"ಶಾಂತರಾಗಿರಿ ಮತ್ತು ಸಮೀಪದಲ್ಲೆಲ್ಲಾದರೂ ಆಶ್ರಯ ಪಡೆದುಕೊಳ್ಳಿ."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"ತುರ್ತು ಸಂದೇಶಗಳ ಪರೀಕ್ಷೆ"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"ಸಿಮ್‌ಗೆ ಅನುಮತಿಯಿಲ್ಲ"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"ಸಿಮ್ ಸಿದ್ಧವಾಗಿಲ್ಲ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 497cfe914f56..9685e832dcdf 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"즉시 해안 지대나 강가에서 떨어져 고지대 등 안전한 장소로 대피하세요."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"침착하게 가까운 대피소를 찾으세요."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"긴급 메시지 테스트"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM이 허용되지 않음"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM이 프로비저닝되지 않음"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index ea01218bac1b..b9e143c958b1 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1770,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Деңиз жана дарыя жээгинде жайгашкан аймактардан бийик тоо сыяктуу коопсуз жерге тезинен чыгып кетиңиз."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Эс алып, жакын жерден калканч издеңиз."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Өзгөчө кырдаалда жөнөтүлүүчү билдирүүлөрдү сыноо"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM картаны колдонууга тыюу салынган"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM карта таанылган жок"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 9bdfd39d7394..affd2874990d 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"ອົບພະຍົບອອກຈາກເຂດຊາຍຝັ່ງທະເລ ແລະ ບໍລິເວນແມ່ນ້ຳໄປບ່ອນທີ່ປອດໄພກວ່າ ເຊັ່ນ: ບ່ອນສູງ ໂດຍທັນທີ."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"ໃຈເຢັນໆ ແລະ ຊອກຫາບ່ອນພັກຢູ່ໃກ້ໆ."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"ທົດສອບຂໍ້ຄວາມສຸກເສີນ"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"ບໍ່ອະນຸຍາດໃຫ້ໃຊ້ SIM"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"ບໍ່ມີການນຳໃຊ້ SIM"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index a6aa9c0c11b6..f10d02545d82 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1837,6 +1837,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Nedelsdami pasitraukite nuo pakrančių ir paupių. Eikite į saugią vietą, pvz., vietą, kuri yra aukštai."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Nesijaudinkite ir ieškokite prieglobsčio netoliese."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Kritinės padėties pranešimo bandymas"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM kortelė neleidžiama"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM kortelė neteikiama"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index d96ea068fb61..c9e9e1f735f7 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1803,6 +1803,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Nekavējoties pametiet piekrastes un upju zonas un dodieties uz drošākām (piemēram, augstākām) vietām."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Saglabājiet mieru un meklējiet tuvumā patvērumu."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Ārkārtas ziņojuma pārbaude"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM karti nav atļauts izmantot"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM karte netiek nodrošināta"</string>
diff --git a/core/res/res/values-mcc302-mnc370-bn/strings.xml b/core/res/res/values-mcc302-mnc370-bn/strings.xml
new file mode 100644
index 000000000000..efd9b4b4f8ca
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc370-bn/strings.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcSpnFormats">
+ <item msgid="5022384999749536798">"%s"</item>
+ <item msgid="8117276330682171665">"%s ওয়াই-ফাই"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc370-gu/strings.xml b/core/res/res/values-mcc302-mnc370-gu/strings.xml
new file mode 100644
index 000000000000..b93949e190c7
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc370-gu/strings.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcSpnFormats">
+ <item msgid="5022384999749536798">"%s"</item>
+ <item msgid="8117276330682171665">"%s Wi-Fi"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc370-kn/strings.xml b/core/res/res/values-mcc302-mnc370-kn/strings.xml
new file mode 100644
index 000000000000..636eb01d3eb0
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc370-kn/strings.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcSpnFormats">
+ <item msgid="5022384999749536798">"%s"</item>
+ <item msgid="8117276330682171665">"%s ವೈ-ಫೈ"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc370-ne/strings.xml b/core/res/res/values-mcc302-mnc370-ne/strings.xml
new file mode 100644
index 000000000000..b93949e190c7
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc370-ne/strings.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcSpnFormats">
+ <item msgid="5022384999749536798">"%s"</item>
+ <item msgid="8117276330682171665">"%s Wi-Fi"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc370-pa/strings.xml b/core/res/res/values-mcc302-mnc370-pa/strings.xml
new file mode 100644
index 000000000000..b93949e190c7
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc370-pa/strings.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcSpnFormats">
+ <item msgid="5022384999749536798">"%s"</item>
+ <item msgid="8117276330682171665">"%s Wi-Fi"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc370-ur/strings.xml b/core/res/res/values-mcc302-mnc370-ur/strings.xml
new file mode 100644
index 000000000000..81d28880fd84
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc370-ur/strings.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcSpnFormats">
+ <item msgid="5022384999749536798">"‎%s"</item>
+ <item msgid="8117276330682171665">"%s Wi-Fi"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc720-bn/strings.xml b/core/res/res/values-mcc302-mnc720-bn/strings.xml
new file mode 100644
index 000000000000..543ec7aeed8f
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc720-bn/strings.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcSpnFormats">
+ <item msgid="2776657861851140021">"%s"</item>
+ <item msgid="5094669985484060934">"%s ওয়াই-ফাই"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc720-gu/strings.xml b/core/res/res/values-mcc302-mnc720-gu/strings.xml
new file mode 100644
index 000000000000..9b2336d8006d
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc720-gu/strings.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcSpnFormats">
+ <item msgid="2776657861851140021">"%s"</item>
+ <item msgid="5094669985484060934">"%s Wi-Fi"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc720-kn/strings.xml b/core/res/res/values-mcc302-mnc720-kn/strings.xml
new file mode 100644
index 000000000000..6438ffb536ba
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc720-kn/strings.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcSpnFormats">
+ <item msgid="2776657861851140021">"%s"</item>
+ <item msgid="5094669985484060934">"%s ವೈ-ಫೈ"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc720-ne/strings.xml b/core/res/res/values-mcc302-mnc720-ne/strings.xml
new file mode 100644
index 000000000000..9b2336d8006d
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc720-ne/strings.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcSpnFormats">
+ <item msgid="2776657861851140021">"%s"</item>
+ <item msgid="5094669985484060934">"%s Wi-Fi"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc720-pa/strings.xml b/core/res/res/values-mcc302-mnc720-pa/strings.xml
new file mode 100644
index 000000000000..9b2336d8006d
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc720-pa/strings.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcSpnFormats">
+ <item msgid="2776657861851140021">"%s"</item>
+ <item msgid="5094669985484060934">"%s Wi-Fi"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mcc302-mnc720-ur/strings.xml b/core/res/res/values-mcc302-mnc720-ur/strings.xml
new file mode 100644
index 000000000000..566f852435e2
--- /dev/null
+++ b/core/res/res/values-mcc302-mnc720-ur/strings.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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcSpnFormats">
+ <item msgid="2776657861851140021">"‎%s"</item>
+ <item msgid="5094669985484060934">"%s Wi-Fi"</item>
+ </string-array>
+</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 9ffc7ad1fa68..6b68427b3cdd 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1772,6 +1772,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Итна евакуација од крајбрежните региони и областите покрај реки на побезбедно место, како на пр., терени на повисока надморска височина."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Бидете смирени и побарајте засолниште во близина."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Тестирање пораки за итни случаи"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Не е дозволена SIM-картичка"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Не е обезбедена SIM-картичка"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index cc19ec617417..344f9f2e40df 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1770,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"തീരപ്രദേശങ്ങളിൽ നിന്നും നദിക്കരകളിൽ നിന്നും ആളുകളെ ഉടനടി ഒഴിപ്പിച്ച് ഉയർന്ന ഭൂമിയിൽ എത്തിക്കുക."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"പരിഭ്രമിക്കാതിരിക്കുക, അടുത്തുള്ള അഭയകേന്ദ്രം തേടുക."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"അടിയന്തര സന്ദേശ ടെസ്റ്റ്"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM അനുവദനീയമല്ല"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM പ്രൊവിഷൻ ചെയ്തിട്ടില്ല"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index a2b08e0a7067..c9a585360330 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1767,6 +1767,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Эргийн бүс, голын эргийн бүсээс өндөрлөг газар зэрэг аюулгүй газар руу нэн даруй шилжинэ үү."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Тайван байж, ойролцоох нуугдах газар хайна уу."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Онцгой байдлын зурвасын тест"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM боломжгүй"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-г хийгээгүй"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 12026d84ca24..cd9124a9fa7a 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1770,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"किनारपट्टीचे प्रदेश आणि नदीकाठची क्षेत्रे त्वरित रिकामी करून उंच मैदानासारख्या अधिक सुरक्षित ठिकाणी जा."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"शांत रहा आणि जवळपास निवारा शोधा."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"आणीबाणी संदेश चाचणी"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"सिमला अनुमती नाही"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"सिमसाठी तरतूद नाही"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index bd7e6ac3e938..19bc7d7da8be 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Segera beredar dari kawasan pinggir laut dan tepi sungai dan berpindah ke tempat yang lebih selamat seperti kawasan tinggi."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Bertenang dan cari perlindungan di kawasan yang berdekatan."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Ujian mesej kecemasan"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM tidak dibenarkan"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM tidak diperuntukkan"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 983213737348..f24ab13c6bb7 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1770,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"ကမ်းရိုးတန်းနှင့် မြစ်ကမ်းရိုးတစ်လျှောက်ရှိ နေရာဒေသတို့မှ ချက်ချင်းထွက်ခွာပြီး ဘေးကင်းရာကုန်းမြင့်ဒေသသို့ ပြောင်းရွှေ့ပါ။"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"စိတ်ငြိမ်ငြိမ်ထားပြီး အနီးအနားတဝိုက်တွင် ခိုနားစရာ နေရာရှာပါ။"</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"အရေးပေါ် မက်ဆေ့ဂျ် စမ်းသပ်မှု"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"ဆင်းမ်ကို ခွင့်မပြုပါ"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"ဆင်းမ်ကို ထောက်ပံ့မထားပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 7103ea9ef418..72ad6d1e20f8 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -119,7 +119,7 @@
<string name="roamingTextSearching" msgid="8360141885972279963">"Leter etter tjeneste"</string>
<string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi-anrop"</string>
<string-array name="wfcOperatorErrorAlertMessages">
- <item msgid="3910386316304772394">"For å ringe og sende meldinger over Wi-Fi må du først be operatøren om å konfigurere denne tjenesten. Deretter slår du på Wi-Fi-anrop igjen fra Innstillinger. (Feilkode: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ <item msgid="3910386316304772394">"For å ringe og sende meldinger over Wi-Fi, må du først be operatøren om å konfigurere denne tjenesten. Deretter slår du på Wi-Fi-anrop igjen fra Innstillinger. (Feilkode: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="6177300162212449033">"Registrer deg hos operatøren din"</item>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Evakuer umiddelbart fra kyst- og elveområder til et tryggere sted, for eksempel høyt terreng."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Hold deg rolig og søk ly i nærheten."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test av nødmeldinger"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-kortet er ikke tillatt"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-kortet er ikke klargjort"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 717b91fb4b77..c576c89e7d2e 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -349,9 +349,9 @@
<string name="permdesc_receiveBootCompleted" product="tv" msgid="4525890122209673621">"अनुप्रयोगलाई अनुमति दिन्छ प्रणालीले बुटिङ सकेपछि आफै सुरूवात हुन। यसले TV सुरू गर्न लामो समय लिन सक्छ र अनुप्रयोगहरूलाई अनुमति दिन सक्छ सँधै सञ्चालन भई समग्र रूपमा ट्याब्लेटलाई ढिलो गराएर।"</string>
<string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"अनुप्रयोगलाई प्रणाली बुट गरी सकेपछि जति सक्दो चाँडो आफैंमा सुरु गर्न अनुमति दिन्छ। यसले फोन सुरु गर्नमा ढिला गर्न सक्दछ र अनप्रयोगलाई समग्रमा फोन सधैँ चालु गरेर ढिला बनाउँदछ।"</string>
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"स्टिकि प्रसारण पठाउनुहोस्"</string>
- <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"औपचारिक प्रसारणलाई पठाउनको लागि एउटा अनुप्रयोगलाई अनुमति दिन्छ, जुन प्रसारण समाप्त भएपछि बाँकी रहन्छ। अत्याधिक प्रयोगले धेरै मेमोरी प्रयोग गरेको कारणले ट्याब्लेटलाई ढिलो र अस्थिर बनाउन सक्छ।"</string>
+ <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"औपचारिक प्रसारणलाई पठाउनको लागि एउटा अनुप्रयोगलाई अनुमति दिन्छ, जुन प्रसारण समाप्त भएपछि बाँकी रहन्छ। अत्यधिक प्रयोगले धेरै मेमोरी प्रयोग गरेको कारणले ट्याब्लेटलाई ढिलो र अस्थिर बनाउन सक्छ।"</string>
<string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"अनुप्रयोगलाई टाँसिने प्रसारणहरू पठाउन अनुमति दिन्छ, जुन प्रसारण पछि पनि रहन्छ। अत्यन्य धेरै मेमोरी प्रयोग गर्ने बनाएर अत्यधिक प्रयोगले TV लाई ढिलो वा अस्थिर बनाउन सक्छ ।"</string>
- <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"औपचारिक प्रसारणलाई पठाउनको लागि एक अनुप्रयोगलाई अनुमति दिन्छ, जुन प्रसारण समाप्त भएपछि बाँकी रहन्छ। अत्याधिक प्रयोगले धेरै मेमोरी प्रयोग गरेको कारणले फोनलाई ढिलो र अस्थिर बनाउन सक्छ।"</string>
+ <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"औपचारिक प्रसारणलाई पठाउनको लागि एक अनुप्रयोगलाई अनुमति दिन्छ, जुन प्रसारण समाप्त भएपछि बाँकी रहन्छ। अत्यधिक प्रयोगले धेरै मेमोरी प्रयोग गरेको कारणले फोनलाई ढिलो र अस्थिर बनाउन सक्छ।"</string>
<string name="permlab_readContacts" msgid="8348481131899886131">"तपाईँका सम्पर्कहरू पढ्नुहोस्"</string>
<string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"अनुप्रयोगलाई निर्दिष्ट व्यक्तिगतसँग अन्य तरिकाहरूबाट कल गर्नु भएका, इमेल गर्नु भएका वा अन्तर्क्रिया गर्नुभएका आवृतिसहितको तपाईंको ट्याब्लेटमा भण्डारण गरिएका सम्पर्कहरूको डेटा पढ्न अनुमति दिन्छ। यो अनुमतिले तपाईंको सम्पर्क डेटा बचत गर्न अनुमति दिन्छ, र खराब अनुप्रयोगहरूले तपाईंको जानकारी बिना सम्पर्क डेटा साझेदारी गर्न सक्दछन्।"</string>
<string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"अनुप्रयोगलाई अनुमति दिन्छ तपाईँको TV मा भण्डारण गरिएका तपाईँका सम्पर्कका डेटा, तपाईँको कल, इमेलको बारम्बारता, वा अन्य तरीकाले खास व्यक्तिहरूसँग गरिएको सञ्चार लगायत, पढ्न।यस अनुमतिले अनुप्रयोगलाई अनुमति दिन्छ तपाईँको सम्पर्क डेटा सुरक्षित गर्न र दुस्प्रभावी अनुप्रयोगहरूले तपाईँको ज्ञान बिना सम्पर्क डेटा साझेदारी गर्न सक्छन्।"</string>
@@ -708,7 +708,7 @@
<string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"फेरि प्रयास गर्नुहोस्"</string>
<string name="lockscreen_password_wrong" msgid="5737815393253165301">"फेरि प्रयास गर्नुहोस्"</string>
<string name="lockscreen_storage_locked" msgid="9167551160010625200">"सबै सुविधाहरू र डेटाका लागि अनलक गर्नुहोस्"</string>
- <string name="faceunlock_multiple_failures" msgid="754137583022792429">"अत्याधिक मोहडा खोल्ने प्रयासहरू बढी भए।"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"अत्यधिक मोहडा खोल्ने प्रयासहरू बढी भए।"</string>
<string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"SIM कार्ड छैन"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"ट्याब्लेटमा SIM कार्ड छैन।"</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"TV मा कुनै SIM कार्ड छैन।"</string>
@@ -1775,6 +1775,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"तटीय क्षेत्र र नदीछेउका ठाउँहरू छाडी उच्च सतहमा अवस्थित कुनै अझ सुरक्षित ठाउँमा जानुहोस्।"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"शान्त रहनुहोस् र नजिकै आश्रयस्थल खोज्नुहोस्।"</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"आपतकालीन सन्देशहरूको परीक्षण"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM लाई अनुमति छैन"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM को प्रावधान छैन"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 72072557a7ed..d690fc6e25c4 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1150,7 +1150,7 @@
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Verzenden"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Annuleren"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Mijn keuze onthouden"</string>
- <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"U kunt dit later wijzigen in \'Instellingen\' &gt; \'Apps\'"</string>
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"U kunt dit later wijzigen in Instellingen &gt; Apps"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Altijd toestaan"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Nooit toestaan"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Simkaart verwijderd"</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Verlaat kustgebieden en rivieroevers onmiddellijk en zoek een hoger gelegen gebied op."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Blijf kalm en zoek onderdak in de buurt."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test voor noodberichten"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Simkaart niet toegestaan"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Simkaart niet geregistreerd"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index c779361b1b36..0a237b18211f 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -83,7 +83,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"ਕੋਈ ਆਵਾਜ਼ੀ/ਸੰਕਟਕਾਲੀਨ ਸੇਵਾ ਨਹੀਂ"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"ਤੁਹਾਡੇ ਟਿਕਾਣੇ \'ਤੇ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਵੱਲੋਂ ਉਪਲਬਧ ਨਹੀਂ ਕਰਵਾਈ ਗਈ"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"ਨੈੱਟਵਰਕ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"ਸਿਗਨਲ ਪ੍ਰਾਪਤੀ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ, ਸੈਟਿੰਗਾਂ &gt; ਨੈੱਟਵਰਕ ਅਤੇ ਇੰਟਰਨੈੱਟ &gt; ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ &gt; ਤਰਜੀਹੀ ਨੈੱਟਵਰਕ ਦੀ ਕਿਸਮ \'ਤੇ ਚੁਣੀ ਗਈ ਕਿਸਮ ਨੂੰ ਬਦਲਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"ਸਿਗਨਲ ਪ੍ਰਾਪਤੀ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ, ਸੈਟਿੰਗਾਂ &gt; ਨੈੱਟਵਰਕ ਅਤੇ ਇੰਟਰਨੈੱਟ &gt; ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ &gt; ਤਰਜੀਹੀ ਨੈੱਟਵਰਕ ਦੀ ਕਿਸਮ \'ਤੇ ਜਾਓ ਅਤੇ ਚੁਣੀ ਗਈ ਕਿਸਮ ਨੂੰ ਬਦਲਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"ਸੁਚੇਤਨਾਵਾਂ"</string>
<string name="notification_channel_call_forward" msgid="2419697808481833249">"ਕਾਲ ਫਾਰਵਾਰਡਿੰਗ"</string>
<string name="notification_channel_emergency_callback" msgid="6686166232265733921">"ਸੰਕਟਕਾਲੀਨ ਕਾਲਬੈਕ ਮੋਡ"</string>
@@ -118,7 +118,9 @@
<string name="roamingText12" msgid="1189071119992726320">"ਰੋਮਿੰਗ ਬੈਨਰ ਬੰਦ"</string>
<string name="roamingTextSearching" msgid="8360141885972279963">"ਸੇਵਾ ਦੀ ਖੋਜ ਕਰ ਰਿਹਾ ਹੈ"</string>
<string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi ਕਾਲਿੰਗ"</string>
- <!-- no translation found for wfcOperatorErrorAlertMessages:0 (3910386316304772394) -->
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item msgid="3910386316304772394">"Wi-Fi ਤੋਂ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਸੁਨੇਹੇ ਭੇਜਣ ਦੇ ਲਈ, ਸਭ ਤੋਂ ਪਹਿਲਾਂ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਇਸ ਸੇਵਾ ਦੀ ਸਥਾਪਨਾ ਕਰਨ ਲਈ ਕਹੋ। ਫਿਰ ਸੈਟਿੰਗਾਂ ਵਿੱਚੋਂ Wi-Fi ਕਾਲਿੰਗ ਨੂੰ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰੋ। (ਗੜਬੜੀ ਕੋਡ: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ </string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="6177300162212449033">"ਆਪਣੇ ਕੈਰੀਅਰ ਨਾਲ ਰਜਿਸਟਰ ਕਰੋ"</item>
</string-array>
@@ -1768,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"ਤੁਰੰਤ ਤੱਟੀ ਖੇਤਰਾਂ ਅਤੇ ਨਦੀ ਦੇ ਕਿਨਾਰੇ ਵਾਲੇ ਖੇਤਰਾਂ ਨੂੰ ਖਾਲੀ ਕਰ ਕੇ ਕਿਸੇ ਸੁਰੱਖਿਅਤ ਸਥਾਨ \'ਤੇ ਚਲੇ ਜਾਓ ਜਿਵੇਂ ਕਿ ਉੱਚੀ ਜ਼ਮੀਨ।"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"ਸ਼ਾਂਤ ਰਹੋ ਅਤੇ ਆਸ-ਪਾਸ ਪਨਾਹ ਮੰਗੋ।"</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"ਸੰਕਟਕਾਲੀਨ ਸੰਦੇਸ਼ ਟੈਸਟ"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM ਦੀ ਵਿਵਸਥਾ ਨਹੀਂ ਹੈ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index e36eaf30cfd0..b730e3c54603 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1837,6 +1837,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Niezwłocznie ewakuuj się z regionów nabrzeżnych i położonych przy rzekach w bezpieczniejsze miejsce, np. na wzniesienie."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Zachowaj spokój i poszukaj schronienia w pobliżu."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test komunikatów alarmowych"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Niedozwolona karta SIM"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Nieobsługiwana karta SIM"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index acaafd6f655b..a373b452a280 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1183,7 +1183,7 @@
<string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Acessório de áudio não compatível"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Toque para mais informações"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB conectada"</string>
- <string name="adb_active_notification_message" msgid="4948470599328424059">"Toque para desativar a depuração do USB."</string>
+ <string name="adb_active_notification_message" msgid="4948470599328424059">"Toque para desativar a depuração USB."</string>
<string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecione para desativar a depuração USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Gerando relatório do bug..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Compartilhar relatório do bug?"</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Saia imediatamente de regiões costeiras e áreas ribeirinhas e vá para um lugar mais seguro, como terrenos elevados."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Fique calmo e procure um abrigo por perto."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Teste de mensagens de emergência"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM não permitido"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM não aprovisionado"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 3c1011b59f63..4c3399de1808 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1150,7 +1150,7 @@
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Enviar"</string>
<string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Cancelar"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Memorizar a minha escolha"</string>
- <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Pode depois alterar isto em Definições &gt; Aplicações"</string>
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Pode alterar mais tarde em Definições &gt; Aplicações"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Permitir Sempre"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Nunca Permitir"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Cartão SIM removido"</string>
@@ -1184,7 +1184,7 @@
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Toque para obter mais informações"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB ligada"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Toque para desativar a depuração USB."</string>
- <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleccione para desativar depuração USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecione para desativar a depuração por USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"A criar relatório de erro…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Pretende partilhar o relatório de erro?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"A partilhar relatório de erro…"</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Abandone imediatamente regiões costeiras e zonas ribeirinhas em direção a um local mais seguro, como um terreno elevado."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Mantenha a calma e procure abrigo nas proximidades."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Teste de mensagens de emergência"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM não permitido"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM não ativado"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index acaafd6f655b..a373b452a280 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1183,7 +1183,7 @@
<string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Acessório de áudio não compatível"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Toque para mais informações"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB conectada"</string>
- <string name="adb_active_notification_message" msgid="4948470599328424059">"Toque para desativar a depuração do USB."</string>
+ <string name="adb_active_notification_message" msgid="4948470599328424059">"Toque para desativar a depuração USB."</string>
<string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecione para desativar a depuração USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Gerando relatório do bug..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Compartilhar relatório do bug?"</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Saia imediatamente de regiões costeiras e áreas ribeirinhas e vá para um lugar mais seguro, como terrenos elevados."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Fique calmo e procure um abrigo por perto."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Teste de mensagens de emergência"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM não permitido"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM não aprovisionado"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 33c36d896b7a..83afac8b20f2 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -273,7 +273,7 @@
<string name="permgroupdesc_sms" msgid="4656988620100940350">"trimită și să vadă mesajele SMS"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Stocare"</string>
<string name="permgroupdesc_storage" msgid="637758554581589203">"acceseze fotografiile, conținutul media și fișierele de pe dispozitiv"</string>
- <string name="permgrouplab_microphone" msgid="171539900250043464">"Microfonul"</string>
+ <string name="permgrouplab_microphone" msgid="171539900250043464">"Microfon"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"înregistreze sunet"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Camera foto"</string>
<string name="permgroupdesc_camera" msgid="3250611594678347720">"fotografieze și să înregistreze videoclipuri"</string>
@@ -1803,6 +1803,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Părăsiți imediat zonele de coastă și din apropierea râurilor și îndreptați-vă spre un loc mai sigur, cum ar fi o zonă aflată la înălțime."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Păstrați-vă calmul și căutați un adăpost în apropiere."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Testarea mesajelor de urgență"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Cardul SIM nu este permis"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Cardul SIM nu este activat"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 853586f15a9e..913c93bd9985 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1228,7 +1228,7 @@
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Нажмите, чтобы получить дополнительную информацию"</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="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>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Отправка отчета об ошибке"</string>
@@ -1837,6 +1837,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Немедленно эвакуируйтесь из прибрежной зоны в более высокое место."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Сохраняйте спокойствие и поищите укрытие поблизости."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Тестовое экстренное сообщение"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Использование SIM-карты запрещено"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-карта не активирована"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 1f373fe8b847..641bd4053cdf 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1771,6 +1771,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"මුහුදු බඩ ප්‍රදේශ සහ ගංඉවුරු ප්‍රදේශ සිට ඉහළ ප්‍රදේශයක් වැනි ආරක්‍ෂිත තැනකට දැන්ම යන්න."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"සන්සුන්ව ඉන්න සහ අවට ඇති නවාතැන් පහසුකම් බලන්න."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"හදිසි පණිවිඩ පරීක්ෂණය"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM එක සඳහා ඉඩ නොදේ"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM එක සක්‍රීය කර නොමැත"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 47b0b850bd18..d68ebc450efc 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1228,7 +1228,7 @@
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Ďalšie informácie zobrazíte klepnutím"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Ladenie cez USB pripojené"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Klepnutím zakážete ladenie cez USB."</string>
- <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Výberom zakážete ladenie USB."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Vyberte, ak chcete zakázať ladenie cez USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Preberá sa hlásenie chyby…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Chcete zdieľať hlásenie chyby?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Zdieľa sa hlásenie chyby…"</string>
@@ -1837,6 +1837,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Okamžite začnite evakuáciu z prímorských a nábrežných oblastí na bezpečnejšie miesto, napríklad do vyššie položených regiónov."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Zachovajte pokoj a vyhľadajte úkryt v okolí."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test tiesňových správ"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM karta je zakázaná"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM karta nie je k dispozícii"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 457f324e81f2..48baf056fa3b 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1837,6 +1837,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Takoj se umaknite z obalnih območij in bregov rek na varnejše mesto, na primer na višje ležeča mesta."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Ostanite mirni in poiščite zavetje v bližini."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Preskus sporočil v sili"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Kartica SIM ni dovoljena"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Kartica SIM ni omogočena za uporabo"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 96f3ae6ad728..381154f8c6ea 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1770,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Evakuohu menjëherë nga rajonet bregdetare dhe zonat pranë lumenjve drejt një vendi më të sigurt, si për shembull në një terren të ngritur."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Qëndro i qetë dhe kërko strehim në afërsi."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Testim për mesazhet e urgjencës"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Karta SIM nuk lejohet"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Karta SIM nuk është dhënë"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 9d5963b79076..704869dd78c3 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1204,7 +1204,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Додирните за још опција."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Додатна опрема за аудио садржај није подржана"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Додирните за више информација"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"Отклањање грешака са 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>
@@ -1803,6 +1803,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Одмах се склоните из приобалних региона и области поред река на неко безбедније место, на пример, на неко узвишење."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Останите мирни и потражите склониште у околини."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Тестирање порука у хитним случајевима"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM картица није дозвољена"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM картица није подешена"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 59f59c62044b..7339480b71cb 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1184,7 +1184,7 @@
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Tryck för mer information"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-felsökning ansluten"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Tryck om du vill inaktivera USB-felsökning."</string>
- <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Välj att inaktivera USB-felsökning."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Välj för att inaktivera USB-felsökning."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Felrapporten överförs …"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vill du dela felrapporten?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Felrapporten delas …"</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Utrym kust- och flodområden omedelbart och förflytta er till en säkrare plats, till exempel ett högt beläget område."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Håll dig lugn och sök skydd i närheten."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test för nödmeddelanden"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-kort tillåts inte"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-kort tillhandahålls inte"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 472867236862..a8552314dbbf 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1767,6 +1767,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Ondoka mara moja kwenye maeneo ya ufuo na mito ili uende kwenye sehemu salama kama vile milimani."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Tulia na utafute hifadhi ya karibu."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Jaribio la ujumbe wa dharura"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM imekataliwa"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM haikubaliwi"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index e9ced05c9f3f..45ac5c5f0834 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1770,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"கடலோரப் பகுதிகளிலும் ஆற்றங்கரைகளிலும் வசிப்பவர்கள் உடனடியாகப் பாதுகாப்பான இடத்திற்குச் (மேட்டுப்பகுதி) செல்லவும்."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"பதட்டப்படாதீர்கள், அருகில் ஏதேனும் பாதுகாப்பான இடம் உள்ளதா எனப் பாருங்கள்."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"அவசரக் காலச் செய்திகளுக்கான சோதனை"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"சிம் அனுமதிக்கப்படவில்லை"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"சிம் அமைக்கப்படவில்லை"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 375c82db7c5d..307833068913 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1770,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"వెంటనే తీర ప్రాంతాలు మరియు నదీ పరీవాహక ప్రాంతాలను ఖాళీ చేసి మెట్ట ప్రాంతాలకు తరలి వెళ్లండి."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"ప్రశాంతంగా ఉండండి మరియు దగ్గర్లో తలదాచుకోండి."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"అత్యవసర సందేశాల పరీక్ష"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM అనుమతించబడదు"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM సక్రియం కాలేదు"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 9a58edd997e7..9be0d4a9e365 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1105,7 +1105,7 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"ลงชื่อเข้าใช้เครือข่าย"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ไม่สามารถเข้าถึงอินเทอร์เน็ต"</string>
+ <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi เชื่อมต่ออินเทอร์เน็ตไม่ได้"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"แตะเพื่อดูตัวเลือก"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"เปลี่ยนเป็น <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
<string name="network_switch_metered_detail" msgid="5325661434777870353">"อุปกรณ์จะใช้ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> เมื่อ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ไม่สามารถเข้าถึงอินเทอร์เน็ต อาจมีค่าบริการ"</string>
@@ -1182,7 +1182,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"แตะเพื่อดูตัวเลือกเพิ่มเติม"</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"ไม่รองรับอุปกรณ์เสริมสำหรับเสียง"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"แตะเพื่อดูข้อมูลเพิ่มเติม"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"เชื่อมต่อการแก้ไขข้อบกพร่อง 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>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"อพยพออกจากจากเขตชายฝั่งทะเลและบริเวณริมแม่น้ำไปยังสถานที่ที่ปลอดภัยกว่า เช่น ที่สูง โดยทันที"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"ทำใจให้สงบและหาที่กำบังในบริเวณใกล้เคียง"</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"การทดสอบข้อความกรณีฉุกเฉิน"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"ไม่อนุญาตให้ใช้ซิม"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"ไม่มีการจัดสรรซิม"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 2c33a0f930f9..a85e2e52d85a 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Umalis kaagad sa mga baybayin at pampang, at pumunta sa isang mas ligtas na lokasyon tulad ng isang mataas na lugar."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Manatiling kalmado at maghanap ng matutuluyan sa malapit."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Pagsubok sa mga mensaheng pang-emergency"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"Hindi pinahihintulutan ang SIM"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"Hindi naprobisyon ang SIM"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 8c4c4277bfeb..aa6356248b73 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1184,7 +1184,7 @@
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Daha fazla bilgi için dokunun"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB hata ayıklaması bağlandı"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB hata ayıklama özelliğini devre dışı bırakmak için dokunun."</string>
- <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB hata ayıklamasını devre dışı bırakmak için tıklayın."</string>
+ <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB hata ayıklamasını devre dışı bırakmak için seçin."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Hata raporu alınıyor…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Hata raporu paylaşılsın mı?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Hata raporu paylaşılıyor..."</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Kıyı kesimlerini ve nehir kenarlarını hemen boşaltarak yüksek yerler gibi daha güvenli bölgelere gidin."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Sakin olun ve yakınlarda sığınabileceğiniz bir yer bulun."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Acil durum mesajları testi"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM\'e izin verilmiyor"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM için temel hazırlık yapılmadı"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 79bf1f9f6d1f..0e318e7438a7 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1052,7 +1052,7 @@
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"Очистити налаштування за умовчанням у меню Налаштування системи &gt; Програми &gt; Завантажені."</string>
<string name="chooseActivity" msgid="7486876147751803333">"Виберіть дію"</string>
<string name="chooseUsbActivity" msgid="6894748416073583509">"Вибрати програму для пристрою USB"</string>
- <string name="noApplications" msgid="2991814273936504689">"Жодна програма не може виконати цю дію."</string>
+ <string name="noApplications" msgid="2991814273936504689">"Жодний додаток не може виконати цю дію."</string>
<string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g>: збій у роботі"</string>
<string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g>: збій у роботі"</string>
<string name="aerr_application_repeated" msgid="3146328699537439573">"Додаток <xliff:g id="APPLICATION">%1$s</xliff:g> періодично перестає працювати"</string>
@@ -1228,7 +1228,7 @@
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Торкніться, щоб дізнатися більше"</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="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>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Надсилається звіт про помилку…"</string>
@@ -1837,6 +1837,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Негайно евакуюйтеся з прибережних районів і територій поблизу річок у безпечніше місце, як-от на територію на підвищенні."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Не хвилюйтеся та знайдіть прихисток поблизу."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Перевірка екстрених повідомлень"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM-карта заборонена"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM-карту не затверджено"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 38353f142e3d..da90d589052d 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -118,7 +118,9 @@
<string name="roamingText12" msgid="1189071119992726320">"رومنگ بینر آف"</string>
<string name="roamingTextSearching" msgid="8360141885972279963">"سروس کی تلاش کر رہا ہے"</string>
<string name="wfcRegErrorTitle" msgid="2301376280632110664">"‏Wi-Fi کالنگ"</string>
- <!-- no translation found for wfcOperatorErrorAlertMessages:0 (3910386316304772394) -->
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item msgid="3910386316304772394">"‏Wi-Fi سے کالز کرنے اور پیغامات بھیجنے کے لیے، پہلے اپنے کیریئر سے اس سروس کو سیٹ اپ کرنے کے لیے کہیں۔ پھر ترتیبات سے دوبارہ Wi-Fi کالنگ آن کریں۔ (خراب کوڈ: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ </string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="6177300162212449033">"اپنے کیریئر کے ساتھ رجسٹر کریں"</item>
</string-array>
@@ -1768,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"ساحلی خطوں اور دریائی کناروں کے علاقوں کو فوری طور پر خالی کر کے اونچے ٹیلے جیسے کسی زیادہ محفوظ مقام پر چلے جائیں۔"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"پُرسکون رہیں اور قریبی پناہ حاصل کریں۔"</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"ایمرجنسی پیغامات کی جانچ"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"‏SIM کی اجازت نہیں ہے"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"‏SIM فراہم کردہ نہیں ہے"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index b20440117fb1..d93a0f5e640f 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1770,6 +1770,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Qirg‘oq va daryo bo‘ylaridan yuqori tepalik kabi xavfsiz joylarga darhol evakuatsiya qiling."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Tinchlaning va yaqin-atrofdan boshpana qidiring."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Favqulodda holatlar uchun sinov xabarlari"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM karta ishlatish taqiqlangan"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM karta yo‘q"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 689c31f00cbe..4e935127d573 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1182,7 +1182,7 @@
<string name="usb_notification_message" msgid="3370903770828407960">"Nhấn để biết thêm tùy chọn."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Phụ kiện âm thanh không được hỗ trợ"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Nhấn để biết thêm thông tin"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"Gỡ lỗi USB đã được kết nối"</string>
+ <string name="adb_active_notification_title" msgid="6729044778949189918">"Đã kết nối gỡ lỗi USB"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"Nhấn để vô hiệu hóa gỡ lỗi USB."</string>
<string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Chọn để vô hiệu hóa gỡ lỗi USB."</string>
<string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Đang thu thập báo cáo lỗi…"</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Ngay lập tức sơ tán khỏi các vùng ven biển và khu vực ven sông để tới một nơi an toàn hơn như vùng đất cao."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Hãy bình tĩnh và tìm kiếm nơi trú ẩn gần đó."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Kiểm tra thông báo khẩn cấp"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM không được cho phép"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM không được cấp phép"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index d22c09cc9537..0a39be07eb22 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1182,9 +1182,9 @@
<string name="usb_notification_message" msgid="3370903770828407960">"点按即可查看更多选项。"</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"音频配件不受支持"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"点按即可了解详情"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"已连接到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="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>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享错误报告…"</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"请立即从沿海和河滨区域撤离到高地等较安全的地方。"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"请保持冷静,并寻找附近的避难地点。"</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"紧急消息测试"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"不受允许的 SIM 卡"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"未配置的 SIM 卡"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 76187d8fe647..e9a19ca59826 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -83,7 +83,7 @@
<string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"沒有語音/緊急服務"</string>
<string name="RestrictedStateContent" msgid="4278821484643362350">"您所在位置的流動網絡暫不提供這項服務"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"無法連接網絡"</string>
- <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"如要改善接收品質,請前往 [設定] &gt; [網絡與互聯網] &gt; [流動網絡] &gt; [偏好的網絡類型],然後選取其他網路類型。"</string>
+ <string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"如要接收更強訊號,請前往 [設定] &gt; [網絡與互聯網] &gt; [流動網絡] &gt; [偏好的網絡類型] 更改網絡類型。"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"通知"</string>
<string name="notification_channel_call_forward" msgid="2419697808481833249">"來電轉駁"</string>
<string name="notification_channel_emergency_callback" msgid="6686166232265733921">"緊急回撥模式"</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"請立即從沿海和河岸地區撤離,前往高地等較安全的地點。"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"請保持冷靜,並尋找附近的避難所。"</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"緊急訊息測試"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"不允許使用 SIM 卡"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"無法識別 SIM 卡"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 3af73739bd95..a040520e388c 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1184,7 +1184,7 @@
<string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"輕觸即可瞭解詳情"</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="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>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享錯誤報告…"</string>
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"請立即從沿海與河岸地區撤離,前往高地這類較安全的地點。"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"請保持冷靜並尋找附近的避難地點。"</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"緊急訊息測試"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"不受允許的 SIM 卡"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"未佈建的 SIM 卡"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 77bcd8402b3f..5ab61a6763aa 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1769,6 +1769,8 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Phuma ngokushesha kusukela kuzifunda ezingasolwandle nasezindaweni zemifula uye endaweni ephephile efana nendawo ephakeme."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Hlala ubeke umoya phansi uphinde ufune ukukhuselwa eduze."</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"Ukuhlolwa kwemilayezo yesimo esiphuthumayo"</string>
+ <!-- no translation found for notification_reply_button_accessibility (3621714652387814344) -->
+ <skip />
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="7729819349669603406">"I-SIM ayivunyelwe"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"I-SIM ayinikezelwe"</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index ced22cc37f5a..01b8e1558fb3 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -561,6 +561,35 @@
to be set for all windows of this activity -->
<attr name="showForAllUsers" format="boolean" />
+ <!-- Specifies whether an {@link Activity} should be shown on top of the the lock screen
+ whenever the lockscreen is up and the activity is resumed. Normally an activity will be
+ transitioned to the stopped state if it is started while the lockscreen is up, but with
+ this flag set the activity will remain in the resumed state visible on-top of the lock
+ screen.
+
+ <p>This should be used instead of {@link android.view.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
+ flag set for Windows. When using the Window flag during activity startup, there may not be
+ time to add it before the system stops your activity for being behind the lock-screen.
+ This leads to a double life-cycle as it is then restarted.</p> -->
+ <attr name="showWhenLocked" format="boolean" />
+
+ <!-- Specifies whether the screen should be turned on when the {@link Activity} is resumed.
+ Normally an activity will be transitioned to the stopped state if it is started while the
+ screen if off, but with this flag set the activity will cause the screen to turn on if the
+ activity will be visible and resumed due to the screen coming on. The screen will not be
+ turned on if the activity won't be visible after the screen is turned on. This flag is
+ normally used in conjunction with the {@link android.R.attr#showWhenLocked} flag to make
+ sure the activity is visible after the screen is turned on when the lockscreen is up. In
+ addition, if this flag is set and the activity calls
+ {@link KeyguardManager#requestDismissKeyguard(Activity, KeyguardManager.KeyguardDismissCallback)}
+ the screen will turn on.
+
+ <p>This should be used instead of {@link android.view.LayoutParams.FLAG_TURN_SCREEN_ON}
+ flag set for Windows. When using the Window flag during activity startup, there may not be
+ time to add it before the system stops your activity because the screen has not yet turned
+ on. This leads to a double life-cycle as it is then restarted.</p> -->
+ <attr name="turnScreenOn" format="boolean" />
+
<!-- Specify the authorities under which this content provider can be
found. Multiple authorities may be supplied by separating them
with a semicolon. Authority names should use a Java-style naming
@@ -2093,6 +2122,10 @@
<attr name="maxAspectRatio" />
<attr name="lockTaskMode" />
<attr name="showForAllUsers" />
+
+ <attr name="showWhenLocked" />
+ <attr name="turnScreenOn" />
+
<attr name="directBootAware" />
<!-- @hide This activity is always focusable regardless of if it is in a task/stack whose
activities are normally not focusable.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3033f8c6543a..55030d533db7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -289,6 +289,13 @@
Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
<integer translatable="false" name="config_networkAvoidBadWifi">1</integer>
+ <!-- If the hardware supports specially marking packets that caused a wakeup of the
+ main CPU, set this value to the mark used. -->
+ <integer name="config_networkWakeupPacketMark">0</integer>
+
+ <!-- Mask to use when checking skb mark defined in config_networkWakeupPacketMark above. -->
+ <integer name="config_networkWakeupPacketMask">0</integer>
+
<!-- Default value for ConnectivityManager.getMultipathPreference() on metered networks. Actual
device behaviour is controlled by Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE.
This is the default value of that setting. -->
@@ -407,12 +414,21 @@
<!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
<!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
<!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
+ <!-- This list is also modified by code within the framework, including:
+
+ - TYPE_ETHERNET (9) is prepended to this list, and
+ - the output of TelephonyManager.getTetherApnRequired()
+ determines whether both TYPE_MOBILE (0) and TYPE_HIPRI (5)
+ or TYPE_MOBILE_DUN (4) are appended (if not already present).
+
+ For other changes applied to this list, now and in the future, see
+ com.android.server.connectivity.tethering.TetheringConfiguration.
+ -->
<integer-array translatable="false" name="config_tether_upstream_types">
<item>0</item>
<item>1</item>
<item>5</item>
<item>7</item>
- <item>9</item>
</integer-array>
<!-- If the DUN connection for this CDMA device supports more than just DUN -->
@@ -2975,4 +2991,7 @@
<!-- Show area update info settings in CellBroadcastReceiver and information in SIM status in Settings app -->
<bool name="config_showAreaUpdateInfoSettings">false</bool>
+
+ <!-- Enable the RingtonePickerActivity in 'com.android.providers.media'. -->
+ <bool name="config_defaultRingtonePickerEnabled">true</bool>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 5e2334d20da1..fa33d567983e 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -67,6 +67,9 @@
<!-- The amount to leave on-screen when the PIP is minimized. -->
<dimen name="pip_minimized_visible_size">48dp</dimen>
+ <!-- The the PIP decelerates at while moving from a fling. -->
+ <dimen name="pip_fling_deceleration">-3000dp</dimen>
+
<!-- Min width for a tablet device -->
<dimen name="min_xlarge_screen_width">800dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 48e667a06aa0..2a4881d6b167 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2843,6 +2843,8 @@
<eat-comment />
<public-group type="attr" first-id="0x01010569">
+ <public name="showWhenLocked"/>
+ <public name="turnScreenOn"/>
</public-group>
<public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c4e43a35b113..d9ce7fb47069 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1570,6 +1570,7 @@
<java-symbol type="dimen" name="docked_stack_divider_insets" />
<java-symbol type="dimen" name="docked_stack_minimize_thickness" />
<java-symbol type="dimen" name="pip_minimized_visible_size" />
+ <java-symbol type="dimen" name="pip_fling_deceleration" />
<java-symbol type="integer" name="config_dockedStackDividerSnapMode" />
<java-symbol type="integer" name="config_pictureInPictureSnapMode" />
<java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
@@ -1826,6 +1827,8 @@
<java-symbol type="integer" name="config_networkNotifySwitchType" />
<java-symbol type="array" name="config_networkNotifySwitches" />
<java-symbol type="integer" name="config_networkAvoidBadWifi" />
+ <java-symbol type="integer" name="config_networkWakeupPacketMark" />
+ <java-symbol type="integer" name="config_networkWakeupPacketMask" />
<java-symbol type="integer" name="config_networkMeteredMultipathPreference" />
<java-symbol type="integer" name="config_notificationsBatteryFullARGB" />
<java-symbol type="integer" name="config_notificationsBatteryLedOff" />
@@ -2902,6 +2905,7 @@
<java-symbol type="id" name="autofill_dataset_picker"/>
<java-symbol type="id" name="autofill_dataset_list"/>
<java-symbol type="id" name="autofill" />
+ <java-symbol type="id" name="autofill_save_custom_subtitle" />
<java-symbol type="id" name="autofill_save_title" />
<java-symbol type="id" name="autofill_save_subtitle" />
<java-symbol type="id" name="autofill_save_no" />
@@ -3048,4 +3052,5 @@
<java-symbol type="string" name="popup_window_default_title" />
<java-symbol type="bool" name="config_showAreaUpdateInfoSettings" />
+ <java-symbol type="layout" name="shutdown_dialog" />
</resources>
diff --git a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
index c7cb43d3dbc0..7800f4ab0598 100644
--- a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
@@ -18,11 +18,12 @@ package android.database;
import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_COLUMNNAME_INDEX;
import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_DEFAULT_INDEX;
+
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDebug;
import android.database.sqlite.SQLiteException;
-import android.os.Handler;
import android.os.Parcel;
import android.test.AndroidTestCase;
import android.test.PerformanceTestCase;
@@ -40,6 +41,9 @@ import java.util.Arrays;
import java.util.List;
import java.util.Locale;
+/**
+ * Usage: bit FrameworksCoreTests:android.database.DatabaseGeneralTest
+ */
public class DatabaseGeneralTest extends AndroidTestCase implements PerformanceTestCase {
private static final String TAG = "DatabaseGeneralTest";
@@ -68,7 +72,7 @@ public class DatabaseGeneralTest extends AndroidTestCase implements PerformanceT
@Override
protected void tearDown() throws Exception {
mDatabase.close();
- mDatabaseFile.delete();
+ SQLiteDatabase.deleteDatabase(mDatabaseFile);
super.tearDown();
}
@@ -1044,6 +1048,52 @@ public class DatabaseGeneralTest extends AndroidTestCase implements PerformanceT
}
}
+ @SmallTest
+ public void testOpenDatabaseLookasideConfig() {
+ // First check that lookaside is active
+ verifyLookasideStats(false);
+ // Reopen test db with lookaside disabled
+ mDatabase.close();
+ SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder()
+ .setLookasideConfig(0, 0).build();
+ mDatabase = SQLiteDatabase.openDatabase(mDatabaseFile.getPath(), params);
+ verifyLookasideStats(true);
+ }
+
+ @SmallTest
+ public void testOpenParamsSetLookasideConfigValidation() {
+ try {
+ SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder()
+ .setLookasideConfig(-1, 0).build();
+ fail("Negative slot size should be rejected");
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder()
+ .setLookasideConfig(0, -10).build();
+ fail("Negative slot count should be rejected");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ void verifyLookasideStats(boolean expectDisabled) {
+ boolean dbStatFound = false;
+ SQLiteDebug.PagerStats info = SQLiteDebug.getDatabaseInfo();
+ for (SQLiteDebug.DbStats dbStat : info.dbStats) {
+ if (dbStat.dbName.endsWith(mDatabaseFile.getName())) {
+ dbStatFound = true;
+ Log.i(TAG, "Lookaside for " + dbStat.dbName + " " + dbStat.lookaside);
+ if (expectDisabled) {
+ assertTrue("lookaside slots count should be zero", dbStat.lookaside == 0);
+ } else {
+ assertTrue("lookaside slots count should be greater than zero",
+ dbStat.lookaside > 0);
+ }
+ }
+ }
+ assertTrue("No dbstat found for " + mDatabaseFile.getName(), dbStatFound);
+ }
+
@LargeTest
public void testDefaultDatabaseErrorHandler() {
DefaultDatabaseErrorHandler errorHandler = new DefaultDatabaseErrorHandler();
diff --git a/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java b/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java
new file mode 100644
index 000000000000..75eeb93f5b9a
--- /dev/null
+++ b/core/tests/coretests/src/android/database/SQLiteOpenHelperTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.database;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDatabaseConfiguration;
+import android.database.sqlite.SQLiteDebug;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link SQLiteOpenHelper}
+ *
+ * <p>Run with: bit FrameworksCoreTests:android.database.SQLiteOpenHelperTest
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SQLiteOpenHelperTest {
+ private static final String TAG = "SQLiteOpenHelperTest";
+
+ private TestHelper mTestHelper;
+ private Context mContext;
+ private List<SQLiteOpenHelper> mHelpersToClose;
+
+ private static class TestHelper extends SQLiteOpenHelper {
+ TestHelper(Context context) { // In-memory
+ super(context, null, null, 1);
+ }
+
+ TestHelper(Context context, String name) {
+ super(context, name, null, 1);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ }
+ }
+
+ @Before
+ public void setup() {
+ mContext = InstrumentationRegistry.getContext();
+ mTestHelper = new TestHelper(mContext, "openhelper_test");
+ mHelpersToClose = new ArrayList<>();
+ mHelpersToClose.add(mTestHelper);
+ }
+
+ @After
+ public void teardown() {
+ for (SQLiteOpenHelper helper : mHelpersToClose) {
+ try {
+ helper.close();
+ if (mTestHelper.getDatabaseName() != null) {
+ SQLiteDatabase.deleteDatabase(
+ mContext.getDatabasePath(mTestHelper.getDatabaseName()));
+ }
+ } catch (RuntimeException ex) {
+ Log.w(TAG, "Error occured when closing db helper " + helper, ex);
+ }
+ }
+ }
+
+ @Test
+ public void testLookasideDefault() throws Exception {
+ assertNotNull(mTestHelper.getWritableDatabase());
+ verifyLookasideStats(false);
+ }
+
+ @Test
+ public void testLookasideDisabled() throws Exception {
+ mTestHelper.setLookasideConfig(0, 0);
+ assertNotNull(mTestHelper.getWritableDatabase());
+ verifyLookasideStats(true);
+ }
+
+ @Test
+ public void testInMemoryLookasideDisabled() throws Exception {
+ TestHelper memHelper = new TestHelper(mContext);
+ mHelpersToClose.add(memHelper);
+ memHelper.setLookasideConfig(0, 0);
+ assertNotNull(memHelper.getWritableDatabase());
+ verifyLookasideStats(SQLiteDatabaseConfiguration.MEMORY_DB_PATH, true);
+ }
+
+ @Test
+ public void testInMemoryLookasideDefault() throws Exception {
+ TestHelper memHelper = new TestHelper(mContext);
+ mHelpersToClose.add(memHelper);
+ assertNotNull(memHelper.getWritableDatabase());
+ verifyLookasideStats(SQLiteDatabaseConfiguration.MEMORY_DB_PATH, false);
+ }
+
+ @Test
+ public void testSetLookasideConfigValidation() {
+ try {
+ mTestHelper.setLookasideConfig(-1, 0);
+ fail("Negative slot size should be rejected");
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ mTestHelper.setLookasideConfig(0, -10);
+ fail("Negative slot count should be rejected");
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ mTestHelper.setLookasideConfig(1, 0);
+ fail("Illegal config should be rejected");
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ mTestHelper.setLookasideConfig(0, 1);
+ fail("Illegal config should be rejected");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ private void verifyLookasideStats(boolean expectDisabled) {
+ verifyLookasideStats(mTestHelper.getDatabaseName(), expectDisabled);
+ }
+
+ private static void verifyLookasideStats(String dbName, boolean expectDisabled) {
+ boolean dbStatFound = false;
+ SQLiteDebug.PagerStats info = SQLiteDebug.getDatabaseInfo();
+ for (SQLiteDebug.DbStats dbStat : info.dbStats) {
+ if (dbStat.dbName.endsWith(dbName)) {
+ dbStatFound = true;
+ Log.i(TAG, "Lookaside for " + dbStat.dbName + " " + dbStat.lookaside);
+ if (expectDisabled) {
+ assertTrue("lookaside slots count should be zero", dbStat.lookaside == 0);
+ } else {
+ assertTrue("lookaside slots count should be greater than zero",
+ dbStat.lookaside > 0);
+ }
+ }
+ }
+ assertTrue("No dbstat found for " + dbName, dbStatFound);
+ }
+}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 1ebd42925b98..b96bda1596b6 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -26,6 +26,7 @@ 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;
@@ -37,6 +38,7 @@ import java.util.HashSet;
import java.util.Set;
/** Tests that ensure appropriate settings are backed up. */
+@Presubmit
@RunWith(AndroidJUnit4.class)
@SmallTest
public class SettingsBackupTest {
@@ -98,6 +100,7 @@ public class SettingsBackupTest {
Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED,
Settings.Global.ALWAYS_FINISH_ACTIVITIES,
Settings.Global.ANIMATOR_DURATION_SCALE,
+ Settings.Global.ANOMALY_DETECTION_CONSTANTS,
Settings.Global.APN_DB_UPDATE_CONTENT_URL,
Settings.Global.APN_DB_UPDATE_METADATA_URL,
Settings.Global.APP_IDLE_CONSTANTS,
@@ -117,7 +120,6 @@ public class SettingsBackupTest {
Settings.Global.BLUETOOTH_INTEROPERABILITY_LIST,
Settings.Global.BLUETOOTH_MAP_CLIENT_PRIORITY_PREFIX,
Settings.Global.BLUETOOTH_MAP_PRIORITY_PREFIX,
- Settings.Global.BLUETOOTH_ON, // Candidate for backup?
Settings.Global.BLUETOOTH_PAN_PRIORITY_PREFIX,
Settings.Global.BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX,
Settings.Global.BLUETOOTH_SAP_PRIORITY_PREFIX,
@@ -166,6 +168,7 @@ public class SettingsBackupTest {
Settings.Global.DEVICE_IDLE_CONSTANTS,
Settings.Global.DEVICE_IDLE_CONSTANTS_WATCH,
Settings.Global.BATTERY_SAVER_CONSTANTS,
+ Settings.Global.DEFAULT_SM_DP_PLUS,
Settings.Global.DEVICE_NAME,
Settings.Global.DEVICE_POLICY_CONSTANTS,
Settings.Global.DEVICE_PROVISIONED,
@@ -190,11 +193,14 @@ public class SettingsBackupTest {
Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED,
Settings.Global.ENABLE_CACHE_QUOTA_CALCULATION,
Settings.Global.ENABLE_CELLULAR_ON_BOOT,
+ Settings.Global.ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE,
Settings.Global.ENABLE_DISKSTATS_LOGGING,
Settings.Global.ENABLE_EPHEMERAL_FEATURE,
Settings.Global.ENHANCED_4G_MODE_ENABLED,
Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
Settings.Global.ERROR_LOGCAT_PREFIX,
+ Settings.Global.EUICC_PROVISIONED,
+ Settings.Global.EUICC_WIPING_TIMEOUT_MILLIS,
Settings.Global.FANCY_IME_ANIMATIONS,
Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
Settings.Global.FSTRIM_MANDATORY_INTERVAL,
@@ -211,6 +217,7 @@ public class SettingsBackupTest {
Settings.Global.HTTP_PROXY,
Settings.Global.INET_CONDITION_DEBOUNCE_DOWN_DELAY,
Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY,
+ Settings.Global.INSTANT_APP_DEXOPT_ENABLED,
Settings.Global.INTENT_FIREWALL_UPDATE_CONTENT_URL,
Settings.Global.INTENT_FIREWALL_UPDATE_METADATA_URL,
Settings.Global.JOB_SCHEDULER_CONSTANTS,
@@ -330,6 +337,7 @@ public class SettingsBackupTest {
Settings.Global.TCP_DEFAULT_INIT_RWND,
Settings.Global.TETHER_DUN_APN,
Settings.Global.TETHER_DUN_REQUIRED,
+ Settings.Global.TETHER_OFFLOAD_DISABLED,
Settings.Global.TETHER_SUPPORTED,
Settings.Global.THEATER_MODE_ON,
Settings.Global.TRANSITION_ANIMATION_SCALE,
@@ -488,6 +496,7 @@ public class SettingsBackupTest {
Settings.Secure.TRUST_AGENTS_INITIALIZED,
Settings.Secure.TV_INPUT_CUSTOM_LABELS,
Settings.Secure.TV_INPUT_HIDDEN_INPUTS,
+ Settings.Secure.TV_USER_SETUP_COMPLETE,
Settings.Secure.UI_NIGHT_MODE, // candidate?
Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED,
Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS,
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 8bfb6f355b94..19cc7b30e341 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -147,6 +147,7 @@ applications that come with the platform
<permission name="android.permission.MANAGE_USERS"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
<permission name="android.permission.PERFORM_CDMA_PROVISIONING"/>
+ <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.READ_SEARCH_INDEXABLES"/>
<permission name="android.permission.REBOOT"/>
diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
index 8616d58a0319..1d0cfa5ff082 100644
--- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
+++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
@@ -289,6 +289,9 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
}
private void updateLayerBounds(Rect bounds) {
+ if (bounds.isEmpty()) {
+ return;
+ }
try {
suspendChildInvalidation();
updateLayerBoundsInternal(bounds);
@@ -1109,4 +1112,4 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
mCheckedStateful = false;
}
}
-} \ No newline at end of file
+}
diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java
index 0122338a7255..3dfd68018a6b 100644
--- a/graphics/java/android/graphics/drawable/TransitionDrawable.java
+++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java
@@ -118,6 +118,18 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba
}
/**
+ * Show the second layer on top of the first layer immediately
+ *
+ * @hide
+ */
+ public void showSecondLayer() {
+ mAlpha = 255;
+ mReverse = false;
+ mTransitionState = TRANSITION_NONE;
+ invalidateSelf();
+ }
+
+ /**
* Show only the first layer.
*/
public void resetTransition() {
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
index e6839997d57e..ae5ae1a26055 100644
--- a/legacy-test/Android.mk
+++ b/legacy-test/Android.mk
@@ -31,6 +31,96 @@ LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
include $(BUILD_JAVA_LIBRARY)
+# Generate the stub source files for legacy.test.stubs
+# ====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := \
+ core-oj \
+ core-libart \
+ framework \
+
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src
+
+LEGACY_TEST_OUTPUT_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/legacy.test.stubs_intermediates/api.txt
+LEGACY_TEST_OUTPUT_REMOVED_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/legacy.test.stubs_intermediates/removed.txt
+
+LEGACY_TEST_API_FILE := $(LOCAL_PATH)/api/legacy-test-current.txt
+LEGACY_TEST_REMOVED_API_FILE := $(LOCAL_PATH)/api/legacy-test-removed.txt
+
+LOCAL_DROIDDOC_OPTIONS:= \
+ -stubpackages android.test:android.test.suitebuilder.annotation:com.android.internal.util:junit.framework \
+ -stubsourceonly \
+ -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/legacy.test.stubs_intermediates/src \
+ -nodocs \
+ -api $(LEGACY_TEST_OUTPUT_API_FILE) \
+ -removedApi $(LEGACY_TEST_OUTPUT_REMOVED_API_FILE) \
+
+LOCAL_UNINSTALLABLE_MODULE := true
+LOCAL_MODULE := legacy-test-api-stubs-gen
+
+include $(BUILD_DROIDDOC)
+
+# Remember the target that will trigger the code generation.
+legacy_test_api_gen_stamp := $(full_target)
+
+# Add some additional dependencies
+$(LEGACY_TEST_OUTPUT_API_FILE): $(full_target)
+$(LEGACY_TEST_OUTPUT_REMOVED_API_FILE): $(full_target)
+
+# Build the legacy.test.stubs library
+# ===================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := legacy.test.stubs
+
+LOCAL_SOURCE_FILES_ALL_GENERATED := true
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Make sure to run droiddoc first to generate the stub source files.
+$(full_classes_compiled_jar) : $(legacy_test_api_gen_stamp)
+$(full_classes_jack) : $(legacy_test_api_gen_stamp)
+
+# Archive a copy of the classes.jar in SDK build.
+$(call dist-for-goals,sdk win_sdk,$(full_classes_jar):legacy.test.stubs.jar)
+
+# Check that the legacy.test.stubs library has not changed
+# ========================================================
+
+# Check that the API we're building hasn't changed from the not-yet-released
+# SDK version.
+$(eval $(call check-api, \
+ check-legacy-test-api-current, \
+ $(LEGACY_TEST_API_FILE), \
+ $(LEGACY_TEST_OUTPUT_API_FILE), \
+ $(LEGACY_TEST_REMOVED_API_FILE), \
+ $(LEGACY_TEST_OUTPUT_REMOVED_API_FILE), \
+ -error 2 -error 3 -error 4 -error 5 -error 6 \
+ -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
+ -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 \
+ -error 25 -error 26 -error 27, \
+ cat $(LOCAL_PATH)/api/apicheck_msg_legacy_test.txt, \
+ check-legacy-test-api, \
+ $(call doc-timestamp-for,legacy-test-api-stubs-gen) \
+ ))
+
+.PHONY: check-legacy-test-api
+checkapi: check-legacy-test-api
+
+.PHONY: update-legacy-test-api
+update-api: update-legacy-test-api
+
+update-legacy-test-api: $(LEGACY_TEST_OUTPUT_API_FILE) | $(ACP)
+ @echo Copying current.txt
+ $(hide) $(ACP) $(LEGACY_TEST_OUTPUT_API_FILE) $(LEGACY_TEST_API_FILE)
+ @echo Copying removed.txt
+ $(hide) $(ACP) $(LEGACY_TEST_OUTPUT_REMOVED_API_FILE) $(LEGACY_TEST_REMOVED_API_FILE)
+
# Build the legacy-android-test library
# =====================================
# This contains the android.test classes that were in Android API level 25,
diff --git a/legacy-test/api/apicheck_msg_legacy_test.txt b/legacy-test/api/apicheck_msg_legacy_test.txt
new file mode 100644
index 000000000000..ad5f2359b8b1
--- /dev/null
+++ b/legacy-test/api/apicheck_msg_legacy_test.txt
@@ -0,0 +1,17 @@
+
+******************************
+You have tried to change the API from what has been previously approved.
+
+To make these errors go away, you have two choices:
+ 1) You can add "@hide" javadoc comments to the methods, etc. listed in the
+ errors above.
+
+ 2) You can update legacy-test-current.txt by executing the following command:
+ make update-legacy-test-api
+
+ To submit the revised legacy-test-current.txt to the main Android repository,
+ you will need approval.
+******************************
+
+
+
diff --git a/legacy-test/api/legacy-test-current.txt b/legacy-test/api/legacy-test-current.txt
new file mode 100644
index 000000000000..7ebd6aa8a4a2
--- /dev/null
+++ b/legacy-test/api/legacy-test-current.txt
@@ -0,0 +1,227 @@
+package android.test {
+
+ public deprecated class AndroidTestCase extends junit.framework.TestCase {
+ ctor public AndroidTestCase();
+ method public void assertActivityRequiresPermission(java.lang.String, java.lang.String, java.lang.String);
+ method public void assertReadingContentUriRequiresPermission(android.net.Uri, java.lang.String);
+ method public void assertWritingContentUriRequiresPermission(android.net.Uri, java.lang.String);
+ method public android.content.Context getContext();
+ method protected void scrubClass(java.lang.Class<?>) throws java.lang.IllegalAccessException;
+ method public void setContext(android.content.Context);
+ method public void testAndroidTestCaseSetupProperly();
+ field protected android.content.Context mContext;
+ }
+
+ public abstract deprecated class FlakyTest implements java.lang.annotation.Annotation {
+ }
+
+ public deprecated class InstrumentationTestCase extends junit.framework.TestCase {
+ ctor public InstrumentationTestCase();
+ method public android.app.Instrumentation getInstrumentation();
+ method public deprecated void injectInsrumentation(android.app.Instrumentation);
+ method public void injectInstrumentation(android.app.Instrumentation);
+ method public final <T extends android.app.Activity> T launchActivity(java.lang.String, java.lang.Class<T>, android.os.Bundle);
+ method public final <T extends android.app.Activity> T launchActivityWithIntent(java.lang.String, java.lang.Class<T>, android.content.Intent);
+ method public void runTestOnUiThread(java.lang.Runnable) throws java.lang.Throwable;
+ method public void sendKeys(java.lang.String);
+ method public void sendKeys(int...);
+ method public void sendRepeatedKeys(int...);
+ }
+
+ public deprecated class InstrumentationTestSuite extends junit.framework.TestSuite {
+ ctor public InstrumentationTestSuite(android.app.Instrumentation);
+ ctor public InstrumentationTestSuite(java.lang.String, android.app.Instrumentation);
+ ctor public InstrumentationTestSuite(java.lang.Class, android.app.Instrumentation);
+ method public void addTestSuite(java.lang.Class);
+ }
+
+ public abstract deprecated interface PerformanceTestCase {
+ method public abstract boolean isPerformanceOnly();
+ method public abstract int startPerformance(android.test.PerformanceTestCase.Intermediates);
+ }
+
+ public static abstract interface PerformanceTestCase.Intermediates {
+ method public abstract void addIntermediate(java.lang.String);
+ method public abstract void addIntermediate(java.lang.String, long);
+ method public abstract void finishTiming(boolean);
+ method public abstract void setInternalIterations(int);
+ method public abstract void startTiming(boolean);
+ }
+
+ public abstract deprecated class UiThreadTest implements java.lang.annotation.Annotation {
+ }
+
+}
+
+package android.test.suitebuilder.annotation {
+
+ public abstract deprecated class LargeTest implements java.lang.annotation.Annotation {
+ }
+
+ public abstract deprecated class MediumTest implements java.lang.annotation.Annotation {
+ }
+
+ public abstract deprecated class SmallTest implements java.lang.annotation.Annotation {
+ }
+
+ public abstract deprecated class Smoke implements java.lang.annotation.Annotation {
+ }
+
+ public abstract deprecated class Suppress implements java.lang.annotation.Annotation {
+ }
+
+}
+
+package com.android.internal.util {
+
+ public abstract deprecated interface Predicate<T> {
+ method public abstract boolean apply(T);
+ }
+
+}
+
+package junit.framework {
+
+ public class Assert {
+ ctor protected Assert();
+ method public static void assertEquals(java.lang.String, java.lang.Object, java.lang.Object);
+ method public static void assertEquals(java.lang.Object, java.lang.Object);
+ method public static void assertEquals(java.lang.String, java.lang.String, java.lang.String);
+ method public static void assertEquals(java.lang.String, java.lang.String);
+ method public static void assertEquals(java.lang.String, double, double, double);
+ method public static void assertEquals(double, double, double);
+ method public static void assertEquals(java.lang.String, float, float, float);
+ method public static void assertEquals(float, float, float);
+ method public static void assertEquals(java.lang.String, long, long);
+ method public static void assertEquals(long, long);
+ method public static void assertEquals(java.lang.String, boolean, boolean);
+ method public static void assertEquals(boolean, boolean);
+ method public static void assertEquals(java.lang.String, byte, byte);
+ method public static void assertEquals(byte, byte);
+ method public static void assertEquals(java.lang.String, char, char);
+ method public static void assertEquals(char, char);
+ method public static void assertEquals(java.lang.String, short, short);
+ method public static void assertEquals(short, short);
+ method public static void assertEquals(java.lang.String, int, int);
+ method public static void assertEquals(int, int);
+ method public static void assertFalse(java.lang.String, boolean);
+ method public static void assertFalse(boolean);
+ method public static void assertNotNull(java.lang.Object);
+ method public static void assertNotNull(java.lang.String, java.lang.Object);
+ method public static void assertNotSame(java.lang.String, java.lang.Object, java.lang.Object);
+ method public static void assertNotSame(java.lang.Object, java.lang.Object);
+ method public static void assertNull(java.lang.Object);
+ method public static void assertNull(java.lang.String, java.lang.Object);
+ method public static void assertSame(java.lang.String, java.lang.Object, java.lang.Object);
+ method public static void assertSame(java.lang.Object, java.lang.Object);
+ method public static void assertTrue(java.lang.String, boolean);
+ method public static void assertTrue(boolean);
+ method public static void fail(java.lang.String);
+ method public static void fail();
+ method public static void failNotEquals(java.lang.String, java.lang.Object, java.lang.Object);
+ method public static void failNotSame(java.lang.String, java.lang.Object, java.lang.Object);
+ method public static void failSame(java.lang.String);
+ method public static java.lang.String format(java.lang.String, java.lang.Object, java.lang.Object);
+ }
+
+ public class AssertionFailedError extends java.lang.AssertionError {
+ ctor public AssertionFailedError();
+ ctor public AssertionFailedError(java.lang.String);
+ }
+
+ public class ComparisonFailure extends junit.framework.AssertionFailedError {
+ ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String);
+ method public java.lang.String getActual();
+ method public java.lang.String getExpected();
+ }
+
+ public abstract interface Protectable {
+ method public abstract void protect() throws java.lang.Throwable;
+ }
+
+ public abstract interface Test {
+ method public abstract int countTestCases();
+ method public abstract void run(junit.framework.TestResult);
+ }
+
+ public abstract class TestCase extends junit.framework.Assert implements junit.framework.Test {
+ ctor public TestCase();
+ ctor public TestCase(java.lang.String);
+ method public int countTestCases();
+ method protected junit.framework.TestResult createResult();
+ method public java.lang.String getName();
+ method public junit.framework.TestResult run();
+ method public void run(junit.framework.TestResult);
+ method public void runBare() throws java.lang.Throwable;
+ method protected void runTest() throws java.lang.Throwable;
+ method public void setName(java.lang.String);
+ method protected void setUp() throws java.lang.Exception;
+ method protected void tearDown() throws java.lang.Exception;
+ }
+
+ public class TestFailure {
+ ctor public TestFailure(junit.framework.Test, java.lang.Throwable);
+ method public java.lang.String exceptionMessage();
+ method public junit.framework.Test failedTest();
+ method public boolean isFailure();
+ method public java.lang.Throwable thrownException();
+ method public java.lang.String trace();
+ field protected junit.framework.Test fFailedTest;
+ field protected java.lang.Throwable fThrownException;
+ }
+
+ public abstract interface TestListener {
+ method public abstract void addError(junit.framework.Test, java.lang.Throwable);
+ method public abstract void addFailure(junit.framework.Test, junit.framework.AssertionFailedError);
+ method public abstract void endTest(junit.framework.Test);
+ method public abstract void startTest(junit.framework.Test);
+ }
+
+ public class TestResult {
+ ctor public TestResult();
+ method public synchronized void addError(junit.framework.Test, java.lang.Throwable);
+ method public synchronized void addFailure(junit.framework.Test, junit.framework.AssertionFailedError);
+ method public synchronized void addListener(junit.framework.TestListener);
+ method public void endTest(junit.framework.Test);
+ method public synchronized int errorCount();
+ method public synchronized java.util.Enumeration<junit.framework.TestFailure> errors();
+ method public synchronized int failureCount();
+ method public synchronized java.util.Enumeration<junit.framework.TestFailure> failures();
+ method public synchronized void removeListener(junit.framework.TestListener);
+ method protected void run(junit.framework.TestCase);
+ method public synchronized int runCount();
+ method public void runProtected(junit.framework.Test, junit.framework.Protectable);
+ method public synchronized boolean shouldStop();
+ method public void startTest(junit.framework.Test);
+ method public synchronized void stop();
+ method public synchronized boolean wasSuccessful();
+ field protected java.util.Vector<junit.framework.TestFailure> fErrors;
+ field protected java.util.Vector<junit.framework.TestFailure> fFailures;
+ field protected java.util.Vector<junit.framework.TestListener> fListeners;
+ field protected int fRunTests;
+ }
+
+ public class TestSuite implements junit.framework.Test {
+ ctor public TestSuite();
+ ctor public TestSuite(java.lang.Class<?>);
+ ctor public TestSuite(java.lang.Class<? extends junit.framework.TestCase>, java.lang.String);
+ ctor public TestSuite(java.lang.String);
+ ctor public TestSuite(java.lang.Class<?>...);
+ ctor public TestSuite(java.lang.Class<? extends junit.framework.TestCase>[], java.lang.String);
+ method public void addTest(junit.framework.Test);
+ method public void addTestSuite(java.lang.Class<? extends junit.framework.TestCase>);
+ method public int countTestCases();
+ method public static junit.framework.Test createTest(java.lang.Class<?>, java.lang.String);
+ method public java.lang.String getName();
+ method public static java.lang.reflect.Constructor<?> getTestConstructor(java.lang.Class<?>) throws java.lang.NoSuchMethodException;
+ method public void run(junit.framework.TestResult);
+ method public void runTest(junit.framework.Test, junit.framework.TestResult);
+ method public void setName(java.lang.String);
+ method public junit.framework.Test testAt(int);
+ method public int testCount();
+ method public java.util.Enumeration<junit.framework.Test> tests();
+ method public static junit.framework.Test warning(java.lang.String);
+ }
+
+}
+
diff --git a/legacy-test/api/legacy-test-removed.txt b/legacy-test/api/legacy-test-removed.txt
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/legacy-test/api/legacy-test-removed.txt
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 0782269d7de1..99ccc98a1b31 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -1901,8 +1901,6 @@ int ResTable_config::compare(const ResTable_config& o) const {
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);
@@ -1914,6 +1912,11 @@ int ResTable_config::compare(const ResTable_config& o) const {
diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp);
if (diff != 0) return diff;
diff = (int32_t)(screenSizeDp - o.screenSizeDp);
+ if (diff != 0) return diff;
+
+ // Version MUST be last to ensure that a sorted list of configurations will always have the
+ // versions beside each other.
+ diff = (int32_t)(version - o.version);
return (int)diff;
}
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 2e9a6e895d8a..c19c1a11e3e2 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -457,11 +457,13 @@ GlopBuilder& GlopBuilder::setFillTextureLayer(GlLayer& layer, float alpha) {
return *this;
}
-GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture, Matrix4& textureTransform) {
+GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture, Matrix4& textureTransform,
+ bool requiresFilter) {
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
- mOutGlop->fill.texture = { &texture, GL_LINEAR, GL_CLAMP_TO_EDGE, &textureTransform };
+ GLenum filter = requiresFilter ? GL_LINEAR : GL_NEAREST;
+ mOutGlop->fill.texture = { &texture, filter, GL_CLAMP_TO_EDGE, &textureTransform };
setFill(SK_ColorWHITE, 1.0f, SkBlendMode::kSrc, Blend::ModeOrderSwap::NoSwap,
nullptr, nullptr);
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index 87b1568ed72b..6d11da19e138 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -75,7 +75,8 @@ public:
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);
+ GlopBuilder& setFillExternalTexture(Texture& texture, Matrix4& textureTransform,
+ bool requiresFilter);
GlopBuilder& setTransform(const Matrix4& canvas, const int transformFlags);
diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp
index b073070b58b6..19d5d9d2250e 100644
--- a/libs/hwui/OpenGLReadback.cpp
+++ b/libs/hwui/OpenGLReadback.cpp
@@ -199,6 +199,7 @@ inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
GL_TEXTURE_2D, texture, 0);
{
+ bool requiresFilter;
// Draw & readback
renderState.setViewport(destWidth, destHeight);
renderState.scissor().setEnabled(false);
@@ -216,12 +217,17 @@ inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
croppedTexTransform.scale(srcRect.getWidth() / sourceTexture.width(),
srcRect.getHeight() / sourceTexture.height(), 1);
croppedTexTransform.multiply(sFlipV);
+ requiresFilter = srcRect.getWidth() != (float) destWidth
+ || srcRect.getHeight() != (float) destHeight;
+ } else {
+ requiresFilter = sourceTexture.width() != (uint32_t) destWidth
+ || sourceTexture.height() != (uint32_t) destHeight;
}
Glop glop;
GlopBuilder(renderState, caches, &glop)
.setRoundRectClipState(nullptr)
.setMeshTexturedUnitQuad(nullptr)
- .setFillExternalTexture(sourceTexture, croppedTexTransform)
+ .setFillExternalTexture(sourceTexture, croppedTexTransform, requiresFilter)
.setTransform(Matrix4::identity(), TransformFlags::None)
.setModelViewMapUnitToRect(Rect(destWidth, destHeight))
.build();
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 912551f5e4a9..b2903c4689e0 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -97,13 +97,12 @@ public final class GnssStatus {
CONSTELLATION_QZSS, CONSTELLATION_BEIDOU, CONSTELLATION_GALILEO})
public @interface ConstellationType {}
- /* These package private values are modified by the LocationManager class */
- /* package */ int[] mSvidWithFlags;
- /* package */ float[] mCn0DbHz;
- /* package */ float[] mElevations;
- /* package */ float[] mAzimuths;
- /* package */ int mSvCount;
- /* package */ float[] mCarrierFrequencies;
+ final int[] mSvidWithFlags;
+ final float[] mCn0DbHz;
+ final float[] mElevations;
+ final float[] mAzimuths;
+ final int mSvCount;
+ final float[] mCarrierFrequencies;
GnssStatus(int svCount, int[] svidWithFlags, float[] cn0s, float[] elevations,
float[] azimuths, float[] carrierFrequencies) {
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 26ac2a23d8c5..968f596e0cc5 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -74,7 +74,8 @@ public class LocationManager {
new HashMap<>();
private final HashMap<OnNmeaMessageListener, GnssStatusListenerTransport> mGnssNmeaListeners =
new HashMap<>();
- private GnssStatus mGnssStatus;
+ // volatile + GnssStatus final-fields pattern to avoid a partially published object
+ private volatile GnssStatus mGnssStatus;
private int mTimeToFirstFix;
/**
@@ -1563,7 +1564,7 @@ public class LocationManager {
float[] cn0s, float[] elevations, float[] azimuths, float[] carrierFreqs) {
if (mGnssCallback != null) {
mGnssStatus = new GnssStatus(svCount, prnWithFlags, cn0s, elevations, azimuths,
- carrierFreqs);
+ carrierFreqs);
Message msg = Message.obtain();
msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
@@ -1949,7 +1950,7 @@ public class LocationManager {
status = new GpsStatus();
}
// When mGnssStatus is null, that means that this method is called outside
- // onGpsStatusChanged(). Return an empty status to maintain backwards compatibility.
+ // onGpsStatusChanged(). Return an empty status to maintain backwards compatibility.
if (mGnssStatus != null) {
status.setStatus(mGnssStatus, mTimeToFirstFix);
}
diff --git a/native/android/include/android/multinetwork.h b/native/android/include/android/multinetwork.h
new file mode 120000
index 000000000000..0feab3aa27cd
--- /dev/null
+++ b/native/android/include/android/multinetwork.h
@@ -0,0 +1 @@
+../../../../../native/include/android/multinetwork.h \ No newline at end of file
diff --git a/native/android/include/multinetwork.h b/native/android/include/multinetwork.h
deleted file mode 120000
index f9d051aa9f24..000000000000
--- a/native/android/include/multinetwork.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../../native/include/android/multinetwork.h \ No newline at end of file
diff --git a/packages/CarrierDefaultApp/res/values-ca/strings.xml b/packages/CarrierDefaultApp/res/values-ca/strings.xml
index c1ddbd39c15c..66a8f37b1cf0 100644
--- a/packages/CarrierDefaultApp/res/values-ca/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ca/strings.xml
@@ -10,7 +10,7 @@
<string name="no_mobile_data_connection_title" msgid="7449525772416200578">"No hi ha connexió de dades mòbils"</string>
<string name="no_mobile_data_connection" msgid="544980465184147010">"Afegeix un pla de dades o d\'itinerància amb %s"</string>
<string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Estat de les dades mòbils"</string>
- <string name="action_bar_label" msgid="4290345990334377177">"Inicia la sessió a la xarxa de telefonia mòbil"</string>
+ <string name="action_bar_label" msgid="4290345990334377177">"Inicia la sessió a la xarxa mòbil"</string>
<string name="ssl_error_warning" msgid="3127935140338254180">"La xarxa a què et vols connectar té problemes de seguretat."</string>
<string name="ssl_error_example" msgid="6188711843183058764">"Per exemple, la pàgina d\'inici de sessió podria no pertànyer a l\'organització que es mostra."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continua igualment mitjançant el navegador"</string>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index 3b29a6cd7b6c..1e262314284d 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -77,7 +77,7 @@ public class DeviceDiscoveryService extends Service {
private BluetoothAdapter mBluetoothAdapter;
private WifiManager mWifiManager;
- private BluetoothLeScanner mBLEScanner;
+ @Nullable private BluetoothLeScanner mBLEScanner;
private ScanSettings mDefaultScanSettings = new ScanSettings.Builder().build();
private List<DeviceFilter<?>> mFilters;
@@ -185,7 +185,7 @@ public class DeviceDiscoveryService extends Service {
mBluetoothAdapter.startDiscovery();
}
- if (shouldScan(mBLEFilters)) {
+ if (shouldScan(mBLEFilters) && mBLEScanner != null) {
mBLEScanCallback = new BLEScanCallback();
mBLEScanner.startScan(mBLEScanFilters, mDefaultScanSettings, mBLEScanCallback);
}
@@ -224,7 +224,7 @@ public class DeviceDiscoveryService extends Service {
unregisterReceiver(mBluetoothBroadcastReceiver);
mBluetoothBroadcastReceiver = null;
}
- mBLEScanner.stopScan(mBLEScanCallback);
+ if (mBLEScanner != null) mBLEScanner.stopScan(mBLEScanCallback);
if (mWifiBroadcastReceiver != null) {
unregisterReceiver(mWifiBroadcastReceiver);
mWifiBroadcastReceiver = null;
diff --git a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
index 49fe52be9127..9c29ff27d5e0 100644
--- a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
+++ b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4469836075319831821">"Štamp. iz memor."</string>
+ <string name="app_label" msgid="4469836075319831821">"Štampanje iz memorije"</string>
<string name="more_options_button" msgid="2243228396432556771">"Još opcija"</string>
<string name="label_destination" msgid="9132510997381599275">"Odredište"</string>
<string name="label_copies" msgid="3634531042822968308">"Kopije"</string>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index c20a5af89e66..cb23c3cc4b81 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4469836075319831821">"Штамп. из мемор."</string>
+ <string name="app_label" msgid="4469836075319831821">"Штампање из меморије"</string>
<string name="more_options_button" msgid="2243228396432556771">"Још опција"</string>
<string name="label_destination" msgid="9132510997381599275">"Одредиште"</string>
<string name="label_copies" msgid="3634531042822968308">"Копије"</string>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 6576035ddcf6..7e50996a76ec 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Gekoppel (geen media nie)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Gekoppel (geen boodskaptoegang nie)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Gekoppel (geen foon of media nie)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media-oudio"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Foonoproepe"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Lêeroordrag"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index d7ddedcf34b5..79cedfa58789 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"ተያይዟል (ምንም ማህደረ መረጃ የለም)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"ተገናኝቷል (ምንም የመልዕክት መዳረሻ የለም)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"ተያይዟል (ምንም ስልክ ወይም ማህደረ መረጃ የለም)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"የማህደረ መረጃ ኦዲዮ"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"የስልክ ጥሪዎች"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"ፋይል ማስተላለፍ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index c879100aef9c..d1b13a4da61b 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"متصل (بجهاز غير الوسائط)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"تم الاتصال (يتعذر الدخول إلى الرسائل)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"متصل (بجهاز غير الهاتف أو الوسائط)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"الإعدادات الصوتية للوسائط"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"المكالمات الهاتفية"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"نقل الملف"</string>
@@ -110,7 +118,7 @@
<string name="unknown" msgid="1592123443519355854">"غير معروف"</string>
<string name="running_process_item_user_label" msgid="3129887865552025943">"المستخدم: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="313159469856372621">"تم تعيين بعض الإعدادات الافتراضية"</string>
- <string name="launch_defaults_none" msgid="4241129108140034876">"لم يتم تعيين إعدادات افتراضية"</string>
+ <string name="launch_defaults_none" msgid="4241129108140034876">"لم يتم تعيين إعدادات تلقائية"</string>
<string name="tts_settings" msgid="8186971894801348327">"إعدادات تحويل النص إلى كلام"</string>
<string name="tts_settings_title" msgid="1237820681016639683">"إخراج تحويل النص إلى كلام"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"معدل سرعة الكلام"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 6b32c3533b8f..95ea112a6f3a 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Qoşuludur (media yoxdur)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Qoşulu (mesaj girişi yoxdur)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Bağlantı yaradılıb (telefon və ya media deyil)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media audio"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefon zəngləri"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Fayl transferi"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 0f323ddaea4f..7a2ee50fd3bb 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Povezano (bez medija)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Povezano je (nema pristupa porukama)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Povezano (bez telefona ili medija)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Zvuk medija"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefonski pozivi"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Prenos datoteke"</string>
@@ -352,7 +360,7 @@
<string name="disabled" msgid="9206776641295849915">"Onemogućeno"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Dozvoljeno"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Nije dozvoljeno"</string>
- <string name="install_other_apps" msgid="6986686991775883017">"Instalirajte nepozn. apl."</string>
+ <string name="install_other_apps" msgid="6986686991775883017">"Instaliranje nepoznatih aplikacija"</string>
<string name="home" msgid="3256884684164448244">"Početna za Podešavanja"</string>
<string-array name="battery_labels">
<item msgid="8494684293649631252">"0%"</item>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 5f7332cd806a..834e6897da09 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Падключэнне (без носьбіта)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Падлучана (без доступу да паведамленняў)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Падключаны (без тэлефона або носьбіта)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Аўдыё медыяпрылады"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Тэлефонныя выклікі"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Перадача файлаў"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index b69e290e02df..ce9ee567dfa4 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Свързано (без мултимедията)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Има връзка (няма достъп до съобщенията)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Свързано (без телефона или мултимедията)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Мултимедийно аудио"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Телефонни обаждания"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Прехвърляне на файл"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index e8faf5dfeaab..5093a6a75455 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"সংযুক্ত (কোনো মিডিয়া নেই)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"সংযুক্ত (কোনো বার্তা অ্যাক্সেস নেই)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"সংযুক্ত (কোনো ফোন বা মিডিয়া নেই)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"মিডিয়া অডিও"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"ফোন কল"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"ফাইল স্থানান্তর"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index deab61da1bb2..1af6e30725b0 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Povezano (bez medija)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Povezano (bez pristupa porukama)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Povezano (bez zvuka telefona ili medija)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Zvuk medija"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefonski pozivi"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Prenošenje fajla"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 438cbbbb16fe..a5524ae1c2fc 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Connectat (sense fitxers multimèdia)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Connectat (no hi ha accés als missatges)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Connectat (sense telèfon o disp. mult.)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Àudio multimèdia"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Trucades telefòniques"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transferència del fitxer"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 2b8f811eabae..8d82e80cf939 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Připojeno (žádná média)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Připojeno (bez přístupu ke zprávám)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Připojeno (žádný telefon nebo média)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Zvuk médií"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefonní hovory"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Přenos souborů"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index c82a0cb221bc..73662943730d 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Tilsluttet (intet medie)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Forbundet (ingen adgang til meddelelse)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Forbundet (ingen telefon eller medier)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Medielyd"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefonopkald"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Filoverførsel"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index a6e0fd9b870b..ccfa67535ee4 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Verbunden (außer Audiomedien)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Verbunden (ohne Nachrichtenzugriff)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Verbunden (außer Telefon- und Audiomedien)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media-Audio"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefonanrufe"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Dateiübertragung"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 7ae277829f47..e424b285793e 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Συνδεδεμένο (όχι μέσα)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Συνδεδεμένο (χωρίς πρόσβαση μηνύματος)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Συνδεδεμένο (χωρίς τηλέφωνο ή πολυμέσα)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Ήχος πολυμέσων"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Τηλεφωνικές κλήσεις"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Μεταφορά αρχείου"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index d10726f9dd01..de32f3c69bb2 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Connected (no media)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Connected (no message access)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Connected (no phone or media)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media audio"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Phone calls"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"File transfer"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index d10726f9dd01..de32f3c69bb2 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Connected (no media)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Connected (no message access)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Connected (no phone or media)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media audio"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Phone calls"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"File transfer"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index d10726f9dd01..de32f3c69bb2 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Connected (no media)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Connected (no message access)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Connected (no phone or media)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media audio"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Phone calls"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"File transfer"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 29490122fb9e..f261cbff8102 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Conectado (sin audio multimedia)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Conectado (sin acceso a mensajes)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Conectado (sin tel. ni audio multimedia)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Audio multimedia"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Llamadas telefónicas"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transferencia de archivos"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 487d84782279..d52ac0682e83 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Conectado (sin audio multimedia)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Conectado (sin acceso a mensajes)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Conectado (sin teléfono ni multimedia)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Audio multimedia"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Llamadas de teléfono"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transferencia de archivos"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 91e75912c1a4..5cb3e2a6dff9 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Ühendatud (meediat pole)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Ühendatud (sõnumita juurdepääs)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Ühendatud (pole telefoni ega meediat)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Meedia heli"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefonikõned"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Failiedastus"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 7f00f08f9bf5..e4b6c95d5d3e 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Konektatuta (ez dago euskarririk)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Konektatuta (mezuetarako sarbiderik ez)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Konektatuta (ez dago telef./euskarririk)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Euskarriaren audioa"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefono-deiak"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Fitxategi-transferentzia"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index fac966ad0f35..bf10b1ab3d41 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"متصل شد (بدون رسانه)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"متصل (عدم دسترسی به پیام)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"متصل شد (بدون تلفن یا رسانه)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"رسانه صوتی"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"تماس‌های تلفنی"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"انتقال فایل"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 3ec8e4883632..42a0127a4937 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Yhdistetty (ei median ääntä)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Yhdistetty (ei MAP)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Yhdistetty (ei puhelimen/median ääntä)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Median ääni"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Puhelut"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Tiedostonsiirto"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index bc4b7814da95..88fd9cbacb80 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Connecté (sans audio contenu mutimédia)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Connecté (sans accès aux messages)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Connecté (sans audio tel./multimédia)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Paramètres audio du support"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Appels téléphoniques"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transfert de fichier"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 4853bc8507fb..c5f951d8b308 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Connecté (sans audio contenu mutimédia)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Connecté (sans accès aux messages)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Connecté (sans audio tel./multimédia)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Multimédia"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Appels téléphoniques"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transfert de fichier"</string>
@@ -352,7 +360,7 @@
<string name="disabled" msgid="9206776641295849915">"Désactivée"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Autorisé"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Non autorisé"</string>
- <string name="install_other_apps" msgid="6986686991775883017">"Installation d\'applications inconnues"</string>
+ <string name="install_other_apps" msgid="6986686991775883017">"Installation d\'applis inconnues"</string>
<string name="home" msgid="3256884684164448244">"Paramètres"</string>
<string-array name="battery_labels">
<item msgid="8494684293649631252">"0 %"</item>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 90437127defe..d60d072426a1 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Conectado (sen ficheiros multimedia)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Conectado (sen acceso ás mensaxes)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Conectado (ningún teléfono nin soporte)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Audio multimedia"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Chamadas telefónicas"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transferencia de ficheiros"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 9ec0c33ac807..20d92f2b7052 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"કનેક્ટ કર્યું (મીડિયા નથી)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"કનેક્ટ કર્યું (કોઇ સંદેશ ઍક્સેસ નથી)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"કનેક્ટ કરેલ (કોઈ ફોન અથવા મીડિયા નથી)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"મીડિયા ઑડિઓ"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"ફોન કૉલ"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"ફાઇલ સ્થાનાંતરણ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 9078817233c3..217099d0547a 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"कनेक्‍ट है (मीडि‍या नहीं)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"कनेक्ट किया गया (कोई संदेश एक्सेस नहीं)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"कनेक्‍ट है (फ़ोन या मीडि‍या नहीं)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"मीडिया ऑडियो"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"फ़ोन कॉल"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"फ़ाइल स्थानांतरण"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index ed6f06e56c12..6c4f29386d3c 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Povezano (bez medija)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Povezano (bez pristupa porukama)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Povezano (bez telefona ili medija)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Medijski zvuk"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefonski pozivi"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Prijenos datoteke"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 822ff0b1da6c..479290ff225a 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Csatlakoztatva (nincs hordozó)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Csatlakoztatva (nincs üzenet-hozzáférés)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Csatlakoztatva (nincs telefon vagy hordozó)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Média audió"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefonhívások"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Fájlátvitel"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 1b7615b39a95..ec6c1a2f852c 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Միացված է (առանց մեդիա)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Միացված է (հաղորդագրությանը մուտք չկա)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Միացված է (առանց հեռախոսի և մեդիայի)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Մեդիա աուդիո"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Հեռախոսազանգեր"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Ֆայլերի փոխանցում"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 6e862b4f1d14..6027821a79c9 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Terhubung (kecuali media)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Tersambung (tidak ada akses pesan)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Terhubung (bukan telepon atau media)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Audio media"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Panggilan telepon"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transfer file"</string>
@@ -352,7 +360,7 @@
<string name="disabled" msgid="9206776641295849915">"Dinonaktifkan"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Diizinkan"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Tidak diizinkan"</string>
- <string name="install_other_apps" msgid="6986686991775883017">"Instal aplikasi yang tidak dikenal"</string>
+ <string name="install_other_apps" msgid="6986686991775883017">"Menginstal aplikasi yang tidak dikenal"</string>
<string name="home" msgid="3256884684164448244">"Layar Utama Setelan"</string>
<string-array name="battery_labels">
<item msgid="8494684293649631252">"0%"</item>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 6b556852a145..4db2d5eb5399 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Tengt (ekki efnisspilun)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Tengt (enginn skilaboðaaðgangur)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Tengt (ekki sími eða efnisspilun)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Hljóð efnis"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Símtöl"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Skráaflutningur"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 7f2d85ac6384..2ab2f7eebeff 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Collegato (contenuti multimed. esclusi)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Connesso (nessun accesso ai messaggi)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Collegato (telef. o conten. mult. esclusi)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Audio multimediale"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefonate"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Trasferimento file"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 36117ed3c706..5c9ef23be142 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"מחובר (ללא מדיה)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"מחובר (אין גישה להודעות)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"מחובר (ללא טלפון או מדיה)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"אודיו של מדיה"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"שיחות טלפון"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"העברת קבצים"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 1e82d3a4a5b4..0d6334db8869 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"接続済み(メディアを除く)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"接続済み(メッセージへのアクセスなし)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"接続済み(電話/メディアを除く)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"メディアの音声"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"電話"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"ファイル転送"</string>
@@ -110,7 +118,7 @@
<string name="unknown" msgid="1592123443519355854">"不明"</string>
<string name="running_process_item_user_label" msgid="3129887865552025943">"ユーザー: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="313159469856372621">"一部デフォルトを設定"</string>
- <string name="launch_defaults_none" msgid="4241129108140034876">"既定の設定なし"</string>
+ <string name="launch_defaults_none" msgid="4241129108140034876">"デフォルトの設定なし"</string>
<string name="tts_settings" msgid="8186971894801348327">"テキスト読み上げの設定"</string>
<string name="tts_settings_title" msgid="1237820681016639683">"テキスト読み上げの出力"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"音声の速度"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index a63c7a1fa224..c48018d46aee 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"მიერთებულია (მედიის გარდა)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"დაკავშირებულია (შეტყობინებაზე წვდომა არ არის)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"დაკავშირება (გარდა ტელეფონისა და მედიისა)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"მედია აუდიო"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"სატელეფონო ზარები"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"ფაილების გადაცემა"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index b2de42177ccc..be03821ed55a 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Жалғанған (медиа жоқ)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Жалғанған (хабарлар қол жетімсіз)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Жалғанған (телефон және медиа жоқ)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Meдиа аудиосы"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Телефон қоңыраулары"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Файл жіберу"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 8f9066f4f476..d8fac1663d03 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"បាន​តភ្ជាប់ (គ្មាន​មេឌៀ)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"បាន​ភ្ជាប់ (គ្មាន​ការ​ចូល​ដំណើរការ​សារ)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"បាន​តភ្ជាប់ (គ្មាន​ទូរស័ព្ទ ឬ​មេឌៀ)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"សំឡេង​មេឌៀ"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"ការហៅ​ទូរសព្ទ"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"ផ្ទេរ​ឯកសារ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 0c7ebff945ee..3989e98fbfee 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"ಸಂಪರ್ಕಗೊಂಡಿದೆ (ಮಾಧ್ಯಮವಿಲ್ಲ)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ (ಯಾವುದೇ ಸಂದೇಶ ಪ್ರವೇಶವಿಲ್ಲ)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"ಸಂಪರ್ಕಗೊಂಡಿದೆ (ಫೋನ್ ಅಥವಾ ಮಾಧ್ಯಮವಿಲ್ಲ)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"ಮಾಧ್ಯಮ ಆಡಿಯೋ"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"ಫೋನ್ ಕರೆಗಳು"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"ಫೈಲ್ ವರ್ಗಾವಣೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index eb20fdc5ad60..385172daf875 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"연결됨(미디어 없음)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"연결됨(메시지 액세스 없음)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"연결됨(전화 또는 미디어 없음)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"미디어 오디오"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"전화 통화"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"파일 전송"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 64bea17994ec..a5cee81a3af7 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Туташып турат (медиасыз)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Байланышта (билдирүү алмашуу жок)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Туташып турат (телефониясыз же медиасыз)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Аудио"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Телефон чалуулар"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Файл алмашуу"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index e02e6ffac828..ddacdf26ef5a 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"ເຊື່ອມຕໍ່ແລ້ວ (ບໍ່ມີສື່)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"ເຊື່ອມຕໍ່ (ບໍ່ມີການເຂົ້າເຖິງຂໍ້ຄວາມ)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"ເຊື່ອມຕໍ່ແລ້ວ (ບໍ່ມີໂທລະສັບ ຫຼືສື່)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"ສຽງ"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"ການໂທ"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"ການໂອນຍ້າຍໄຟລ໌"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index ff5b79b84397..99d28751ed85 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Prijungta (be laikmenos)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Prisijungta (be prieigos prie pranešimų)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Prijungta (be telefono ar laikmenos)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Laikmenos garsas"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefono skambučiai"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Failo perkėlimas"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 3784768ba848..8ade7d4bb6ac 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Sav. ir izveidots (nav multivides)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Savienots (nav piekļuves ziņojumam)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Sav. ir izveidots (nav tel. vai multiv.)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Multivides audio"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Tālruņa zvani"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Failu pārsūtīšana"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 694a9c81b342..666cc12fe297 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Поврзани (без медиуми)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Поврзано (без порака за пристап)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Поврзан (без телефон или медиуми)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Аудио на медиуми"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Телефонски повици"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Пренос на датотека"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 7de21c4ca669..f657b4305fb7 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"കണക്‌റ്റുചെയ്‌തു (മീഡിയ ഇല്ല)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"കണക്റ്റുചെയ്‌തു (സന്ദേശ ആക്‌സസ്സില്ല)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"കണ‌ക്റ്റുചെ‌യ്തു (ഫോണോ മീഡിയയോ അല്ല)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"മീഡിയ ഓഡിയോ"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"ഫോണ്‍‌ കോളുകൾ"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"ഫയൽ കൈമാറൽ"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 5a0a7229aeab..a0f3cee765d0 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Холбогдсон (медиа байхгүй)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Холбогдсон (зурвас хандалт байхгүй)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Холбогдсон (утас буюу медиа байхгүй)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Медиа аудио"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Утасны дуудлага"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Файл дамжуулалт"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 80323924f462..0a90722ab813 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"कनेक्ट केले (मीडिया नाही)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"कनेक्ट केलेले आहे (कोणत्याही संदेशामध्ये प्रवेश नाही)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"कनेक्ट केले (फोन किंवा मीडिया नाही)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"मीडिया ऑडिओ"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"फोन कॉल"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"फाइल स्थानांतरण"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index eedc1a0a913a..8aadf7c02356 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Disambungkan (tiada media)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Disambungkan (tiada akses mesej)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Disambungkan (tiada telefon atau media)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Audio media"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Panggilan telefon"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Pemindahan fail"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 4e5873e21640..85f89a1f8d5d 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"ချိတ်ဆက်ထားပြီး (မီဒီယာမရှိ)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"ချိတ်ဆက်မိသည် (သတင်းရယူမှုမရှိ)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"ချိတ်ဆက်ပြီး (ဖုန်း သို့ မီဒီယာမဟုတ်ပါ)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"မီဒီယာ အသံ"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"ဖုန်းခေါ်ဆိုမှုများ"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"ဖိုင်လွဲပြောင်းခြင်း"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 81a1eb5f793d..7cb6816efaec 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Tilkoblet (ingen medier)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Tilkoblet (ingen meldingstilgang)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Tilkoblet (ingen telefon eller media)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Medielyd"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefonsamtaler"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Filoverføring"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index dbb1977abb33..5abcf195e309 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"जडित (कुनै पनि मिडिया छैन)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"जडित छ (सन्देशमा पहुँच छैन)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"जडित (फोन वा मिडिया छैन)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"मिडिया अडियो"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"फोन कलहरू"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"फाइल स्थानान्तरण"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index b94f2c766f05..2649a4f496c0 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Gekoppeld (geen media)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Verbonden (geen toegang tot berichten)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Gekoppeld (geen telefoon of media)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media-audio"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefoongesprekken"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Bestandsoverdracht"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index fa5c3b7005bd..77ba3f8590c9 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"ਕਨੈਕਟ ਕੀਤਾ (ਕੋਈ ਮੀਡੀਆ ਨਹੀਂ)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"ਕਨੈਕਟ ਕੀਤਾ (ਕੋਈ ਸੁਨੇਹਾ ਪਹੁੰਚ ਨਹੀਂ)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"ਕਨੈਕਟ ਕੀਤਾ (ਕੋਈ ਫੋਨ ਜਾਂ ਮੀਡੀਆ ਨਹੀਂ)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"ਮੀਡੀਆ ਔਡੀਓ"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"ਫ਼ੋਨ ਕਾਲਾਂ"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"ਫਾਈਲ ਟ੍ਰਾਂਸਫਰ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index ee1ba4d4f6f9..b216ff1faf1a 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Połączono (bez multimediów)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Połączono (brak dostępu do wiadomości)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Połączono (bez telefonu ani multimediów)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Dźwięk multimediów"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Połączenia telefoniczne"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Przesyłanie pliku"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 675a6d09ebea..d98570ff84e7 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Conectado (sem mídia)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Conectado (sem acesso a mensagens)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Conectado (sem telefone ou mídia)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Áudio da mídia"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Chamadas telefônicas"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transferência de arquivo"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 736579fc6c83..dc1aeaccc5a8 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Ligado (sem multimédia)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Ligado (sem acesso a mensagens)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Ligado (sem telefone ou multimédia)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Áudio de multimédia"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Chamadas telefónicas"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transferência do ficheiro"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 675a6d09ebea..d98570ff84e7 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Conectado (sem mídia)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Conectado (sem acesso a mensagens)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Conectado (sem telefone ou mídia)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Áudio da mídia"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Chamadas telefônicas"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transferência de arquivo"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index f14aed0d5337..23bc4f7fca19 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Conectat (fără conținut media)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Conectat (fără acces la mesaje)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Conectat (fără telefon sau conț. media)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Conținut media audio"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Apeluri telefonice"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transfer de fișiere"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index ff6c838536e0..e5fe5f74f63b 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Подключено (кроме A2DP)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Подключено (нет доступа к сообщениям)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Подключено (кроме HSP/HFP/A2DP)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Профиль A2DP"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Звонки"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Профиль OPP"</string>
@@ -213,7 +221,7 @@
<string name="allow_mock_location_summary" msgid="317615105156345626">"Разрешить использование фиктивных местоположений"</string>
<string name="debug_view_attributes" msgid="6485448367803310384">"Включить проверку атрибутов"</string>
<string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Не отключать передачу данных по мобильной сети даже при активном Wi-Fi-подключении (для быстрого переключения между сетями)."</string>
- <string name="adb_warning_title" msgid="6234463310896563253">"Разрешить отладку USB?"</string>
+ <string name="adb_warning_title" msgid="6234463310896563253">"Разрешить отладку по USB?"</string>
<string name="adb_warning_message" msgid="7316799925425402244">"Отладка по USB – это режим, который позволяет использовать ваше устройство как внешний накопитель: перемещать файлы (с компьютера и на компьютер), напрямую устанавливать приложения, а также просматривать системные журналы."</string>
<string name="adb_keys_warning_message" msgid="5659849457135841625">"Запретить доступ к USB-отладке для всех компьютеров, которым он был разрешен?"</string>
<string name="dev_settings_warning_title" msgid="7244607768088540165">"Изменение настроек"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 5486aa60160c..9fc96d5e7746 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"සම්බන්ධිතයි (මාධ්‍යයක් නොමැත)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"සම්බන්ධිතයි (පණිවිඩ ප්‍රවේශ නොමැත)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"සම්බන්ධිතයි (දුරකතනයක් හෝ මාධ්‍යයක් නැත)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"මාධ්‍ය ශ්‍රව්‍ය"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"දුරකථන ඇමතුම්"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"ගොනු හුවමාරුව"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index db3c5c37c662..fba2edcf41a9 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Pripojené (bez média)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Pripojené (bez prístupu ku správam)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Pripojené (bez telefónu alebo média)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Zvuk medií"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefonické hovory"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Prenos súborov"</string>
@@ -65,8 +73,8 @@
<string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Zdieľanie pripojenia na Internet"</string>
<string name="bluetooth_profile_map" msgid="1019763341565580450">"Textové správy"</string>
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"Prístup k SIM karte"</string>
- <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"Zvuk v HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
- <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"Zvuk v HD"</string>
+ <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD zvuk: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
+ <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD zvuk"</string>
<string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Pripojené ku zvukovému médiu"</string>
<string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Pripojené ku zvuku telefónu"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Pripojené na server pre prenos údajov"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 9c20947b0781..a206c30ce53b 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Povezava vzpostavljena (brez predstavnosti)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Povezava vzp. (ni dostopa do sporočil)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Povezava vzpostavljena (brez telefona ali predstavnosti)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Zvok predstavnosti"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefonski klici"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Prenos datoteke"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 9dddf7304436..c3ad1f2888e0 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"U lidh (nuk ka media)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"U lidh (pa qasje te mesazhet)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"I lidhur (pa telefon apo media)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Audioja e klipit \"media\""</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefonatat"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transferimi i skedarëve"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 1cda30791c75..aa8387b67fd4 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Повезано (без медија)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Повезано је (нема приступа порукама)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Повезано (без телефона или медија)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Звук медија"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Телефонски позиви"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Пренос датотеке"</string>
@@ -352,7 +360,7 @@
<string name="disabled" msgid="9206776641295849915">"Онемогућено"</string>
<string name="external_source_trusted" msgid="2707996266575928037">"Дозвољено"</string>
<string name="external_source_untrusted" msgid="2677442511837596726">"Није дозвољено"</string>
- <string name="install_other_apps" msgid="6986686991775883017">"Инсталирајте непозн. апл."</string>
+ <string name="install_other_apps" msgid="6986686991775883017">"Инсталирање непознатих апликација"</string>
<string name="home" msgid="3256884684164448244">"Почетна за Подешавања"</string>
<string-array name="battery_labels">
<item msgid="8494684293649631252">"0%"</item>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 260554f7a49b..deaa6ae54665 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Ansluten (inga media)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Ansluten (ingen meddelandeåtkomst)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Ansluten (ingen telefon och inga media)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Medialjud"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefonsamtal"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Filöverföring"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 04f80a99312a..3582f50ff864 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Imeunganishwa(hakuna vyombo vya habari)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Imeunganishwa (hakuna ufikiaji kwa ujumbe)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Imeunganishwa(hakuna simu au vyombo vya habari)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media ya sauti"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Simu"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Uhamishaji wa faili"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 74f88d2091eb..2eca4d749f89 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"இணைக்கப்பட்டது (மீடியா இல்லை)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"இணைக்கப்பட்டது (செய்திக்கான அணுகல் இல்லை)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"இணைக்கப்பட்டது (மொபைல் அல்லது மீடியாவுடன் அல்ல)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"மீடியா ஆடியோ"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"ஃபோன் அழைப்புகள்"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"கோப்பு இடமாற்றம்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 6f432d065992..b7936fc5797b 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"కనెక్ట్ చేయబడింది (మీడియా కాదు)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"కనెక్ట్ చేయబడింది (సందేశ ప్రాప్యత లేదు)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"కనెక్ట్ చేయబడింది (ఫోన్ లేదా మీడియా కాకుండా)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"మీడియా ఆడియో"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"ఫోన్ కాల్‌లు"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"ఫైల్ బదిలీ"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index d8950b81b23a..4631e8524f41 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"เชื่อมต่อแล้ว (ยกเว้นเสียงสื่อ)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"เชื่อมต่อแล้ว (ไม่มีการเข้าถึงข้อความ)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"เชื่อมต่อ (ยกเว้นเสียงโทรศัพท์หรือสื่อ)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"เสียงสื่อ"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"การโทรศัพท์"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"การถ่ายโอนไฟล์"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 7b10c851ca48..88b92323f528 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Nakakonekta (walang media)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Nakakonekta (walang access sa mensahe)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Nakakonekta (walang telepono o media)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Audio ng media"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Mga tawag sa telepono"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Paglilipat ng file"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 8ceb1d8c630b..2c8e1ec29285 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Bağlandı (medya yok)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Bağlı (mesaj erişimi yok)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Bağlandı (telefon veya medya yok)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Medya sesi"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefon çağrıları"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Dosya aktarımı"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index ad3222287b79..e7bd0c8bffda 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Під’єднано (без медіа-файлів)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Під’єднано (без доступу до повідомлень)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Під’єднано (без телефону чи медіа)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Звук медіа-файлів"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Телефонні дзвінки"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Передавання файлів"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 6e9cdde588c6..7e3723c0b8b6 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"مربوط (کوئی میڈیا نہیں ہے)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"مربوط (کسی پیغام تک رسائی نہیں ہے)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"مربوط (کوئی فون یا میڈیا نہیں ہے)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"میڈيا آڈیو"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"فون کالز"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"فائل کی منتقلی"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 70cc95a2c2db..0d9bc50c2544 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Ulanildi (mediadan tashqari)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Ulangan (xabarlarga kirib bo‘lmaydi)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Ulangan (telefon yoki media qurilma emas)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media audio"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Telefon chaqiruvlari"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Fayl o‘tkazish"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 9ba6457282e6..4bf4ec4442ec 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Đã kết nối (không có phương tiện)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Đã kết nối (không truy cập tin nhắn)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Đã k.nối (kg có ĐT hoặc p.tiện nào)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Âm thanh của phương tiện"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Cuộc gọi điện thoại"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Chuyển tệp"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 43fa66e6bb6c..addd04d5af70 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"已连接(无媒体)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"已连接(无消息权限)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"已连接(没有手机或媒体信号)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"媒体音频"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"通话"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"文件传输"</string>
@@ -110,7 +118,7 @@
<string name="unknown" msgid="1592123443519355854">"未知"</string>
<string name="running_process_item_user_label" msgid="3129887865552025943">"用户:<xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="313159469856372621">"已设置部分默认选项"</string>
- <string name="launch_defaults_none" msgid="4241129108140034876">"未设置任何默认选项"</string>
+ <string name="launch_defaults_none" msgid="4241129108140034876">"没有默认操作"</string>
<string name="tts_settings" msgid="8186971894801348327">"文字转语音设置"</string>
<string name="tts_settings_title" msgid="1237820681016639683">"文字转语音 (TTS) 输出"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"语速"</string>
@@ -160,9 +168,9 @@
<string name="vpn_settings_not_available" msgid="956841430176985598">"此用户无权修改VPN设置"</string>
<string name="tethering_settings_not_available" msgid="6765770438438291012">"此用户无权修改网络共享设置"</string>
<string name="apn_settings_not_available" msgid="7873729032165324000">"此用户无权修改接入点名称设置"</string>
- <string name="enable_adb" msgid="7982306934419797485">"USB调试"</string>
+ <string name="enable_adb" msgid="7982306934419797485">"USB 调试"</string>
<string name="enable_adb_summary" msgid="4881186971746056635">"连接USB后启用调试模式"</string>
- <string name="clear_adb_keys" msgid="4038889221503122743">"撤消USB调试授权"</string>
+ <string name="clear_adb_keys" msgid="4038889221503122743">"撤消 USB 调试授权"</string>
<string name="bugreport_in_power" msgid="7923901846375587241">"错误报告快捷方式"</string>
<string name="bugreport_in_power_summary" msgid="1778455732762984579">"在电源菜单中显示用于提交错误报告的按钮"</string>
<string name="keep_screen_on" msgid="1146389631208760344">"不锁定屏幕"</string>
@@ -213,9 +221,9 @@
<string name="allow_mock_location_summary" msgid="317615105156345626">"允许模拟位置"</string>
<string name="debug_view_attributes" msgid="6485448367803310384">"启用视图属性检查功能"</string>
<string name="mobile_data_always_on_summary" msgid="8149773901431697910">"始终开启移动数据网络,即使 WLAN 网络已开启(便于快速切换网络)。"</string>
- <string name="adb_warning_title" msgid="6234463310896563253">"是否允许USB调试?"</string>
+ <string name="adb_warning_title" msgid="6234463310896563253">"是否允许 USB 调试?"</string>
<string name="adb_warning_message" msgid="7316799925425402244">"USB 调试仅用于开发目的。该功能可用于在您的计算机和设备之间复制数据、在您的设备上安装应用(事先不发通知)以及读取日志数据。"</string>
- <string name="adb_keys_warning_message" msgid="5659849457135841625">"是否针对您之前授权的所有计算机撤消USB调试的访问权限?"</string>
+ <string name="adb_keys_warning_message" msgid="5659849457135841625">"是否针对您之前授权的所有计算机撤消 USB 调试的访问权限?"</string>
<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>
@@ -232,7 +240,7 @@
<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>
+ <string name="wait_for_debugger" msgid="1202370874528893091">"等待调试程序"</string>
<string name="wait_for_debugger_summary" msgid="1766918303462746804">"调试应用会在执行前等待附加调试器"</string>
<string name="telephony_monitor_switch" msgid="1764958220062121194">"电话监控器"</string>
<string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"电话监控器会在检测到电话/调制解调器功能存在问题时收集相关日志,并向用户发出通知,提醒用户提交错误报告"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 41eb94f173b0..ee4ff6b12e7c 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -55,13 +55,21 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"已連線 (無媒體)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"已連結 (無訊息存取權)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"已連線 (無手機或媒體)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"媒體音效"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"通話"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"檔案傳輸"</string>
<string name="bluetooth_profile_hid" msgid="3680729023366986480">"輸入裝置"</string>
<string name="bluetooth_profile_pan" msgid="3391606497945147673">"互聯網連線"</string>
- <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"聯絡人共用"</string>
- <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"用於聯絡人共用"</string>
+ <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"共用聯絡人"</string>
+ <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"用於共用聯絡人"</string>
<string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"互聯網連線分享"</string>
<string name="bluetooth_profile_map" msgid="1019763341565580450">"短訊"</string>
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM 卡存取"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index edd02c9f238a..0a4e48399684 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"已連線 (無媒體音訊)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"已連線 (無訊息存取權)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"已連線 (無手機或媒體音訊)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"媒體音訊"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"通話"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"檔案傳輸"</string>
@@ -65,8 +73,8 @@
<string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"網際網路連線分享"</string>
<string name="bluetooth_profile_map" msgid="1019763341565580450">"簡訊"</string>
<string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM 卡存取權"</string>
- <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD 高解析度音訊:<xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
- <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD 高解析度音訊"</string>
+ <string name="bluetooth_profile_a2dp_high_quality" msgid="5444517801472820055">"HD 高解析音訊:<xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
+ <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="8510588052415438887">"HD 高解析音訊"</string>
<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>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index b2e5ae32029c..a142c32f4a2e 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -55,6 +55,14 @@
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Ixhunyiwe (ayikho imidiya)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Kuxhunyiwe (akukho ukufinyelela umlayezo)"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Ixhunyiwe (ayikho ifoni noma imidiya)"</string>
+ <!-- no translation found for bluetooth_connected_battery_level (7049181126136692368) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_battery_level (5504193961248406027) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_a2dp_battery_level (4751724026365870779) -->
+ <skip />
+ <!-- no translation found for bluetooth_connected_no_headset_no_a2dp_battery_level (1549265779323455261) -->
+ <skip />
<string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Umsindo wemidiya"</string>
<string name="bluetooth_profile_headset" msgid="7815495680863246034">"Amakholi efoni"</string>
<string name="bluetooth_profile_opp" msgid="9168139293654233697">"Dlulisa ifayela"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index fd994b572981..a4302880dfaf 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -130,6 +130,15 @@
<!-- Bluetooth settings. Message when connected to a device, except for phone/media audio. [CHAR LIMIT=40] -->
<string name="bluetooth_connected_no_headset_no_a2dp">Connected (no phone or media)</string>
+ <!-- Bluetooth settings. Message when connected to a device, showing remote device battery level. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_connected_battery_level">Connected, battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string>
+ <!-- Bluetooth settings. Message when connected to a device, except for phone audio, showing remote device battery level. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_connected_no_headset_battery_level">Connected (no phone), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string>
+ <!-- Bluetooth settings. Message when connected to a device, except for media audio, showing remote device battery level. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_connected_no_a2dp_battery_level">Connected (no media), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string>
+ <!-- Bluetooth settings. Message when connected to a device, except for phone/media audio, showing remote device battery level. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_connected_no_headset_no_a2dp_battery_level">Connected (no phone or media), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string>
+
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the A2DP profile. -->
<string name="bluetooth_profile_a2dp">Media audio</string>
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the headset or handsfree profile. -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/TronUtils.java b/packages/SettingsLib/src/com/android/settingslib/TronUtils.java
index bea6e8f77dd2..945cb5797e8f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/TronUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/TronUtils.java
@@ -16,48 +16,18 @@
package com.android.settingslib;
import android.content.Context;
-import android.net.NetworkBadging;
import com.android.internal.logging.MetricsLogger;
+import com.android.settingslib.wifi.AccessPoint.Speed;
/** Utilites for Tron Logging. */
public final class TronUtils {
- private TronUtils() {};
-
- public static void logWifiSettingsBadge(Context context, int badgeEnum) {
- logNetworkBadgeMetric(context, "settings_wifibadging", badgeEnum);
- }
+ private static final String TAG = "TronUtils";
- /**
- * Logs an occurrence of the given network badge to a Histogram.
- *
- * @param context Context
- * @param histogram the Tron histogram name to write to
- * @param badgeEnum the {@link NetworkBadging.Badging} badge value
- * @throws IllegalArgumentException if the given badge enum is not supported
- */
- private static void logNetworkBadgeMetric(
- Context context, String histogram, int badgeEnum)
- throws IllegalArgumentException {
- int bucket;
- switch (badgeEnum) {
- case NetworkBadging.BADGING_NONE:
- bucket = 0;
- break;
- case NetworkBadging.BADGING_SD:
- bucket = 1;
- break;
- case NetworkBadging.BADGING_HD:
- bucket = 2;
- break;
- case NetworkBadging.BADGING_4K:
- bucket = 3;
- break;
- default:
- throw new IllegalArgumentException("Unsupported badge enum: " + badgeEnum);
- }
+ private TronUtils() {};
- MetricsLogger.histogram(context, histogram, bucket);
+ public static void logWifiSettingsSpeed(Context context, @Speed int speedEnum) {
+ MetricsLogger.histogram(context, "settings_wifi_speed_labels", speedEnum);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
index 167ffe61e42b..fa41c8349540 100644
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
@@ -91,12 +91,10 @@ public class SuggestionParser {
// Shared prefs keys for storing dismissed state.
// Index into current dismissed state.
+ public static final String SETUP_TIME = "_setup_time";
private static final String DISMISS_INDEX = "_dismiss_index";
- private static final String SETUP_TIME = "_setup_time";
private static final String IS_DISMISSED = "_is_dismissed";
- private static final long MILLIS_IN_DAY = 24 * 60 * 60 * 1000;
-
// Default dismiss control for smart suggestions.
private static final String DEFAULT_SMART_DISMISS_CONTROL = "0,10";
@@ -386,7 +384,7 @@ public class SuggestionParser {
}
private long getEndTime(long startTime, int daysDelay) {
- long days = daysDelay * MILLIS_IN_DAY;
+ long days = daysDelay * DateUtils.DAY_IN_MILLIS;
return startTime + days;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index d45ed1922aa4..4a5445163650 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -16,6 +16,7 @@
package com.android.settingslib.wifi;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.AppGlobals;
import android.content.Context;
@@ -53,6 +54,8 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.R;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
@@ -82,35 +85,30 @@ public class AccessPoint implements Comparable<AccessPoint> {
*/
public static final int HIGHER_FREQ_5GHZ = 5900;
- /**
- * Constant value representing an unlabeled / unscored network.
- */
- @VisibleForTesting
- static final int SPEED_NONE = 0;
-
- /**
- * Constant value representing a slow speed network connection.
- */
- @VisibleForTesting
- static final int SPEED_SLOW = 5;
-
- /**
- * Constant value representing a medium speed network connection.
- */
- @VisibleForTesting
- static final int SPEED_MEDIUM = 10;
-
- /**
- * Constant value representing a fast speed network connection.
- */
- @VisibleForTesting
- static final int SPEED_FAST = 20;
-
- /**
- * Constant value representing a very fast speed network connection.
- */
- @VisibleForTesting
- static final int SPEED_VERY_FAST = 30;
+ @IntDef({Speed.NONE, Speed.SLOW, Speed.MODERATE, Speed.FAST, Speed.VERY_FAST})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Speed {
+ /**
+ * Constant value representing an unlabeled / unscored network.
+ */
+ int NONE = 0;
+ /**
+ * Constant value representing a slow speed network connection.
+ */
+ int SLOW = 5;
+ /**
+ * Constant value representing a medium speed network connection.
+ */
+ int MODERATE = 10;
+ /**
+ * Constant value representing a fast speed network connection.
+ */
+ int FAST = 20;
+ /**
+ * Constant value representing a very fast speed network connection.
+ */
+ int VERY_FAST = 30;
+ }
/**
* Experimental: we should be able to show the user the list of BSSIDs and bands
@@ -177,7 +175,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
private Object mTag;
private int mRankingScore = Integer.MIN_VALUE;
- private int mSpeed = AccessPoint.SPEED_NONE;
+ private int mSpeed = Speed.NONE;
private boolean mIsScoredNetworkMetered = false;
// used to co-relate internal vs returned accesspoint.
@@ -322,8 +320,15 @@ public class AccessPoint implements Comparable<AccessPoint> {
if (difference != 0) {
return difference;
}
+
// Sort by ssid.
- return getSsidStr().compareToIgnoreCase(other.getSsidStr());
+ difference = getSsidStr().compareToIgnoreCase(other.getSsidStr());
+ if (difference != 0) {
+ return difference;
+ }
+
+ // Do a case sensitive comparison to distinguish SSIDs that differ in case only
+ return getSsidStr().compareTo(other.getSsidStr());
}
@Override
@@ -368,7 +373,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
if (mRankingScore != Integer.MIN_VALUE) {
builder.append(",rankingScore=").append(mRankingScore);
}
- if (mSpeed != SPEED_NONE) {
+ if (mSpeed != Speed.NONE) {
builder.append(",speed=").append(mSpeed);
}
builder.append(",metered=").append(isMetered());
@@ -399,7 +404,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
private boolean updateScores(WifiNetworkScoreCache scoreCache) {
int oldSpeed = mSpeed;
int oldRankingScore = mRankingScore;
- mSpeed = SPEED_NONE;
+ mSpeed = Speed.NONE;
mRankingScore = Integer.MIN_VALUE;
for (ScanResult result : mScanResultCache.values()) {
@@ -675,7 +680,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
// TODO(b/62354743): Standardize and international delimiter usage
final String concatenator = " / ";
- if (mSpeed != SPEED_NONE) {
+ if (mSpeed != Speed.NONE) {
summary.append(getSpeedLabel() + concatenator);
}
@@ -799,7 +804,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
if (mRankingScore != Integer.MIN_VALUE) {
visibility.append(" rankingScore=").append(getRankingScore());
}
- if (mSpeed != SPEED_NONE) {
+ if (mSpeed != Speed.NONE) {
visibility.append(" speed=").append(getSpeedLabel());
}
visibility.append(String.format(" tx=%.1f,", mInfo.txSuccessRate));
@@ -1053,6 +1058,12 @@ public class AccessPoint implements Comparable<AccessPoint> {
final int oldLevel = getLevel();
if (info != null && isInfoForThisAccessPoint(config, info)) {
updated = (mInfo == null);
+ if (mConfig != config) {
+ // We do not set updated = true as we do not want to increase the amount of sorting
+ // and copying performed in WifiTracker at this time. If issues involving refresh
+ // are still seen, we will investigate further.
+ update(config); // Notifies the AccessPointListener of the change
+ }
if (mRssi != info.getRssi()) {
mRssi = info.getRssi();
updated = true;
@@ -1104,15 +1115,15 @@ public class AccessPoint implements Comparable<AccessPoint> {
@Nullable
String getSpeedLabel() {
switch (mSpeed) {
- case SPEED_VERY_FAST:
+ case Speed.VERY_FAST:
return mContext.getString(R.string.speed_label_very_fast);
- case SPEED_FAST:
+ case Speed.FAST:
return mContext.getString(R.string.speed_label_fast);
- case SPEED_MEDIUM:
+ case Speed.MODERATE:
return mContext.getString(R.string.speed_label_okay);
- case SPEED_SLOW:
+ case Speed.SLOW:
return mContext.getString(R.string.speed_label_slow);
- case SPEED_NONE:
+ case Speed.NONE:
default:
return null;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index e7525f3edbc4..92995a8e850d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -70,6 +70,19 @@ public class AccessPointPreference extends Preference {
R.string.accessibility_wifi_signal_full
};
+ public static String generatePreferenceKey(AccessPoint accessPoint) {
+ StringBuilder builder = new StringBuilder();
+
+ if (TextUtils.isEmpty(accessPoint.getBssid())) {
+ builder.append(accessPoint.getSsidStr());
+ } else {
+ builder.append(accessPoint.getBssid());
+ }
+
+ builder.append(',').append(accessPoint.getSecurity());
+ return builder.toString();
+ }
+
// Used for dummy pref.
public AccessPointPreference(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -161,7 +174,7 @@ public class AccessPointPreference extends Preference {
safeSetDefaultIcon();
return;
}
- TronUtils.logWifiSettingsBadge(context, mWifiSpeed);
+ TronUtils.logWifiSettingsSpeed(context, mWifiSpeed);
// TODO(b/62355275): Revert this to N code after deleting NetworkBadging API
Drawable drawable = NetworkBadging.getWifiIcon(
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java b/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
index 2213ae647e98..4307cb0f1b7b 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
@@ -26,9 +26,9 @@ import android.os.Bundle;
/**
* Build and return a valid AccessPoint.
*
-* Only intended for testing the AccessPoint class;
-* AccessPoints were designed to only be populated
-* by the mechanisms of scan results and wifi configurations.
+* Only intended for testing the AccessPoint class or creating Access points to be used in testing
+* applications. AccessPoints were designed to only be populated by the mechanisms of scan results
+* and wifi configurations.
*/
public class TestAccessPointBuilder {
// match the private values in WifiManager
@@ -36,12 +36,14 @@ public class TestAccessPointBuilder {
private static final int MAX_RSSI = -55;
// set some sensible defaults
+ private String mBssid = null;
private int mRssi = AccessPoint.UNREACHABLE_RSSI;
private int mNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
private String ssid = "TestSsid";
private NetworkInfo mNetworkInfo = null;
private String mFqdn = null;
private String mProviderFriendlyName = null;
+ private int mSecurity = AccessPoint.SECURITY_NONE;
private WifiConfiguration mWifiConfig;
private WifiInfo mWifiInfo;
@@ -56,6 +58,7 @@ public class TestAccessPointBuilder {
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.networkId = mNetworkId;
+ wifiConfig.BSSID = mBssid;
bundle.putString(AccessPoint.KEY_SSID, ssid);
bundle.putParcelable(AccessPoint.KEY_CONFIG, wifiConfig);
@@ -67,6 +70,8 @@ public class TestAccessPointBuilder {
if (mProviderFriendlyName != null) {
bundle.putString(AccessPoint.KEY_PROVIDER_FRIENDLY_NAME, mProviderFriendlyName);
}
+ bundle.putInt(AccessPoint.KEY_SECURITY, mSecurity);
+
AccessPoint ap = new AccessPoint(mContext, bundle);
ap.setRssi(mRssi);
return ap;
@@ -141,6 +146,11 @@ public class TestAccessPointBuilder {
return this;
}
+ public TestAccessPointBuilder setSecurity(int security) {
+ mSecurity = security;
+ return this;
+ }
+
public TestAccessPointBuilder setSsid(String newSsid) {
ssid = newSsid;
return this;
@@ -171,4 +181,9 @@ public class TestAccessPointBuilder {
mNetworkId = networkId;
return this;
}
+
+ public TestAccessPointBuilder setBssid(String bssid) {
+ mBssid = bssid;
+ return this;
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 9083d90b9085..596eaefcd054 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -16,6 +16,7 @@
package com.android.settingslib.wifi;
import android.annotation.MainThread;
+import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -36,7 +37,6 @@ import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.WifiNetworkScoreCache.CacheListener;
-import android.os.ConditionVariable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -91,7 +91,7 @@ public class WifiTracker {
private final boolean mIncludeScans;
private final boolean mIncludePasspoints;
@VisibleForTesting final MainHandler mMainHandler;
- private final WorkHandler mWorkHandler;
+ @VisibleForTesting final WorkHandler mWorkHandler;
private WifiTrackerNetworkCallback mNetworkCallback;
@@ -247,7 +247,10 @@ public class WifiTracker {
mWorkHandler.removeMessages(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
mLastInfo = mWifiManager.getConnectionInfo();
mLastNetworkInfo = mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());
- updateAccessPointsLocked();
+
+ final List<ScanResult> newScanResults = mWifiManager.getScanResults();
+ List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+ updateAccessPointsLocked(newScanResults, configs);
if (DBG) {
Log.d(TAG, "force update - internal access point list:\n" + mInternalAccessPoints);
@@ -377,7 +380,7 @@ public class WifiTracker {
mNetworkScoreManager.unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, mScoreCache);
mScoreCache.clearScores();
- // Synchronize on mLock to avoid concurrent modification during updateAccessPointsLocked
+ // Synchronize on mLock to avoid concurrent modification during updateAccessPoints
synchronized (mLock) {
mRequestedScores.clear();
}
@@ -427,9 +430,8 @@ public class WifiTracker {
mScanId = 0;
}
- private Collection<ScanResult> fetchScanResults() {
+ private Collection<ScanResult> updateScanResultCache(final List<ScanResult> newResults) {
mScanId++;
- final List<ScanResult> newResults = mWifiManager.getScanResults();
for (ScanResult newResult : newResults) {
if (newResult.SSID == null || newResult.SSID.isEmpty()) {
continue;
@@ -457,8 +459,8 @@ public class WifiTracker {
return mScanResultCache.values();
}
- private WifiConfiguration getWifiConfigurationForNetworkId(int networkId) {
- final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+ private WifiConfiguration getWifiConfigurationForNetworkId(
+ int networkId, final List<WifiConfiguration> configs) {
if (configs != null) {
for (WifiConfiguration config : configs) {
if (mLastInfo != null && networkId == config.networkId &&
@@ -470,20 +472,37 @@ public class WifiTracker {
return null;
}
- /** Safely modify {@link #mInternalAccessPoints} by acquiring {@link #mLock} first. */
- private void updateAccessPointsLocked() {
+ /**
+ * Safely modify {@link #mInternalAccessPoints} by acquiring {@link #mLock} first.
+ *
+ * <p>Will not perform the update if {@link #mStaleScanResults} is true
+ */
+ private void updateAccessPoints() {
+ List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+ final List<ScanResult> newScanResults = mWifiManager.getScanResults();
+
synchronized (mLock) {
- updateAccessPoints();
+ if(!mStaleScanResults) {
+ updateAccessPointsLocked(newScanResults, configs);
+ }
}
}
/**
* Update the internal list of access points.
*
- * <p>Should never be called directly, use {@link #updateAccessPointsLocked()} instead.
+ * <p>Do not called directly (except for forceUpdate), use {@link #updateAccessPoints()} which
+ * respects {@link #mStaleScanResults}.
*/
@GuardedBy("mLock")
- private void updateAccessPoints() {
+ private void updateAccessPointsLocked(final List<ScanResult> newScanResults,
+ List<WifiConfiguration> configs) {
+ WifiConfiguration connectionConfig = null;
+ if (mLastInfo != null) {
+ connectionConfig = getWifiConfigurationForNetworkId(
+ mLastInfo.getNetworkId(), mWifiManager.getConfiguredNetworks());
+ }
+
// Swap the current access points into a cached list.
List<AccessPoint> cachedAccessPoints = new ArrayList<>(mInternalAccessPoints);
ArrayList<AccessPoint> accessPoints = new ArrayList<>();
@@ -496,14 +515,9 @@ public class WifiTracker {
/* Lookup table to more quickly update AccessPoints by only considering objects with the
* correct SSID. Maps SSID -> List of AccessPoints with the given SSID. */
Multimap<String, AccessPoint> apMap = new Multimap<String, AccessPoint>();
- WifiConfiguration connectionConfig = null;
- if (mLastInfo != null) {
- connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId());
- }
- final Collection<ScanResult> results = fetchScanResults();
+ final Collection<ScanResult> results = updateScanResultCache(newScanResults);
- final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
if (configs != null) {
for (WifiConfiguration config : configs) {
if (config.selfAdded && config.numAssociation == 0) {
@@ -653,6 +667,7 @@ public class WifiTracker {
/* sticky broadcasts can call this when wifi is disabled */
if (!mWifiManager.isWifiEnabled()) {
mMainHandler.sendEmptyMessage(MainHandler.MSG_PAUSE_SCANNING);
+ clearAccessPointsAndConditionallyUpdate();
return;
}
@@ -670,7 +685,8 @@ public class WifiTracker {
WifiConfiguration connectionConfig = null;
mLastInfo = mWifiManager.getConnectionInfo();
if (mLastInfo != null) {
- connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId());
+ connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId(),
+ mWifiManager.getConfiguredNetworks());
}
boolean updated = false;
@@ -696,6 +712,17 @@ public class WifiTracker {
}
}
+ private void clearAccessPointsAndConditionallyUpdate() {
+ synchronized (mLock) {
+ if (!mInternalAccessPoints.isEmpty()) {
+ mInternalAccessPoints.clear();
+ if (!mMainHandler.hasMessages(MainHandler.MSG_ACCESS_POINT_CHANGED)) {
+ mMainHandler.sendEmptyMessage(MainHandler.MSG_ACCESS_POINT_CHANGED);
+ }
+ }
+ }
+ }
+
/**
* Update all the internal access points rankingScores, badge and metering.
*
@@ -720,6 +747,9 @@ public class WifiTracker {
private void updateWifiState(int state) {
mWorkHandler.obtainMessage(WorkHandler.MSG_UPDATE_WIFI_STATE, state, 0).sendToTarget();
+ if (!mWifiManager.isWifiEnabled()) {
+ clearAccessPointsAndConditionallyUpdate();
+ }
}
public static List<AccessPoint> getCurrentAccessPoints(Context context, boolean includeSaved,
@@ -803,8 +833,15 @@ public class WifiTracker {
mListener.onWifiStateChanged(msg.arg1);
break;
case MSG_ACCESS_POINT_CHANGED:
- copyAndNotifyListeners(true /*notifyListeners*/);
- mListener.onAccessPointsChanged();
+ // Only notify listeners of changes if we have fresh scan results, otherwise the
+ // UI will be updated with stale results. We want to copy the APs regardless,
+ // for instances where forceUpdate was invoked by the caller.
+ if (mStaleScanResults) {
+ copyAndNotifyListeners(false /*notifyListeners*/);
+ } else {
+ copyAndNotifyListeners(true /*notifyListeners*/);
+ mListener.onAccessPointsChanged();
+ }
break;
case MSG_RESUME_SCANNING:
if (mScanner != null) {
@@ -828,7 +865,8 @@ public class WifiTracker {
}
}
- private final class WorkHandler extends Handler {
+ @VisibleForTesting
+ final class WorkHandler extends Handler {
private static final int MSG_UPDATE_ACCESS_POINTS = 0;
private static final int MSG_UPDATE_NETWORK_INFO = 1;
private static final int MSG_RESUME = 2;
@@ -845,15 +883,12 @@ public class WifiTracker {
}
}
- @GuardedBy("mLock")
private void processMessage(Message msg) {
if (!mRegistered) return;
switch (msg.what) {
case MSG_UPDATE_ACCESS_POINTS:
- if (!mStaleScanResults) {
- updateAccessPointsLocked();
- }
+ updateAccessPoints();
break;
case MSG_UPDATE_NETWORK_INFO:
updateNetworkInfo((NetworkInfo) msg.obj);
diff --git a/packages/SettingsLib/tests/integ/AndroidManifest.xml b/packages/SettingsLib/tests/integ/AndroidManifest.xml
index 0d5ff2ca05a5..e8e0b41ffd41 100644
--- a/packages/SettingsLib/tests/integ/AndroidManifest.xml
+++ b/packages/SettingsLib/tests/integ/AndroidManifest.xml
@@ -21,6 +21,7 @@
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY"/>
<uses-permission android:name="android.permission.SET_TIME_ZONE" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 89328ee47f1c..5c64cff78a88 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -20,6 +20,8 @@ import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -169,6 +171,21 @@ public class AccessPointTest {
}
@Test
+ public void testCompareTo_GivesSsidCasePrecendenceAfterAlphabetical() {
+
+ final String firstName = "aaAaaa";
+ final String secondName = "aaaaaa";
+ final String thirdName = "BBBBBB";
+
+ AccessPoint firstAp = new TestAccessPointBuilder(mContext).setSsid(firstName).build();
+ AccessPoint secondAp = new TestAccessPointBuilder(mContext).setSsid(secondName).build();
+ AccessPoint thirdAp = new TestAccessPointBuilder(mContext).setSsid(thirdName).build();
+
+ assertSortingWorks(firstAp, secondAp);
+ assertSortingWorks(secondAp, thirdAp);
+ }
+
+ @Test
public void testCompareTo_AllSortingRulesCombined() {
AccessPoint active = new TestAccessPointBuilder(mContext).setActive(true).build();
@@ -334,11 +351,11 @@ public class AccessPointTest {
when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
.thenReturn(buildScoredNetworkWithMockBadgeCurve());
- when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.SPEED_VERY_FAST);
+ when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.VERY_FAST);
ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */);
- assertThat(ap.getSpeed()).isEqualTo(AccessPoint.SPEED_VERY_FAST);
+ assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.VERY_FAST);
assertThat(ap.getSpeedLabel())
.isEqualTo(mContext.getString(R.string.speed_label_very_fast));
}
@@ -349,11 +366,11 @@ public class AccessPointTest {
when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
.thenReturn(buildScoredNetworkWithMockBadgeCurve());
- when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.SPEED_FAST);
+ when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.FAST);
ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */);
- assertThat(ap.getSpeed()).isEqualTo(AccessPoint.SPEED_FAST);
+ assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.FAST);
assertThat(ap.getSpeedLabel())
.isEqualTo(mContext.getString(R.string.speed_label_fast));
}
@@ -364,11 +381,11 @@ public class AccessPointTest {
when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
.thenReturn(buildScoredNetworkWithMockBadgeCurve());
- when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.SPEED_MEDIUM);
+ when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.MODERATE);
ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */);
- assertThat(ap.getSpeed()).isEqualTo(AccessPoint.SPEED_MEDIUM);
+ assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.MODERATE);
assertThat(ap.getSpeedLabel())
.isEqualTo(mContext.getString(R.string.speed_label_okay));
}
@@ -379,11 +396,11 @@ public class AccessPointTest {
when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
.thenReturn(buildScoredNetworkWithMockBadgeCurve());
- when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.SPEED_SLOW);
+ when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.SLOW);
ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */);
- assertThat(ap.getSpeed()).isEqualTo(AccessPoint.SPEED_SLOW);
+ assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.SLOW);
assertThat(ap.getSpeedLabel())
.isEqualTo(mContext.getString(R.string.speed_label_slow));
}
@@ -394,7 +411,7 @@ public class AccessPointTest {
when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
.thenReturn(buildScoredNetworkWithMockBadgeCurve());
- when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.SPEED_VERY_FAST);
+ when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.VERY_FAST);
ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */);
@@ -408,7 +425,7 @@ public class AccessPointTest {
when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
.thenReturn(buildScoredNetworkWithMockBadgeCurve());
- when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.SPEED_VERY_FAST);
+ when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.VERY_FAST);
ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */);
@@ -607,4 +624,36 @@ public class AccessPointTest {
NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values
assertThat(ap.update(config, wifiInfo, newInfo)).isFalse();
}
+
+ @Test
+ public void testUpdateWithConfigChangeOnly_returnsFalseButInvokesListener() {
+ int networkId = 123;
+ int rssi = -55;
+ WifiConfiguration config = new WifiConfiguration();
+ config.networkId = networkId;
+ config.numNoInternetAccessReports = 1;
+
+ WifiInfo wifiInfo = new WifiInfo();
+ wifiInfo.setNetworkId(networkId);
+ wifiInfo.setRssi(rssi);
+
+ NetworkInfo networkInfo =
+ new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
+ networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
+
+ AccessPoint ap = new TestAccessPointBuilder(mContext)
+ .setNetworkInfo(networkInfo)
+ .setNetworkId(networkId)
+ .setRssi(rssi)
+ .setWifiInfo(wifiInfo)
+ .build();
+
+ AccessPoint.AccessPointListener mockListener = mock(AccessPoint.AccessPointListener.class);
+ ap.setListener(mockListener);
+ WifiConfiguration newConfig = new WifiConfiguration(config);
+ config.validatedInternetAccess = true;
+
+ assertThat(ap.update(newConfig, wifiInfo, networkInfo)).isFalse();
+ verify(mockListener).onAccessPointChanged(ap);
+ }
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 340ef016d74d..071f9216ea56 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -59,6 +59,7 @@ import android.provider.Settings;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.FlakyTest;
import org.junit.After;
import org.junit.Before;
@@ -94,7 +95,7 @@ public class WifiTrackerTest {
new NetworkKey(new WifiKey('"' + SSID_1 + '"', BSSID_1));
private static final int RSSI_1 = -30;
private static final byte SCORE_1 = 10;
- private static final int BADGE_1 = AccessPoint.SPEED_MEDIUM;
+ private static final int BADGE_1 = AccessPoint.Speed.MODERATE;
private static final String SSID_2 = "ssid2";
private static final String BSSID_2 = "AA:AA:AA:AA:AA:AA";
@@ -102,7 +103,7 @@ public class WifiTrackerTest {
new NetworkKey(new WifiKey('"' + SSID_2 + '"', BSSID_2));
private static final int RSSI_2 = -30;
private static final byte SCORE_2 = 15;
- private static final int BADGE_2 = AccessPoint.SPEED_FAST;
+ private static final int BADGE_2 = AccessPoint.Speed.FAST;
private static final int CONNECTED_NETWORK_ID = 123;
private static final int CONNECTED_RSSI = -50;
@@ -256,6 +257,7 @@ public class WifiTrackerTest {
}
sendScanResultsAndProcess(tracker);
+ waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
return tracker;
}
@@ -341,6 +343,23 @@ public class WifiTrackerTest {
return createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(intent);
}
+ private void waitForHandlersToProcessCurrentlyEnqueuedMessages(WifiTracker tracker)
+ throws InterruptedException {
+ CountDownLatch workerLatch = new CountDownLatch(1);
+ tracker.mWorkHandler.post(() -> {
+ workerLatch.countDown();
+ });
+ assertTrue("Latch timed out while waiting for WorkerHandler",
+ workerLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
+
+ CountDownLatch mainLatch = new CountDownLatch(1);
+ tracker.mMainHandler.post(() -> {
+ mainLatch.countDown();
+ });
+ assertTrue("Latch timed out while waiting for MainHandler",
+ mainLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
+ }
+
@Test
public void testAccessPointListenerSetWhenLookingUpUsingScanResults() {
ScanResult scanResult = new ScanResult();
@@ -426,7 +445,7 @@ public class WifiTrackerTest {
@Test
public void startTrackingShouldSetConnectedAccessPointAsActive() throws InterruptedException {
- WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
+ WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
List<AccessPoint> aps = tracker.getAccessPoints();
@@ -460,18 +479,21 @@ public class WifiTrackerTest {
startTracking(tracker);
sendScanResultsAndProcess(tracker);
- updateScoresAndWaitForAccessPointsChangedCallback();
+ updateScoresAndWaitForAccessPointsChangedCallback(tracker);
}
- private void updateScoresAndWaitForAccessPointsChangedCallback() throws InterruptedException {
+ private void updateScoresAndWaitForAccessPointsChangedCallback(WifiTracker tracker)
+ throws InterruptedException {
// Updating scores can happen together or one after the other, so the latch countdown is set
// to 2.
- mAccessPointsChangedLatch = new CountDownLatch(2);
+ mAccessPointsChangedLatch = new CountDownLatch(1);
updateScores();
- assertTrue("onAccessPointChanged was not called twice",
+ assertTrue("onAccessPointChanged was not called after updating scores",
mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
+ waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
}
+ @FlakyTest
@Test
public void scoreCacheUpdateScoresShouldChangeSortOrder() throws InterruptedException {
WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
@@ -480,7 +502,7 @@ public class WifiTrackerTest {
assertEquals(aps.get(0).getSsidStr(), SSID_1);
assertEquals(aps.get(1).getSsidStr(), SSID_2);
- updateScoresAndWaitForAccessPointsChangedCallback();
+ updateScoresAndWaitForAccessPointsChangedCallback(tracker);
aps = tracker.getAccessPoints();
assertTrue(aps.size() == 2);
@@ -502,7 +524,7 @@ public class WifiTrackerTest {
assertEquals(aps.get(0).getSsidStr(), SSID_1);
assertEquals(aps.get(1).getSsidStr(), SSID_2);
- updateScoresAndWaitForAccessPointsChangedCallback();
+ updateScoresAndWaitForAccessPointsChangedCallback(tracker);
aps = tracker.getAccessPoints();
assertTrue(aps.size() == 2);
@@ -510,11 +532,12 @@ public class WifiTrackerTest {
assertEquals(aps.get(1).getSsidStr(), SSID_2);
}
+ @FlakyTest
@Test
public void scoreCacheUpdateScoresShouldInsertSpeedIntoAccessPoint()
throws InterruptedException {
WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
- updateScoresAndWaitForAccessPointsChangedCallback();
+ updateScoresAndWaitForAccessPointsChangedCallback(tracker);
List<AccessPoint> aps = tracker.getAccessPoints();
@@ -531,7 +554,7 @@ public class WifiTrackerTest {
public void scoreCacheUpdateMeteredShouldUpdateAccessPointMetering()
throws InterruptedException {
WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
- updateScoresAndWaitForAccessPointsChangedCallback();
+ updateScoresAndWaitForAccessPointsChangedCallback(tracker);
List<AccessPoint> aps = tracker.getAccessPoints();
@@ -553,15 +576,15 @@ public class WifiTrackerTest {
0 /* disabled */);
WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
- updateScoresAndWaitForAccessPointsChangedCallback();
+ updateScoresAndWaitForAccessPointsChangedCallback(tracker);
List<AccessPoint> aps = tracker.getAccessPoints();
for (AccessPoint ap : aps) {
if (ap.getSsidStr().equals(SSID_1)) {
- assertEquals(AccessPoint.SPEED_NONE, ap.getSpeed());
+ assertEquals(AccessPoint.Speed.NONE, ap.getSpeed());
} else if (ap.getSsidStr().equals(SSID_2)) {
- assertEquals(AccessPoint.SPEED_NONE, ap.getSpeed());
+ assertEquals(AccessPoint.Speed.NONE, ap.getSpeed());
}
}
}
@@ -754,13 +777,10 @@ public class WifiTrackerTest {
throws Exception {
WifiTracker tracker = createMockedWifiTracker();
startTracking(tracker);
- tracker.stopTracking();
+ waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
- CountDownLatch latch1 = new CountDownLatch(1);
- tracker.mMainHandler.post(() -> {
- latch1.countDown();
- });
- assertTrue("Latch 1 timed out", latch1.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
+ tracker.stopTracking();
+ waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
startTracking(tracker);
@@ -770,14 +790,24 @@ public class WifiTrackerTest {
tracker.mReceiver.onReceive(
mContext, new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION));
- CountDownLatch latch2 = new CountDownLatch(1);
- tracker.mMainHandler.post(() -> {
- latch2.countDown();
- });
- assertTrue("Latch 2 timed out", latch2.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
+ waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
verify(mockWifiListener, never()).onAccessPointsChanged();
sendScanResultsAndProcess(tracker); // verifies onAccessPointsChanged is invoked
}
+
+ @Test
+ public void disablingWifiShouldClearExistingAccessPoints() throws Exception {
+ WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
+
+ when(mockWifiManager.isWifiEnabled()).thenReturn(false);
+ mAccessPointsChangedLatch = new CountDownLatch(1);
+ tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
+
+ mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+ waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
+
+ assertThat(tracker.getAccessPoints()).isEmpty();
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java
new file mode 100644
index 000000000000..335653bc2f18
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.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.settingslib.wifi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import com.android.settingslib.SettingLibRobolectricTestRunner;
+import com.android.settingslib.TestConfig;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class AccessPointPreferenceTest {
+
+ private Context mContext = RuntimeEnvironment.application;
+
+ @Test
+ public void generatePreferenceKey_shouldReturnSsidPlusSecurity() {
+ String ssid = "ssid";
+ int security = AccessPoint.SECURITY_WEP;
+ String expectedKey = ssid + ',' + security;
+
+ TestAccessPointBuilder builder = new TestAccessPointBuilder(mContext);
+ builder.setSsid(ssid).setSecurity(security);
+
+ assertThat(AccessPointPreference.generatePreferenceKey(builder.build()))
+ .isEqualTo(expectedKey);
+ }
+
+ @Test
+ public void generatePreferenceKey_shouldReturnBssidPlusSecurity() {
+ String bssid = "bssid";
+ int security = AccessPoint.SECURITY_WEP;
+ String expectedKey = bssid + ',' + security;
+
+ TestAccessPointBuilder builder = new TestAccessPointBuilder(mContext);
+ builder.setBssid(bssid).setSecurity(security);
+
+ assertThat(AccessPointPreference.generatePreferenceKey(builder.build()))
+ .isEqualTo(expectedKey);
+ }
+}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index d57124381c1f..a648345e9c04 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -31,9 +31,9 @@ import com.android.systemui.plugins.qs.QS.HeightListener;
@DependsOn(target = HeightListener.class)
public interface QS extends FragmentBase {
- public static final String ACTION = "com.android.systemui.action.PLUGIN_QS";
+ String ACTION = "com.android.systemui.action.PLUGIN_QS";
- public static final int VERSION = 6;
+ int VERSION = 6;
String TAG = "QS";
@@ -66,8 +66,8 @@ public interface QS extends FragmentBase {
}
@ProvidesInterface(version = HeightListener.VERSION)
- public interface HeightListener {
- public static final int VERSION = 1;
+ interface HeightListener {
+ int VERSION = 1;
void onQsHeightChanged();
}
diff --git a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_bottom.xml b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_bottom.xml
deleted file mode 100644
index b003e92f7a15..000000000000
--- a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_bottom.xml
+++ /dev/null
@@ -1,33 +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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="367"
- android:propertyName="fillAlpha"
- android:valueFrom="1"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
- <objectAnimator
- android:duration="33"
- android:propertyName="fillAlpha"
- android:valueFrom="1"
- android:valueTo="0"
- android:interpolator="@android:interpolator/linear" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_top.xml b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_top.xml
deleted file mode 100644
index b003e92f7a15..000000000000
--- a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_top.xml
+++ /dev/null
@@ -1,33 +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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="367"
- android:propertyName="fillAlpha"
- android:valueFrom="1"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
- <objectAnimator
- android:duration="33"
- android:propertyName="fillAlpha"
- android:valueFrom="1"
- android:valueTo="0"
- android:interpolator="@android:interpolator/linear" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_bottom.xml b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_bottom.xml
deleted file mode 100644
index fa10b1194977..000000000000
--- a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_bottom.xml
+++ /dev/null
@@ -1,33 +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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="50"
- android:propertyName="fillAlpha"
- android:valueFrom="0"
- android:valueTo="0"
- android:interpolator="@android:interpolator/linear" />
- <objectAnimator
- android:duration="33"
- android:propertyName="fillAlpha"
- android:valueFrom="0"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_top.xml b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_top.xml
deleted file mode 100644
index fa10b1194977..000000000000
--- a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_top.xml
+++ /dev/null
@@ -1,33 +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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="50"
- android:propertyName="fillAlpha"
- android:valueFrom="0"
- android:valueTo="0"
- android:interpolator="@android:interpolator/linear" />
- <objectAnimator
- android:duration="33"
- android:propertyName="fillAlpha"
- android:valueFrom="0"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_body.xml b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_body.xml
deleted file mode 100644
index aa22c3b72540..000000000000
--- a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_body.xml
+++ /dev/null
@@ -1,35 +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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="67"
- android:propertyName="pathData"
- android:valueFrom="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
- android:valueTo="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
- android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:duration="217"
- android:propertyName="pathData"
- android:valueFrom="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
- android:valueTo="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
- android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device.xml b/packages/SystemUI/res/anim/ic_landscape_to_rotate_arrows_animation.xml
index 6a0a20bd1242..8fdad809f0d1 100644
--- a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device.xml
+++ b/packages/SystemUI/res/anim/ic_landscape_to_rotate_arrows_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,11 +14,13 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
<objectAnimator
- android:duration="400"
+ android:duration="616"
android:propertyName="rotation"
- android:valueFrom="0"
- android:valueTo="-135"
+ android:valueFrom="-90.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/fast_out_slow_in" />
</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_bottom.xml b/packages/SystemUI/res/anim/ic_landscape_to_rotate_bottom_merged_animation.xml
index 682dcf35e076..3c3c131ef16b 100644
--- a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_bottom.xml
+++ b/packages/SystemUI/res/anim/ic_landscape_to_rotate_bottom_merged_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,20 +14,23 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
<set
android:ordering="sequentially" >
<objectAnimator
android:duration="50"
android:propertyName="fillAlpha"
- android:valueFrom="0"
- android:valueTo="0"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
<objectAnimator
android:duration="83"
android:propertyName="fillAlpha"
- android:valueFrom="0"
- android:valueTo="1"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
</set>
</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_to_rotate_landscape_animation.xml b/packages/SystemUI/res/anim/ic_landscape_to_rotate_landscape_animation.xml
new file mode 100644
index 000000000000..57132e19dcc5
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_landscape_to_rotate_landscape_animation.xml
@@ -0,0 +1,50 @@
+<?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.
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="466"
+ android:propertyName="scaleX"
+ android:valueFrom="1.0"
+ android:valueTo="0.909"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/ic_landscape_to_rotate_animation_interpolator_0" />
+ <objectAnimator
+ android:duration="466"
+ android:propertyName="scaleY"
+ android:valueFrom="1.0"
+ android:valueTo="0.909"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/ic_landscape_to_rotate_animation_interpolator_0" />
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="rotation"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="400"
+ android:propertyName="rotation"
+ android:valueFrom="0.0"
+ android:valueTo="45.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device_1.xml b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device_1.xml
deleted file mode 100644
index 92b19add4bcb..000000000000
--- a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device_1.xml
+++ /dev/null
@@ -1,35 +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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="167"
- android:propertyName="pathData"
- android:valueFrom="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
- android:valueTo="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
- android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:duration="217"
- android:propertyName="pathData"
- android:valueFrom="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
- android:valueTo="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
- android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrows.xml b/packages/SystemUI/res/anim/ic_portrait_to_rotate_arrows_0_animation.xml
index 61bdfeaa27a0..ad2a5fad5268 100644
--- a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrows.xml
+++ b/packages/SystemUI/res/anim/ic_portrait_to_rotate_arrows_0_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,41 +14,40 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
<set
android:ordering="sequentially" >
<objectAnimator
- android:duration="117"
+ android:duration="116"
android:propertyName="scaleX"
- android:valueFrom="1"
- android:valueTo="1"
+ android:valueFrom="1.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
<objectAnimator
android:duration="333"
android:propertyName="scaleX"
- android:valueFrom="1"
+ android:valueFrom="1.0"
android:valueTo="0.9"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
</set>
<set
android:ordering="sequentially" >
<objectAnimator
- android:duration="117"
+ android:duration="116"
android:propertyName="scaleY"
- android:valueFrom="1"
- android:valueTo="1"
+ android:valueFrom="1.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
<objectAnimator
android:duration="333"
android:propertyName="scaleY"
- android:valueFrom="1"
+ android:valueFrom="1.0"
android:valueTo="0.9"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
</set>
- <objectAnimator
- android:duration="617"
- android:propertyName="rotation"
- android:valueFrom="0"
- android:valueTo="-221"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_device.xml b/packages/SystemUI/res/anim/ic_portrait_to_rotate_arrows_animation.xml
index 2530f08179a2..cdb7890dc170 100644
--- a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_device.xml
+++ b/packages/SystemUI/res/anim/ic_portrait_to_rotate_arrows_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,11 +14,13 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
<objectAnimator
- android:duration="400"
+ android:duration="616"
android:propertyName="rotation"
- android:valueFrom="-45"
- android:valueTo="0"
+ android:valueFrom="0.0"
+ android:valueTo="-221.0"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/fast_out_slow_in" />
</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_bottom.xml b/packages/SystemUI/res/anim/ic_portrait_to_rotate_bottom_merged_animation.xml
index 4e20d8190bbc..46100b407831 100644
--- a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_bottom.xml
+++ b/packages/SystemUI/res/anim/ic_portrait_to_rotate_bottom_merged_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,20 +14,23 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
<set
android:ordering="sequentially" >
<objectAnimator
android:duration="400"
android:propertyName="fillAlpha"
- android:valueFrom="1"
- android:valueTo="1"
+ android:valueFrom="1.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
<objectAnimator
android:duration="83"
android:propertyName="fillAlpha"
- android:valueFrom="1"
- android:valueTo="0"
+ android:valueFrom="1.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
</set>
</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_device.xml b/packages/SystemUI/res/anim/ic_portrait_to_rotate_device_0_animation.xml
index 27fd65324bab..8f6d24d0d61d 100644
--- a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_device.xml
+++ b/packages/SystemUI/res/anim/ic_portrait_to_rotate_device_0_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,11 +14,13 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
<objectAnimator
android:duration="400"
android:propertyName="rotation"
- android:valueFrom="0"
- android:valueTo="-45"
+ android:valueFrom="0.0"
+ android:valueTo="-135.0"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/fast_out_slow_in" />
</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_body.xml b/packages/SystemUI/res/anim/ic_portrait_to_rotate_device_merged_animation.xml
index aa086c9399d4..300ed53052a8 100644
--- a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_body.xml
+++ b/packages/SystemUI/res/anim/ic_portrait_to_rotate_device_merged_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,18 +14,19 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
<set
android:ordering="sequentially" >
<objectAnimator
- android:duration="67"
+ android:duration="66"
android:propertyName="pathData"
android:valueFrom="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
android:valueTo="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
+ android:interpolator="@android:interpolator/linear" />
<objectAnimator
- android:duration="217"
+ android:duration="216"
android:propertyName="pathData"
android:valueFrom="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
android:valueTo="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
diff --git a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrows.xml b/packages/SystemUI/res/anim/ic_rotate_to_landscape_arrows_0_animation.xml
index 9fa8ec0d65d4..ad2a5fad5268 100644
--- a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrows.xml
+++ b/packages/SystemUI/res/anim/ic_rotate_to_landscape_arrows_0_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,41 +14,40 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
<set
android:ordering="sequentially" >
<objectAnimator
- android:duration="133"
+ android:duration="116"
android:propertyName="scaleX"
- android:valueFrom="0.9"
- android:valueTo="0.9"
+ android:valueFrom="1.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
<objectAnimator
android:duration="333"
android:propertyName="scaleX"
- android:valueFrom="0.9"
- android:valueTo="1"
+ android:valueFrom="1.0"
+ android:valueTo="0.9"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
</set>
<set
android:ordering="sequentially" >
<objectAnimator
- android:duration="133"
+ android:duration="116"
android:propertyName="scaleY"
- android:valueFrom="0.9"
- android:valueTo="0.9"
+ android:valueFrom="1.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
<objectAnimator
android:duration="333"
android:propertyName="scaleY"
- android:valueFrom="0.9"
- android:valueTo="1"
+ android:valueFrom="1.0"
+ android:valueTo="0.9"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
</set>
- <objectAnimator
- android:duration="617"
- android:propertyName="rotation"
- android:valueFrom="-221"
- android:valueTo="0"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
</set>
diff --git a/packages/SystemUI/res/anim/ic_rotate_to_landscape_arrows_animation.xml b/packages/SystemUI/res/anim/ic_rotate_to_landscape_arrows_animation.xml
new file mode 100644
index 000000000000..c1521520c427
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_rotate_to_landscape_arrows_animation.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.
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="616"
+ android:propertyName="rotation"
+ android:valueFrom="0.0"
+ android:valueTo="-180.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_top.xml b/packages/SystemUI/res/anim/ic_rotate_to_landscape_bottom_merged_animation.xml
index 4e20d8190bbc..b2c1eb8b93a3 100644
--- a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_top.xml
+++ b/packages/SystemUI/res/anim/ic_rotate_to_landscape_bottom_merged_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,20 +14,23 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
<set
android:ordering="sequentially" >
<objectAnimator
- android:duration="400"
+ android:duration="200"
android:propertyName="fillAlpha"
- android:valueFrom="1"
- android:valueTo="1"
+ android:valueFrom="1.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
<objectAnimator
android:duration="83"
android:propertyName="fillAlpha"
- android:valueFrom="1"
- android:valueTo="0"
+ android:valueFrom="1.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
</set>
</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrows.xml b/packages/SystemUI/res/anim/ic_rotate_to_landscape_landscape_animation.xml
index 5c374797e7dd..2a9bbe32975e 100644
--- a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrows.xml
+++ b/packages/SystemUI/res/anim/ic_rotate_to_landscape_landscape_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,41 +14,47 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
<set
android:ordering="sequentially" >
<objectAnimator
- android:duration="117"
+ android:duration="116"
android:propertyName="scaleX"
- android:valueFrom="1"
- android:valueTo="1"
+ android:valueFrom="0.909"
+ android:valueTo="0.909"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
<objectAnimator
- android:duration="333"
+ android:duration="166"
android:propertyName="scaleX"
- android:valueFrom="1"
- android:valueTo="0.9"
- android:interpolator="@android:interpolator/linear" />
+ android:valueFrom="0.909"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/ic_rotate_to_landscape_animation_interpolator_0" />
</set>
<set
android:ordering="sequentially" >
<objectAnimator
- android:duration="117"
+ android:duration="116"
android:propertyName="scaleY"
- android:valueFrom="1"
- android:valueTo="1"
+ android:valueFrom="0.909"
+ android:valueTo="0.909"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
<objectAnimator
- android:duration="333"
+ android:duration="166"
android:propertyName="scaleY"
- android:valueFrom="1"
- android:valueTo="0.9"
- android:interpolator="@android:interpolator/linear" />
+ android:valueFrom="0.909"
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/ic_rotate_to_landscape_animation_interpolator_0" />
</set>
<objectAnimator
- android:duration="450"
+ android:duration="616"
android:propertyName="rotation"
- android:valueFrom="0"
- android:valueTo="-135"
- android:interpolator="@interpolator/ic_landscape_from_auto_rotate_arrows_rotation_interpolator" />
+ android:valueFrom="45.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrows.xml b/packages/SystemUI/res/anim/ic_rotate_to_portrait_arrows_0_animation.xml
index caae73a1445c..ce267704dac5 100644
--- a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrows.xml
+++ b/packages/SystemUI/res/anim/ic_rotate_to_portrait_arrows_0_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,23 +14,20 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
<objectAnimator
- android:duration="333"
+ android:duration="466"
android:propertyName="scaleX"
android:valueFrom="0.9"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/ic_rotate_to_portrait_animation_interpolator_0" />
<objectAnimator
- android:duration="333"
+ android:duration="466"
android:propertyName="scaleY"
android:valueFrom="0.9"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
- <objectAnimator
- android:duration="450"
- android:propertyName="rotation"
- android:valueFrom="-135"
- android:valueTo="0"
- android:interpolator="@interpolator/ic_landscape_to_auto_rotate_arrows_rotation_interpolator" />
+ android:valueTo="1.0"
+ android:valueType="floatType"
+ android:interpolator="@interpolator/ic_rotate_to_portrait_animation_interpolator_0" />
</set>
diff --git a/packages/SystemUI/res/anim/ic_rotate_to_portrait_arrows_animation.xml b/packages/SystemUI/res/anim/ic_rotate_to_portrait_arrows_animation.xml
new file mode 100644
index 000000000000..6e8941d608cd
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_rotate_to_portrait_arrows_animation.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.
+-->
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="616"
+ android:propertyName="rotation"
+ android:valueFrom="-221.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_top.xml b/packages/SystemUI/res/anim/ic_rotate_to_portrait_bottom_merged_animation.xml
index 682dcf35e076..3c3c131ef16b 100644
--- a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_top.xml
+++ b/packages/SystemUI/res/anim/ic_rotate_to_portrait_bottom_merged_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,20 +14,23 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
<set
android:ordering="sequentially" >
<objectAnimator
android:duration="50"
android:propertyName="fillAlpha"
- android:valueFrom="0"
- android:valueTo="0"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
<objectAnimator
android:duration="83"
android:propertyName="fillAlpha"
- android:valueFrom="0"
- android:valueTo="1"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/linear" />
</set>
</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device.xml b/packages/SystemUI/res/anim/ic_rotate_to_portrait_device_0_animation.xml
index 3208eee2c2c6..fd8e4f881160 100644
--- a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device.xml
+++ b/packages/SystemUI/res/anim/ic_rotate_to_portrait_device_0_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,20 +14,23 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
<set
android:ordering="sequentially" >
<objectAnimator
android:duration="50"
android:propertyName="rotation"
- android:valueFrom="-135"
- android:valueTo="-135"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
+ android:valueFrom="-135.0"
+ android:valueTo="-135.0"
+ android:valueType="floatType"
+ android:interpolator="@android:interpolator/linear" />
<objectAnimator
android:duration="400"
android:propertyName="rotation"
- android:valueFrom="-135"
- android:valueTo="0"
+ android:valueFrom="-135.0"
+ android:valueTo="0.0"
+ android:valueType="floatType"
android:interpolator="@android:interpolator/fast_out_slow_in" />
</set>
</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device_1.xml b/packages/SystemUI/res/anim/ic_rotate_to_portrait_device_merged_animation.xml
index c1124af4e234..a77a536e46c0 100644
--- a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device_1.xml
+++ b/packages/SystemUI/res/anim/ic_rotate_to_portrait_device_merged_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,7 +14,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
<set
android:ordering="sequentially" >
<objectAnimator
@@ -23,7 +24,7 @@
android:valueFrom="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
android:valueTo="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
+ android:interpolator="@android:interpolator/linear" />
<objectAnimator
android:duration="500"
android:propertyName="pathData"
diff --git a/packages/SystemUI/res/drawable/brightness_mirror_background.xml b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
index 0c69d89b4709..b3a04841e64f 100644
--- a/packages/SystemUI/res/drawable/brightness_mirror_background.xml
+++ b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
@@ -15,5 +15,5 @@
~ limitations under the License
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="?android:attr/colorPrimary" />
+ <solid android:color="@color/qs_background_dark" />
</shape>
diff --git a/packages/SystemUI/res/drawable/car_qs_background_primary.xml b/packages/SystemUI/res/drawable/car_qs_background_primary.xml
new file mode 100644
index 000000000000..0f77987bb7ce
--- /dev/null
+++ b/packages/SystemUI/res/drawable/car_qs_background_primary.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android">
+ <shape>
+ <solid android:color="?android:attr/colorPrimaryDark"/>
+ </shape>
+</inset>
diff --git a/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate.xml
index 8b2585bb9958..061f9fe81a75 100644
--- a/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate.xml
+++ b/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,49 +14,52 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="ic_rotate_to_landscape"
android:height="48dp"
android:width="48dp"
android:viewportHeight="48"
android:viewportWidth="48"
android:tint="?android:attr/colorControlNormal" >
<group
- android:name="ic_screen_rotation_48px_outlines"
+ android:name="device"
android:translateX="24"
android:translateY="24" >
<group
- android:name="ic_screen_rotation_48px_outlines_pivot"
+ android:name="device_pivot"
android:translateX="-24.15"
android:translateY="-24.25" >
<group
- android:name="arrows"
- android:translateX="24.1"
- android:translateY="24.1" >
- <group
- android:name="arrows_pivot"
- android:translateX="-24.1"
- android:translateY="-24.1" >
- <path
- android:name="arrow_top"
- android:pathData="M 33.1499938965,5.25 c 6.5,3.10000610352 11.1999969482,9.40000915527 11.8999938965,17.0 c 0.0,0.0 3.00001525879,0.0 3.00001525879,0.0 c -1.00001525879,-12.3000030518 -11.3000030518,-22.0 -23.9000091553,-22.0 c -0.399993896484,0.0 -0.899993896484,0.0 -1.30000305176,0.100006103516 c 0.0,0.0 7.60000610352,7.59999084473 7.60000610352,7.59999084473 c 0.0,0.0 2.69999694824,-2.69999694824 2.69999694824,-2.69999694824 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
- <path
- android:name="arrow_bottom"
- android:pathData="M 15.1499938965,43.25 c -6.5,-3.09999084473 -11.1999969482,-9.5 -11.8999938965,-17.0 c 0.0,0.0 -3.0,0.0 -3.0,0.0 c 1.0,12.3000030518 11.299987793,22.0 23.8999938965,22.0 c 0.399993896484,0.0 0.899993896484,0.0 1.30000305176,-0.0999908447266 c 0.0,0.0 -7.60000610352,-7.60000610352 -7.60000610352,-7.60000610352 c 0.0,0.0 -2.69999694824,2.69999694824 -2.69999694824,2.69999694824 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
- </group>
+ android:name="landscape"
+ android:translateX="24"
+ android:translateY="24"
+ android:scaleX="0.909"
+ android:scaleY="0.909"
+ android:rotation="45" >
+ <path
+ android:name="device_merged"
+ android:pathData="M -21.9799957275,-10.0 c 0.0,0.0 -0.0200042724609,20.0 -0.0200042724609,20.0 c 0.0,2.19999694824 1.80000305176,4.0 4.0,4.0 c 0.0,0.0 36.0,0.0 36.0,0.0 c 2.19999694824,0.0 4.0,-1.80000305176 4.0,-4.0 c 0.0,0.0 0.0,-20.0 0.0,-20.0 c 0.0,-2.19999694824 -1.80000305176,-4.0 -4.0,-4.0 c 0.0,0.0 -36.0,0.0 -36.0,0.0 c -2.19999694824,0.0 -3.97999572754,1.80000305176 -3.97999572754,4.0 Z M 14.0,10.0 c 0.0,0.0 -28.0,0.0 -28.0,0.0 c 0.0,0.0 0.0,-20.0 0.0,-20.0 c 0.0,0.0 28.0,0.0 28.0,0.0 c 0.0,0.0 0.0,20.0 0.0,20.0 Z"
+ android:fillColor="#FFFFFFFF" />
</group>
+ </group>
+ </group>
+ <group
+ android:name="arrows"
+ android:translateX="24"
+ android:translateY="24" >
+ <group
+ android:name="arrows_pivot"
+ android:translateX="-24.0798"
+ android:translateY="-24.23" >
<group
- android:name="device"
- android:translateX="24.14999"
- android:translateY="24.25" >
+ android:name="arrows_0"
+ android:translateX="12.2505"
+ android:translateY="37.2145" >
<path
- android:name="body"
- android:pathData="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
+ android:name="bottom_merged"
+ android:pathData="M 20.7395019531,-31.9844970703 c 6.23999023438,2.83999633789 10.6999969482,8.7200012207 11.8399963379,15.7799987793 c 0.119995117188,0.699996948242 0.740005493164,1.2200012207 1.46099853516,1.2200012207 c 0.919998168945,0.0 1.6190032959,-0.84001159668 1.47900390625,-1.74000549316 c -1.75900268555,-10.3800048828 -9.75900268555,-19.1199951172 -22.5800018311,-20.1600036621 c -0.919998168945,-0.0800018310547 -1.43899536133,1.04000854492 -0.800003051758,1.70001220703 c 0.0,0.0 5.12100219727,5.11999511719 5.12100219727,5.11999511719 c 0.378997802734,0.380004882812 0.97900390625,0.380004882812 1.37899780273,0.020004272461 c 0.0,0.0 2.10000610352,-1.94000244141 2.10000610352,-1.94000244141 Z M 2.73950195312,6.01550292969 c -6.26000976562,-2.83999633789 -10.7200012207,-8.76000976562 -11.8399963379,-15.8600006104 c -0.118011474609,-0.667007446289 -0.702011108398,-1.15100097656 -1.38000488281,-1.13999938965 c -0.860000610352,0.0 -1.52000427246,0.759994506836 -1.38000488281,1.61999511719 c 1.54000854492,10.4000091553 9.5,19.2200012207 22.4199981689,20.2799987793 c 0.920013427734,0.0800018310547 1.44100952148,-1.03999328613 0.800003051758,-1.69999694824 c 0.0,0.0 -5.11999511719,-5.11999511719 -5.11999511719,-5.11999511719 c -0.380004882812,-0.376007080078 -0.988998413086,-0.385009765625 -1.38000488281,-0.0200042724609 c 0.0,0.0 -2.11999511719,1.94000244141 -2.11999511719,1.94000244141 Z"
+ android:fillColor="#FFFFFFFF" />
</group>
</group>
</group>
diff --git a/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate_animation.xml b/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate_animation.xml
index 400a28ba4e7d..00bcaf6e2359 100644
--- a/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,21 +14,19 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_landscape_from_auto_rotate" >
<target
- android:name="arrows"
- android:animation="@anim/ic_landscape_from_auto_rotate_animation_arrows" />
- <target
- android:name="arrow_top"
- android:animation="@anim/ic_landscape_from_auto_rotate_animation_arrow_top" />
+ android:name="landscape"
+ android:animation="@anim/ic_rotate_to_landscape_landscape_animation" />
<target
- android:name="arrow_bottom"
- android:animation="@anim/ic_landscape_from_auto_rotate_animation_arrow_bottom" />
+ android:name="arrows"
+ android:animation="@anim/ic_rotate_to_landscape_arrows_animation" />
<target
- android:name="device"
- android:animation="@anim/ic_landscape_from_auto_rotate_animation_device" />
+ android:name="arrows_0"
+ android:animation="@anim/ic_rotate_to_landscape_arrows_0_animation" />
<target
- android:name="body"
- android:animation="@anim/ic_landscape_from_auto_rotate_animation_body" />
+ android:name="bottom_merged"
+ android:animation="@anim/ic_rotate_to_landscape_bottom_merged_animation" />
</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate.xml
index 603d0bfd11bc..cde67976337e 100644
--- a/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate.xml
+++ b/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,53 +14,51 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="ic_landscape_to_rotate"
android:height="48dp"
android:width="48dp"
android:viewportHeight="48"
android:viewportWidth="48"
android:tint="?android:attr/colorControlNormal" >
<group
- android:name="ic_screen_rotation_48px_outlines"
+ android:name="device"
android:translateX="24"
android:translateY="24" >
<group
- android:name="ic_screen_rotation_48px_outlines_pivot"
+ android:name="device_pivot"
android:translateX="-24.15"
android:translateY="-24.25" >
<group
- android:name="arrows"
- android:translateX="24.1"
- android:translateY="24.1"
- android:scaleX="0.9"
- android:scaleY="0.9"
- android:rotation="-135" >
- <group
- android:name="arrows_pivot"
- android:translateX="-24.1"
- android:translateY="-24.1" >
- <path
- android:name="arrow_top"
- android:pathData="M 33.1499938965,5.25 c 6.5,3.10000610352 11.1999969482,9.40000915527 11.8999938965,17.0 c 0.0,0.0 3.00001525879,0.0 3.00001525879,0.0 c -1.00001525879,-12.3000030518 -11.3000030518,-22.0 -23.9000091553,-22.0 c -0.399993896484,0.0 -0.899993896484,0.0 -1.30000305176,0.100006103516 c 0.0,0.0 7.60000610352,7.59999084473 7.60000610352,7.59999084473 c 0.0,0.0 2.69999694824,-2.69999694824 2.69999694824,-2.69999694824 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="0" />
- <path
- android:name="arrow_bottom"
- android:pathData="M 15.1499938965,43.25 c -6.5,-3.09999084473 -11.1999969482,-9.5 -11.8999938965,-17.0 c 0.0,0.0 -3.0,0.0 -3.0,0.0 c 1.0,12.3000030518 11.299987793,22.0 23.8999938965,22.0 c 0.399993896484,0.0 0.899993896484,0.0 1.30000305176,-0.0999908447266 c 0.0,0.0 -7.60000610352,-7.60000610352 -7.60000610352,-7.60000610352 c 0.0,0.0 -2.69999694824,2.69999694824 -2.69999694824,2.69999694824 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="0" />
- </group>
+ android:name="landscape"
+ android:translateX="24"
+ android:translateY="24" >
+ <path
+ android:name="device_merged"
+ android:pathData="M -21.9799957275,-10.0 c 0.0,0.0 -0.0200042724609,20.0 -0.0200042724609,20.0 c 0.0,2.19999694824 1.80000305176,4.0 4.0,4.0 c 0.0,0.0 36.0,0.0 36.0,0.0 c 2.19999694824,0.0 4.0,-1.80000305176 4.0,-4.0 c 0.0,0.0 0.0,-20.0 0.0,-20.0 c 0.0,-2.19999694824 -1.80000305176,-4.0 -4.0,-4.0 c 0.0,0.0 -36.0,0.0 -36.0,0.0 c -2.19999694824,0.0 -3.97999572754,1.80000305176 -3.97999572754,4.0 Z M 14.0,10.0 c 0.0,0.0 -28.0,0.0 -28.0,0.0 c 0.0,0.0 0.0,-20.0 0.0,-20.0 c 0.0,0.0 28.0,0.0 28.0,0.0 c 0.0,0.0 0.0,20.0 0.0,20.0 Z"
+ android:fillColor="#FFFFFFFF" />
</group>
+ </group>
+ </group>
+ <group
+ android:name="arrows"
+ android:translateX="24"
+ android:translateY="24"
+ android:rotation="-90" >
+ <group
+ android:name="arrows_pivot"
+ android:translateX="-24.0798"
+ android:translateY="-24.23" >
<group
- android:name="device"
- android:translateX="24.14999"
- android:translateY="24.25"
- android:rotation="-45" >
+ android:name="arrows_0"
+ android:translateX="12.2505"
+ android:translateY="37.2145" >
<path
- android:name="body"
- android:pathData="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
+ android:name="bottom_merged"
+ android:pathData="M 20.7395019531,-31.9844970703 c 6.23999023438,2.83999633789 10.6999969482,8.7200012207 11.8399963379,15.7799987793 c 0.119995117188,0.699996948242 0.740005493164,1.2200012207 1.46099853516,1.2200012207 c 0.919998168945,0.0 1.6190032959,-0.84001159668 1.47900390625,-1.74000549316 c -1.75900268555,-10.3800048828 -9.75900268555,-19.1199951172 -22.5800018311,-20.1600036621 c -0.919998168945,-0.0800018310547 -1.43899536133,1.04000854492 -0.800003051758,1.70001220703 c 0.0,0.0 5.12100219727,5.11999511719 5.12100219727,5.11999511719 c 0.378997802734,0.380004882812 0.97900390625,0.380004882812 1.37899780273,0.020004272461 c 0.0,0.0 2.10000610352,-1.94000244141 2.10000610352,-1.94000244141 Z M 2.73950195312,6.01550292969 c -6.26000976562,-2.83999633789 -10.7200012207,-8.76000976562 -11.8399963379,-15.8600006104 c -0.118011474609,-0.667007446289 -0.702011108398,-1.15100097656 -1.38000488281,-1.13999938965 c -0.860000610352,0.0 -1.52000427246,0.759994506836 -1.38000488281,1.61999511719 c 1.54000854492,10.4000091553 9.5,19.2200012207 22.4199981689,20.2799987793 c 0.920013427734,0.0800018310547 1.44100952148,-1.03999328613 0.800003051758,-1.69999694824 c 0.0,0.0 -5.11999511719,-5.11999511719 -5.11999511719,-5.11999511719 c -0.380004882812,-0.376007080078 -0.988998413086,-0.385009765625 -1.38000488281,-0.0200042724609 c 0.0,0.0 -2.11999511719,1.94000244141 -2.11999511719,1.94000244141 Z"
android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
+ android:fillAlpha="0" />
</group>
</group>
</group>
diff --git a/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate_animation.xml b/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate_animation.xml
index 5263eb49df66..86dc6ce978bf 100644
--- a/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,21 +14,16 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_landscape_to_auto_rotate" >
<target
- android:name="arrows"
- android:animation="@anim/ic_landscape_to_auto_rotate_animation_arrows" />
- <target
- android:name="arrow_top"
- android:animation="@anim/ic_landscape_to_auto_rotate_animation_arrow_top" />
+ android:name="landscape"
+ android:animation="@anim/ic_landscape_to_rotate_landscape_animation" />
<target
- android:name="arrow_bottom"
- android:animation="@anim/ic_landscape_to_auto_rotate_animation_arrow_bottom" />
- <target
- android:name="device"
- android:animation="@anim/ic_landscape_to_auto_rotate_animation_device" />
+ android:name="arrows"
+ android:animation="@anim/ic_landscape_to_rotate_arrows_animation" />
<target
- android:name="body"
- android:animation="@anim/ic_landscape_to_auto_rotate_animation_body" />
+ android:name="bottom_merged"
+ android:animation="@anim/ic_landscape_to_rotate_bottom_merged_animation" />
</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate.xml
index 17185a7c36b0..bce494c975ed 100644
--- a/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate.xml
+++ b/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,50 +14,51 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="ic_portrait_to_rotate"
android:height="48dp"
android:width="48dp"
android:viewportHeight="48"
android:viewportWidth="48"
android:tint="?android:attr/colorControlNormal" >
<group
- android:name="icon"
+ android:name="device"
android:translateX="24"
android:translateY="24" >
<group
- android:name="icon_pivot"
+ android:name="device_pivot"
android:translateX="-24.15"
android:translateY="-24.25" >
<group
- android:name="arrows"
- android:translateX="24.1"
- android:translateY="24.1" >
- <group
- android:name="arrows_pivot"
- android:translateX="-24.1"
- android:translateY="-24.1" >
- <path
- android:name="arrow_top"
- android:pathData="M 33.1499938965,5.25 c 6.5,3.10000610352 11.1999969482,9.40000915527 11.8999938965,17.0 c 0.0,0.0 3.00001525879,0.0 3.00001525879,0.0 c -1.00001525879,-12.3000030518 -11.3000030518,-22.0 -23.9000091553,-22.0 c -0.399993896484,0.0 -0.899993896484,0.0 -1.30000305176,0.100006103516 c 0.0,0.0 7.60000610352,7.59999084473 7.60000610352,7.59999084473 c 0.0,0.0 2.69999694824,-2.69999694824 2.69999694824,-2.69999694824 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
- <path
- android:name="arrow_bottom"
- android:pathData="M 15.1499938965,43.25 c -6.5,-3.09999084473 -11.1999969482,-9.5 -11.8999938965,-17.0 c 0.0,0.0 -3.0,0.0 -3.0,0.0 c 1.0,12.3000030518 11.299987793,22.0 23.8999938965,22.0 c 0.399993896484,0.0 0.899993896484,0.0 1.30000305176,-0.0999908447266 c 0.0,0.0 -7.60000610352,-7.60000610352 -7.60000610352,-7.60000610352 c 0.0,0.0 -2.69999694824,2.69999694824 -2.69999694824,2.69999694824 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
- </group>
- </group>
- <group
- android:name="device"
+ android:name="device_0"
android:translateX="24.14999"
android:translateY="24.25" >
<path
- android:name="device_1"
+ android:name="device_merged"
android:pathData="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
+ android:fillColor="#FFFFFFFF" />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="arrows"
+ android:translateX="24"
+ android:translateY="24" >
+ <group
+ android:name="arrows_pivot"
+ android:translateX="-24.0798"
+ android:translateY="-24.23" >
+ <group
+ android:name="arrows_0"
+ android:translateX="12.2505"
+ android:translateY="37.2145" >
+ <path
+ android:name="bottom_merged"
+ android:pathData="M 20.7395019531,-31.9844970703 c 6.23999023438,2.83999633789 10.6999969482,8.7200012207 11.8399963379,15.7799987793 c 0.119995117188,0.699996948242 0.740005493164,1.2200012207 1.46099853516,1.2200012207 c 0.919998168945,0.0 1.6190032959,-0.84001159668 1.47900390625,-1.74000549316 c -1.75900268555,-10.3800048828 -9.75900268555,-19.1199951172 -22.5800018311,-20.1600036621 c -0.919998168945,-0.0800018310547 -1.43899536133,1.04000854492 -0.800003051758,1.70001220703 c 0.0,0.0 5.12100219727,5.11999511719 5.12100219727,5.11999511719 c 0.378997802734,0.380004882812 0.97900390625,0.380004882812 1.37899780273,0.020004272461 c 0.0,0.0 2.10000610352,-1.94000244141 2.10000610352,-1.94000244141 Z M 2.73950195312,6.01550292969 c -6.26000976562,-2.83999633789 -10.7200012207,-8.76000976562 -11.8399963379,-15.8600006104 c -0.118011474609,-0.667007446289 -0.702011108398,-1.15100097656 -1.38000488281,-1.13999938965 c -0.860000610352,0.0 -1.52000427246,0.759994506836 -1.38000488281,1.61999511719 c 1.54000854492,10.4000091553 9.5,19.2200012207 22.4199981689,20.2799987793 c 0.920013427734,0.0800018310547 1.44100952148,-1.03999328613 0.800003051758,-1.69999694824 c 0.0,0.0 -5.11999511719,-5.11999511719 -5.11999511719,-5.11999511719 c -0.380004882812,-0.376007080078 -0.988998413086,-0.385009765625 -1.38000488281,-0.0200042724609 c 0.0,0.0 -2.11999511719,1.94000244141 -2.11999511719,1.94000244141 Z"
+ android:fillColor="#FFFFFFFF" />
</group>
</group>
</group>
</vector>
+
diff --git a/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate_animation.xml b/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate_animation.xml
index 565ef269743d..b8465f4ba6b6 100644
--- a/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,21 +14,22 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_portrait_from_auto_rotate" >
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/ic_portrait_to_auto_rotate" >
<target
- android:name="arrows"
- android:animation="@anim/ic_portrait_from_auto_rotate_animation_arrows" />
+ android:name="device_0"
+ android:animation="@anim/ic_portrait_to_rotate_device_0_animation" />
<target
- android:name="arrow_top"
- android:animation="@anim/ic_portrait_from_auto_rotate_animation_arrow_top" />
+ android:name="device_merged"
+ android:animation="@anim/ic_portrait_to_rotate_device_merged_animation" />
<target
- android:name="arrow_bottom"
- android:animation="@anim/ic_portrait_from_auto_rotate_animation_arrow_bottom" />
+ android:name="arrows"
+ android:animation="@anim/ic_portrait_to_rotate_arrows_animation" />
<target
- android:name="device"
- android:animation="@anim/ic_portrait_from_auto_rotate_animation_device" />
+ android:name="arrows_0"
+ android:animation="@anim/ic_portrait_to_rotate_arrows_0_animation" />
<target
- android:name="device_1"
- android:animation="@anim/ic_portrait_from_auto_rotate_animation_device_1" />
+ android:name="bottom_merged"
+ android:animation="@anim/ic_portrait_to_rotate_bottom_merged_animation" />
</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate.xml
index 88bf486be459..0ef15f0582f7 100644
--- a/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate.xml
+++ b/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,53 +14,54 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="ic_rotate_to_portrait"
android:height="48dp"
android:width="48dp"
android:viewportHeight="48"
android:viewportWidth="48"
android:tint="?android:attr/colorControlNormal" >
<group
- android:name="icon"
+ android:name="device"
android:translateX="24"
android:translateY="24" >
<group
- android:name="icon_pivot"
+ android:name="device_pivot"
android:translateX="-24.15"
android:translateY="-24.25" >
<group
- android:name="arrows"
- android:translateX="24.1"
- android:translateY="24.1"
- android:scaleX="0.9"
- android:scaleY="0.9"
- android:rotation="-221" >
- <group
- android:name="arrows_pivot"
- android:translateX="-24.1"
- android:translateY="-24.1" >
- <path
- android:name="arrow_top"
- android:pathData="M 33.1499938965,5.25 c 6.5,3.10000610352 11.1999969482,9.40000915527 11.8999938965,17.0 c 0.0,0.0 3.00001525879,0.0 3.00001525879,0.0 c -1.00001525879,-12.3000030518 -11.3000030518,-22.0 -23.9000091553,-22.0 c -0.399993896484,0.0 -0.899993896484,0.0 -1.30000305176,0.100006103516 c 0.0,0.0 7.60000610352,7.59999084473 7.60000610352,7.59999084473 c 0.0,0.0 2.69999694824,-2.69999694824 2.69999694824,-2.69999694824 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="0" />
- <path
- android:name="arrow_bottom"
- android:pathData="M 15.1499938965,43.25 c -6.5,-3.09999084473 -11.1999969482,-9.5 -11.8999938965,-17.0 c 0.0,0.0 -3.0,0.0 -3.0,0.0 c 1.0,12.3000030518 11.299987793,22.0 23.8999938965,22.0 c 0.399993896484,0.0 0.899993896484,0.0 1.30000305176,-0.0999908447266 c 0.0,0.0 -7.60000610352,-7.60000610352 -7.60000610352,-7.60000610352 c 0.0,0.0 -2.69999694824,2.69999694824 -2.69999694824,2.69999694824 Z"
- android:fillColor="#FFFFFFFF"
- android:fillAlpha="0" />
- </group>
- </group>
- <group
- android:name="device"
+ android:name="device_0"
android:translateX="24.14999"
android:translateY="24.25"
android:rotation="-135" >
<path
- android:name="device_1"
+ android:name="device_merged"
android:pathData="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
+ android:fillColor="#FFFFFFFF" />
+ </group>
+ </group>
+ </group>
+ <group
+ android:name="arrows"
+ android:translateX="24"
+ android:translateY="24"
+ android:rotation="-221" >
+ <group
+ android:name="arrows_pivot"
+ android:translateX="-24.0798"
+ android:translateY="-24.23" >
+ <group
+ android:name="arrows_0"
+ android:translateX="12.2505"
+ android:translateY="37.2145"
+ android:scaleX="0.9"
+ android:scaleY="0.9" >
+ <path
+ android:name="bottom_merged"
+ android:pathData="M 20.7395019531,-31.9844970703 c 6.23999023438,2.83999633789 10.6999969482,8.7200012207 11.8399963379,15.7799987793 c 0.119995117188,0.699996948242 0.740005493164,1.2200012207 1.46099853516,1.2200012207 c 0.919998168945,0.0 1.6190032959,-0.84001159668 1.47900390625,-1.74000549316 c -1.75900268555,-10.3800048828 -9.75900268555,-19.1199951172 -22.5800018311,-20.1600036621 c -0.919998168945,-0.0800018310547 -1.43899536133,1.04000854492 -0.800003051758,1.70001220703 c 0.0,0.0 5.12100219727,5.11999511719 5.12100219727,5.11999511719 c 0.378997802734,0.380004882812 0.97900390625,0.380004882812 1.37899780273,0.020004272461 c 0.0,0.0 2.10000610352,-1.94000244141 2.10000610352,-1.94000244141 Z M 2.73950195312,6.01550292969 c -6.26000976562,-2.83999633789 -10.7200012207,-8.76000976562 -11.8399963379,-15.8600006104 c -0.118011474609,-0.667007446289 -0.702011108398,-1.15100097656 -1.38000488281,-1.13999938965 c -0.860000610352,0.0 -1.52000427246,0.759994506836 -1.38000488281,1.61999511719 c 1.54000854492,10.4000091553 9.5,19.2200012207 22.4199981689,20.2799987793 c 0.920013427734,0.0800018310547 1.44100952148,-1.03999328613 0.800003051758,-1.69999694824 c 0.0,0.0 -5.11999511719,-5.11999511719 -5.11999511719,-5.11999511719 c -0.380004882812,-0.376007080078 -0.988998413086,-0.385009765625 -1.38000488281,-0.0200042724609 c 0.0,0.0 -2.11999511719,1.94000244141 -2.11999511719,1.94000244141 Z"
android:fillColor="#FFFFFFFF"
- android:fillAlpha="1" />
+ android:fillAlpha="0" />
</group>
</group>
</group>
diff --git a/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate_animation.xml b/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate_animation.xml
index f75617f04bef..6d3fd372b222 100644
--- a/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate_animation.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,21 +14,22 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_portrait_to_auto_rotate" >
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/ic_portrait_from_auto_rotate" >
<target
- android:name="arrows"
- android:animation="@anim/ic_portrait_to_auto_rotate_animation_arrows" />
+ android:name="device_0"
+ android:animation="@anim/ic_rotate_to_portrait_device_0_animation" />
<target
- android:name="arrow_top"
- android:animation="@anim/ic_portrait_to_auto_rotate_animation_arrow_top" />
+ android:name="device_merged"
+ android:animation="@anim/ic_rotate_to_portrait_device_merged_animation" />
<target
- android:name="arrow_bottom"
- android:animation="@anim/ic_portrait_to_auto_rotate_animation_arrow_bottom" />
+ android:name="arrows"
+ android:animation="@anim/ic_rotate_to_portrait_arrows_animation" />
<target
- android:name="device"
- android:animation="@anim/ic_portrait_to_auto_rotate_animation_device" />
+ android:name="arrows_0"
+ android:animation="@anim/ic_rotate_to_portrait_arrows_0_animation" />
<target
- android:name="device_1"
- android:animation="@anim/ic_portrait_to_auto_rotate_animation_device_1" />
+ android:name="bottom_merged"
+ android:animation="@anim/ic_rotate_to_portrait_bottom_merged_animation" />
</animated-vector>
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_dark.xml b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
index 951269bd37b1..b837ebef78eb 100644
--- a/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
+++ b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
@@ -14,11 +14,16 @@ Copyright (C) 2014 The Android Open Source Project
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48.0dp"
- android:height="48.0dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path
- android:fillColor="@color/recents_task_bar_dark_icon_color"
- android:pathData="M38.000000,12.800000l-2.799999,-2.800000 -11.200001,11.200001 -11.200000,-11.200001 -2.800000,2.800000 11.200001,11.200000 -11.200001,11.200001 2.800000,2.799999 11.200000,-11.200001 11.200001,11.200001 2.799999,-2.799999 -11.200001,-11.200001z"/>
+android:width="24dp"
+android:height="24dp"
+android:viewportWidth="24"
+android:viewportHeight="24">
+
+<path
+ android:fillColor="@color/recents_task_bar_dark_icon_color"
+ android:pathData="M18.3 5.71a.996 .996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996 .996 0 1 0 5.7
+7.11L10.59 12 5.7 16.89a.996 .996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996 .996 0
+1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38 .38 -1.02 0-1.4z" />
+<path
+ android:pathData="M0 0h24v24H0z" />
</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_light.xml b/packages/SystemUI/res/drawable/recents_dismiss_light.xml
index 1f44c1c846bb..2b2081404b69 100644
--- a/packages/SystemUI/res/drawable/recents_dismiss_light.xml
+++ b/packages/SystemUI/res/drawable/recents_dismiss_light.xml
@@ -14,11 +14,16 @@ Copyright (C) 2014 The Android Open Source Project
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48.0dp"
- android:height="48.0dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path
- android:fillColor="@color/recents_task_bar_light_icon_color"
- android:pathData="M38.000000,12.800000l-2.799999,-2.800000 -11.200001,11.200001 -11.200000,-11.200001 -2.800000,2.800000 11.200001,11.200000 -11.200001,11.200001 2.800000,2.799999 11.200000,-11.200001 11.200001,11.200001 2.799999,-2.799999 -11.200001,-11.200001z"/>
+android:width="24dp"
+android:height="24dp"
+android:viewportWidth="24"
+android:viewportHeight="24">
+
+<path
+ android:fillColor="@color/recents_task_bar_light_icon_color"
+ android:pathData="M18.3 5.71a.996 .996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996 .996 0 1 0 5.7
+7.11L10.59 12 5.7 16.89a.996 .996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996 .996 0
+1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38 .38 -1.02 0-1.4z" />
+<path
+ android:pathData="M0 0h24v24H0z" />
</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/interpolator/ic_landscape_to_auto_rotate_arrows_rotation_interpolator.xml b/packages/SystemUI/res/interpolator/ic_landscape_to_rotate_animation_interpolator_0.xml
index ac27e4dae373..793e7fff11e0 100644
--- a/packages/SystemUI/res/interpolator/ic_landscape_to_auto_rotate_arrows_rotation_interpolator.xml
+++ b/packages/SystemUI/res/interpolator/ic_landscape_to_rotate_animation_interpolator_0.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,5 +14,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.4,0.143709151 0.2,1 1,1" />
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 c 0.4,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_landscape_from_auto_rotate_arrows_rotation_interpolator.xml b/packages/SystemUI/res/interpolator/ic_rotate_to_landscape_animation_interpolator_0.xml
index 76f5667f5fcc..793e7fff11e0 100644
--- a/packages/SystemUI/res/interpolator/ic_landscape_from_auto_rotate_arrows_rotation_interpolator.xml
+++ b/packages/SystemUI/res/interpolator/ic_rotate_to_landscape_animation_interpolator_0.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,5 +14,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.458031162,0 0.299442342,0.748308635 1,1" />
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 c 0.4,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_rotate_to_portrait_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/ic_rotate_to_portrait_animation_interpolator_0.xml
new file mode 100644
index 000000000000..793e7fff11e0
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/ic_rotate_to_portrait_animation_interpolator_0.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 c 0.4,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/layout/car_qs_footer.xml b/packages/SystemUI/res/layout/car_qs_footer.xml
new file mode 100644
index 000000000000..2ef3b05f0565
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_qs_footer.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- extends RelativeLayout -->
+<com.android.systemui.qs.car.CarQSFooter
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/qs_footer"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_footer_height"
+ android:baselineAligned="false"
+ android:clickable="false"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:paddingBottom="16dp"
+ android:paddingTop="16dp"
+ android:paddingEnd="32dp"
+ android:paddingStart="32dp"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+
+ <com.android.systemui.statusbar.phone.MultiUserSwitch
+ android:id="@+id/multi_user_switch"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:background="@drawable/ripple_drawable"
+ android:focusable="true">
+
+ <ImageView
+ android:id="@+id/multi_user_avatar"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:scaleType="centerInside"/>
+ </com.android.systemui.statusbar.phone.MultiUserSwitch>
+
+ <com.android.systemui.statusbar.phone.SettingsButton
+ android:id="@+id/settings_button"
+ android:layout_alignParentEnd="true"
+ android:layout_centerVertical="true"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:background="@drawable/ripple_drawable"
+ android:contentDescription="@string/accessibility_quick_settings_settings"
+ android:scaleType="centerCrop"
+ android:src="@drawable/ic_settings_16dp"
+ android:tint="?android:attr/colorForeground"
+ style="@android:style/Widget.Material.Button.Borderless" />
+
+</com.android.systemui.qs.car.CarQSFooter>
diff --git a/packages/SystemUI/res/layout/car_qs_panel.xml b/packages/SystemUI/res/layout/car_qs_panel.xml
new file mode 100644
index 000000000000..d1f7ff83db93
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_qs_panel.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/quick_settings_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/car_qs_background_primary"
+ android:orientation="vertical"
+ android:elevation="4dp">
+
+ <include layout="@layout/car_status_bar_header" />
+ <include layout="@layout/car_qs_footer" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/car_status_bar_header.xml b/packages/SystemUI/res/layout/car_status_bar_header.xml
new file mode 100644
index 000000000000..158907e03541
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_status_bar_header.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- Extends RelativeLayout -->
+<com.android.systemui.qs.car.CarStatusBarHeader
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/header"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/car_qs_header_system_icons_area_height"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp" >
+
+ <include
+ layout="@layout/system_icons"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true" />
+
+ <com.android.systemui.statusbar.policy.Clock
+ android:id="@+id/clock"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:layout_centerVertical="true"
+ android:singleLine="true"
+ android:paddingStart="@dimen/status_bar_clock_starting_padding"
+ android:paddingEnd="@dimen/status_bar_clock_end_padding"
+ systemui:showDark="false" />
+</com.android.systemui.qs.car.CarStatusBarHeader>
diff --git a/packages/SystemUI/res/layout/qs_footer.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index db39905cf52a..43e88ba32736 100644
--- a/packages/SystemUI/res/layout/qs_footer.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -15,10 +15,10 @@
** limitations under the License.
-->
-<!-- Extends RelativeLayout -->
-<com.android.systemui.qs.QSFooter
+<!-- Extends FrameLayout -->
+<com.android.systemui.qs.QSFooterImpl
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/header"
+ android:id="@+id/qs_footer"
android:layout_width="match_parent"
android:layout_height="48dp"
android:baselineAligned="false"
@@ -114,4 +114,4 @@
android:padding="14dp" />
</LinearLayout>
-</com.android.systemui.qs.QSFooter>
+</com.android.systemui.qs.QSFooterImpl>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 87101e4b3d14..5541f3de8e7c 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -32,8 +32,7 @@
<include layout="@layout/quick_status_bar_expanded_header" />
- <include android:id="@+id/qs_footer"
- layout="@layout/qs_footer" />
+ <include layout="@layout/qs_footer_impl" />
<include android:id="@+id/qs_detail" layout="@layout/qs_detail" />
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 2ff626aa89a9..e8b418cd902b 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -18,7 +18,6 @@
<!-- Extends RelativeLayout -->
<com.android.systemui.qs.QuickStatusBarHeader
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="@dimen/status_bar_header_height"
@@ -31,46 +30,7 @@
android:paddingEnd="0dp"
android:paddingStart="0dp">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="32dp"
- android:layout_alignParentEnd="true"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:gravity="center"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:orientation="horizontal">
-
-
- <com.android.keyguard.CarrierText
- android:id="@+id/qs_carrier_text"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center_vertical|start"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorPrimary"
- android:singleLine="true" />
-
- <com.android.systemui.BatteryMeterView android:id="@+id/battery"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- />
-
- <com.android.systemui.statusbar.policy.Clock
- android:id="@+id/clock"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:singleLine="true"
- android:paddingStart="@dimen/status_bar_clock_starting_padding"
- android:paddingEnd="@dimen/status_bar_clock_end_padding"
- android:gravity="center_vertical|start"
- systemui:showDark="false"
- />
- </LinearLayout>
+ <include layout="@layout/quick_status_bar_header_system_icons" />
<com.android.systemui.qs.QuickQSPanel
android:id="@+id/quick_qs_panel"
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
new file mode 100644
index 000000000000..849bea49a62c
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
@@ -0,0 +1,58 @@
+<?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"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_header_system_icons_area_height"
+ android:layout_alignParentEnd="true"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:gravity="center"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:orientation="horizontal">
+
+
+ <com.android.keyguard.CarrierText
+ android:id="@+id/qs_carrier_text"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="center_vertical|start"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"
+ android:singleLine="true" />
+
+ <com.android.systemui.BatteryMeterView android:id="@+id/battery"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ />
+
+ <com.android.systemui.statusbar.policy.Clock
+ android:id="@+id/clock"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:singleLine="true"
+ android:paddingStart="@dimen/status_bar_clock_starting_padding"
+ android:paddingEnd="@dimen/status_bar_clock_end_padding"
+ android:gravity="center_vertical|start"
+ systemui:showDark="false"
+ />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/rounded_corners.xml b/packages/SystemUI/res/layout/rounded_corners.xml
index 8d391e0eb5e1..d1ef5d638e78 100644
--- a/packages/SystemUI/res/layout/rounded_corners.xml
+++ b/packages/SystemUI/res/layout/rounded_corners.xml
@@ -22,6 +22,7 @@
android:id="@+id/left"
android:layout_width="12dp"
android:layout_height="12dp"
+ android:layout_gravity="left"
android:tint="#ff000000"
android:src="@drawable/rounded" />
<ImageView
@@ -29,6 +30,6 @@
android:layout_width="12dp"
android:layout_height="12dp"
android:tint="#ff000000"
- android:layout_gravity="end"
+ android:layout_gravity="right"
android:src="@drawable/rounded" />
</FrameLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index c59365592bf8..62ceada38fd0 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Meer instellings"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Klaar"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Gekoppel"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Koppel tans …"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"USB-verbinding"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Warmkol"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 6689907df1c5..17964d8fb9fc 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"ተጨማሪ ቅንብሮች"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"ተከናውኗል"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"ተገናኝቷል"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-am/strings_tv.xml b/packages/SystemUI/res/values-am/strings_tv.xml
index 89fd6920b409..7a375a9e8991 100644
--- a/packages/SystemUI/res/values-am/strings_tv.xml
+++ b/packages/SystemUI/res/values-am/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"ፎቶ በፎቶ"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"ስዕል-ላይ-ስዕል"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(ርዕስ የሌለው ፕሮግራም)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIPን ዝጋ"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"ሙሉ ማያ ገጽ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index bc6104f2f64a..aabc9d7a7589 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -74,8 +74,8 @@
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"جارٍ حفظ لقطة الشاشة..."</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"جارٍ حفظ لقطة الشاشة..."</string>
<string name="screenshot_saving_text" msgid="2419718443411738818">"يتم حفظ لقطة."</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"تم التقاط لقطة الشاشة."</string>
- <string name="screenshot_saved_text" msgid="2685605830386712477">"انقر لعرض لقطة الشاشة."</string>
+ <string name="screenshot_saved_title" msgid="6461865960961414961">"تم التقاط لقطة الشاشة"</string>
+ <string name="screenshot_saved_text" msgid="2685605830386712477">"انقر لعرض لقطة الشاشة"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"تعذر التقاط لقطة الشاشة."</string>
<string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"حدثت مشكلة أثناء حفظ لقطة الشاشة."</string>
<string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"يتعذر حفظ لقطة الشاشة نظرًا لأن مساحة التخزين المتاحة محدودة."</string>
@@ -161,7 +161,7 @@
<string name="accessibility_cell_data_off" msgid="443267573897409704">"إيقاف بيانات الجوال"</string>
<string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"ربط البلوتوث."</string>
<string name="accessibility_airplane_mode" msgid="834748999790763092">"وضع الطائرة."</string>
- <string name="accessibility_vpn_on" msgid="5993385083262856059">"‏الشبكة الظاهرية الخاصة (VPN) قيد التشغيل."</string>
+ <string name="accessibility_vpn_on" msgid="5993385083262856059">"‏الشبكة الافتراضية الخاصة (VPN) قيد التشغيل."</string>
<string name="accessibility_no_sims" msgid="3957997018324995781">"‏ليس هناك شريحة SIM."</string>
<string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"جارٍ تغيير شبكة مشغِّل شبكة الجوّال."</string>
<string name="accessibility_battery_details" msgid="7645516654955025422">"فتح تفاصيل البطارية"</string>
@@ -318,6 +318,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"المزيد من الإعدادات"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"تم"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"متصل"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
@@ -428,22 +430,22 @@
<string name="quick_settings_disclosure_named_management_named_vpn" msgid="6290456493852584017">"يخضع الجهاز لإدارة <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> وتم ربطه بـ <xliff:g id="VPN_APP">%2$s</xliff:g>"</string>
<string name="quick_settings_disclosure_management" msgid="3294967280853150271">"يخضع الجهاز لإدارة مؤسستك"</string>
<string name="quick_settings_disclosure_named_management" msgid="1059403025094542908">"تتم إدارة هذا الجهاز بواسطة <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>"</string>
- <string name="quick_settings_disclosure_management_vpns" msgid="3698767349925266482">"يخضع الجهاز لإدارة مؤسستك وتم ربطه بالشبكات الظاهرية الخاصة"</string>
- <string name="quick_settings_disclosure_named_management_vpns" msgid="7777821385318891527">"يخضع الجهاز لإدارة <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> وتم ربطه بالشبكات الظاهرية الخاصة"</string>
+ <string name="quick_settings_disclosure_management_vpns" msgid="3698767349925266482">"يخضع الجهاز لإدارة مؤسستك وتم ربطه بالشبكات الافتراضية الخاصة"</string>
+ <string name="quick_settings_disclosure_named_management_vpns" msgid="7777821385318891527">"يخضع الجهاز لإدارة <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> وتم ربطه بالشبكات الافتراضية الخاصة"</string>
<string name="quick_settings_disclosure_managed_profile_monitoring" msgid="5125463987558278215">"يمكن لمؤسستك مراقبة حركة بيانات الشبكة في الملف الشخصي للعمل"</string>
<string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8973606847896650284">"يمكن لـ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> مراقبة حركة بيانات الشبكة في ملفك الشخصي للعمل"</string>
<string name="quick_settings_disclosure_monitoring" msgid="679658227269205728">"قد تكون الشبكة خاضعة للمراقبة"</string>
- <string name="quick_settings_disclosure_vpns" msgid="8170318392053156330">"تم ربط الجهاز بالشبكات الظاهرية الخاصة"</string>
+ <string name="quick_settings_disclosure_vpns" msgid="8170318392053156330">"تم ربط الجهاز بالشبكات الافتراضية الخاصة"</string>
<string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="3494535754792751741">"تم ربط الملف الشخصي للعمل بـ <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="quick_settings_disclosure_personal_profile_named_vpn" msgid="4467456202486569906">"تم ربط الملف الشخصي بـ <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="quick_settings_disclosure_named_vpn" msgid="6943724064780847080">"تم ربط الجهاز بـ <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="monitoring_title_device_owned" msgid="1652495295941959815">"إدارة الأجهزة"</string>
<string name="monitoring_title_profile_owned" msgid="6790109874733501487">"مراقبة الملف الشخصي"</string>
<string name="monitoring_title" msgid="169206259253048106">"مراقبة الشبكات"</string>
- <string name="monitoring_subtitle_vpn" msgid="876537538087857300">"‏شبكة ظاهرية خاصة (VPN)"</string>
+ <string name="monitoring_subtitle_vpn" msgid="876537538087857300">"‏شبكة افتراضية خاصة (VPN)"</string>
<string name="monitoring_subtitle_network_logging" msgid="3341264304793193386">"تسجيل بيانات الشبكة"</string>
<string name="monitoring_subtitle_ca_certificate" msgid="3874151893894355988">"‏شهادات CA"</string>
- <string name="disable_vpn" msgid="4435534311510272506">"تعطيل الشبكة الظاهرية الخاصة"</string>
+ <string name="disable_vpn" msgid="4435534311510272506">"تعطيل الشبكة الافتراضية الخاصة"</string>
<string name="disconnect_vpn" msgid="1324915059568548655">"‏قطع الاتصال بشبكة VPN"</string>
<string name="monitoring_button_view_policies" msgid="100913612638514424">"عرض السياسات"</string>
<string name="monitoring_description_named_management" msgid="5281789135578986303">"تتم إدارة جهازك بواسطة <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nيمكن للمشرف مراقبة وإدارة الإعدادات والدخول إلى المؤسسة والتطبيقات والبيانات المرتبطة بجهازك ومعلومات الموقع الجغرافي للجهاز.\n\nللحصول على المزيد من المعلومات، اتصل بالمشرف."</string>
@@ -463,13 +465,13 @@
<string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"مزيد من المعلومات"</string>
<string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"لقد اتصلت بتطبيق <xliff:g id="VPN_APP">%1$s</xliff:g>، الذي يمكن أن يراقب نشاط الشبكة، بما في ذلك رسائل البريد الإلكتروني والتطبيقات والمواقع الإلكترونية."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
- <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"‏فتح إعدادات الشبكة الظاهرية الخاصة (VPN)"</string>
+ <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"‏فتح إعدادات الشبكة الافتراضية الخاصة (VPN)"</string>
<string name="monitoring_description_ca_cert_settings_separator" msgid="4987350385906393626">" "</string>
<string name="monitoring_description_ca_cert_settings" msgid="5489969458872997092">"فتح بيانات الاعتماد الموثوق بها"</string>
<string name="monitoring_description_network_logging" msgid="7223505523384076027">"شغَّل المشرف ميزة تسجيل بيانات الشبكة، والتي يتم من خلالها مراقبة حركة البيانات على جهازك.\n\nللحصول على المزيد من المعلومات، اتصل بالمشرف."</string>
- <string name="monitoring_description_vpn" msgid="4445150119515393526">"‏لقد منحت تطبيقًا الإذن لإعداد اتصال شبكة ظاهرية خاصة (VPN).\n\nيمكن لهذا التطبيق مراقبة أنشطتك على الجهاز والشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
- <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"تتم إدارة ملفك الشخصي للعمل بواسطة <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nويمكن للمشرف مراقبة نشاط الشبكة، بما في ذلك رسائل البريد الإلكتروني والتطبيقات والمواقع الإلكترونية.\n\nللحصول على المزيد من المعلومات، اتصل بالمشرف.\n\nوتجدر الإشارة إلى أنك متصل أيضًا بشبكة ظاهرية خاصة يمكن أن تراقب نشاط الشبكة."</string>
- <string name="legacy_vpn_name" msgid="6604123105765737830">"شبكة ظاهرية خاصة"</string>
+ <string name="monitoring_description_vpn" msgid="4445150119515393526">"‏لقد منحت تطبيقًا الإذن لإعداد اتصال شبكة افتراضية خاصة (VPN).\n\nيمكن لهذا التطبيق مراقبة أنشطتك على الجهاز والشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
+ <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"تتم إدارة ملفك الشخصي للعمل بواسطة <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nويمكن للمشرف مراقبة نشاط الشبكة، بما في ذلك رسائل البريد الإلكتروني والتطبيقات والمواقع الإلكترونية.\n\nللحصول على المزيد من المعلومات، اتصل بالمشرف.\n\nوتجدر الإشارة إلى أنك متصل أيضًا بشبكة افتراضية خاصة يمكن أن تراقب نشاط الشبكة."</string>
+ <string name="legacy_vpn_name" msgid="6604123105765737830">"شبكة افتراضية خاصة"</string>
<string name="monitoring_description_app" msgid="1828472472674709532">"تم ربطك بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index a5fb4484978b..a8ad009a480e 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Digər ayarlar"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Hazır"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Qoşulu"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Qoşulur..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Birləşmə"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 9d8473e2b06e..ed4eb728d831 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Još podešavanja"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Gotovo"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Povezan"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Povezuje se..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Povezivanje"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 8d36b0bb70f7..48a56b7cecea 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -316,6 +316,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Дадатковыя налады"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Гатова"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Падлучана"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index bcdcfd5f4a66..f6fbaf5b6d71 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Още настройки"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Готово"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Установена е връзка"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
@@ -725,8 +727,8 @@
<string name="pip_phone_minimize" msgid="1079119422589131792">"Намаляване"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Затваряне"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Преместете надолу с плъзгане, за да отхвърлите"</string>
- <string name="pip_menu_title" msgid="3328510504196964712">"Меню за режима „Картина в картина“"</string>
- <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> е в режима „Картина в картина“"</string>
+ <string name="pip_menu_title" msgid="3328510504196964712">"Меню за режима „Картина в картината“"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> е в режима „Картина в картината“"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"Ако не искате <xliff:g id="NAME">%s</xliff:g> да използва тази функция, докоснете, за да отворите настройките, и я изключете."</string>
<string name="pip_play" msgid="1417176722760265888">"Пускане"</string>
<string name="pip_pause" msgid="8881063404466476571">"Поставяне на пауза"</string>
diff --git a/packages/SystemUI/res/values-bg/strings_tv.xml b/packages/SystemUI/res/values-bg/strings_tv.xml
index ffe9007ef1e0..a5eb8b930a32 100644
--- a/packages/SystemUI/res/values-bg/strings_tv.xml
+++ b/packages/SystemUI/res/values-bg/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"Картина в картина"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Картина в картината"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Програма без заглавие)"</string>
<string name="pip_close" msgid="3480680679023423574">"Затваряне на PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Цял екран"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 58293e20ce26..edcb004d1c51 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"আরো সেটিংস"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"সম্পন্ন হয়েছে"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"সংযুক্ত হয়েছে"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 97c2e1cd3ea0..b8206a06ae5a 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Više postavki"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Gotovo"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Povezano"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Povezivanje..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Dijeljenje veze"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Pristupna tačka"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 129d605811c5..0675706bf9d2 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Més opcions"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Fet"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Connectat"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"S\'està connectant..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Compartició de xarxa"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Punt d\'accés Wi-Fi"</string>
diff --git a/packages/SystemUI/res/values-car/dimens.xml b/packages/SystemUI/res/values-car/dimens.xml
new file mode 100644
index 000000000000..b2e7bd1b881e
--- /dev/null
+++ b/packages/SystemUI/res/values-car/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+-->
+<resources>
+ <!-- The height of the quick settings footer that holds the user switcher, settings icon,
+ etc. in the car setting.-->
+ <dimen name="qs_footer_height">74dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 8fc3300e0450..7a0fbfc870bf 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -316,6 +316,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Další nastavení"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Hotovo"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Připojeno"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Připojování..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Sdílené připojení"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -739,8 +741,8 @@
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalizovat"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Zavřít"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Nápovědu zavřete přetažením dolů"</string>
- <string name="pip_menu_title" msgid="3328510504196964712">"Nabídka typu obraz v obraze"</string>
- <string name="pip_notification_title" msgid="3204024940158161322">"Aplikace <xliff:g id="NAME">%s</xliff:g> je v zobrazení obraz v obraze"</string>
+ <string name="pip_menu_title" msgid="3328510504196964712">"Nabídka režimu obraz v obraze"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"Aplikace <xliff:g id="NAME">%s</xliff:g> je v režimu obraz v obraze"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"Pokud nechcete, aby aplikace <xliff:g id="NAME">%s</xliff:g> tuto funkci používala, klepnutím otevřete nastavení a funkci vypněte."</string>
<string name="pip_play" msgid="1417176722760265888">"Přehrát"</string>
<string name="pip_pause" msgid="8881063404466476571">"Pozastavit"</string>
diff --git a/packages/SystemUI/res/values-cs/strings_tv.xml b/packages/SystemUI/res/values-cs/strings_tv.xml
index f27974fa8570..a9282184ec24 100644
--- a/packages/SystemUI/res/values-cs/strings_tv.xml
+++ b/packages/SystemUI/res/values-cs/strings_tv.xml
@@ -21,6 +21,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="134047986446577723">"Obraz v obraze"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Bez názvu)"</string>
- <string name="pip_close" msgid="3480680679023423574">"Ukončit PIP"</string>
+ <string name="pip_close" msgid="3480680679023423574">"Ukončit obraz v obraze (PIP)"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Celá obrazovka"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 04a1dde5e8c8..08f57617e309 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Flere indstillinger"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Udfør"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Tilsluttet"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Opretter forbindelse…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Netdeling"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
diff --git a/packages/SystemUI/res/values-da/strings_tv.xml b/packages/SystemUI/res/values-da/strings_tv.xml
index d24cb3abe669..aa8af7442e18 100644
--- a/packages/SystemUI/res/values-da/strings_tv.xml
+++ b/packages/SystemUI/res/values-da/strings_tv.xml
@@ -21,6 +21,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="notification_channel_tv_pip" msgid="134047986446577723">"Integreret billede"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Program uden titel)"</string>
- <string name="pip_close" msgid="3480680679023423574">"Luk PIP"</string>
+ <string name="pip_close" msgid="3480680679023423574">"Luk integreret billede"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Fuld skærm"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 8db9281be413..50d0a446de96 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -301,7 +301,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Kein Netz"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"WLAN aus"</string>
<string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"WLAN an"</string>
- <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Keine WLAN-Netzwerke verfügbar"</string>
+ <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Keine WLANs verfügbar"</string>
<string name="quick_settings_cast_title" msgid="7709016546426454729">"Streamen"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Wird übertragen"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Unbenanntes Gerät"</string>
@@ -314,6 +314,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Weitere Einstellungen"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Fertig"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Verbunden"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Verbindung wird hergestellt…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 6419922c6ad5..4c4bc007e96f 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Περισσότερες ρυθμίσεις"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Τέλος"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Συνδέθηκε"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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">"Σημείο πρόσβασης Wi-Fi"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 80c8c884a145..e832f447e825 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"More settings"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Done"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Connected"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Connecting..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings_tv.xml b/packages/SystemUI/res/values-en-rAU/strings_tv.xml
index ffcd655e160b..31cbd8377fd5 100644
--- a/packages/SystemUI/res/values-en-rAU/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-Picture"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(No title program)"</string>
<string name="pip_close" msgid="3480680679023423574">"Close PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Full screen"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 80c8c884a145..e832f447e825 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"More settings"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Done"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Connected"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Connecting..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings_tv.xml b/packages/SystemUI/res/values-en-rGB/strings_tv.xml
index ffcd655e160b..31cbd8377fd5 100644
--- a/packages/SystemUI/res/values-en-rGB/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-Picture"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(No title program)"</string>
<string name="pip_close" msgid="3480680679023423574">"Close PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Full screen"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 80c8c884a145..e832f447e825 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"More settings"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Done"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Connected"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Connecting..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings_tv.xml b/packages/SystemUI/res/values-en-rIN/strings_tv.xml
index ffcd655e160b..31cbd8377fd5 100644
--- a/packages/SystemUI/res/values-en-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-Picture"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(No title program)"</string>
<string name="pip_close" msgid="3480680679023423574">"Close PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Full screen"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index ed31175bb98b..0fe9d475a6ed 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Más configuraciones"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Listo"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Conectado"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Conectando…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Anclaje a red"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index a5df2a730f5b..5a0a6256c73e 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Más opciones"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Listo"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Conectado"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Conectando..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Compartir Internet"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona Wi-Fi"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 3aad84330554..f476a353f187 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Rohkem seadeid"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Valmis"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Ühendatud"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Ühenduse loomine ..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Jagamine"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Leviala"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 76728fead85c..122bacad44c3 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Ezarpen gehiago"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Eginda"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Konektatuta"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Konektatzen…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Konexioa partekatzea"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Sare publikoa"</string>
@@ -727,8 +729,8 @@
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizatu"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Itxi"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Baztertzeko, arrastatu behera"</string>
- <string name="pip_menu_title" msgid="3328510504196964712">"Pantaila txikiaren menua"</string>
- <string name="pip_notification_title" msgid="3204024940158161322">"Pantaila txikian dago <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="pip_menu_title" msgid="3328510504196964712">"Pantaila txiki gainjarriaren menua"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"Pantaila txiki gainjarrian dago <xliff:g id="NAME">%s</xliff:g>"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"Ez baduzu nahi <xliff:g id="NAME">%s</xliff:g> zerbitzuak eginbide hori erabiltzea, sakatu hau ezarpenak ireki eta aukera desaktibatzeko."</string>
<string name="pip_play" msgid="1417176722760265888">"Erreproduzitu"</string>
<string name="pip_pause" msgid="8881063404466476571">"Pausatu"</string>
diff --git a/packages/SystemUI/res/values-eu/strings_tv.xml b/packages/SystemUI/res/values-eu/strings_tv.xml
index 6dd81a6f963c..081d1fee046f 100644
--- a/packages/SystemUI/res/values-eu/strings_tv.xml
+++ b/packages/SystemUI/res/values-eu/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"Pantaila txikia"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Pantaila txiki gainjarria"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Programa izengabea)"</string>
<string name="pip_close" msgid="3480680679023423574">"Itxi PIPa"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Pantaila osoa"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index d89611aed58d..a36c1c85c6ad 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"تنظیمات بیشتر"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"تمام"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"متصل"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index e3193c79ef40..307f5d4dccfc 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Lisäasetukset"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Valmis"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Yhdistetty"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Yhdistetään…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Jaettu yhteys"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 1d9a7f359317..5bd01791148e 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Plus de paramètres"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Terminé"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Connecté"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Connexion en cours…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Partage de connexion"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Point d\'accès sans fil"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 8ec4cbac8d9e..2db32f9aa3c0 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Plus de paramètres"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"OK"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Connecté"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Connexion en cours..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Partage de connexion"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Point d\'accès"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index c6281f515781..aa836824f154 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Máis opcións"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Feito"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Conectado"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Conectando..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Conexión compartida"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona wifi"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index b2aca4405dec..abc3e4691f80 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"વધુ સેટિંગ્સ"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"થઈ ગયું"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"કનેક્ટ થયેલ"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index ee688a1b049e..add9bb6d855a 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"और सेटिंग"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"पूर्ण"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"कनेक्ट है"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
@@ -726,7 +728,7 @@
<string name="pip_phone_close" msgid="8416647892889710330">"बंद करें"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"खारिज करने के लिए नीचे खींचें"</string>
<string name="pip_menu_title" msgid="3328510504196964712">"चित्र में चित्र मेनू"</string>
- <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> तस्वीर-में-तस्वीर के अंदर है"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> स्क्रीन में स्क्रीन के अंदर है"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"अगर आप नहीं चाहते कि <xliff:g id="NAME">%s</xliff:g> इस सुविधा का उपयोग करे, तो सेटिंग खोलने के लिए टैप करें और उसे बंद करें ."</string>
<string name="pip_play" msgid="1417176722760265888">"चलाएं"</string>
<string name="pip_pause" msgid="8881063404466476571">"रोकें"</string>
diff --git a/packages/SystemUI/res/values-hi/strings_tv.xml b/packages/SystemUI/res/values-hi/strings_tv.xml
index 39f06f6b728f..5e65e4668950 100644
--- a/packages/SystemUI/res/values-hi/strings_tv.xml
+++ b/packages/SystemUI/res/values-hi/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"चित्र में चित्र"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"स्क्रीन में स्क्रीन"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(कोई शीर्षक कार्यक्रम नहीं)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP बंद करें"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"पूर्ण स्‍क्रीन"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 57061789a377..9c610fbfba42 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Više postavki"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Gotovo"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Povezano"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Povezivanje..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Dijeljenje veze"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Žarišna točka"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index cba779a44fb9..45ad6be9a03e 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"További beállítások"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Kész"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Csatlakoztatva"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Csatlakozás…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Megosztás"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 22be081ff64f..dbc484f365f0 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Հավելյալ կարգավորումներ"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Պատրաստ է"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Կապակցված է"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 4eea7a1aeaf0..116390032150 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Setelan lainnya"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Selesai"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Tersambung"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Menyambung..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Menambatkan"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -725,8 +727,8 @@
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalkan"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Tutup"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Seret ke bawah untuk menutup"</string>
- <string name="pip_menu_title" msgid="3328510504196964712">"Menu gambar dalam gambar"</string>
- <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> adalah gambar-dalam-gambar"</string>
+ <string name="pip_menu_title" msgid="3328510504196964712">"Menu picture in picture"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> adalah picture-in-picture"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"Jika Anda tidak ingin <xliff:g id="NAME">%s</xliff:g> menggunakan fitur ini, tap untuk membuka setelan dan menonaktifkannya."</string>
<string name="pip_play" msgid="1417176722760265888">"Putar"</string>
<string name="pip_pause" msgid="8881063404466476571">"Jeda"</string>
diff --git a/packages/SystemUI/res/values-in/strings_tv.xml b/packages/SystemUI/res/values-in/strings_tv.xml
index ca3b32fc2cde..a1aa16816b4d 100644
--- a/packages/SystemUI/res/values-in/strings_tv.xml
+++ b/packages/SystemUI/res/values-in/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"Gambar-dalam-Gambar"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-picture"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Program tanpa judul)"</string>
<string name="pip_close" msgid="3480680679023423574">"Tutup PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Layar penuh"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 243c5d7727b7..8c1c61dd7f80 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Fleiri stillingar"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Lokið"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Tengt"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Tengist..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tjóðrun"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Heitur reitur"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 0eca3ece1c03..df3c4430313f 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Altre impostazioni"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Fine"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Connesso"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Connessione..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -727,8 +729,8 @@
<string name="pip_phone_minimize" msgid="1079119422589131792">"Riduci a icona"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Chiudi"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Trascina verso il basso per ignorare"</string>
- <string name="pip_menu_title" msgid="3328510504196964712">"Menu Picture-in-picture"</string>
- <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> è in picture-in-picture"</string>
+ <string name="pip_menu_title" msgid="3328510504196964712">"Menu Picture in picture"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> è in Picture in picture"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"Se non desideri che l\'app <xliff:g id="NAME">%s</xliff:g> utilizzi questa funzione, tocca per aprire le impostazioni e disattivarla."</string>
<string name="pip_play" msgid="1417176722760265888">"Riproduci"</string>
<string name="pip_pause" msgid="8881063404466476571">"Metti in pausa"</string>
diff --git a/packages/SystemUI/res/values-it/strings_tv.xml b/packages/SystemUI/res/values-it/strings_tv.xml
index 629e30628956..81d76d541bf4 100644
--- a/packages/SystemUI/res/values-it/strings_tv.xml
+++ b/packages/SystemUI/res/values-it/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-Picture"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture in picture"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Programma senza titolo)"</string>
<string name="pip_close" msgid="3480680679023423574">"Chiudi PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Schermo intero"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index b4e09fbffb84..d4cf5d3211af 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -314,6 +314,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"הגדרות נוספות"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"בוצע"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"מחובר"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 55437b4c373e..3eb90605b875 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"詳細設定"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"完了"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"接続済み"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
@@ -727,8 +729,8 @@
<string name="pip_phone_minimize" msgid="1079119422589131792">"最小化"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"閉じる"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"下にドラッグして閉じる"</string>
- <string name="pip_menu_title" msgid="3328510504196964712">"PIP メニュー"</string>
- <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g>は PIP 表示中です"</string>
+ <string name="pip_menu_title" msgid="3328510504196964712">"ピクチャー イン ピクチャー メニュー"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g>はピクチャー イン ピクチャーで表示中です"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"<xliff:g id="NAME">%s</xliff:g>でこの機能を使用しない場合は、タップして設定を開いて OFF にしてください。"</string>
<string name="pip_play" msgid="1417176722760265888">"再生"</string>
<string name="pip_pause" msgid="8881063404466476571">"一時停止"</string>
diff --git a/packages/SystemUI/res/values-ja/strings_tv.xml b/packages/SystemUI/res/values-ja/strings_tv.xml
index 134bb18ccad8..4596551677a5 100644
--- a/packages/SystemUI/res/values-ja/strings_tv.xml
+++ b/packages/SystemUI/res/values-ja/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"PIP"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"ピクチャー イン ピクチャー"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(無題の番組)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP を閉じる"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"全画面表示"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 88e1d0512ec2..c7b977a88fb2 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"დამატებითი პარამეტრები"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"დასრულდა"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"დაკავშირებულია"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 97bf3c083ebc..dded6d3108ba 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Қосымша параметрлер"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Дайын"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Қосылды"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-kk/strings_tv.xml b/packages/SystemUI/res/values-kk/strings_tv.xml
index 305ad2ec5e77..71120170655f 100644
--- a/packages/SystemUI/res/values-kk/strings_tv.xml
+++ b/packages/SystemUI/res/values-kk/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"Сурет ішіндегі сурет"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Суреттегі сурет"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Атаусыз бағдарлама)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP жабу"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Толық экран"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 35c628002df8..b01edb279106 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"ការ​កំណត់​ច្រើន​ទៀត"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"រួចរាល់"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"បាន​ភ្ជាប់"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
@@ -725,8 +727,8 @@
<string name="pip_phone_minimize" msgid="1079119422589131792">"បង្រួម"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"បិទ"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"អូស​ចុះក្រោម​ដើម្បី​បដិសេធ"</string>
- <string name="pip_menu_title" msgid="3328510504196964712">"ម៉ឺនុយ​រូបភាព​ក្នុងរូបភាព"</string>
- <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> ស្ថិតក្នុងមុខងាររូបភាពក្នុងរូបភាព"</string>
+ <string name="pip_menu_title" msgid="3328510504196964712">"ម៉ឺនុយ​រូប​ក្នុងរូប"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> ស្ថិតក្នុងមុខងាររូបក្នុងរូប"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"ប្រសិនបើ​អ្នក​មិន​ចង់​ឲ្យ <xliff:g id="NAME">%s</xliff:g> ប្រើ​មុខងារ​នេះ​ សូមចុច​​បើក​ការកំណត់ រួច​បិទ​វា។"</string>
<string name="pip_play" msgid="1417176722760265888">"លេង"</string>
<string name="pip_pause" msgid="8881063404466476571">"ផ្អាក"</string>
diff --git a/packages/SystemUI/res/values-km/strings_tv.xml b/packages/SystemUI/res/values-km/strings_tv.xml
index 5da818e8627b..641bba3de836 100644
--- a/packages/SystemUI/res/values-km/strings_tv.xml
+++ b/packages/SystemUI/res/values-km/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"រូបភាពក្នុងរូបភាព"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"រូបក្នុងរូប"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(កម្មវិធី​គ្មានចំណងជើង)"</string>
<string name="pip_close" msgid="3480680679023423574">"បិទ PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"ពេញអេក្រង់"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 525da4a5763c..cad05a6a8011 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"ಮುಗಿದಿದೆ"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 32202076e523..1df63776b4ae 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"설정 더보기"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"완료"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"연결됨"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 444e225162ff..ce3edb5169e8 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Дагы жөндөөлөр"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Бүттү"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Туташкан"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index b6c4aa755fcd..5a889d8df49c 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"​ການ​ຕັ້ງ​ຄ່າ​ເພີ່ມ​ເຕີມ"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"ແລ້ວໆ"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"ເຊື່ອມ​ຕໍ່ແລ້ວ"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 78f0c7360868..e6df8670a58f 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -314,6 +314,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Daugiau nustatymų"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Atlikta"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Prijungtas"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Prisijungiama..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Susiejimas"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Viešosios interneto prieigos taškas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 336a246963b7..d45096d9fa5f 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Vairāk iestatījumu"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Gatavs"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Pievienota"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Notiek savienojuma izveide…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Piesaiste"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Tīklājs"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 12973fd45df6..9aa8fc496e7d 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Повеќе поставки"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Готово"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Поврзано"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index a07c86810844..397617620784 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"കൂടുതൽ ക്രമീകരണങ്ങൾ"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"പൂർത്തിയാക്കി"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"കണക്‌റ്റുചെയ്‌തു"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 20bb6ea1254d..f00e8eb70014 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -308,6 +308,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Өөр тохиргоо"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Дууссан"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Холбогдсон"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
@@ -725,8 +727,8 @@
<string name="pip_phone_minimize" msgid="1079119422589131792">"Багасгах"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Хаах"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Хаахын тулд доош чирэх"</string>
- <string name="pip_menu_title" msgid="3328510504196964712">"Зургийн цэсэнд байгаа зураг"</string>
- <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> зураг доторх зурганд байна"</string>
+ <string name="pip_menu_title" msgid="3328510504196964712">"Дэлгэцэн доторх дэлгэцийн цэс"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> дэлгэцэн доторх дэлгэцэд байна"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"Та <xliff:g id="NAME">%s</xliff:g>-д энэ онцлогийг ашиглуулахыг хүсэхгүй байвал тохиргоог нээгээд, үүнийг унтраана уу."</string>
<string name="pip_play" msgid="1417176722760265888">"Тоглуулах"</string>
<string name="pip_pause" msgid="8881063404466476571">"Түр зогсоох"</string>
diff --git a/packages/SystemUI/res/values-mn/strings_tv.xml b/packages/SystemUI/res/values-mn/strings_tv.xml
index bbc94c80de83..e250c2db2d86 100644
--- a/packages/SystemUI/res/values-mn/strings_tv.xml
+++ b/packages/SystemUI/res/values-mn/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"Зураг-доторх-Зураг"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Дэлгэцэн-доторх-Дэлгэц"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Гарчиггүй хөтөлбөр)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP-г хаах"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Бүтэн дэлгэц"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 2ddf75c7539e..2ff5e63816a5 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"अधिक सेटिंग्ज"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"पूर्ण झाले"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"कनेक्ट केलेले"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 6a30d506d502..1c6e543d1c4e 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Lagi tetapan"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Selesai"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Disambungkan"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Menyambung..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Penambatan"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Tempat liputan"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 6a426271a995..cf9baeeb27b5 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -262,7 +262,7 @@
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"ဖန်သားပြင် အနေအထားက ဒေါင်လိုက်အဖြစ် ပုံသေ လုပ်ထားပါသည်"</string>
<string name="accessibility_rotation_lock_off_changed" msgid="8134601071026305153">"ယခုတော့ မျက်နှာပြင်သည် အလိုအလျောက် လည်နေမည်။"</string>
<string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"မျက်နှာပြင် အနေအထားကို ဘေးတိုက် အဖြစ် သော့ချထားသည်။"</string>
- <string name="accessibility_rotation_lock_on_portrait_changed" msgid="8922481981834012126">"မျက်နှာပြင် အနေအထားကို ထောင်လိုက် အဖြစ် သော့ချထားသည်။"</string>
+ <string name="accessibility_rotation_lock_on_portrait_changed" msgid="8922481981834012126">"မျက်နှာပြင်အနေအထားကို ထောင်လိုက်အဖြစ် ပုံသေသတ်မှတ်ထားသည်။"</string>
<string name="dessert_case" msgid="1295161776223959221">"မုန့်ထည့်သော ပုံး"</string>
<string name="start_dreams" msgid="5640361424498338327">"ဖန်သားပြင်အသုံးပြုမှု ချွေတာမှုစနစ်"</string>
<string name="ethernet_label" msgid="7967563676324087464">"အီသာနက်"</string>
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"နောက်ထပ် ဆက်တင်များ"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"လုပ်ပြီး"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"ချိတ်ဆက်ထား"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 71c28ac9f44b..e14646edc78d 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Flere innstillinger"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Ferdig"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Tilkoblet"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Kobler til …"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Internettdeling"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Wi-Fi-sone"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 6c6b62c220c5..a1746725f4ce 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"थप सेटिङहरू"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"भयो"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"जोडिएको"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
@@ -726,7 +728,7 @@
<string name="pip_phone_close" msgid="8416647892889710330">"बन्द गर्नुहोस्"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"खारेज गर्न तल तान्नुहोस्"</string>
<string name="pip_menu_title" msgid="3328510504196964712">"तस्बिर मेनुमा तस्बिर"</string>
- <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> तस्बिरभित्रको तस्बिरमा छ"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> Picture-in-picture मा छ"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"तपाईं <xliff:g id="NAME">%s</xliff:g> ले सुविधा प्रयोग नगरोस् भन्ने चाहनुहुन्छ भने ट्याप गरेर सेटिङहरू खोल्नुहोस् र यसलाई निष्क्रिय पार्नुहोस्।"</string>
<string name="pip_play" msgid="1417176722760265888">"प्ले गर्नुहोस्"</string>
<string name="pip_pause" msgid="8881063404466476571">"पज गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-ne/strings_tv.xml b/packages/SystemUI/res/values-ne/strings_tv.xml
index 2c5c1863ffa0..2e42b6c0345e 100644
--- a/packages/SystemUI/res/values-ne/strings_tv.xml
+++ b/packages/SystemUI/res/values-ne/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"तस्बिरभित्रको तस्बिर"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-Picture"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(शीर्षकविहीन कार्यक्रम)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP लाई बन्द गर्नुहोस्"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"पूर्ण स्क्रिन"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 8e3100ffaff1..fb494c0ea467 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Meer instellingen"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Gereed"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Verbonden"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Verbinding maken…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -725,8 +727,8 @@
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimaliseren"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Sluiten"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Sleep omlaag om te sluiten"</string>
- <string name="pip_menu_title" msgid="3328510504196964712">"Beeld-in-beeld-menu"</string>
- <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> is in beeld-in-beeld"</string>
+ <string name="pip_menu_title" msgid="3328510504196964712">"Scherm-in-scherm-menu"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> is in scherm-in-scherm"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"Als je niet wilt dat <xliff:g id="NAME">%s</xliff:g> deze functie gebruikt, tik je om de instellingen te openen en schakel je de functie uit."</string>
<string name="pip_play" msgid="1417176722760265888">"Afspelen"</string>
<string name="pip_pause" msgid="8881063404466476571">"Onderbreken"</string>
diff --git a/packages/SystemUI/res/values-nl/strings_tv.xml b/packages/SystemUI/res/values-nl/strings_tv.xml
index fae484fe5276..8270feebc122 100644
--- a/packages/SystemUI/res/values-nl/strings_tv.xml
+++ b/packages/SystemUI/res/values-nl/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"Beeld-in-beeld"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Scherm-in-scherm"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Naamloos programma)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP sluiten"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Volledig scherm"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 2da760662418..23f60fd26acc 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"ਹੋਰ ਸੈਟਿੰਗਾਂ"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"ਹੋ ਗਿਆ"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"ਕਨੈਕਟ ਕੀਤਾ"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index f925b60af060..5c7b0377356a 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -314,6 +314,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Więcej ustawień"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Gotowe"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Połączono"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Łączę..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Powiązanie"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index ab7d3db62a7e..e0e1c76cee91 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Mais configurações"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Concluído"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Conectado"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Conectando..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Ponto de acesso"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 2f31c02ec430..37e1c7edfc35 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Mais definições"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Concluído"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Ligado"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"A ligar..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Associação"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona Wi-Fi"</string>
@@ -725,8 +727,8 @@
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizar"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Fechar"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Arrastar para baixo para ignorar"</string>
- <string name="pip_menu_title" msgid="3328510504196964712">"Menu de imagem na imagem"</string>
- <string name="pip_notification_title" msgid="3204024940158161322">"A aplicação <xliff:g id="NAME">%s</xliff:g> está no modo de imagem na imagem"</string>
+ <string name="pip_menu_title" msgid="3328510504196964712">"Menu de ecrã no ecrã"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"A aplicação <xliff:g id="NAME">%s</xliff:g> está no modo de ecrã no ecrã"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"Se não pretende que a aplicação <xliff:g id="NAME">%s</xliff:g> utilize esta funcionalidade, toque para abrir as definições e desative-a."</string>
<string name="pip_play" msgid="1417176722760265888">"Reproduzir"</string>
<string name="pip_pause" msgid="8881063404466476571">"Colocar em pausa"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
index a621877ef317..ee90009d3dc2 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"Imagem na imagem"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Ecrã no ecrã"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Sem título do programa)"</string>
<string name="pip_close" msgid="3480680679023423574">"Fechar PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Ecrã inteiro"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index ab7d3db62a7e..e0e1c76cee91 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Mais configurações"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Concluído"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Conectado"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Conectando..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Ponto de acesso"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index bba92ecc63ac..be529f343129 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -314,6 +314,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Mai multe setări"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Terminat"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Conectat"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Se conectează..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -733,7 +735,7 @@
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimizați"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Închideți"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Trageți în jos pentru a închide"</string>
- <string name="pip_menu_title" msgid="3328510504196964712">"Meniul imagine în imagine"</string>
+ <string name="pip_menu_title" msgid="3328510504196964712">"Meniul picture-in-picture"</string>
<string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> este în modul picture-in-picture"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"Dacă nu doriți ca <xliff:g id="NAME">%s</xliff:g> să utilizeze această funcție, atingeți pentru a deschide setările și dezactivați-o."</string>
<string name="pip_play" msgid="1417176722760265888">"Redați"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 35c860c846d2..88deda02fadc 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -316,6 +316,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Настройки"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Готово"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Подключено"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 1eab2516ea30..9cd3701abbba 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"තව සැකසීම්"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"නිමයි"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"සම්බන්ධිත"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index f6b1e504d6bd..a93013e99d4d 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -66,7 +66,7 @@
<string name="usb_debugging_message" msgid="2220143855912376496">"Digitálny odtlačok RSA počítača je:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"Vždy povoliť z tohto počítača"</string>
<string name="usb_debugging_secondary_user_title" msgid="6353808721761220421">"Ladenie cez USB nie je povolené"</string>
- <string name="usb_debugging_secondary_user_message" msgid="8572228137833020196">"Používateľ, ktorý je práve prihlásený na tomto zariadení, nemôže zapnúť ladenie USB. Ak chcete použiť túto funkciu, prepnite na používateľa s oprávneniami správcu."</string>
+ <string name="usb_debugging_secondary_user_message" msgid="8572228137833020196">"Používateľ, ktorý je práve prihlásený na tomto zariadení, nemôže zapnúť ladenie cez USB. Ak chcete použiť túto funkciu, prepnite na používateľa s oprávneniami správcu."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"Priblížiť na celú obrazovku"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"Na celú obrazovku"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"Prebieha ukladanie snímky obrazovky..."</string>
@@ -316,6 +316,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Ďalšie nastavenia"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Hotovo"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Pripojené"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Pripája sa..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Zdieľané pripojenie"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -739,8 +741,8 @@
<string name="pip_phone_minimize" msgid="1079119422589131792">"Minimalizovať"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Zavrieť"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Zrušíte presunutím nadol"</string>
- <string name="pip_menu_title" msgid="3328510504196964712">"Ponuka obrazu v obraze"</string>
- <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> je na obraze v obraze"</string>
+ <string name="pip_menu_title" msgid="3328510504196964712">"Ponuka režimu obraz v obraze"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> je v režime obraz v obraze"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"Ak nechcete, aby aplikácia <xliff:g id="NAME">%s</xliff:g> používala túto funkciu, klepnutím otvorte nastavenia a vypnite ju."</string>
<string name="pip_play" msgid="1417176722760265888">"Prehrať"</string>
<string name="pip_pause" msgid="8881063404466476571">"Pozastaviť"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 270fb6da220a..449ac24afc01 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -316,6 +316,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Več nastavitev"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Končano"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Povezava je vzpostavljena"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Vzpostavljanje povezave ..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Internet prek mobilne naprave"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Dostopna točka"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index c9b22ff63cae..a254953688c5 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Cilësime të tjera"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"U krye!"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"I lidhur"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Po lidhet..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Lidhje çiftimi"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Qasje në zona publike interneti"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 8556eaeab0b2..561a56a52b07 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Још подешавања"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Готово"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Повезан"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index ce9e7e245231..cb5c214846c4 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Fler inställningar"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Klart"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Ansluten"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Ansluter ..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Internetdelning"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Trådlös surfzon"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 3a35ff6111b6..31d2328102f2 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Mipangilio zaidi"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Nimemaliza"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Imeunganishwa"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Inaunganisha..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Kusambaza mtandao"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Mtandao-hewa"</string>
@@ -726,7 +728,7 @@
<string name="pip_phone_close" msgid="8416647892889710330">"Funga"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Buruta ili uondoe"</string>
<string name="pip_menu_title" msgid="3328510504196964712">"Menyu ya picha ndani ya picha"</string>
- <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> iko katika picha ndani ya picha"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> iko katika hali ya picha ndani ya picha nyingine"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"Ikiwa hutaki <xliff:g id="NAME">%s</xliff:g> itumie kipengele hiki, gonga ili ufungue mipangilio na uizime."</string>
<string name="pip_play" msgid="1417176722760265888">"Cheza"</string>
<string name="pip_pause" msgid="8881063404466476571">"Sitisha"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 8a9cba2acb2d..30defe356ad0 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"அமைப்பில் மாற்று"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"முடிந்தது"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"இணைக்கப்பட்டது"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
@@ -725,8 +727,8 @@
<string name="pip_phone_minimize" msgid="1079119422589131792">"சிறிதாக்கு"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"மூடு"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"நிராகரிக்க, கீழே இழுக்கவும்"</string>
- <string name="pip_menu_title" msgid="3328510504196964712">"பிக்ச்சர் இன் பிக்ச்சர் மெனு"</string>
- <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> தற்போது பிக்ச்சர் இன் பிக்ச்சரில் உள்ளது"</string>
+ <string name="pip_menu_title" msgid="3328510504196964712">"பிக்ச்சர்-இன்-பிக்ச்சர் மெனு"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g> தற்போது பிக்ச்சர்-இன்-பிக்ச்சரில் உள்ளது"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"<xliff:g id="NAME">%s</xliff:g> இந்த அம்சத்தைப் பயன்படுத்த வேண்டாம் என நினைத்தால், அமைப்புகளைத் திறந்து அதை முடக்க, தட்டவும்."</string>
<string name="pip_play" msgid="1417176722760265888">"இயக்கு"</string>
<string name="pip_pause" msgid="8881063404466476571">"இடைநிறுத்து"</string>
diff --git a/packages/SystemUI/res/values-ta/strings_tv.xml b/packages/SystemUI/res/values-ta/strings_tv.xml
index 5ddab5646e8c..f7c81ee340e3 100644
--- a/packages/SystemUI/res/values-ta/strings_tv.xml
+++ b/packages/SystemUI/res/values-ta/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"பிக்ச்சர் இன் பிக்ச்சர்"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"பிக்ச்சர்-இன்-பிக்ச்சர்"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(தலைப்பு இல்லை)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIPஐ மூடு"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"முழுத்திரை"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index b3421a95a126..2a2d394f185e 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"మరిన్ని సెట్టింగ్‌లు"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"పూర్తయింది"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"కనెక్ట్ చేయబడినది"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 944c4293f82f..969ba34dc412 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"การตั้งค่าเพิ่มเติม"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"เสร็จสิ้น"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"เชื่อมต่อ"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index b4787051c9ea..1d223d03e80c 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Marami pang setting"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Tapos na"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Nakakonekta"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Kumokonekta..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Nagte-tether"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 8c18bf0720f0..0b2fa4e4f90c 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Diğer ayarlar"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Bitti"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Bağlı"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Bağlanılıyor..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
@@ -725,8 +727,8 @@
<string name="pip_phone_minimize" msgid="1079119422589131792">"Simge durumuna getir"</string>
<string name="pip_phone_close" msgid="8416647892889710330">"Kapat"</string>
<string name="pip_phone_dismiss_hint" msgid="6351678169095923899">"Kapatmak için aşağıya sürükleyin"</string>
- <string name="pip_menu_title" msgid="3328510504196964712">"Ekran içinde ekran menüsü"</string>
- <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g>, ekran içinde ekran özelliğini kullanıyor"</string>
+ <string name="pip_menu_title" msgid="3328510504196964712">"Pencere içinde pencere menüsü"</string>
+ <string name="pip_notification_title" msgid="3204024940158161322">"<xliff:g id="NAME">%s</xliff:g>, pencere içinde pencere özelliğini kullanıyor"</string>
<string name="pip_notification_message" msgid="5619512781514343311">"<xliff:g id="NAME">%s</xliff:g> uygulamasının bu özelliği kullanmasını istemiyorsanız dokunarak ayarları açın ve söz konusu özelliği kapatın."</string>
<string name="pip_play" msgid="1417176722760265888">"Oynat"</string>
<string name="pip_pause" msgid="8881063404466476571">"Duraklat"</string>
diff --git a/packages/SystemUI/res/values-tr/strings_tv.xml b/packages/SystemUI/res/values-tr/strings_tv.xml
index ec2c7844c37c..fb3951099300 100644
--- a/packages/SystemUI/res/values-tr/strings_tv.xml
+++ b/packages/SystemUI/res/values-tr/strings_tv.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="notification_channel_tv_pip" msgid="134047986446577723">"Ekran İçinde Ekran"</string>
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Pencere İçinde Pencere"</string>
<string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Başlıksız program)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP\'yi kapat"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Tam ekran"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 8fb2363ca08e..d11cfda29829 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -316,6 +316,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Більше налаштувань"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Готово"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Під’єднано"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index c00b74162d39..e071922e5ef5 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"مزید ترتیبات"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"ہو گیا"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"مربوط"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index caf4df7b7187..cf6fa00d526e 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Boshqa sozlamalar"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Tayyor"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Ulangan"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Ulanmoqda…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Modem rejimi"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 9a2ef2d0f4d7..5b884ec26613 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Cài đặt khác"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Xong"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Đã kết nối"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Đang kết nối..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Đang dùng làm điểm truy cập Internet"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Điểm phát sóng"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 094d9e326a34..4065ff687b11 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -60,7 +60,7 @@
<string name="label_view" msgid="6304565553218192990">"查看"</string>
<string name="always_use_device" msgid="1450287437017315906">"默认情况下用于该USB设备"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"默认情况下用于该USB配件"</string>
- <string name="usb_debugging_title" msgid="4513918393387141949">"允许USB调试吗?"</string>
+ <string name="usb_debugging_title" msgid="4513918393387141949">"允许 USB 调试吗?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"这台计算机的 RSA 密钥指纹如下:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"一律允许使用这台计算机进行调试"</string>
<string name="usb_debugging_secondary_user_title" msgid="6353808721761220421">"不允许使用 USB 调试功能"</string>
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"更多设置"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"完成"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"已连接"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 7152052cca3f..5fc1ff634d84 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -312,6 +312,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"更多設定"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"完成"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"已連線"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index a184f3af2727..9bbb1887b773 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"更多設定"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"完成"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"已連線"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<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>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index d2584d773495..1a70bc4882a5 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -310,6 +310,8 @@
<string name="quick_settings_more_settings" msgid="326112621462813682">"Izilungiselelo eziningi"</string>
<string name="quick_settings_done" msgid="3402999958839153376">"Kwenziwe"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Ixhunyiwe"</string>
+ <!-- no translation found for quick_settings_connected_battery_level (4136051440381328892) -->
+ <skip />
<string name="quick_settings_connecting" msgid="47623027419264404">"Iyaxhuma..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Ukusebenzisa njengemodemu"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"I-Hotspot"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 2ad6f2da7fb0..02a2e8fc5313 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -247,6 +247,11 @@
-->
<string name="doze_pickup_subtype_performs_proximity_check"></string>
+ <!-- Type of a sensor that provides a low-power estimate of the desired display
+ brightness, suitable to listen to while the device is asleep (e.g. during
+ always-on display) -->
+ <string name="doze_brightness_sensor_type" translatable="false"></string>
+
<!-- Doze: pulse parameter - how long does it take to fade in? -->
<integer name="doze_pulse_duration_in">900</integer>
@@ -316,26 +321,6 @@
<!-- Whether or not a background should be drawn behind a notification. -->
<bool name="config_drawNotificationBackground">true</bool>
- <!-- Whether or not the edit icon on the quick settings header is shown. -->
- <bool name="config_showQuickSettingsEditingIcon">true</bool>
-
- <!-- Whether or not the multi-user switcher should be visible even if the quick settings are
- not expanded. If there are not multiple users on the system, the switcher will still
- hide itself. -->
- <bool name="config_alwaysShowMultiUserSwitcher">false</bool>
-
- <!-- Whether or not the expand indicator is visible for manually expanding the quick settings
- panel. -->
- <bool name="config_showQuickSettingsExpandIndicator">true</bool>
-
- <!-- Whether or not to display the row of quick settings icons separate from the full quick
- settings panel. -->
- <bool name="config_showQuickSettingsRow">true</bool>
-
- <!-- Whether or not the quick settings should be revealed on an overscroll of the
- notifications panel. -->
- <bool name="config_enableQuickSettingsOverscrollExpansion">true</bool>
-
<!-- Whether or the notifications can be shown and dismissed with a drag. -->
<bool name="config_enableNotificationShadeDrag">true</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 93d2072e955c..1fd9b2e9ae9b 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -189,6 +189,23 @@
<!-- Height of the status bar header bar -->
<dimen name="status_bar_header_height">124dp</dimen>
+ <!-- Height of the status bar header bar in the car setting. -->
+ <dimen name="car_status_bar_header_height">128dp</dimen>
+
+ <!-- The bottom padding of the status bar header. -->
+ <dimen name="status_bar_header_padding_bottom">48dp</dimen>
+
+ <!-- The height of the container that holds the system icons in the quick settings header. -->
+ <dimen name="qs_header_system_icons_area_height">40dp</dimen>
+
+ <!-- The height of the container that holds the system icons in the quick settings header in the
+ car setting. -->
+ <dimen name="car_qs_header_system_icons_area_height">54dp</dimen>
+
+ <!-- The height of the quick settings footer that holds the user switcher, settings icon,
+ etc. -->
+ <dimen name="qs_footer_height">48dp</dimen>
+
<!-- Height of the status bar header bar when expanded -->
<dimen name="status_bar_header_height_expanded">124dp</dimen>
@@ -827,7 +844,4 @@
<!-- How far to inset the rounded edges -->
<dimen name="stat_sys_mobile_signal_circle_inset">0.9dp</dimen>
- <!-- Width of the hollow triangle for empty signal state -->
- <dimen name="mobile_signal_empty_strokewidth">2dp</dimen>
-
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 20531d395fb5..837cb8fcb3ba 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -741,6 +741,8 @@
<string name="quick_settings_done">Done</string>
<!-- QuickSettings: Control panel: Label for connected device. [CHAR LIMIT=NONE] -->
<string name="quick_settings_connected">Connected</string>
+ <!-- QuickSettings: Control panel: Label for connected device, showing remote device battery level. [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_connected_battery_level">Connected, battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string>
<!-- QuickSettings: Control panel: Label for connecting device. [CHAR LIMIT=NONE] -->
<string name="quick_settings_connecting">Connecting...</string>
<!-- QuickSettings: Tethering. [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index c67e49ae1150..93a0742dd2d7 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -300,9 +300,8 @@
<style name="Animation.StatusBar">
</style>
- <!-- Overlay styles will replace this theme -->
- <style name="systemui_base" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
- </style>
+ <!-- Overlay manager may replace this theme -->
+ <style name="systemui_base" parent="@*android:style/Theme.DeviceDefault.QuickSettings" />
<style name="systemui_theme" parent="systemui_base">
<item name="lightIconTheme">@style/DualToneLightTheme</item>
@@ -317,7 +316,10 @@
<item name="*android:successColor">?android:attr/textColorPrimaryInverse</item>
</style>
- <style name="qs_theme" parent="systemui_theme">
+ <!-- Overlay manager may replace this theme -->
+ <style name="qs_base" parent="@*android:style/Theme.DeviceDefault.QuickSettings" />
+
+ <style name="qs_theme" parent="qs_base">
<item name="lightIconTheme">@style/QSIconTheme</item>
<item name="darkIconTheme">@style/QSIconTheme</item>
</style>
@@ -473,7 +475,7 @@
<item name="android:paddingEnd">8dp</item>
</style>
- <style name="edit_theme" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
+ <style name="edit_theme" parent="qs_base">
<item name="android:colorBackground">?android:attr/colorSecondary</item>
</style>
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
index bb0f2f9f3ac0..22bb2a3c8f5b 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -19,6 +19,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
+import android.content.res.Configuration;
import android.provider.Settings;
import android.util.AttributeSet;
import android.view.Gravity;
@@ -28,9 +29,15 @@ import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
-
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.systemui.util.leak.RotationUtils;
+
+import java.util.ArrayList;
+
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
public class HardwareUiLayout extends FrameLayout implements Tunable {
@@ -49,7 +56,7 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
private int mEndPoint;
private boolean mEdgeBleed;
private boolean mRoundedDivider;
- private boolean mLandscape;
+ private int mRotation = ROTATION_NONE;
private boolean mRotatedBackground;
public HardwareUiLayout(Context context, AttributeSet attrs) {
@@ -93,8 +100,10 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
private void updateEdgeMargin(int edge) {
if (mChild != null) {
MarginLayoutParams params = (MarginLayoutParams) mChild.getLayoutParams();
- if (mLandscape) {
+ if (mRotation == ROTATION_LANDSCAPE) {
params.topMargin = edge;
+ } else if (mRotation == ROTATION_SEASCAPE) {
+ params.bottomMargin = edge;
} else {
params.rightMargin = edge;
}
@@ -118,6 +127,7 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
mChild.addOnLayoutChangeListener(
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
updatePosition());
+ updateRotation();
} else {
return;
}
@@ -127,30 +137,69 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
animateChild(mOldHeight, newHeight);
}
post(() -> updatePosition());
- boolean landscape = getMeasuredWidth() > getMeasuredHeight();
- if (landscape != mLandscape) {
- mLandscape = landscape;
- if (mLandscape) {
- toLandscape();
- if (mChild instanceof LinearLayout) {
- mRotatedBackground = true;
- mBackground.setRotatedBackground(true);
- ((LinearLayout) mChild).setOrientation(LinearLayout.HORIZONTAL);
- swapDimens(mChild);
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ updateRotation();
+ }
+
+ private void updateRotation() {
+ int rotation = RotationUtils.getRotation(getContext());
+ if (rotation != mRotation) {
+ rotate(mRotation, rotation);
+ mRotation = rotation;
+ }
+ }
+
+ private void rotate(int from, int to) {
+ if (from != ROTATION_NONE && to != ROTATION_NONE) {
+ // Rather than handling this confusing case, just do 2 rotations.
+ rotate(from, ROTATION_NONE);
+ rotate(ROTATION_NONE, to);
+ return;
+ }
+ if (from == ROTATION_LANDSCAPE || to == ROTATION_SEASCAPE) {
+ rotateRight();
+ } else {
+ rotateLeft();
+ }
+ if (to != ROTATION_NONE) {
+ if (mChild instanceof LinearLayout) {
+ mRotatedBackground = true;
+ mBackground.setRotatedBackground(true);
+ LinearLayout linearLayout = (LinearLayout) mChild;
+ if (to == ROTATION_SEASCAPE) {
+ swapOrder(linearLayout);
}
- } else {
- fromLandscape();
- if (mChild instanceof LinearLayout) {
- mRotatedBackground = false;
- mBackground.setRotatedBackground(false);
- ((LinearLayout) mChild).setOrientation(LinearLayout.VERTICAL);
- swapDimens(mChild);
+ linearLayout.setOrientation(LinearLayout.HORIZONTAL);
+ swapDimens(this.mChild);
+ }
+ } else {
+ if (mChild instanceof LinearLayout) {
+ mRotatedBackground = false;
+ mBackground.setRotatedBackground(false);
+ LinearLayout linearLayout = (LinearLayout) mChild;
+ if (from == ROTATION_SEASCAPE) {
+ swapOrder(linearLayout);
}
+ linearLayout.setOrientation(LinearLayout.VERTICAL);
+ swapDimens(mChild);
}
}
}
- private void fromLandscape() {
+ private void swapOrder(LinearLayout linearLayout) {
+ ArrayList<View> children = new ArrayList<>();
+ for (int i = 0; i < linearLayout.getChildCount(); i++) {
+ children.add(0, linearLayout.getChildAt(i));
+ linearLayout.removeViewAt(i);
+ }
+ children.forEach(v -> linearLayout.addView(v));
+ }
+
+ private void rotateRight() {
rotateRight(this);
rotateRight(mChild);
swapDimens(this);
@@ -202,7 +251,7 @@ public class HardwareUiLayout extends FrameLayout implements Tunable {
return retGravity;
}
- private void toLandscape() {
+ private void rotateLeft() {
rotateLeft(this);
rotateLeft(mChild);
swapDimens(this);
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 3cc81dfb45d7..4437d314a7c2 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -47,6 +47,7 @@ public final class Prefs {
Key.QS_INVERT_COLORS_ADDED,
Key.QS_WORK_ADDED,
Key.QS_NIGHTDISPLAY_ADDED,
+ Key.SEEN_MULTI_USER,
})
public @interface Key {
@Deprecated
@@ -62,12 +63,18 @@ public final class Prefs {
String DND_FAVORITE_BUCKET_INDEX = "DndCountdownMinuteIndex";
String DND_NONE_SELECTED = "DndNoneSelected";
String DND_FAVORITE_ZEN = "DndFavoriteZen";
+ String QS_DATA_SAVER_DIALOG_SHOWN = "QsDataSaverDialogShown";
+ @Deprecated
String QS_HOTSPOT_ADDED = "QsHotspotAdded";
+ @Deprecated
String QS_DATA_SAVER_ADDED = "QsDataSaverAdded";
- String QS_DATA_SAVER_DIALOG_SHOWN = "QsDataSaverDialogShown";
+ @Deprecated
String QS_INVERT_COLORS_ADDED = "QsInvertColorsAdded";
+ @Deprecated
String QS_WORK_ADDED = "QsWorkAdded";
+ @Deprecated
String QS_NIGHTDISPLAY_ADDED = "QsNightDisplayAdded";
+ String SEEN_MULTI_USER = "HasSeenMultiUser";
}
public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/RoundedCorners.java b/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
index 73e0d7ff33ac..40ea4ece803c 100644
--- a/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
+++ b/packages/SystemUI/src/com/android/systemui/RoundedCorners.java
@@ -93,16 +93,17 @@ public class RoundedCorners extends SystemUI implements Tunable {
private void setupPadding(int padding) {
// Add some padding to all the content near the edge of the screen.
StatusBar sb = getComponent(StatusBar.class);
- View statusBar = sb.getStatusBarWindow();
-
- TunablePadding.addTunablePadding(statusBar.findViewById(R.id.keyguard_header), PADDING,
- padding, FLAG_END);
-
- FragmentHostManager fragmentHostManager = FragmentHostManager.get(statusBar);
- fragmentHostManager.addTagListener(CollapsedStatusBarFragment.TAG,
- new TunablePaddingTagListener(padding, R.id.status_bar));
- fragmentHostManager.addTagListener(QS.TAG,
- new TunablePaddingTagListener(padding, R.id.header));
+ View statusBar = (sb != null ? sb.getStatusBarWindow() : null);
+ if (statusBar != null) {
+ TunablePadding.addTunablePadding(statusBar.findViewById(R.id.keyguard_header), PADDING,
+ padding, FLAG_END);
+
+ FragmentHostManager fragmentHostManager = FragmentHostManager.get(statusBar);
+ fragmentHostManager.addTagListener(CollapsedStatusBarFragment.TAG,
+ new TunablePaddingTagListener(padding, R.id.status_bar));
+ fragmentHostManager.addTagListener(QS.TAG,
+ new TunablePaddingTagListener(padding, R.id.header));
+ }
}
private WindowManager.LayoutParams getWindowLayoutParams() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 8506734036dc..e92ed2f75d49 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -34,7 +34,6 @@ import android.view.accessibility.AccessibilityManager;
import com.android.systemui.Dependency;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.analytics.DataCollector;
-import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.statusbar.StatusBarState;
import java.io.PrintWriter;
@@ -76,6 +75,7 @@ public class FalsingManager implements SensorEventListener {
private boolean mSessionActive = false;
private int mState = StatusBarState.SHADE;
private boolean mScreenOn;
+ private boolean mShowingAod;
private Runnable mPendingWtf;
protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
@@ -122,7 +122,7 @@ public class FalsingManager implements SensorEventListener {
.append(" mState=").append(StatusBarState.toShortString(mState))
.toString()
);
- return isEnabled() && mScreenOn && (mState == StatusBarState.KEYGUARD);
+ return isEnabled() && mScreenOn && (mState == StatusBarState.KEYGUARD) && !mShowingAod;
}
private boolean sessionEntrypoint() {
@@ -144,6 +144,14 @@ public class FalsingManager implements SensorEventListener {
}
}
+ public void updateSessionActive() {
+ if (shouldSessionBeActive()) {
+ sessionEntrypoint();
+ } else {
+ sessionExitpoint(false /* force */);
+ }
+ }
+
private void onSessionStart() {
if (FalsingLog.ENABLED) {
FalsingLog.i("onSessionStart", "classifierEnabled=" + isClassiferEnabled());
@@ -249,6 +257,11 @@ public class FalsingManager implements SensorEventListener {
return mEnforceBouncer;
}
+ public void setShowingAod(boolean showingAod) {
+ mShowingAod = showingAod;
+ updateSessionActive();
+ }
+
public void setStatusBarState(int state) {
if (FalsingLog.ENABLED) {
FalsingLog.i("setStatusBarState", new StringBuilder()
@@ -257,11 +270,7 @@ public class FalsingManager implements SensorEventListener {
.toString());
}
mState = state;
- if (shouldSessionBeActive()) {
- sessionEntrypoint();
- } else {
- sessionExitpoint(false /* force */);
- }
+ updateSessionActive();
}
public void onScreenTurningOn() {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 1cc10c22082a..4804ac23f3af 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -19,11 +19,14 @@ package com.android.systemui.doze;
import android.app.AlarmManager;
import android.app.Application;
import android.content.Context;
+import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.os.Handler;
import com.android.internal.hardware.AmbientDisplayConfiguration;
+import com.android.systemui.R;
import com.android.systemui.SystemUIApplication;
+import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.wakelock.DelayedWakeLock;
import com.android.systemui.util.wakelock.WakeLock;
@@ -46,25 +49,38 @@ public class DozeFactory {
WakeLock wakeLock = new DelayedWakeLock(handler,
WakeLock.createPartial(context, "Doze"));
- DozeMachine machine = new DozeMachine(
- DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(
- DozeScreenStatePreventingAdapter.wrapIfNeeded(dozeService, params), params),
- config,
- wakeLock);
+ DozeMachine.Service wrappedService = DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(
+ DozeScreenStatePreventingAdapter.wrapIfNeeded(dozeService, params), params);
+ DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock);
machine.setParts(new DozeMachine.Part[]{
- createDozeTriggers(context, sensorManager, host, config, params, handler, wakeLock,
- machine),
+ new DozePauser(handler, machine, alarmManager),
+ new DozeFalsingManagerAdapter(FalsingManager.getInstance(context)),
+ createDozeTriggers(context, sensorManager, host, alarmManager, config, params,
+ handler, wakeLock, machine),
createDozeUi(context, host, wakeLock, machine, handler, alarmManager),
+ createDozeScreenState(wrappedService),
+ createDozeScreenBrightness(context, wrappedService, sensorManager, handler),
});
return machine;
}
+ private DozeMachine.Part createDozeScreenState(DozeMachine.Service service) {
+ return new DozeScreenState(service);
+ }
+
+ private DozeMachine.Part createDozeScreenBrightness(Context context,
+ DozeMachine.Service service, SensorManager sensorManager, Handler handler) {
+ Sensor sensor = DozeSensors.findSensorWithType(sensorManager,
+ context.getString(R.string.doze_brightness_sensor_type));
+ return new DozeScreenBrightness(context, service, sensorManager, sensor, handler);
+ }
+
private DozeTriggers createDozeTriggers(Context context, SensorManager sensorManager,
- DozeHost host, AmbientDisplayConfiguration config, DozeParameters params,
- Handler handler, WakeLock wakeLock, DozeMachine machine) {
+ DozeHost host, AlarmManager alarmManager, AmbientDisplayConfiguration config,
+ DozeParameters params, Handler handler, WakeLock wakeLock, DozeMachine machine) {
boolean allowPulseTriggers = true;
- return new DozeTriggers(context, machine, host, config, params,
+ return new DozeTriggers(context, machine, host, alarmManager, config, params,
sensorManager, handler, wakeLock, allowPulseTriggers);
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java
new file mode 100644
index 000000000000..00ca9a48386e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.doze;
+
+import com.android.systemui.classifier.FalsingManager;
+
+/**
+ * Notifies FalsingManager of whether or not AOD is showing.
+ */
+public class DozeFalsingManagerAdapter implements DozeMachine.Part {
+
+ private final FalsingManager mFalsingManager;
+
+ public DozeFalsingManagerAdapter(FalsingManager falsingManager) {
+ mFalsingManager = falsingManager;
+ }
+
+ @Override
+ public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
+ mFalsingManager.setShowingAod(isAodMode(newState));
+ }
+
+ private boolean isAodMode(DozeMachine.State state) {
+ switch (state) {
+ case DOZE_AOD:
+ case DOZE_AOD_PAUSING:
+ case DOZE_AOD_PAUSED:
+ return true;
+ default:
+ return false;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 5526e6ba3f45..0be4eda8a069 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -60,13 +60,16 @@ public class DozeMachine {
/** Doze is done. DozeService is finished. */
FINISH,
/** AOD, but the display is temporarily off. */
- DOZE_AOD_PAUSED;
+ DOZE_AOD_PAUSED,
+ /** AOD, prox is near, transitions to DOZE_AOD_PAUSED after a timeout. */
+ DOZE_AOD_PAUSING;
boolean canPulse() {
switch (this) {
case DOZE:
case DOZE_AOD:
case DOZE_AOD_PAUSED:
+ case DOZE_AOD_PAUSING:
return true;
default:
return false;
@@ -93,6 +96,7 @@ public class DozeMachine {
case DOZE_PULSING:
return Display.STATE_ON;
case DOZE_AOD:
+ case DOZE_AOD_PAUSING:
return Display.STATE_DOZE_SUSPEND;
default:
return Display.STATE_UNKNOWN;
@@ -222,7 +226,6 @@ public class DozeMachine {
updatePulseReason(newState, oldState, pulseReason);
performTransitionOnComponents(oldState, newState);
- updateScreenState(newState);
updateWakeLockState(newState);
resolveIntermediateState(newState);
@@ -284,7 +287,8 @@ public class DozeMachine {
if (mState == State.FINISH) {
return State.FINISH;
}
- if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD || mState == State.DOZE)
+ if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD_PAUSING
+ || mState == State.DOZE_AOD || mState == State.DOZE)
&& requestedState == State.DOZE_PULSE_DONE) {
Log.i(TAG, "Dropping pulse done because current state is already done: " + mState);
return mState;
@@ -307,13 +311,6 @@ public class DozeMachine {
}
}
- private void updateScreenState(State newState) {
- int state = newState.screenState();
- if (state != Display.STATE_UNKNOWN) {
- mDozeService.setDozeScreenState(state);
- }
- }
-
private void resolveIntermediateState(State state) {
switch (state) {
case INITIALIZED:
@@ -360,5 +357,36 @@ public class DozeMachine {
/** Request waking up. */
void requestWakeUp();
+
+ /** Set screen brightness */
+ void setDozeScreenBrightness(int brightness);
+
+ class Delegate implements Service {
+ private final Service mDelegate;
+
+ public Delegate(Service delegate) {
+ mDelegate = delegate;
+ }
+
+ @Override
+ public void finish() {
+ mDelegate.finish();
+ }
+
+ @Override
+ public void setDozeScreenState(int state) {
+ mDelegate.setDozeScreenState(state);
+ }
+
+ @Override
+ public void requestWakeUp() {
+ mDelegate.requestWakeUp();
+ }
+
+ @Override
+ public void setDozeScreenBrightness(int brightness) {
+ mDelegate.setDozeScreenBrightness(brightness);
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java b/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
new file mode 100644
index 000000000000..a33b454c6430
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.doze;
+
+import android.app.AlarmManager;
+import android.os.Handler;
+
+import com.android.systemui.util.AlarmTimeout;
+
+/**
+ * Moves the doze machine from the pausing to the paused state after a timeout.
+ */
+public class DozePauser implements DozeMachine.Part {
+ public static final String TAG = DozePauser.class.getSimpleName();
+ private static final long TIMEOUT = 10 * 1000;
+ private final AlarmTimeout mPauseTimeout;
+ private final DozeMachine mMachine;
+
+ public DozePauser(Handler handler, DozeMachine machine, AlarmManager alarmManager) {
+ mMachine = machine;
+ mPauseTimeout = new AlarmTimeout(alarmManager, this::onTimeout, TAG, handler);
+ }
+
+ @Override
+ public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
+ switch (newState) {
+ case DOZE_AOD_PAUSING:
+ mPauseTimeout.schedule(TIMEOUT, AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
+ break;
+ default:
+ mPauseTimeout.cancel();
+ break;
+ }
+ }
+
+ private void onTimeout() {
+ mMachine.requestState(DozeMachine.State.DOZE_AOD_PAUSED);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
new file mode 100644
index 000000000000..e461986da5e0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -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.
+ */
+
+package com.android.systemui.doze;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.Handler;
+
+/**
+ * Controls the screen brightness when dozing.
+ */
+public class DozeScreenBrightness implements DozeMachine.Part, SensorEventListener {
+ private final Context mContext;
+ private final DozeMachine.Service mDozeService;
+ private final Handler mHandler;
+ private final SensorManager mSensorManager;
+ private final Sensor mLightSensor;
+ private boolean mRegistered;
+
+ public DozeScreenBrightness(Context context, DozeMachine.Service service,
+ SensorManager sensorManager, Sensor lightSensor, Handler handler) {
+ mContext = context;
+ mDozeService = service;
+ mSensorManager = sensorManager;
+ mLightSensor = lightSensor;
+ mHandler = handler;
+ }
+
+ @Override
+ public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
+ switch (newState) {
+ case INITIALIZED:
+ resetBrightnessToDefault();
+ break;
+ case DOZE_AOD:
+ case DOZE_REQUEST_PULSE:
+ setLightSensorEnabled(true);
+ break;
+ case DOZE:
+ case DOZE_AOD_PAUSED:
+ setLightSensorEnabled(false);
+ resetBrightnessToDefault();
+ break;
+ case FINISH:
+ setLightSensorEnabled(false);
+ break;
+ }
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ if (mRegistered) {
+ mDozeService.setDozeScreenBrightness(Math.max(1, (int) event.values[0]));
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ }
+
+ private void resetBrightnessToDefault() {
+ mDozeService.setDozeScreenBrightness(mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_screenBrightnessDoze));
+ }
+
+ private void setLightSensorEnabled(boolean enabled) {
+ if (enabled && !mRegistered && mLightSensor != null) {
+ mRegistered = mSensorManager.registerListener(this, mLightSensor,
+ SensorManager.SENSOR_DELAY_NORMAL, mHandler);
+ } else if (!enabled && mRegistered) {
+ mSensorManager.unregisterListener(this);
+ mRegistered = false;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
new file mode 100644
index 000000000000..846ec27c451e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.doze;
+
+import android.content.Context;
+import android.view.Display;
+
+/**
+ * Controls the screen when dozing.
+ */
+public class DozeScreenState implements DozeMachine.Part {
+ private final DozeMachine.Service mDozeService;
+
+ public DozeScreenState(DozeMachine.Service service) {
+ mDozeService = service;
+ }
+
+ @Override
+ public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
+ int screenState = newState.screenState();
+ if (screenState != Display.STATE_UNKNOWN) {
+ mDozeService.setDozeScreenState(screenState);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenStatePreventingAdapter.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenStatePreventingAdapter.java
index ad5897aa71c2..5d0a9d70e99d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenStatePreventingAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenStatePreventingAdapter.java
@@ -24,18 +24,11 @@ import com.android.systemui.statusbar.phone.DozeParameters;
/**
* Prevents usage of doze screen states on devices that don't support them.
*/
-public class DozeScreenStatePreventingAdapter implements DozeMachine.Service {
-
- private final DozeMachine.Service mInner;
+public class DozeScreenStatePreventingAdapter extends DozeMachine.Service.Delegate {
@VisibleForTesting
DozeScreenStatePreventingAdapter(DozeMachine.Service inner) {
- mInner = inner;
- }
-
- @Override
- public void finish() {
- mInner.finish();
+ super(inner);
}
@Override
@@ -43,12 +36,7 @@ public class DozeScreenStatePreventingAdapter implements DozeMachine.Service {
if (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND) {
state = Display.STATE_ON;
}
- mInner.setDozeScreenState(state);
- }
-
- @Override
- public void requestWakeUp() {
- mInner.requestWakeUp();
+ super.setDozeScreenState(state);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 23da716706d3..67de020cdfde 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -18,6 +18,7 @@ package com.android.systemui.doze;
import android.annotation.AnyThread;
import android.app.ActivityManager;
+import android.app.AlarmManager;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
@@ -29,6 +30,7 @@ import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
import android.net.Uri;
import android.os.Handler;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -38,6 +40,7 @@ import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.util.AlarmTimeout;
import com.android.systemui.util.wakelock.WakeLock;
import java.io.PrintWriter;
@@ -51,6 +54,7 @@ public class DozeSensors {
private static final String TAG = "DozeSensors";
private final Context mContext;
+ private final AlarmManager mAlarmManager;
private final SensorManager mSensorManager;
private final TriggerSensor[] mSensors;
private final ContentResolver mResolver;
@@ -65,10 +69,12 @@ public class DozeSensors {
private final ProxSensor mProxSensor;
- public DozeSensors(Context context, SensorManager sensorManager, DozeParameters dozeParameters,
+ public DozeSensors(Context context, AlarmManager alarmManager, SensorManager sensorManager,
+ DozeParameters dozeParameters,
AmbientDisplayConfiguration config, WakeLock wakeLock, Callback callback,
Consumer<Boolean> proxCallback) {
mContext = context;
+ mAlarmManager = alarmManager;
mSensorManager = sensorManager;
mDozeParameters = dozeParameters;
mConfig = config;
@@ -100,10 +106,14 @@ public class DozeSensors {
}
private Sensor findSensorWithType(String type) {
+ return findSensorWithType(mSensorManager, type);
+ }
+
+ static Sensor findSensorWithType(SensorManager sensorManager, String type) {
if (TextUtils.isEmpty(type)) {
return null;
}
- List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
+ List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_ALL);
for (Sensor s : sensorList) {
if (type.equals(s.getStringType())) {
return s;
@@ -140,7 +150,7 @@ public class DozeSensors {
}
public void setProxListening(boolean listen) {
- mProxSensor.setRegistered(listen);
+ mProxSensor.setRequested(listen);
}
private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
@@ -168,11 +178,23 @@ public class DozeSensors {
private class ProxSensor implements SensorEventListener {
+ static final long COOLDOWN_TRIGGER = 2 * 1000;
+ static final long COOLDOWN_PERIOD = 5 * 1000;
+
+ boolean mRequested;
boolean mRegistered;
Boolean mCurrentlyFar;
+ long mLastNear;
+ final AlarmTimeout mCooldownTimer;
- void setRegistered(boolean register) {
- if (mRegistered == register) {
+
+ public ProxSensor() {
+ mCooldownTimer = new AlarmTimeout(mAlarmManager, this::updateRegistered,
+ "prox_cooldown", mHandler);
+ }
+
+ void setRequested(boolean requested) {
+ if (mRequested == requested) {
// Send an update even if we don't re-register.
mHandler.post(() -> {
if (mCurrentlyFar != null) {
@@ -181,6 +203,18 @@ public class DozeSensors {
});
return;
}
+ mRequested = requested;
+ updateRegistered();
+ }
+
+ private void updateRegistered() {
+ setRegistered(mRequested && !mCooldownTimer.isScheduled());
+ }
+
+ private void setRegistered(boolean register) {
+ if (mRegistered == register) {
+ return;
+ }
if (register) {
mRegistered = mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY),
@@ -196,6 +230,17 @@ public class DozeSensors {
public void onSensorChanged(SensorEvent event) {
mCurrentlyFar = event.values[0] >= event.sensor.getMaximumRange();
mProxCallback.accept(mCurrentlyFar);
+
+ long now = SystemClock.elapsedRealtime();
+ if (!mCurrentlyFar) {
+ mLastNear = now;
+ } else if (mCurrentlyFar && now - mLastNear < COOLDOWN_TRIGGER) {
+ // If the last near was very recent, we might be using more power for prox
+ // wakeups than we're saving from turning of the screen. Instead, turn it off
+ // for a while.
+ mCooldownTimer.schedule(COOLDOWN_PERIOD, AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
+ updateRegistered();
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index d9fb087a6041..98b110619a1c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -76,8 +76,6 @@ public class DozeService extends DreamService
super.onDreamingStarted();
mDozeMachine.requestState(DozeMachine.State.INITIALIZED);
startDozing();
- setDozeScreenBrightness(getResources().getInteger(
- com.android.internal.R.integer.config_screenBrightnessDoze));
if (mDozePlugin != null) {
mDozePlugin.onDreamingStarted();
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapter.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapter.java
index 1e067974e3cc..1c6521f641bf 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapter.java
@@ -24,18 +24,11 @@ import com.android.systemui.statusbar.phone.DozeParameters;
/**
* Prevents usage of doze screen states on devices that don't support them.
*/
-public class DozeSuspendScreenStatePreventingAdapter implements DozeMachine.Service {
-
- private final DozeMachine.Service mInner;
+public class DozeSuspendScreenStatePreventingAdapter extends DozeMachine.Service.Delegate {
@VisibleForTesting
DozeSuspendScreenStatePreventingAdapter(DozeMachine.Service inner) {
- mInner = inner;
- }
-
- @Override
- public void finish() {
- mInner.finish();
+ super(inner);
}
@Override
@@ -43,12 +36,7 @@ public class DozeSuspendScreenStatePreventingAdapter implements DozeMachine.Serv
if (state == Display.STATE_DOZE_SUSPEND) {
state = Display.STATE_DOZE;
}
- mInner.setDozeScreenState(state);
- }
-
- @Override
- public void requestWakeUp() {
- mInner.requestWakeUp();
+ super.setDozeScreenState(state);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 8d1d6e0ce460..9981972a96c5 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -16,6 +16,7 @@
package com.android.systemui.doze;
+import android.app.AlarmManager;
import android.app.UiModeManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -70,7 +71,7 @@ public class DozeTriggers implements DozeMachine.Part {
public DozeTriggers(Context context, DozeMachine machine, DozeHost dozeHost,
- AmbientDisplayConfiguration config,
+ AlarmManager alarmManager, AmbientDisplayConfiguration config,
DozeParameters dozeParameters, SensorManager sensorManager, Handler handler,
WakeLock wakeLock, boolean allowPulseTriggers) {
mContext = context;
@@ -82,8 +83,8 @@ public class DozeTriggers implements DozeMachine.Part {
mHandler = handler;
mWakeLock = wakeLock;
mAllowPulseTriggers = allowPulseTriggers;
- mDozeSensors = new DozeSensors(context, mSensorManager, dozeParameters, config,
- wakeLock, this::onSensor, this::onProximityFar);
+ mDozeSensors = new DozeSensors(context, alarmManager, mSensorManager, dozeParameters,
+ config, wakeLock, this::onSensor, this::onProximityFar);
mUiModeManager = mContext.getSystemService(UiModeManager.class);
}
@@ -152,18 +153,22 @@ public class DozeTriggers implements DozeMachine.Part {
private void onProximityFar(boolean far) {
final boolean near = !far;
- DozeMachine.State state = mMachine.getState();
+ final DozeMachine.State state = mMachine.getState();
+ final boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED);
+ final boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING);
+ final boolean aod = (state == DozeMachine.State.DOZE_AOD);
+
if (near && state == DozeMachine.State.DOZE_PULSING) {
if (DEBUG) Log.i(TAG, "Prox NEAR, ending pulse");
DozeLog.tracePulseCanceledByProx(mContext);
mMachine.requestState(DozeMachine.State.DOZE_PULSE_DONE);
}
- if (far && state == DozeMachine.State.DOZE_AOD_PAUSED) {
+ if (far && (paused || pausing)) {
if (DEBUG) Log.i(TAG, "Prox FAR, unpausing AOD");
mMachine.requestState(DozeMachine.State.DOZE_AOD);
- } else if (near && state == DozeMachine.State.DOZE_AOD) {
+ } else if (near && aod) {
if (DEBUG) Log.i(TAG, "Prox NEAR, pausing AOD");
- mMachine.requestState(DozeMachine.State.DOZE_AOD_PAUSED);
+ mMachine.requestState(DozeMachine.State.DOZE_AOD_PAUSING);
}
}
@@ -186,12 +191,13 @@ public class DozeTriggers implements DozeMachine.Part {
case DOZE:
case DOZE_AOD:
mDozeSensors.setProxListening(newState != DozeMachine.State.DOZE);
- mDozeSensors.setListening(true);
if (oldState != DozeMachine.State.INITIALIZED) {
mDozeSensors.reregisterAllSensors();
}
+ mDozeSensors.setListening(true);
break;
case DOZE_AOD_PAUSED:
+ case DOZE_AOD_PAUSING:
mDozeSensors.setProxListening(true);
mDozeSensors.setListening(false);
break;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index cf87fca56f39..1dc37cdbca7a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -23,6 +23,7 @@ import android.os.SystemClock;
import android.text.format.Formatter;
import android.util.Log;
+import com.android.systemui.util.AlarmTimeout;
import com.android.systemui.util.wakelock.WakeLock;
import java.util.Calendar;
@@ -35,26 +36,23 @@ public class DozeUi implements DozeMachine.Part {
private static final long TIME_TICK_DEADLINE_MILLIS = 90 * 1000; // 1.5min
private final Context mContext;
- private final AlarmManager mAlarmManager;
private final DozeHost mHost;
private final Handler mHandler;
private final WakeLock mWakeLock;
private final DozeMachine mMachine;
- private final AlarmManager.OnAlarmListener mTimeTick;
+ private final AlarmTimeout mTimeTicker;
- private boolean mTimeTickScheduled = false;
private long mLastTimeTickElapsed = 0;
public DozeUi(Context context, AlarmManager alarmManager, DozeMachine machine,
WakeLock wakeLock, DozeHost host, Handler handler) {
mContext = context;
- mAlarmManager = alarmManager;
mMachine = machine;
mWakeLock = wakeLock;
mHost = host;
mHandler = handler;
- mTimeTick = this::onTimeTick;
+ mTimeTicker = new AlarmTimeout(alarmManager, this::onTimeTick, "doze_time_tick", handler);
}
private void pulseWhileDozing(int reason) {
@@ -76,6 +74,7 @@ public class DozeUi implements DozeMachine.Part {
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
switch (newState) {
case DOZE_AOD:
+ case DOZE_AOD_PAUSING:
scheduleTimeTick();
break;
case DOZE:
@@ -112,25 +111,21 @@ public class DozeUi implements DozeMachine.Part {
}
private void scheduleTimeTick() {
- if (mTimeTickScheduled) {
+ if (mTimeTicker.isScheduled()) {
return;
}
long delta = roundToNextMinute(System.currentTimeMillis()) - System.currentTimeMillis();
- mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + delta, "doze_time_tick", mTimeTick, mHandler);
-
- mTimeTickScheduled = true;
+ mTimeTicker.schedule(delta, AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
mLastTimeTickElapsed = SystemClock.elapsedRealtime();
}
private void unscheduleTimeTick() {
- if (!mTimeTickScheduled) {
+ if (!mTimeTicker.isScheduled()) {
return;
}
verifyLastTimeTick();
- mAlarmManager.cancel(mTimeTick);
- mTimeTickScheduled = false;
+ mTimeTicker.cancel();
}
private void verifyLastTimeTick() {
@@ -153,10 +148,6 @@ public class DozeUi implements DozeMachine.Part {
}
private void onTimeTick() {
- if (!mTimeTickScheduled) {
- // Alarm was canceled, but we still got the callback. Ignore.
- return;
- }
verifyLastTimeTick();
mHost.dozeTimeTick();
@@ -164,7 +155,6 @@ public class DozeUi implements DozeMachine.Part {
// Keep wakelock until a frame has been pushed.
mHandler.post(mWakeLock.wrap(() -> {}));
- mTimeTickScheduled = false;
scheduleTimeTick();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 1a8a474a4187..31d41acc3925 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -682,10 +682,14 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn
/** {@inheritDoc} */
public void onClick(DialogInterface dialog, int which) {
- if (!(mAdapter.getItem(which) instanceof SilentModeTriStateAction)) {
+ Action item = mAdapter.getItem(which);
+ if ((item instanceof PowerAction)
+ || (item instanceof RestartAction)) {
+ if (mDialog != null) mDialog.fadeOut();
+ } else if (!(item instanceof SilentModeTriStateAction)) {
dialog.dismiss();
}
- mAdapter.getItem(which).onPress();
+ item.onPress();
}
/**
@@ -1321,6 +1325,17 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogIn
.start();
}
+ public void fadeOut() {
+ mHardwareLayout.setTranslationX(0);
+ mHardwareLayout.setAlpha(1);
+ mListView.animate()
+ .alpha(0)
+ .translationX(getAnimTranslation())
+ .setDuration(300)
+ .setInterpolator(new LogAccelerateInterpolator())
+ .start();
+ }
+
private float getAnimTranslation() {
return getContext().getResources().getDimension(
com.android.systemui.R.dimen.global_actions_panel_width) / 2;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index b8771d7e0fb6..cebb22f07aaf 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -241,14 +241,14 @@ public class PipMotionHelper implements Handler.Callback {
/**
* Flings the minimized PiP to the closest minimized snap target.
*/
- Rect flingToMinimizedState(float velocityY, Rect movementBounds) {
+ Rect flingToMinimizedState(float velocityY, Rect movementBounds, Point dragStartPosition) {
cancelAnimations();
// We currently only allow flinging the minimized stack up and down, so just lock the
// movement bounds to the current stack bounds horizontally
movementBounds = new Rect(mBounds.left, movementBounds.top, mBounds.left,
movementBounds.bottom);
Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
- 0 /* velocityX */, velocityY);
+ 0 /* velocityX */, velocityY, dragStartPosition);
if (!mBounds.equals(toBounds)) {
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN);
mFlingAnimationUtils.apply(mBoundsAnimator, 0,
@@ -281,10 +281,11 @@ public class PipMotionHelper implements Handler.Callback {
* Flings the PiP to the closest snap target.
*/
Rect flingToSnapTarget(float velocity, float velocityX, float velocityY, Rect movementBounds,
- AnimatorUpdateListener updateListener, AnimatorListener listener) {
+ AnimatorUpdateListener updateListener, AnimatorListener listener,
+ Point startPosition) {
cancelAnimations();
Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
- velocityX, velocityY);
+ velocityX, velocityY, startPosition);
if (!mBounds.equals(toBounds)) {
mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, 0, FAST_OUT_SLOW_IN);
mFlingAnimationUtils.apply(mBoundsAnimator, 0,
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 3682ae655f7c..9588b03b53bd 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -185,7 +185,7 @@ public class PipTouchHandler {
mDismissViewController = new PipDismissViewController(context);
mSnapAlgorithm = new PipSnapAlgorithm(mContext);
mTouchState = new PipTouchState(mViewConfig);
- mFlingAnimationUtils = new FlingAnimationUtils(context, 2f);
+ mFlingAnimationUtils = new FlingAnimationUtils(context, 2.5f);
mGestures = new PipTouchGesture[] {
mDefaultMovementGesture
};
@@ -534,6 +534,7 @@ public class PipTouchHandler {
private PipTouchGesture mDefaultMovementGesture = new PipTouchGesture() {
// Whether the PiP was on the left side of the screen at the start of the gesture
private boolean mStartedOnLeft;
+ private Point mStartPosition;
@Override
public void onDown(PipTouchState touchState) {
@@ -541,7 +542,9 @@ public class PipTouchHandler {
return;
}
- mStartedOnLeft = mMotionHelper.getBounds().left < mMovementBounds.centerX();
+ Rect bounds = mMotionHelper.getBounds();
+ mStartPosition = new Point(bounds.left, bounds.top);
+ mStartedOnLeft = bounds.left < mMovementBounds.centerX();
mMovementWithinMinimize = true;
mMovementWithinDismiss = touchState.getDownTouchPosition().y >= mMovementBounds.bottom;
@@ -687,7 +690,8 @@ public class PipTouchHandler {
if (isFling) {
mMotionHelper.flingToSnapTarget(velocity, vel.x, vel.y, mMovementBounds,
- mUpdateScrimListener, postAnimationCallback);
+ mUpdateScrimListener, postAnimationCallback,
+ mStartPosition);
} else {
mMotionHelper.animateToClosestSnapTarget(mMovementBounds, mUpdateScrimListener,
postAnimationCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java
new file mode 100644
index 000000000000..f960dc5b4a47
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import static com.android.systemui.statusbar.phone.AutoTileManager.HOTSPOT;
+import static com.android.systemui.statusbar.phone.AutoTileManager.INVERSION;
+import static com.android.systemui.statusbar.phone.AutoTileManager.NIGHT;
+import static com.android.systemui.statusbar.phone.AutoTileManager.SAVER;
+import static com.android.systemui.statusbar.phone.AutoTileManager.WORK;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings.Secure;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Prefs;
+import com.android.systemui.Prefs.Key;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+public class AutoAddTracker {
+
+ private static final String[][] CONVERT_PREFS = {
+ {Key.QS_HOTSPOT_ADDED, HOTSPOT},
+ {Key.QS_DATA_SAVER_ADDED, SAVER},
+ {Key.QS_INVERT_COLORS_ADDED, INVERSION},
+ {Key.QS_WORK_ADDED, WORK},
+ {Key.QS_NIGHTDISPLAY_ADDED, NIGHT},
+ };
+
+ private final ArraySet<String> mAutoAdded;
+ private final Context mContext;
+
+ public AutoAddTracker(Context context) {
+ mContext = context;
+ mAutoAdded = new ArraySet<>(getAdded());
+ for (String[] convertPref : CONVERT_PREFS) {
+ if (Prefs.getBoolean(context, convertPref[0], false)) {
+ setTileAdded(convertPref[1]);
+ Prefs.putBoolean(context, convertPref[0], false);
+ }
+ }
+ mContext.getContentResolver().registerContentObserver(
+ Secure.getUriFor(Secure.QS_AUTO_ADDED_TILES), false, mObserver);
+ }
+
+ public boolean isAdded(String tile) {
+ return mAutoAdded.contains(tile);
+ }
+
+ public void setTileAdded(String tile) {
+ if (mAutoAdded.add(tile)) {
+ saveTiles();
+ }
+ }
+
+ public void destroy() {
+ mContext.getContentResolver().unregisterContentObserver(mObserver);
+ }
+
+ private void saveTiles() {
+ Secure.putString(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES,
+ TextUtils.join(",", mAutoAdded));
+ }
+
+ private Collection<String> getAdded() {
+ String current = Secure.getString(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES);
+ if (current == null) {
+ return Collections.emptyList();
+ }
+ return Arrays.asList(current.split(","));
+ }
+
+ @VisibleForTesting
+ protected final ContentObserver mObserver = new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ mAutoAdded.addAll(getAdded());
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index ed57c043a109..33b5268e03e1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -38,7 +38,7 @@ public class QSContainerImpl extends FrameLayout {
protected View mHeader;
protected float mQsExpansion;
private QSCustomizer mQSCustomizer;
- private QSFooter mQSFooter;
+ private View mQSFooter;
private float mFullElevation;
public QSContainerImpl(Context context, AttributeSet attrs) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
index a318efcf4d50..c454048d0649 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
@@ -100,4 +100,8 @@ public class QSDetailClipper {
mAnimator = null;
};
};
+
+ public void showBackground() {
+ mBackground.showSecondLayer();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 488fc03032fd..3f3cea2eaa17 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,426 +13,60 @@
* See the License for the specific language governing permissions and
* limitations under the License
*/
-
package com.android.systemui.qs;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_DATE;
-
-import android.app.ActivityManager;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.RippleDrawable;
-import android.os.UserManager;
-import android.provider.AlarmClock;
import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
-import android.util.AttributeSet;
import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto;
-import com.android.keyguard.KeyguardStatusView;
-import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
-import com.android.systemui.FontSizeUtils;
-import com.android.systemui.R;
-import com.android.systemui.R.dimen;
-import com.android.systemui.R.id;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.qs.TouchAnimator.Builder;
-import com.android.systemui.qs.TouchAnimator.Listener;
-import com.android.systemui.qs.TouchAnimator.ListenerAdapter;
-import com.android.systemui.statusbar.phone.ExpandableIndicator;
-import com.android.systemui.statusbar.phone.MultiUserSwitch;
-import com.android.systemui.statusbar.phone.SettingsButton;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
-import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
-import com.android.systemui.statusbar.policy.NextAlarmController;
-import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
-import com.android.systemui.tuner.TunerService;
-
-public class QSFooter extends FrameLayout implements
- NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener,
- SignalCallback {
- private static final float EXPAND_INDICATOR_THRESHOLD = .93f;
-
- private ActivityStarter mActivityStarter;
- private NextAlarmController mNextAlarmController;
- private UserInfoController mUserInfoController;
- private SettingsButton mSettingsButton;
- protected View mSettingsContainer;
-
- private TextView mAlarmStatus;
- private View mAlarmStatusCollapsed;
- private View mDate;
-
- private QSPanel mQsPanel;
-
- private boolean mExpanded;
- private boolean mAlarmShowing;
-
- protected ExpandableIndicator mExpandIndicator;
-
- private boolean mListening;
- private AlarmManager.AlarmClockInfo mNextAlarm;
-
- private boolean mShowEmergencyCallsOnly;
- protected MultiUserSwitch mMultiUserSwitch;
- private ImageView mMultiUserAvatar;
- private boolean mAlwaysShowMultiUserSwitch;
-
- protected TouchAnimator mSettingsAlpha;
- private float mExpansionAmount;
-
- protected View mEdit;
- private boolean mShowEditIcon;
- private TouchAnimator mAnimator;
- private View mDateTimeGroup;
- private boolean mKeyguardShowing;
- private TouchAnimator mAlarmAnimator;
-
- public QSFooter(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- Resources res = getResources();
-
- mShowEditIcon = res.getBoolean(R.bool.config_showQuickSettingsEditingIcon);
-
- mEdit = findViewById(android.R.id.edit);
- mEdit.setVisibility(mShowEditIcon ? VISIBLE : GONE);
-
- if (mShowEditIcon) {
- findViewById(android.R.id.edit).setOnClickListener(view ->
- Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() ->
- mQsPanel.showEdit(view)));
- }
-
- mDateTimeGroup = findViewById(id.date_time_alarm_group);
- mDate = findViewById(R.id.date);
-
- mExpandIndicator = findViewById(R.id.expand_indicator);
- mExpandIndicator.setVisibility(
- res.getBoolean(R.bool.config_showQuickSettingsExpandIndicator)
- ? VISIBLE : GONE);
-
- mSettingsButton = findViewById(R.id.settings_button);
- mSettingsContainer = findViewById(R.id.settings_button_container);
- mSettingsButton.setOnClickListener(this);
-
- mAlarmStatusCollapsed = findViewById(R.id.alarm_status_collapsed);
- mAlarmStatus = findViewById(R.id.alarm_status);
- mDateTimeGroup.setOnClickListener(this);
-
- mMultiUserSwitch = findViewById(R.id.multi_user_switch);
- mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
- mAlwaysShowMultiUserSwitch = res.getBoolean(R.bool.config_alwaysShowMultiUserSwitcher);
-
- // RenderThread is doing more harm than good when touching the header (to expand quick
- // settings), so disable it for this view
- ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
- ((RippleDrawable) mExpandIndicator.getBackground()).setForceSoftware(true);
-
- updateResources();
-
- mNextAlarmController = Dependency.get(NextAlarmController.class);
- mUserInfoController = Dependency.get(UserInfoController.class);
- mActivityStarter = Dependency.get(ActivityStarter.class);
- addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight,
- oldBottom) -> updateAnimator(right - left));
- }
-
- private void updateAnimator(int width) {
- int numTiles = QuickQSPanel.getNumQuickTiles(mContext);
- int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size)
- - mContext.getResources().getDimensionPixelSize(dimen.qs_quick_tile_padding);
- int remaining = (width - numTiles * size) / (numTiles - 1);
- int defSpace = mContext.getResources().getDimensionPixelOffset(R.dimen.default_gear_space);
-
- mAnimator = new Builder()
- .addFloat(mSettingsContainer, "translationX", -(remaining - defSpace), 0)
- .addFloat(mSettingsButton, "rotation", -120, 0)
- .build();
- if (mAlarmShowing) {
- mAlarmAnimator = new Builder().addFloat(mDate, "alpha", 1, 0)
- .addFloat(mDateTimeGroup, "translationX", 0, -mDate.getWidth())
- .addFloat(mAlarmStatus, "alpha", 0, 1)
- .setListener(new ListenerAdapter() {
- @Override
- public void onAnimationAtStart() {
- mAlarmStatus.setVisibility(View.GONE);
- }
-
- @Override
- public void onAnimationStarted() {
- mAlarmStatus.setVisibility(View.VISIBLE);
- }
- }).build();
- } else {
- mAlarmAnimator = null;
- mAlarmStatus.setVisibility(View.GONE);
- mDate.setAlpha(1);
- mDateTimeGroup.setTranslationX(0);
- }
- setExpansion(mExpansionAmount);
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- updateResources();
- }
-
- @Override
- public void onRtlPropertiesChanged(int layoutDirection) {
- super.onRtlPropertiesChanged(layoutDirection);
- updateResources();
- }
-
- private void updateResources() {
- FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size);
-
- updateSettingsAnimator();
- }
-
- private void updateSettingsAnimator() {
- mSettingsAlpha = createSettingsAlphaAnimator();
-
- final boolean isRtl = isLayoutRtl();
- if (isRtl && mDate.getWidth() == 0) {
- mDate.addOnLayoutChangeListener(new OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- mDate.setPivotX(getWidth());
- mDate.removeOnLayoutChangeListener(this);
- }
- });
- } else {
- mDate.setPivotX(isRtl ? mDate.getWidth() : 0);
- }
- }
+/**
+ * The bottom footer of the quick settings panel.
+ */
+public interface QSFooter {
+ /**
+ * Sets the given {@link QSPanel} to be the one that will display the quick settings.
+ */
+ void setQSPanel(@Nullable QSPanel panel);
+
+ /**
+ * Sets whether or not the footer should be visible.
+ *
+ * @param visibility One of {@link View#VISIBLE}, {@link View#INVISIBLE} or {@link View#GONE}.
+ * @see View#setVisibility(int)
+ */
+ void setVisibility(int visibility);
+
+ /**
+ * Sets whether the footer is in an expanded state.
+ */
+ void setExpanded(boolean expanded);
+
+ /**
+ * Returns the full height of the footer.
+ */
+ int getHeight();
+
+ /**
+ * Sets the percentage amount that the quick settings has been expanded.
+ *
+ * @param expansion A value from 1 to 0 that indicates how much the quick settings have been
+ * expanded. 1 is fully expanded.
+ */
+ void setExpansion(float expansion);
+
+ /**
+ * Sets whether or not this footer should set itself to listen for changes in any callbacks
+ * that it has implemented.
+ */
+ void setListening(boolean listening);
+
+ /**
+ * Sets whether or not the keyguard is currently being shown.
+ */
+ void setKeyguardShowing(boolean keyguardShowing);
+
+ /**
+ * Returns the {@link View} that should expand the quick settings when clicked.
+ */
@Nullable
- private TouchAnimator createSettingsAlphaAnimator() {
- // If the settings icon is not shown and the user switcher is always shown, then there
- // is nothing to animate.
- if (!mShowEditIcon && mAlwaysShowMultiUserSwitch) {
- return null;
- }
-
- TouchAnimator.Builder animatorBuilder = new TouchAnimator.Builder();
- animatorBuilder.setStartDelay(QSAnimator.EXPANDED_TILE_DELAY);
-
- if (mShowEditIcon) {
- animatorBuilder.addFloat(mEdit, "alpha", 0, 1);
- }
-
- if (!mAlwaysShowMultiUserSwitch) {
- animatorBuilder.addFloat(mMultiUserSwitch, "alpha", 0, 1);
- }
-
- return animatorBuilder.build();
- }
-
- public void setKeyguardShowing(boolean keyguardShowing) {
- mKeyguardShowing = keyguardShowing;
- setExpansion(mExpansionAmount);
- }
-
- public void setExpanded(boolean expanded) {
- if (mExpanded == expanded) return;
- mExpanded = expanded;
- updateEverything();
- }
-
- @Override
- public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
- mNextAlarm = nextAlarm;
- if (nextAlarm != null) {
- String alarmString = KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm);
- mAlarmStatus.setText(alarmString);
- mAlarmStatus.setContentDescription(mContext.getString(
- R.string.accessibility_quick_settings_alarm, alarmString));
- mAlarmStatusCollapsed.setContentDescription(mContext.getString(
- R.string.accessibility_quick_settings_alarm, alarmString));
- }
- if (mAlarmShowing != (nextAlarm != null)) {
- mAlarmShowing = nextAlarm != null;
- updateAnimator(getWidth());
- updateEverything();
- }
- }
-
- public void setExpansion(float headerExpansionFraction) {
- mExpansionAmount = headerExpansionFraction;
- if (mAnimator != null) mAnimator.setPosition(headerExpansionFraction);
- if (mAlarmAnimator != null) mAlarmAnimator.setPosition(
- mKeyguardShowing ? 0 : headerExpansionFraction);
-
- if (mSettingsAlpha != null) {
- mSettingsAlpha.setPosition(headerExpansionFraction);
- }
-
- updateAlarmVisibilities();
-
- mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD);
- }
-
- @Override
- @VisibleForTesting
- public void onDetachedFromWindow() {
- setListening(false);
- super.onDetachedFromWindow();
- }
-
- private void updateAlarmVisibilities() {
- mAlarmStatusCollapsed.setVisibility(mAlarmShowing ? View.VISIBLE : View.GONE);
- }
-
- public void setListening(boolean listening) {
- if (listening == mListening) {
- return;
- }
- mListening = listening;
- updateListeners();
- }
-
- public View getExpandView() {
- return findViewById(R.id.expand_indicator);
- }
-
- public void updateEverything() {
- post(() -> {
- updateVisibilities();
- setClickable(false);
- });
- }
-
- private void updateVisibilities() {
- updateAlarmVisibilities();
- mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
- TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
- final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
-
- mMultiUserSwitch.setVisibility((mExpanded || mAlwaysShowMultiUserSwitch)
- && mMultiUserSwitch.hasMultipleUsers() && !isDemo
- ? View.VISIBLE : View.INVISIBLE);
-
- if (mShowEditIcon) {
- mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
- }
- }
-
- private void updateListeners() {
- if (mListening) {
- mNextAlarmController.addCallback(this);
- mUserInfoController.addCallback(this);
- if (Dependency.get(NetworkController.class).hasVoiceCallingFeature()) {
- Dependency.get(NetworkController.class).addEmergencyListener(this);
- Dependency.get(NetworkController.class).addCallback(this);
- }
- } else {
- mNextAlarmController.removeCallback(this);
- mUserInfoController.removeCallback(this);
- Dependency.get(NetworkController.class).removeEmergencyListener(this);
- Dependency.get(NetworkController.class).removeCallback(this);
- }
- }
-
- public void setQSPanel(final QSPanel qsPanel) {
- mQsPanel = qsPanel;
- if (mQsPanel != null) {
- mMultiUserSwitch.setQsPanel(qsPanel);
- }
- }
-
- @Override
- public void onClick(View v) {
- if (v == mSettingsButton) {
- if (!Dependency.get(DeviceProvisionedController.class).isCurrentUserSetup()) {
- // If user isn't setup just unlock the device and dump them back at SUW.
- mActivityStarter.postQSRunnableDismissingKeyguard(() -> { });
- return;
- }
- MetricsLogger.action(mContext,
- mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH
- : MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH);
- if (mSettingsButton.isTunerClick()) {
- Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> {
- if (TunerService.isTunerEnabled(mContext)) {
- TunerService.showResetRequest(mContext, () -> {
- // Relaunch settings so that the tuner disappears.
- startSettingsActivity();
- });
- } else {
- Toast.makeText(getContext(), R.string.tuner_toast,
- Toast.LENGTH_LONG).show();
- TunerService.setTunerEnabled(mContext, true);
- }
- startSettingsActivity();
-
- });
- } else {
- startSettingsActivity();
- }
- } else if (v == mDateTimeGroup) {
- Dependency.get(MetricsLogger.class).action(ACTION_QS_DATE,
- mNextAlarm != null);
- if (mNextAlarm != null) {
- PendingIntent showIntent = mNextAlarm.getShowIntent();
- mActivityStarter.startPendingIntentDismissingKeyguard(showIntent);
- } else {
- mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
- AlarmClock.ACTION_SHOW_ALARMS), 0);
- }
- }
- }
-
- private void startSettingsActivity() {
- mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS),
- true /* dismissShade */);
- }
-
- @Override
- public void setEmergencyCallsOnly(boolean show) {
- boolean changed = show != mShowEmergencyCallsOnly;
- if (changed) {
- mShowEmergencyCallsOnly = show;
- if (mExpanded) {
- updateEverything();
- }
- }
- }
-
- @Override
- public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
- if (picture != null &&
- UserManager.get(mContext).isGuestUser(ActivityManager.getCurrentUser())) {
- picture = picture.getConstantState().newDrawable().mutate();
- picture.setColorFilter(
- Utils.getColorAttr(mContext, android.R.attr.colorForeground),
- Mode.SRC_IN);
- }
- mMultiUserAvatar.setImageDrawable(picture);
- }
+ View getExpandView();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
new file mode 100644
index 000000000000..94da5f72be10
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.qs;
+
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_DATE;
+
+import android.app.ActivityManager;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.RippleDrawable;
+import android.os.UserManager;
+import android.provider.AlarmClock;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.keyguard.KeyguardStatusView;
+import com.android.settingslib.Utils;
+import com.android.systemui.Dependency;
+import com.android.systemui.FontSizeUtils;
+import com.android.systemui.R;
+import com.android.systemui.R.dimen;
+import com.android.systemui.R.id;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.qs.TouchAnimator.Builder;
+import com.android.systemui.qs.TouchAnimator.Listener;
+import com.android.systemui.qs.TouchAnimator.ListenerAdapter;
+import com.android.systemui.statusbar.phone.ExpandableIndicator;
+import com.android.systemui.statusbar.phone.MultiUserSwitch;
+import com.android.systemui.statusbar.phone.SettingsButton;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
+import com.android.systemui.tuner.TunerService;
+
+public class QSFooterImpl extends FrameLayout implements QSFooter,
+ NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener,
+ SignalCallback {
+ private static final float EXPAND_INDICATOR_THRESHOLD = .93f;
+
+ private ActivityStarter mActivityStarter;
+ private NextAlarmController mNextAlarmController;
+ private UserInfoController mUserInfoController;
+ private SettingsButton mSettingsButton;
+ protected View mSettingsContainer;
+
+ private TextView mAlarmStatus;
+ private View mAlarmStatusCollapsed;
+ private View mDate;
+
+ private QSPanel mQsPanel;
+
+ private boolean mExpanded;
+ private boolean mAlarmShowing;
+
+ protected ExpandableIndicator mExpandIndicator;
+
+ private boolean mListening;
+ private AlarmManager.AlarmClockInfo mNextAlarm;
+
+ private boolean mShowEmergencyCallsOnly;
+ protected MultiUserSwitch mMultiUserSwitch;
+ private ImageView mMultiUserAvatar;
+
+ protected TouchAnimator mSettingsAlpha;
+ private float mExpansionAmount;
+
+ protected View mEdit;
+ private TouchAnimator mAnimator;
+ private View mDateTimeGroup;
+ private boolean mKeyguardShowing;
+ private TouchAnimator mAlarmAnimator;
+
+ public QSFooterImpl(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ Resources res = getResources();
+
+ mEdit = findViewById(android.R.id.edit);
+ mEdit.setOnClickListener(view ->
+ Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() ->
+ mQsPanel.showEdit(view)));
+
+ mDateTimeGroup = findViewById(id.date_time_alarm_group);
+ mDate = findViewById(R.id.date);
+
+ mExpandIndicator = findViewById(R.id.expand_indicator);
+ mSettingsButton = findViewById(R.id.settings_button);
+ mSettingsContainer = findViewById(R.id.settings_button_container);
+ mSettingsButton.setOnClickListener(this);
+
+ mAlarmStatusCollapsed = findViewById(R.id.alarm_status_collapsed);
+ mAlarmStatus = findViewById(R.id.alarm_status);
+ mDateTimeGroup.setOnClickListener(this);
+
+ mMultiUserSwitch = findViewById(R.id.multi_user_switch);
+ mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
+
+ // RenderThread is doing more harm than good when touching the header (to expand quick
+ // settings), so disable it for this view
+ ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
+ ((RippleDrawable) mExpandIndicator.getBackground()).setForceSoftware(true);
+
+ updateResources();
+
+ mNextAlarmController = Dependency.get(NextAlarmController.class);
+ mUserInfoController = Dependency.get(UserInfoController.class);
+ mActivityStarter = Dependency.get(ActivityStarter.class);
+ addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight,
+ oldBottom) -> updateAnimator(right - left));
+ }
+
+ private void updateAnimator(int width) {
+ int numTiles = QuickQSPanel.getNumQuickTiles(mContext);
+ int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size)
+ - mContext.getResources().getDimensionPixelSize(dimen.qs_quick_tile_padding);
+ int remaining = (width - numTiles * size) / (numTiles - 1);
+ int defSpace = mContext.getResources().getDimensionPixelOffset(R.dimen.default_gear_space);
+
+ mAnimator = new Builder()
+ .addFloat(mSettingsContainer, "translationX", -(remaining - defSpace), 0)
+ .addFloat(mSettingsButton, "rotation", -120, 0)
+ .build();
+ if (mAlarmShowing) {
+ mAlarmAnimator = new Builder().addFloat(mDate, "alpha", 1, 0)
+ .addFloat(mDateTimeGroup, "translationX", 0, -mDate.getWidth())
+ .addFloat(mAlarmStatus, "alpha", 0, 1)
+ .setListener(new ListenerAdapter() {
+ @Override
+ public void onAnimationAtStart() {
+ mAlarmStatus.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onAnimationStarted() {
+ mAlarmStatus.setVisibility(View.VISIBLE);
+ }
+ }).build();
+ } else {
+ mAlarmAnimator = null;
+ mAlarmStatus.setVisibility(View.GONE);
+ mDate.setAlpha(1);
+ mDateTimeGroup.setTranslationX(0);
+ }
+ setExpansion(mExpansionAmount);
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ updateResources();
+ }
+
+ @Override
+ public void onRtlPropertiesChanged(int layoutDirection) {
+ super.onRtlPropertiesChanged(layoutDirection);
+ updateResources();
+ }
+
+ private void updateResources() {
+ FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size);
+
+ updateSettingsAnimator();
+ }
+
+ private void updateSettingsAnimator() {
+ mSettingsAlpha = createSettingsAlphaAnimator();
+
+ final boolean isRtl = isLayoutRtl();
+ if (isRtl && mDate.getWidth() == 0) {
+ mDate.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ mDate.setPivotX(getWidth());
+ mDate.removeOnLayoutChangeListener(this);
+ }
+ });
+ } else {
+ mDate.setPivotX(isRtl ? mDate.getWidth() : 0);
+ }
+ }
+
+ @Nullable
+ private TouchAnimator createSettingsAlphaAnimator() {
+ return new TouchAnimator.Builder()
+ .addFloat(mEdit, "alpha", 0, 1)
+ .addFloat(mMultiUserSwitch, "alpha", 0, 1)
+ .build();
+ }
+
+ @Override
+ public void setKeyguardShowing(boolean keyguardShowing) {
+ mKeyguardShowing = keyguardShowing;
+ setExpansion(mExpansionAmount);
+ }
+
+ @Override
+ public void setExpanded(boolean expanded) {
+ if (mExpanded == expanded) return;
+ mExpanded = expanded;
+ updateEverything();
+ }
+
+ @Override
+ public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
+ mNextAlarm = nextAlarm;
+ if (nextAlarm != null) {
+ String alarmString = KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm);
+ mAlarmStatus.setText(alarmString);
+ mAlarmStatus.setContentDescription(mContext.getString(
+ R.string.accessibility_quick_settings_alarm, alarmString));
+ mAlarmStatusCollapsed.setContentDescription(mContext.getString(
+ R.string.accessibility_quick_settings_alarm, alarmString));
+ }
+ if (mAlarmShowing != (nextAlarm != null)) {
+ mAlarmShowing = nextAlarm != null;
+ updateAnimator(getWidth());
+ updateEverything();
+ }
+ }
+
+ @Override
+ public void setExpansion(float headerExpansionFraction) {
+ mExpansionAmount = headerExpansionFraction;
+ if (mAnimator != null) mAnimator.setPosition(headerExpansionFraction);
+ if (mAlarmAnimator != null) mAlarmAnimator.setPosition(
+ mKeyguardShowing ? 0 : headerExpansionFraction);
+
+ if (mSettingsAlpha != null) {
+ mSettingsAlpha.setPosition(headerExpansionFraction);
+ }
+
+ updateAlarmVisibilities();
+
+ mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD);
+ }
+
+ @Override
+ @VisibleForTesting
+ public void onDetachedFromWindow() {
+ setListening(false);
+ super.onDetachedFromWindow();
+ }
+
+ private void updateAlarmVisibilities() {
+ mAlarmStatusCollapsed.setVisibility(mAlarmShowing ? View.VISIBLE : View.GONE);
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ if (listening == mListening) {
+ return;
+ }
+ mListening = listening;
+ updateListeners();
+ }
+
+ @Override
+ public View getExpandView() {
+ return findViewById(R.id.expand_indicator);
+ }
+
+ public void updateEverything() {
+ post(() -> {
+ updateVisibilities();
+ setClickable(false);
+ });
+ }
+
+ private void updateVisibilities() {
+ updateAlarmVisibilities();
+ mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
+ TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
+ final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
+
+ mMultiUserSwitch.setVisibility(mExpanded && mMultiUserSwitch.hasMultipleUsers() && !isDemo
+ ? View.VISIBLE : View.INVISIBLE);
+
+ mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
+ }
+
+ private void updateListeners() {
+ if (mListening) {
+ mNextAlarmController.addCallback(this);
+ mUserInfoController.addCallback(this);
+ if (Dependency.get(NetworkController.class).hasVoiceCallingFeature()) {
+ Dependency.get(NetworkController.class).addEmergencyListener(this);
+ Dependency.get(NetworkController.class).addCallback(this);
+ }
+ } else {
+ mNextAlarmController.removeCallback(this);
+ mUserInfoController.removeCallback(this);
+ Dependency.get(NetworkController.class).removeEmergencyListener(this);
+ Dependency.get(NetworkController.class).removeCallback(this);
+ }
+ }
+
+ @Override
+ public void setQSPanel(final QSPanel qsPanel) {
+ mQsPanel = qsPanel;
+ if (mQsPanel != null) {
+ mMultiUserSwitch.setQsPanel(qsPanel);
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == mSettingsButton) {
+ if (!Dependency.get(DeviceProvisionedController.class).isCurrentUserSetup()) {
+ // If user isn't setup just unlock the device and dump them back at SUW.
+ mActivityStarter.postQSRunnableDismissingKeyguard(() -> { });
+ return;
+ }
+ MetricsLogger.action(mContext,
+ mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH
+ : MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH);
+ if (mSettingsButton.isTunerClick()) {
+ Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> {
+ if (TunerService.isTunerEnabled(mContext)) {
+ TunerService.showResetRequest(mContext, () -> {
+ // Relaunch settings so that the tuner disappears.
+ startSettingsActivity();
+ });
+ } else {
+ Toast.makeText(getContext(), R.string.tuner_toast,
+ Toast.LENGTH_LONG).show();
+ TunerService.setTunerEnabled(mContext, true);
+ }
+ startSettingsActivity();
+
+ });
+ } else {
+ startSettingsActivity();
+ }
+ } else if (v == mDateTimeGroup) {
+ Dependency.get(MetricsLogger.class).action(ACTION_QS_DATE,
+ mNextAlarm != null);
+ if (mNextAlarm != null) {
+ PendingIntent showIntent = mNextAlarm.getShowIntent();
+ mActivityStarter.startPendingIntentDismissingKeyguard(showIntent);
+ } else {
+ mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
+ AlarmClock.ACTION_SHOW_ALARMS), 0);
+ }
+ }
+ }
+
+ private void startSettingsActivity() {
+ mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS),
+ true /* dismissShade */);
+ }
+
+ @Override
+ public void setEmergencyCallsOnly(boolean show) {
+ boolean changed = show != mShowEmergencyCallsOnly;
+ if (changed) {
+ mShowEmergencyCallsOnly = show;
+ if (mExpanded) {
+ updateEverything();
+ }
+ }
+ }
+
+ @Override
+ public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
+ if (picture != null &&
+ UserManager.get(mContext).isGuestUser(ActivityManager.getCurrentUser())) {
+ picture = picture.getConstantState().newDrawable().mutate();
+ picture.setColorFilter(
+ Utils.getColorAttr(mContext, android.R.attr.colorForeground),
+ Mode.SRC_IN);
+ }
+ mMultiUserAvatar.setImageDrawable(picture);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index bb3672511c48..4a91ee026953 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -16,11 +16,11 @@ package com.android.systemui.qs;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.annotation.Nullable;
import android.app.Fragment;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
+import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.view.ContextThemeWrapper;
@@ -80,20 +80,22 @@ public class QSFragment extends Fragment implements QS {
mFooter = view.findViewById(R.id.qs_footer);
mContainer = view.findViewById(id.quick_settings_container);
- mQSDetail.setQsPanel(mQSPanel, mHeader, mFooter);
-
- // If the quick settings row is not shown, then there is no need for the animation from
- // the row to the full QS panel.
- if (getResources().getBoolean(R.bool.config_showQuickSettingsRow)) {
- mQSAnimator = new QSAnimator(this,
- mHeader.findViewById(R.id.quick_qs_panel), mQSPanel);
- }
+ mQSDetail.setQsPanel(mQSPanel, mHeader, (View) mFooter);
+ mQSAnimator = new QSAnimator(this,
+ mHeader.findViewById(R.id.quick_qs_panel), mQSPanel);
mQSCustomizer = view.findViewById(R.id.qs_customize);
mQSCustomizer.setQs(this);
if (savedInstanceState != null) {
setExpanded(savedInstanceState.getBoolean(EXTRA_EXPANDED));
setListening(savedInstanceState.getBoolean(EXTRA_LISTENING));
+ int[] loc = new int[2];
+ View edit = view.findViewById(android.R.id.edit);
+ edit.getLocationInWindow(loc);
+ int x = loc[0] + edit.getWidth() / 2;
+ int y = loc[1] + edit.getHeight() / 2;
+ mQSCustomizer.setEditLocation(x, y);
+ mQSCustomizer.restoreInstanceState(savedInstanceState);
}
}
@@ -110,6 +112,7 @@ public class QSFragment extends Fragment implements QS {
super.onSaveInstanceState(outState);
outState.putBoolean(EXTRA_EXPANDED, mQsExpanded);
outState.putBoolean(EXTRA_LISTENING, mListening);
+ mQSCustomizer.saveInstanceState(outState);
}
@VisibleForTesting
@@ -131,6 +134,7 @@ public class QSFragment extends Fragment implements QS {
public void setHasNotifications(boolean hasNotifications) {
}
+ @Override
public void setPanelView(HeightListener panelView) {
mPanelView = panelView;
}
@@ -154,6 +158,7 @@ public class QSFragment extends Fragment implements QS {
}
}
+ @Override
public boolean isCustomizing() {
return mQSCustomizer.isCustomizing();
}
@@ -195,15 +200,22 @@ public class QSFragment extends Fragment implements QS {
return mQSCustomizer;
}
+ @Override
public boolean isShowingDetail() {
return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail();
}
+ @Override
public void setHeaderClickable(boolean clickable) {
if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable);
- mFooter.getExpandView().setClickable(clickable);
+
+ View expandView = mFooter.getExpandView();
+ if (expandView != null) {
+ expandView.setClickable(clickable);
+ }
}
+ @Override
public void setExpanded(boolean expanded) {
if (DEBUG) Log.d(TAG, "setExpanded " + expanded);
mQsExpanded = expanded;
@@ -211,6 +223,7 @@ public class QSFragment extends Fragment implements QS {
updateQsState();
}
+ @Override
public void setKeyguardShowing(boolean keyguardShowing) {
if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
mKeyguardShowing = keyguardShowing;
@@ -223,12 +236,14 @@ public class QSFragment extends Fragment implements QS {
updateQsState();
}
+ @Override
public void setOverscrolling(boolean stackScrollerOverscrolling) {
if (DEBUG) Log.d(TAG, "setOverscrolling " + stackScrollerOverscrolling);
mStackScrollerOverscrolling = stackScrollerOverscrolling;
updateQsState();
}
+ @Override
public void setListening(boolean listening) {
if (DEBUG) Log.d(TAG, "setListening " + listening);
mListening = listening;
@@ -237,11 +252,13 @@ public class QSFragment extends Fragment implements QS {
mQSPanel.setListening(mListening && mQsExpanded);
}
+ @Override
public void setHeaderListening(boolean listening) {
mHeader.setListening(listening);
mFooter.setListening(listening);
}
+ @Override
public void setQsExpansion(float expansion, float headerTranslation) {
if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation);
mContainer.setExpansion(expansion);
@@ -269,6 +286,7 @@ public class QSFragment extends Fragment implements QS {
mQSPanel.setClipBounds(mQsBounds);
}
+ @Override
public void animateHeaderSlidingIn(long delay) {
if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn");
// If the QS is already expanded we don't need to slide in the header as it's already
@@ -280,6 +298,7 @@ public class QSFragment extends Fragment implements QS {
}
}
+ @Override
public void animateHeaderSlidingOut() {
if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut");
mHeaderAnimating = true;
@@ -300,7 +319,11 @@ public class QSFragment extends Fragment implements QS {
@Override
public void setExpandClickListener(OnClickListener onClickListener) {
- mFooter.getExpandView().setOnClickListener(onClickListener);
+ View expandView = mFooter.getExpandView();
+
+ if (expandView != null) {
+ expandView.setOnClickListener(onClickListener);
+ }
}
@Override
@@ -323,6 +346,7 @@ public class QSFragment extends Fragment implements QS {
* The height this view wants to be. This is different from {@link #getMeasuredHeight} such that
* during closing the detail panel, this already returns the smaller height.
*/
+ @Override
public int getDesiredHeight() {
if (mQSCustomizer.isCustomizing()) {
return getView().getHeight();
@@ -342,6 +366,7 @@ public class QSFragment extends Fragment implements QS {
mContainer.setHeightOverride(desiredHeight);
}
+ @Override
public int getQsMinExpansionHeight() {
return mHeader.getHeight();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 7ec07604fab5..0709e229bd4d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -58,8 +58,6 @@ public class QuickStatusBarHeader extends RelativeLayout {
Resources res = getResources();
mHeaderQsPanel = findViewById(R.id.quick_qs_panel);
- mHeaderQsPanel.setVisibility(res.getBoolean(R.bool.config_showQuickSettingsRow)
- ? VISIBLE : GONE);
// RenderThread is doing more harm than good when touching the header (to expand quick
// settings), so disable it for this view
diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java
new file mode 100644
index 000000000000..9730f29da977
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.android.systemui.qs.car;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.qs.QSFooter;
+import com.android.systemui.qs.QSPanel;
+import com.android.systemui.statusbar.phone.MultiUserSwitch;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+
+/**
+ * The footer view that displays below the status bar in the auto use-case. This view shows the
+ * user switcher and access to settings.
+ */
+public class CarQSFooter extends RelativeLayout implements QSFooter,
+ UserInfoController.OnUserInfoChangedListener {
+ private UserInfoController mUserInfoController;
+
+ private MultiUserSwitch mMultiUserSwitch;
+ private ImageView mMultiUserAvatar;
+
+ public CarQSFooter(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mMultiUserSwitch = findViewById(R.id.multi_user_switch);
+ mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
+
+ mUserInfoController = Dependency.get(UserInfoController.class);
+
+ findViewById(R.id.settings_button).setOnClickListener(v -> {
+ ActivityStarter activityStarter = Dependency.get(ActivityStarter.class);
+
+ if (!Dependency.get(DeviceProvisionedController.class).isCurrentUserSetup()) {
+ // If user isn't setup just unlock the device and dump them back at SUW.
+ activityStarter.postQSRunnableDismissingKeyguard(() -> { });
+ return;
+ }
+
+ activityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS),
+ true /* dismissShade */);
+ });
+ }
+
+ @Override
+ public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
+ mMultiUserAvatar.setImageDrawable(picture);
+ }
+
+ @Override
+ public void setQSPanel(@Nullable QSPanel panel) {
+ if (panel != null) {
+ mMultiUserSwitch.setQsPanel(panel);
+ }
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ if (listening) {
+ mUserInfoController.addCallback(this);
+ } else {
+ mUserInfoController.removeCallback(this);
+ }
+ }
+
+ @Nullable
+ @Override
+ public View getExpandView() {
+ // No view that should expand/collapse the quick settings.
+ return null;
+ }
+
+ @Override
+ public void setExpanded(boolean expanded) {
+ // Do nothing because the quick settings cannot be expanded.
+ }
+
+ @Override
+ public void setExpansion(float expansion) {
+ // Do nothing because the quick settings cannot be expanded.
+ }
+
+ @Override
+ public void setKeyguardShowing(boolean keyguardShowing) {
+ // Do nothing because the footer will not be shown when the keyguard is up.
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
new file mode 100644
index 000000000000..7c2a8129813a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES 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.qs.car;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.qs.QSFooter;
+
+/**
+ * A quick settings fragment for the car. For auto, there is no row for quick settings or ability
+ * to expand the quick settings panel. Instead, the only thing is that displayed is the
+ * status bar, and a static row with access to the user switcher and settings.
+ */
+public class CarQSFragment extends Fragment implements QS {
+ private View mHeader;
+ private QSFooter mFooter;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.car_qs_panel, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ mHeader = view.findViewById(R.id.header);
+ mFooter = view.findViewById(R.id.qs_footer);
+ }
+
+ @Override
+ public void hideImmediately() {
+ getView().setVisibility(View.INVISIBLE);
+ }
+
+ @Override
+ public void setQsExpansion(float qsExpansionFraction, float headerTranslation) {
+ // If the header is to be completed translated down, then set it to be visible.
+ getView().setVisibility(headerTranslation == 0 ? View.VISIBLE : View.INVISIBLE);
+ }
+
+ @Override
+ public View getHeader() {
+ return mHeader;
+ }
+
+ @VisibleForTesting
+ QSFooter getFooter() {
+ return mFooter;
+ }
+
+ @Override
+ public void setHeaderListening(boolean listening) {
+ mFooter.setListening(listening);
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ mFooter.setListening(listening);
+ }
+
+ @Override
+ public int getQsMinExpansionHeight() {
+ return getView().getHeight();
+ }
+
+ @Override
+ public int getDesiredHeight() {
+ return getView().getHeight();
+ }
+
+ @Override
+ public void setPanelView(HeightListener notificationPanelView) {
+ // No quick settings panel.
+ }
+
+ @Override
+ public void setHeightOverride(int desiredHeight) {
+ // No ability to expand quick settings.
+ }
+
+ @Override
+ public void setHeaderClickable(boolean qsExpansionEnabled) {
+ // Usually this sets the expand button to be clickable, but there is no quick settings to
+ // expand.
+ }
+
+ @Override
+ public boolean isCustomizing() {
+ // No ability to customize the quick settings.
+ return false;
+ }
+
+ @Override
+ public void setOverscrolling(boolean overscrolling) {
+ // No overscrolling to reveal quick settings.
+ }
+
+ @Override
+ public void setExpanded(boolean qsExpanded) {
+ // No quick settings to expand
+ }
+
+ @Override
+ public boolean isShowingDetail() {
+ // No detail panel to close.
+ return false;
+ }
+
+ @Override
+ public void closeDetail() {
+ // No detail panel to close.
+ }
+
+ @Override
+ public void setKeyguardShowing(boolean keyguardShowing) {
+ // No keyguard to show.
+ }
+
+ @Override
+ public void animateHeaderSlidingIn(long delay) {
+ // No header to animate.
+ }
+
+ @Override
+ public void animateHeaderSlidingOut() {
+ // No header to animate.
+ }
+
+ @Override
+ public void notifyCustomizeChanged() {
+ // There is no ability to customize quick settings.
+ }
+
+ @Override
+ public void setContainer(ViewGroup container) {
+ // No quick settings, so no container to set.
+ }
+
+ @Override
+ public void setExpandClickListener(OnClickListener onClickListener) {
+ // No ability to expand the quick settings.
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
new file mode 100644
index 000000000000..6797bb9dbe82
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.android.systemui.qs.car;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.support.annotation.IdRes;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+import com.android.settingslib.Utils;
+import com.android.systemui.BatteryMeterView;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+
+/**
+ * A view that forms the header of the notification panel. This view will ensure that any
+ * status icons that are displayed are tinted accordingly to the current theme.
+ */
+public class CarStatusBarHeader extends RelativeLayout {
+ public CarStatusBarHeader(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ // Set the light/dark theming on the header status UI to match the current theme.
+ int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground);
+ float intensity = colorForeground == Color.WHITE ? 0f : 1f;
+ Rect tintArea = new Rect(0, 0, 0, 0);
+
+ applyDarkness(R.id.signal_cluster, tintArea, intensity, colorForeground);
+ applyDarkness(R.id.battery, tintArea, intensity, colorForeground);
+ applyDarkness(R.id.clock, tintArea, intensity, colorForeground);
+
+ ((BatteryMeterView) findViewById(R.id.battery)).setForceShowPercent(true);
+ }
+
+ private void applyDarkness(@IdRes int id, Rect tintArea, float intensity, int color) {
+ View v = findViewById(id);
+ if (v instanceof DarkIconDispatcher.DarkReceiver) {
+ ((DarkIconDispatcher.DarkReceiver) v).onDarkChanged(tintArea, intensity, color);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 30053e35ef05..6c95a8013108 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -20,6 +20,9 @@ import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.TransitionDrawable;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.v7.widget.DefaultItemAnimator;
@@ -42,6 +45,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.qs.QSContainerImpl;
import com.android.systemui.qs.QSDetailClipper;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
@@ -60,6 +64,7 @@ import java.util.List;
public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener {
private static final int MENU_RESET = Menu.FIRST;
+ private static final String EXTRA_QS_CUSTOMIZING = "qs_customizing";
private final QSDetailClipper mClipper;
@@ -109,11 +114,16 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
DefaultItemAnimator animator = new DefaultItemAnimator();
animator.setMoveDuration(TileAdapter.MOVE_DURATION);
mRecyclerView.setItemAnimator(animator);
+ updateNavBackDrop(getResources().getConfiguration());
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ updateNavBackDrop(newConfig);
+ }
+
+ private void updateNavBackDrop(Configuration newConfig) {
View navBackdrop = findViewById(R.id.nav_bar_background);
if (navBackdrop != null) {
boolean shouldShow = newConfig.smallestScreenWidthDp >= 600
@@ -154,6 +164,21 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
}
}
+
+ public void showImmediately() {
+ if (!isShown) {
+ setVisibility(VISIBLE);
+ mClipper.showBackground();
+ isShown = true;
+ setTileSpecs();
+ setCustomizing(true);
+ queryTiles();
+ mNotifQsContainer.setCustomizerAnimating(false);
+ mNotifQsContainer.setCustomizerShowing(true);
+ Dependency.get(KeyguardMonitor.class).addCallback(mKeyguardCallback);
+ }
+ }
+
private void queryTiles() {
mFinishedFetchingTiles = false;
Runnable tileQueryFetchCompletion = () -> {
@@ -227,6 +252,35 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
}
}
+
+ public void saveInstanceState(Bundle outState) {
+ if (isShown) {
+ Dependency.get(KeyguardMonitor.class).removeCallback(mKeyguardCallback);
+ }
+ outState.putBoolean(EXTRA_QS_CUSTOMIZING, mCustomizing);
+ }
+
+ public void restoreInstanceState(Bundle savedInstanceState) {
+ boolean customizing = savedInstanceState.getBoolean(EXTRA_QS_CUSTOMIZING);
+ if (customizing) {
+ setVisibility(VISIBLE);
+ addOnLayoutChangeListener(new OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ removeOnLayoutChangeListener(this);
+ showImmediately();
+ }
+ });
+ }
+ }
+
+ public void setEditLocation(int x, int y) {
+ mX = x;
+ mY = y;
+ }
+
private final Callback mKeyguardCallback = () -> {
if (!isAttachedToWindow()) return;
if (Dependency.get(KeyguardMonitor.class).isShowing() && !mOpening) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 17a0d3302ee6..77c3bfab8de9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -16,7 +16,9 @@ package com.android.systemui.qs.tileimpl;
import android.content.Context;
import android.util.Log;
+import android.view.ContextThemeWrapper;
+import com.android.systemui.R;
import com.android.systemui.plugins.qs.*;
import com.android.systemui.plugins.qs.QSTileView;
import com.android.systemui.qs.external.CustomTile;
@@ -78,7 +80,7 @@ public class QSFactoryImpl implements QSFactory {
@Override
public QSTileView createTileView(QSTile tile, boolean collapsedView) {
- Context context = mHost.getContext();
+ Context context = new ContextThemeWrapper(mHost.getContext(), R.style.qs_theme);
QSIconView icon = tile.createTileView(context);
if (collapsedView) {
return new QSTileBaseView(context, icon, collapsedView);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index afc4c6abb62d..316ad1661898 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -43,14 +43,14 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.systemui.R;
+import com.android.systemui.util.leak.RotationUtils;
import java.util.ArrayList;
-public class ScreenPinningRequest implements View.OnClickListener {
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
- private static final int ROTATION_NONE = 0;
- private static final int ROTATION_LANDSCAPE = 1;
- private static final int ROTATION_SEASCAPE = 2;
+public class ScreenPinningRequest implements View.OnClickListener {
private final Context mContext;
@@ -157,7 +157,7 @@ public class ScreenPinningRequest implements View.OnClickListener {
DisplayMetrics metrics = new DisplayMetrics();
mWindowManager.getDefaultDisplay().getMetrics(metrics);
float density = metrics.density;
- int rotation = getRotation(mContext);
+ int rotation = RotationUtils.getRotation(mContext);
inflateView(rotation);
int bgColor = mContext.getColor(
@@ -199,19 +199,6 @@ public class ScreenPinningRequest implements View.OnClickListener {
mContext.registerReceiver(mReceiver, filter);
}
- private int getRotation(Context context) {
- Configuration config = mContext.getResources().getConfiguration();
- int rot = context.getDisplay().getRotation();
- if (config.smallestScreenWidthDp < 600) {
- if (rot == Surface.ROTATION_90) {
- return ROTATION_LANDSCAPE;
- } else if (rot == Surface.ROTATION_270) {
- return ROTATION_SEASCAPE;
- }
- }
- return ROTATION_NONE;
- }
-
private void inflateView(int rotation) {
// We only want this landscape orientation on <600dp, so rather than handle
// resource overlay for -land and -sw600dp-land, just inflate this
@@ -284,14 +271,14 @@ public class ScreenPinningRequest implements View.OnClickListener {
protected void onConfigurationChanged() {
removeAllViews();
- inflateView(getRotation(mContext));
+ inflateView(RotationUtils.getRotation(mContext));
}
private final Runnable mUpdateLayoutRunnable = new Runnable() {
@Override
public void run() {
if (mLayout != null && mLayout.getParent() != null) {
- mLayout.setLayoutParams(getRequestLayoutParams(getRotation(mContext)));
+ mLayout.setLayoutParams(getRequestLayoutParams(RotationUtils.getRotation(mContext)));
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 7d76b9b7c944..68fe9a83c707 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -952,6 +952,10 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
}
+ public boolean isDrawingAppearAnimation() {
+ return mDrawingAppearAnimation;
+ }
+
@Override
protected void dispatchDraw(Canvas canvas) {
if (mDrawingAppearAnimation) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 429d5ab6f1ab..8046250c9412 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -756,6 +756,19 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return getShowingLayout().getVisibleNotificationHeader();
}
+
+ /**
+ * @return the contracted notification header. This can be different from
+ * {@link #getNotificationHeader()} and also {@link #getVisibleNotificationHeader()} and only
+ * returns the contracted version.
+ */
+ public NotificationHeaderView getContractedNotificationHeader() {
+ if (mIsSummaryWithChildren) {
+ return mChildrenContainer.getHeaderView();
+ }
+ return mPrivateLayout.getContractedNotificationHeader();
+ }
+
public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
mOnExpandClickListener = onExpandClickListener;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 75704b1612d7..9e059c89ffe1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -1308,6 +1308,14 @@ public class NotificationContentView extends FrameLayout {
return header;
}
+
+ public NotificationHeaderView getContractedNotificationHeader() {
+ if (mContractedChild != null) {
+ return mContractedWrapper.getNotificationHeader();
+ }
+ return null;
+ }
+
public NotificationHeaderView getVisibleNotificationHeader() {
NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
return wrapper == null ? null : wrapper.getNotificationHeader();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
index 7f95d48f36d4..43018174de44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
@@ -267,9 +267,10 @@ public class NotificationHeaderUtil {
if (!mApply) {
return;
}
- NotificationHeaderView header = row.getNotificationHeader();
+ NotificationHeaderView header = row.getContractedNotificationHeader();
if (header == null) {
- mApply = false;
+ // No header found. We still consider this to be the same to avoid weird flickering
+ // when for example showing an undo notification
return;
}
Object childData = mExtractor == null ? null : mExtractor.extractData(row);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 7abceaf41c70..a60102854618 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -505,6 +505,11 @@ public class NotificationShelf extends ActivatableNotificationView implements
iconState.scaleX = newSize / icon.getHeight() / icon.getIconScale();
iconState.scaleY = iconState.scaleX;
iconState.hidden = transitionAmount == 0.0f && !iconState.isAnimating(icon);
+ boolean isAppearing = row.isDrawingAppearAnimation() && !row.isInShelf();
+ if (isAppearing) {
+ iconState.hidden = true;
+ iconState.iconAppearAmount = 0.0f;
+ }
iconState.alpha = alpha;
iconState.yTranslation = iconYTranslation;
if (stayingInShelf) {
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 c891418a5b29..92f26d65f25e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
@@ -116,7 +116,7 @@ public class ImageTransformState extends TransformState {
}
@Override
- protected boolean transformScale() {
+ protected boolean transformScale(TransformState otherState) {
return true;
}
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 fb4e2eccadc0..c4aabe48f61c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification;
import android.text.Layout;
+import android.text.Spanned;
import android.text.TextUtils;
import android.util.Pools;
import android.view.View;
@@ -50,12 +51,69 @@ public class TextViewTransformState extends TransformState {
int ownEllipsized = getEllipsisCount();
int otherEllipsized = otherTvs.getEllipsisCount();
return ownEllipsized == otherEllipsized
- && getInnerHeight(mText) == getInnerHeight(otherTvs.mText);
+ && mText.getLineCount() == otherTvs.mText.getLineCount()
+ && hasSameSpans(otherTvs);
}
}
return false;
}
+ private boolean hasSameSpans(TextViewTransformState otherTvs) {
+ boolean hasSpans = mText instanceof Spanned;
+ boolean otherHasSpans = otherTvs.mText instanceof Spanned;
+ if (hasSpans != otherHasSpans) {
+ return false;
+ } else if (!hasSpans) {
+ return true;
+ }
+ // Actually both have spans, let's try to compare them
+ Spanned ownSpanned = (Spanned) mText;
+ Object[] spans = ownSpanned.getSpans(0, ownSpanned.length(), Object.class);
+ Spanned otherSpanned = (Spanned) otherTvs.mText;
+ Object[] otherSpans = otherSpanned.getSpans(0, otherSpanned.length(), Object.class);
+ if (spans.length != otherSpans.length) {
+ return false;
+ }
+ for (int i = 0; i < spans.length; i++) {
+ Object span = spans[i];
+ Object otherSpan = otherSpans[i];
+ if (!span.getClass().equals(otherSpan.getClass())) {
+ return false;
+ }
+ if (ownSpanned.getSpanStart(span) != otherSpanned.getSpanStart(otherSpan)
+ || ownSpanned.getSpanEnd(span) != otherSpanned.getSpanEnd(otherSpan)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ protected boolean transformScale(TransformState otherState) {
+ if (!(otherState instanceof TextViewTransformState)) {
+ return false;
+ }
+ TextViewTransformState otherTvs = (TextViewTransformState) otherState;
+ int lineCount = mText.getLineCount();
+ return lineCount == 1 && lineCount == otherTvs.mText.getLineCount()
+ && getEllipsisCount() == otherTvs.getEllipsisCount()
+ && getViewHeight() != otherTvs.getViewHeight();
+ }
+
+ @Override
+ protected int getViewWidth() {
+ Layout l = mText.getLayout();
+ if (l != null) {
+ return (int) l.getLineWidth(0);
+ }
+ return super.getViewWidth();
+ }
+
+ @Override
+ protected int getViewHeight() {
+ return mText.getLineHeight();
+ }
+
private int getInnerHeight(TextView text) {
return text.getHeight() - text.getPaddingTop() - text.getPaddingBottom();
}
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 a77dd4ee8c43..bafedff4f78c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -108,7 +108,7 @@ public class TransformState {
final View transformedView = mTransformedView;
boolean transformX = (transformationFlags & TRANSFORM_X) != 0;
boolean transformY = (transformationFlags & TRANSFORM_Y) != 0;
- boolean transformScale = transformScale();
+ boolean transformScale = transformScale(otherState);
// lets animate the positions correctly
if (transformationAmount == 0.0f
|| transformX && getTransformationStartX() == UNDEFINED
@@ -132,16 +132,16 @@ public class TransformState {
}
// we also want to animate the scale if we're the same
View otherView = otherState.getTransformedView();
- if (transformScale && otherView.getWidth() != transformedView.getWidth()) {
- setTransformationStartScaleX(otherView.getWidth() * otherView.getScaleX()
- / (float) transformedView.getWidth());
+ if (transformScale && otherState.getViewWidth() != getViewWidth()) {
+ setTransformationStartScaleX(otherState.getViewWidth() * otherView.getScaleX()
+ / (float) getViewWidth());
transformedView.setPivotX(0);
} else {
setTransformationStartScaleX(UNDEFINED);
}
- if (transformScale && otherView.getHeight() != transformedView.getHeight()) {
- setTransformationStartScaleY(otherView.getHeight() * otherView.getScaleY()
- / (float) transformedView.getHeight());
+ if (transformScale && otherState.getViewHeight() != getViewHeight()) {
+ setTransformationStartScaleY(otherState.getViewHeight() * otherView.getScaleY()
+ / (float) getViewHeight());
transformedView.setPivotY(0);
} else {
setTransformationStartScaleY(UNDEFINED);
@@ -205,7 +205,15 @@ public class TransformState {
}
}
- protected boolean transformScale() {
+ protected int getViewWidth() {
+ return mTransformedView.getWidth();
+ }
+
+ protected int getViewHeight() {
+ return mTransformedView.getHeight();
+ }
+
+ protected boolean transformScale(TransformState otherState) {
return false;
}
@@ -259,7 +267,7 @@ public class TransformState {
final View transformedView = mTransformedView;
boolean transformX = (transformationFlags & TRANSFORM_X) != 0;
boolean transformY = (transformationFlags & TRANSFORM_Y) != 0;
- boolean transformScale = transformScale();
+ boolean transformScale = transformScale(otherState);
// lets animate the positions correctly
if (transformationAmount == 0.0f) {
if (transformX) {
@@ -275,13 +283,13 @@ public class TransformState {
setTransformationStartY(start);
}
View otherView = otherState.getTransformedView();
- if (transformScale && otherView.getWidth() != transformedView.getWidth()) {
+ if (transformScale && otherState.getViewWidth() != getViewWidth()) {
setTransformationStartScaleX(transformedView.getScaleX());
transformedView.setPivotX(0);
} else {
setTransformationStartScaleX(UNDEFINED);
}
- if (transformScale && otherView.getHeight() != transformedView.getHeight()) {
+ if (transformScale && otherState.getViewHeight() != getViewHeight()) {
setTransformationStartScaleY(transformedView.getScaleY());
transformedView.setPivotY(0);
} else {
@@ -333,14 +341,14 @@ public class TransformState {
if (transformationStartScaleX != UNDEFINED) {
transformedView.setScaleX(
NotificationUtils.interpolate(transformationStartScaleX,
- (otherView.getWidth() / (float) transformedView.getWidth()),
+ (otherState.getViewWidth() / (float) getViewWidth()),
interpolatedValue));
}
float transformationStartScaleY = getTransformationStartScaleY();
if (transformationStartScaleY != UNDEFINED) {
transformedView.setScaleY(
NotificationUtils.interpolate(transformationStartScaleY,
- (otherView.getHeight() / (float) transformedView.getHeight()),
+ (otherState.getViewHeight() / (float) getViewHeight()),
interpolatedValue));
}
}
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 7512efaba733..1bd90fa9ca08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -24,6 +24,7 @@ import com.android.internal.app.NightDisplayController;
import com.android.systemui.Dependency;
import com.android.systemui.Prefs;
import com.android.systemui.Prefs.Key;
+import com.android.systemui.qs.AutoAddTracker;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.SecureSetting;
import com.android.systemui.statusbar.policy.DataSaverController;
@@ -36,39 +37,47 @@ import com.android.systemui.statusbar.policy.HotspotController.Callback;
*/
public class AutoTileManager {
+ public static final String HOTSPOT = "hotspot";
+ public static final String SAVER = "saver";
+ public static final String INVERSION = "inversion";
+ public static final String WORK = "work";
+ public static final String NIGHT = "night";
private final Context mContext;
private final QSTileHost mHost;
private final Handler mHandler;
+ private final AutoAddTracker mAutoTracker;
public AutoTileManager(Context context, QSTileHost host) {
+ mAutoTracker = new AutoAddTracker(context);
mContext = context;
mHost = host;
mHandler = new Handler((Looper) Dependency.get(Dependency.BG_LOOPER));
- if (!Prefs.getBoolean(context, Key.QS_HOTSPOT_ADDED, false)) {
+ if (!mAutoTracker.isAdded(HOTSPOT)) {
Dependency.get(HotspotController.class).addCallback(mHotspotCallback);
}
- if (!Prefs.getBoolean(context, Key.QS_DATA_SAVER_ADDED, false)) {
+ if (!mAutoTracker.isAdded(SAVER)) {
Dependency.get(DataSaverController.class).addCallback(mDataSaverListener);
}
- if (!Prefs.getBoolean(context, Key.QS_INVERT_COLORS_ADDED, false)) {
+ if (!mAutoTracker.isAdded(INVERSION)) {
mColorsSetting = new SecureSetting(mContext, mHandler,
Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) {
@Override
protected void handleValueChanged(int value, boolean observedChange) {
+ if (mAutoTracker.isAdded(INVERSION)) return;
if (value != 0) {
- mHost.addTile("inversion");
- Prefs.putBoolean(mContext, Key.QS_INVERT_COLORS_ADDED, true);
+ mHost.addTile(INVERSION);
+ mAutoTracker.setTileAdded(INVERSION);
mHandler.post(() -> mColorsSetting.setListening(false));
}
}
};
mColorsSetting.setListening(true);
}
- if (!Prefs.getBoolean(context, Key.QS_WORK_ADDED, false)) {
+ if (!mAutoTracker.isAdded(WORK)) {
Dependency.get(ManagedProfileController.class).addCallback(mProfileCallback);
}
- if (!Prefs.getBoolean(context, Key.QS_NIGHTDISPLAY_ADDED, false)
+ if (!mAutoTracker.isAdded(NIGHT)
&& NightDisplayController.isAvailable(mContext)) {
Dependency.get(NightDisplayController.class).setListener(mNightDisplayCallback);
}
@@ -76,6 +85,7 @@ public class AutoTileManager {
public void destroy() {
mColorsSetting.setListening(false);
+ mAutoTracker.destroy();
Dependency.get(HotspotController.class).removeCallback(mHotspotCallback);
Dependency.get(DataSaverController.class).removeCallback(mDataSaverListener);
Dependency.get(ManagedProfileController.class).removeCallback(mProfileCallback);
@@ -86,9 +96,10 @@ public class AutoTileManager {
new ManagedProfileController.Callback() {
@Override
public void onManagedProfileChanged() {
+ if (mAutoTracker.isAdded(WORK)) return;
if (Dependency.get(ManagedProfileController.class).hasActiveProfile()) {
- mHost.addTile("work");
- Prefs.putBoolean(mContext, Key.QS_WORK_ADDED, true);
+ mHost.addTile(WORK);
+ mAutoTracker.setTileAdded(WORK);
mHandler.post(() -> Dependency.get(ManagedProfileController.class)
.removeCallback(mProfileCallback));
}
@@ -104,9 +115,10 @@ public class AutoTileManager {
private final DataSaverController.Listener mDataSaverListener = new Listener() {
@Override
public void onDataSaverChanged(boolean isDataSaving) {
+ if (mAutoTracker.isAdded(SAVER)) return;
if (isDataSaving) {
- mHost.addTile("saver");
- Prefs.putBoolean(mContext, Key.QS_DATA_SAVER_ADDED, true);
+ mHost.addTile(SAVER);
+ mAutoTracker.setTileAdded(SAVER);
mHandler.post(() -> Dependency.get(DataSaverController.class).removeCallback(
mDataSaverListener));
}
@@ -116,9 +128,10 @@ public class AutoTileManager {
private final HotspotController.Callback mHotspotCallback = new Callback() {
@Override
public void onHotspotChanged(boolean enabled) {
+ if (mAutoTracker.isAdded(HOTSPOT)) return;
if (enabled) {
- mHost.addTile("hotspot");
- Prefs.putBoolean(mContext, Key.QS_HOTSPOT_ADDED, true);
+ mHost.addTile(HOTSPOT);
+ mAutoTracker.setTileAdded(HOTSPOT);
mHandler.post(() -> Dependency.get(HotspotController.class)
.removeCallback(mHotspotCallback));
}
@@ -144,8 +157,9 @@ public class AutoTileManager {
}
private void addNightTile() {
- mHost.addTile("night");
- Prefs.putBoolean(mContext, Key.QS_NIGHTDISPLAY_ADDED, true);
+ if (mAutoTracker.isAdded(NIGHT)) return;
+ mHost.addTile(NIGHT);
+ mAutoTracker.setTileAdded(NIGHT);
mHandler.post(() -> Dependency.get(NightDisplayController.class)
.setListener(null));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index c30bb9a2e6e8..f393dcd368cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -30,6 +30,8 @@ import android.widget.Button;
import android.widget.FrameLayout;
import com.android.systemui.Dependency;
+import com.android.systemui.Prefs;
+import com.android.systemui.Prefs.Key;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
@@ -74,7 +76,8 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener
if (mUserListener == null) {
return false;
}
- return mUserListener.getUserCount() != 0;
+ return mUserListener.getUserCount() != 0
+ && Prefs.getBoolean(getContext(), Key.SEEN_MULTI_USER, false);
}
public void setUserSwitcherController(UserSwitcherController userSwitcherController) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 09ae521ceb2b..6f2c6e0bb60a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -131,9 +131,6 @@ public class NavigationBarInflaterView extends FrameLayout
mRot90.setId(R.id.rot90);
addView(mRot90);
updateAlternativeOrder();
- if (getParent() instanceof NavigationBarView) {
- ((NavigationBarView) getParent()).updateRotatedViews();
- }
}
protected String getDefaultLayout() {
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 18dc7e2fa35b..03dd41ff1ae0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -558,7 +558,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
public void onFinishInflate() {
mNavigationInflaterView = (NavigationBarInflaterView) findViewById(
R.id.navigation_inflater);
- updateRotatedViews();
mNavigationInflaterView.setButtonDispatchers(mButtonDispatchers);
getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
@@ -567,16 +566,14 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
mDockedStackExists = exists;
updateRecentsIcon();
}));
+ updateRotatedViews();
}
- void updateRotatedViews() {
+ private void updateRotatedViews() {
mRotatedViews[Surface.ROTATION_0] =
mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
mRotatedViews[Surface.ROTATION_270] =
mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);
-
- mCurrentRotation = -1;
- reorient();
}
public boolean needsReorient(int rotation) {
@@ -613,12 +610,11 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
if (!updateCurrentView()) {
return;
}
- Log.d(TAG, "reorient", new Throwable());
mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
- if (getRootView() instanceof NavigationBarFrame) {
- ((NavigationBarFrame) getRootView()).setDeadZone(mDeadZone);
- }
+
+ ((NavigationBarFrame) getRootView()).setDeadZone(mDeadZone);
+
mDeadZone.setDisplayRotation(mCurrentRotation);
// force the low profile & disabled states into compliance
@@ -758,6 +754,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
+ reorient();
onPluginDisconnected(null); // Create default gesture helper
Dependency.get(PluginManager.class).addPluginListener(this,
NavGesture.class, false /* Only one */);
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 4701f85c5ff3..96620783ffca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -153,7 +153,6 @@ public class NotificationPanelView extends PanelView implements
protected int mQsMinExpansionHeight;
protected int mQsMaxExpansionHeight;
private int mQsPeekHeight;
- private boolean mQsOverscrollExpansionEnabled;
private boolean mStackScrollerOverscrolling;
private boolean mQsExpansionFromOverscroll;
private float mLastOverscroll;
@@ -242,8 +241,6 @@ public class NotificationPanelView extends PanelView implements
super(context, attrs);
setWillNotDraw(!DEBUG);
mFalsingManager = FalsingManager.getInstance(context);
- mQsOverscrollExpansionEnabled =
- getResources().getBoolean(R.bool.config_enableQuickSettingsOverscrollExpansion);
}
public void setStatusBar(StatusBar bar) {
@@ -348,6 +345,7 @@ public class NotificationPanelView extends PanelView implements
false);
addView(mKeyguardBottomArea, index);
initBottomArea();
+ setDarkAmount(mDarkAmount);
}
private void initBottomArea() {
@@ -668,7 +666,7 @@ public class NotificationPanelView extends PanelView implements
return true;
}
- if (mQsOverscrollExpansionEnabled && !isFullyCollapsed() && onQsIntercept(event)) {
+ if (!isFullyCollapsed() && onQsIntercept(event)) {
return true;
}
return super.onInterceptTouchEvent(event);
@@ -843,8 +841,7 @@ public class NotificationPanelView extends PanelView implements
}
handled |= mHeadsUpTouchHelper.onTouchEvent(event);
- if (mQsOverscrollExpansionEnabled && !mHeadsUpTouchHelper.isTrackingHeadsUp()
- && handleQsTouch(event)) {
+ if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && handleQsTouch(event)) {
return true;
}
if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) {
@@ -1028,10 +1025,6 @@ public class NotificationPanelView extends PanelView implements
@Override
public void onOverscrollTopChanged(float amount, boolean isRubberbanded) {
- if (!mQsOverscrollExpansionEnabled) {
- return;
- }
-
cancelQsAnimation();
if (!mQsExpansionEnabled) {
amount = 0f;
@@ -1046,10 +1039,6 @@ public class NotificationPanelView extends PanelView implements
@Override
public void flingTopOverscroll(float velocity, boolean open) {
- if (!mQsOverscrollExpansionEnabled) {
- return;
- }
-
mLastOverscroll = 0f;
mQsExpansionFromOverscroll = false;
setQsExpansion(mQsExpansionHeight);
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 f3ba5aaf887d..6cdb75706003 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -484,7 +484,8 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
boolean isManagedProfile = mUserManager.isManagedProfile(userId);
mHandler.post(() -> {
final boolean showIcon;
- if (isManagedProfile && !mKeyguardMonitor.isShowing()) {
+ if (isManagedProfile &&
+ (!mKeyguardMonitor.isShowing() || mKeyguardMonitor.isOccluded())) {
showIcon = true;
mIconController.setIcon(mSlotManagedProfile,
R.drawable.stat_sys_managed_profile_status,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
index deea521b7c2f..7a7efbdc6615 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java
@@ -100,12 +100,8 @@ public class SignalDrawable extends Drawable {
// How far the circle defining the corners is inset from the edges
private final float mAppliedCornerInset;
- // The easiest way to understand this is as if we set Style.STROKE and draw the triangle,
- // but that is only theoretically right. Instead, draw the triangle and clip out a smaller
- // one inset by this amount.
- private final float mEmptyStrokeWidth;
private static final float INV_TAN = 1f / (float) Math.tan(Math.PI / 8f);
- private final float mEmptyDiagInset; // == mEmptyStrokeWidth * INV_TAN
+ private static final float CUT_WIDTH_DP = 1f / 12f;
// Where the top and left points of the triangle would be if not for rounding
private final PointF mVirtualTop = new PointF();
@@ -145,11 +141,6 @@ public class SignalDrawable extends Drawable {
Utils.getDefaultColor(context, R.color.light_mode_icon_color_dual_tone_fill);
mIntrinsicSize = context.getResources().getDimensionPixelSize(R.dimen.signal_icon_size);
- // mCutPath parameters
- mEmptyStrokeWidth = context.getResources()
- .getDimensionPixelSize(R.dimen.mobile_signal_empty_strokewidth);
- mEmptyDiagInset = mEmptyStrokeWidth * INV_TAN;
-
mHandler = new Handler();
setDarkIntensity(0);
@@ -326,22 +317,20 @@ public class SignalDrawable extends Drawable {
(padding + cornerRadius + mAppliedCornerInset) - (INV_TAN * cornerRadius),
height - padding);
+ final float cutWidth = CUT_WIDTH_DP * height;
+ final float cutDiagInset = cutWidth * INV_TAN;
+
// Cut out a smaller triangle from the center of mFullPath
mCutPath.reset();
mCutPath.setFillType(FillType.WINDING);
- mCutPath.moveTo(width - padding - mEmptyStrokeWidth,
- height - padding - mEmptyStrokeWidth);
- mCutPath.lineTo(width - padding - mEmptyStrokeWidth,
- mVirtualTop.y + mEmptyDiagInset);
- mCutPath.lineTo(mVirtualLeft.x + mEmptyDiagInset,
- height - padding - mEmptyStrokeWidth);
- mCutPath.lineTo(width - padding - mEmptyStrokeWidth,
- height - padding - mEmptyStrokeWidth);
-
- // In empty state, draw the full path as the foreground paint
- mForegroundPath.set(mFullPath);
- mFullPath.reset();
- mForegroundPath.op(mCutPath, Path.Op.DIFFERENCE);
+ mCutPath.moveTo(width - padding - cutWidth, height - padding - cutWidth);
+ mCutPath.lineTo(width - padding - cutWidth, mVirtualTop.y + cutDiagInset);
+ mCutPath.lineTo(mVirtualLeft.x + cutDiagInset, height - padding - cutWidth);
+ mCutPath.lineTo(width - padding - cutWidth, height - padding - cutWidth);
+
+ // Draw empty state as only background
+ mForegroundPath.reset();
+ mFullPath.op(mCutPath, Path.Op.DIFFERENCE);
} else if (mState == STATE_AIRPLANE) {
// Airplane mode is slashed, full-signal
mForegroundPath.set(mFullPath);
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 4d6fd9c136b5..12e9c009cdb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -182,6 +182,7 @@ import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.Snoo
import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.car.CarQSFragment;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.recents.events.EventBus;
@@ -309,7 +310,7 @@ public class StatusBar extends SystemUI implements DemoMode,
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 = true; // false once b/62623620 is fixed
+ public static final boolean DEBUG_CAMERA_LIFT = false;
public static final boolean DEBUG_WINDOW_STATE = false;
@@ -425,6 +426,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private boolean mWakeUpComingFromTouch;
private PointF mWakeUpTouchLocation;
private boolean mScreenTurningOn;
+ private boolean mScreenFullyOff;
int mPixelFormat;
Object mQueueLock = new Object();
@@ -1149,7 +1151,7 @@ public class StatusBar extends SystemUI implements DemoMode,
ExtensionFragmentListener.attachExtensonToFragment(container, QS.TAG, R.id.qs_frame,
Dependency.get(ExtensionController.class).newExtension(QS.class)
.withPlugin(QS.class)
- .withUiMode(UI_MODE_TYPE_CAR, () -> new QSFragment())
+ .withUiMode(UI_MODE_TYPE_CAR, () -> new CarQSFragment())
.withDefault(() -> new QSFragment())
.build());
final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
@@ -1317,6 +1319,9 @@ public class StatusBar extends SystemUI implements DemoMode,
.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mKeyguardIndicationController.setVisible(mState == StatusBarState.KEYGUARD);
mKeyguardIndicationController.setDozing(mDozing);
+ if (mBrightnessMirrorController != null) {
+ mBrightnessMirrorController.onOverlayChanged();
+ }
}
protected void reevaluateStyles() {
@@ -2811,7 +2816,9 @@ public class StatusBar extends SystemUI implements DemoMode,
}
public void onScreenTurnedOff() {
+ mScreenFullyOff = true;
mFalsingManager.onScreenOff();
+ updateIsKeyguard();
}
public NotificationStackScrollLayout getNotificationScrollLayout() {
@@ -3493,6 +3500,11 @@ public class StatusBar extends SystemUI implements DemoMode,
pw.print (" ");
mNotificationPanel.dump(fd, pw, args);
}
+ pw.println(" mStackScroller: ");
+ if (mStackScroller != null) {
+ pw.print (" ");
+ mStackScroller.dump(fd, pw, args);
+ }
DozeLog.dump(pw);
@@ -4197,15 +4209,18 @@ public class StatusBar extends SystemUI implements DemoMode,
private boolean updateIsKeyguard() {
// For dozing, keyguard needs to be shown whenever the device is non-interactive. Otherwise
- // there's no surface we can show to the user.
- boolean keyguardForDozing = mDozingRequested && !mDeviceInteractive;
+ // there's no surface we can show to the user. Note that the device goes fully interactive
+ // late in the transition, so we also allow the device to start dozing once the screen has
+ // turned off fully.
+ boolean keyguardForDozing = mDozingRequested &&
+ (!mDeviceInteractive || mStartedGoingToSleep && (mScreenFullyOff || mIsKeyguard));
boolean shouldBeKeyguard = mKeyguardRequested || keyguardForDozing;
if (keyguardForDozing) {
updatePanelExpansionForKeyguard();
}
if (shouldBeKeyguard) {
showKeyguardImpl();
- } else if (!shouldBeKeyguard && mIsKeyguard) {
+ } else {
return hideKeyguardImpl();
}
return false;
@@ -5139,6 +5154,7 @@ public class StatusBar extends SystemUI implements DemoMode,
}
public void onScreenTurningOn() {
+ mScreenFullyOff = false;
mScreenTurningOn = true;
mFalsingManager.onScreenTurningOn();
mNotificationPanel.onScreenTurningOn();
@@ -5306,7 +5322,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mDozingRequested = true;
DozeLog.traceDozing(mContext, mDozing);
updateDozing();
-
+ updateIsKeyguard();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 9b0307d6522e..2833ff1db27f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -152,7 +152,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
* {@link KeyguardBouncer#needsFullscreenBouncer()}.
*/
protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) {
- if (mBouncer.needsFullscreenBouncer()) {
+ if (mBouncer.needsFullscreenBouncer() && !mDozing) {
// The keyguard might be showing (already). So we need to hide it.
mStatusBar.hideKeyguard();
@@ -258,8 +258,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
public void setDozing(boolean dozing) {
- mDozing = dozing;
- updateStates();
+ if (mDozing != dozing) {
+ mDozing = dozing;
+ reset(dozing /* hideBouncerWhenShowing */);
+ updateStates();
+ }
}
public void onScreenTurnedOff() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index e78a113af881..0566361439fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -137,7 +137,7 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D
}
private void adjustScreenOrientation(State state) {
- if (state.isKeyguardShowingAndNotOccluded()) {
+ if (state.isKeyguardShowingAndNotOccluded() || state.dozing) {
if (mKeyguardScreenRotation) {
mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index ad406c7f335f..ab55b23c91ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -84,7 +84,6 @@ public class BrightnessMirrorController {
.setInterpolator(Interpolators.ALPHA_IN);
}
-
public void setLocation(View original) {
original.getLocationInWindow(mInt2Cache);
@@ -115,7 +114,15 @@ public class BrightnessMirrorController {
mBrightnessMirror.setLayoutParams(lp);
}
+ public void onOverlayChanged() {
+ reinflate();
+ }
+
public void onDensityOrFontScaleChanged() {
+ reinflate();
+ }
+
+ private void reinflate() {
int index = mStatusBarWindow.indexOfChild(mBrightnessMirror);
mStatusBarWindow.removeView(mBrightnessMirror);
mBrightnessMirror = LayoutInflater.from(mBrightnessMirror.getContext()).inflate(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
index c2618cd5edaf..b79137ea68ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
@@ -262,7 +262,8 @@ public class ExtensionControllerImpl implements ExtensionController {
public UiModeItem(int uiMode, Supplier<T> supplier) {
mDesiredUiMode = uiMode;
mSupplier = supplier;
- mUiMode = mDefaultContext.getResources().getConfiguration().uiMode;
+ mUiMode = mDefaultContext.getResources().getConfiguration().uiMode
+ & Configuration.UI_MODE_TYPE_MASK;
Dependency.get(ConfigurationController.class).addCallback(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index 728005dde131..ccfbb26a61d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -21,12 +21,13 @@ public interface KeyguardMonitor extends CallbackController<Callback> {
boolean isSecure();
boolean canSkipBouncer();
boolean isShowing();
+ boolean isOccluded();
boolean isKeyguardFadingAway();
boolean isKeyguardGoingAway();
long getKeyguardFadingAwayDuration();
long getKeyguardFadingAwayDelay();
- public interface Callback {
+ interface Callback {
void onKeyguardShowingChanged();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
index 7bce33a2950d..5ead02f1f3f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
@@ -58,6 +58,7 @@ public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback
};
}
+ @Override
public void addCallback(Callback callback) {
mCallbacks.add(callback);
if (mCallbacks.size() != 0 && !mListening) {
@@ -69,6 +70,7 @@ public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback
}
}
+ @Override
public void removeCallback(Callback callback) {
if (mCallbacks.remove(callback) && mCallbacks.size() == 0 && mListening) {
mListening = false;
@@ -77,18 +79,22 @@ public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback
}
}
+ @Override
public boolean isShowing() {
return mShowing;
}
+ @Override
public boolean isSecure() {
return mSecure;
}
+ @Override
public boolean isOccluded() {
return mOccluded;
}
+ @Override
public boolean canSkipBouncer() {
return mCanSkipBouncer;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index e0f4429f9998..700c01a55ad6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -57,6 +57,8 @@ import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.GuestResumeSessionReceiver;
+import com.android.systemui.Prefs;
+import com.android.systemui.Prefs.Key;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUISecondaryUserService;
@@ -235,6 +237,9 @@ public class UserSwitcherController {
}
}
}
+ if (records.size() > 1 || guestRecord != null) {
+ Prefs.putBoolean(mContext, Key.SEEN_MULTI_USER, true);
+ }
boolean systemCanCreateUsers = !mUserManager.hasBaseUserRestriction(
UserManager.DISALLOW_ADD_USER, UserHandle.SYSTEM);
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 41cde9c7dd5e..9d197d785ee3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -91,6 +91,8 @@ import com.android.systemui.statusbar.policy.ScrollAdapter;
import android.support.v4.graphics.ColorUtils;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -2587,9 +2589,6 @@ public class NotificationStackScrollLayout extends ViewGroup
}
updateAnimationState(false, child);
- // Make sure the clipRect we might have set is removed
- expandableView.setClipTopAmount(0);
-
focusNextViewIfFocused(child);
}
@@ -3036,10 +3035,6 @@ public class NotificationStackScrollLayout extends ViewGroup
private void generateChildRemovalEvents() {
for (View child : mChildrenToRemoveAnimated) {
boolean childWasSwipedOut = mSwipedOutViews.contains(child);
- int animationType = childWasSwipedOut
- ? AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT
- : AnimationEvent.ANIMATION_TYPE_REMOVE;
- AnimationEvent event = new AnimationEvent(child, animationType);
// we need to know the view after this one
float removedTranslation = child.getTranslationY();
@@ -3050,7 +3045,16 @@ public class NotificationStackScrollLayout extends ViewGroup
removedTranslation = row.getTranslationWhenRemoved();
ignoreChildren = false;
}
+ childWasSwipedOut |= Math.abs(row.getTranslation()) == row.getWidth();
+ }
+ if (!childWasSwipedOut) {
+ Rect clipBounds = child.getClipBounds();
+ childWasSwipedOut = clipBounds.height() == 0;
}
+ int animationType = childWasSwipedOut
+ ? AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT
+ : AnimationEvent.ANIMATION_TYPE_REMOVE;
+ AnimationEvent event = new AnimationEvent(child, animationType);
event.viewAfterChangingView = getFirstChildBelowTranlsationY(removedTranslation,
ignoreChildren);
mAnimationEvents.add(event);
@@ -4257,6 +4261,19 @@ public class NotificationStackScrollLayout extends ViewGroup
mShelf.setDarkOffsetX(shelfOffsetX);
}
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(String.format("[%s: pulsing=%s qsCustomizerShowing=%s visibility=%s"
+ + " alpha:%f scrollY:%d]",
+ this.getClass().getSimpleName(),
+ mPulsing != null ?"T":"f",
+ mAmbientState.isQsCustomizerShowing() ? "T":"f",
+ getVisibility() == View.VISIBLE ? "visible"
+ : getVisibility() == View.GONE ? "gone"
+ : "invisible",
+ getAlpha(),
+ mAmbientState.getScrollY()));
+ }
+
/**
* A listener that is notified when some child locations might have changed.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/util/AlarmTimeout.java b/packages/SystemUI/src/com/android/systemui/util/AlarmTimeout.java
new file mode 100644
index 000000000000..f7f61aff9849
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/AlarmTimeout.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.util;
+
+import android.app.AlarmManager;
+import android.os.Handler;
+import android.os.SystemClock;
+
+/**
+ * Schedules a timeout through AlarmManager. Ensures that the timeout is called even when
+ * the device is asleep.
+ */
+public class AlarmTimeout implements AlarmManager.OnAlarmListener {
+
+ public static final int MODE_CRASH_IF_SCHEDULED = 0;
+ public static final int MODE_IGNORE_IF_SCHEDULED = 1;
+ public static final int MODE_RESCHEDULE_IF_SCHEDULED = 2;
+
+ private final AlarmManager mAlarmManager;
+ private final AlarmManager.OnAlarmListener mListener;
+ private final String mTag;
+ private final Handler mHandler;
+ private boolean mScheduled;
+
+ public AlarmTimeout(AlarmManager alarmManager, AlarmManager.OnAlarmListener listener,
+ String tag, Handler handler) {
+ mAlarmManager = alarmManager;
+ mListener = listener;
+ mTag = tag;
+ mHandler = handler;
+ }
+
+ public void schedule(long timeout, int mode) {
+ switch (mode) {
+ case MODE_CRASH_IF_SCHEDULED:
+ if (mScheduled) {
+ throw new IllegalStateException(mTag + " timeout is already scheduled");
+ }
+ break;
+ case MODE_IGNORE_IF_SCHEDULED:
+ if (mScheduled) {
+ return;
+ }
+ break;
+ case MODE_RESCHEDULE_IF_SCHEDULED:
+ if (mScheduled) {
+ cancel();
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Illegal mode: " + mode);
+ }
+
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + timeout, mTag, this, mHandler);
+ mScheduled = true;
+ }
+
+ public boolean isScheduled() {
+ return mScheduled;
+ }
+
+ public void cancel() {
+ if (mScheduled) {
+ mAlarmManager.cancel(this);
+ mScheduled = false;
+ }
+ }
+
+ @Override
+ public void onAlarm() {
+ if (!mScheduled) {
+ // We canceled the alarm, but it still fired. Ignore.
+ return;
+ }
+ mScheduled = false;
+ mListener.onAlarm();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java b/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
new file mode 100644
index 000000000000..ad2090009714
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.util.leak;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.view.Surface;
+
+public class RotationUtils {
+
+ public static final int ROTATION_NONE = 0;
+ public static final int ROTATION_LANDSCAPE = 1;
+ public static final int ROTATION_SEASCAPE = 2;
+
+ public static int getRotation(Context context) {
+ Configuration config = context.getResources().getConfiguration();
+ int rot = context.getDisplay().getRotation();
+ if (config.smallestScreenWidthDp < 600) {
+ if (rot == Surface.ROTATION_90) {
+ return ROTATION_LANDSCAPE;
+ } else if (rot == Surface.ROTATION_270) {
+ return ROTATION_SEASCAPE;
+ }
+ }
+ return ROTATION_NONE;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/RoundedCornersTest.java b/packages/SystemUI/tests/src/com/android/systemui/RoundedCornersTest.java
index 13ed2a25abf9..2a447715fb6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/RoundedCornersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/RoundedCornersTest.java
@@ -46,7 +46,6 @@ import com.android.systemui.tuner.TunablePadding.TunablePaddingService;
import com.android.systemui.tuner.TunerService;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -105,7 +104,6 @@ public class RoundedCornersTest extends SysuiTestCase {
}
@Test
- @Ignore
public void testRounding() {
mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 20);
mContext.getOrCreateTestableResources()
@@ -115,8 +113,8 @@ public class RoundedCornersTest extends SysuiTestCase {
// Add 2 windows for rounded corners (top and bottom).
verify(mWindowManager, times(2)).addView(any(), any());
- // Add 3 tag listeners for each of the fragments that are needed.
- verify(mFragmentHostManager, times(3)).addTagListener(any(), any());
+ // Add 2 tag listeners for each of the fragments that are needed.
+ verify(mFragmentHostManager, times(2)).addTagListener(any(), any());
// One tunable.
verify(mTunerService, times(1)).addTunable(any(), any());
// One TunablePadding.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index 3a09ce07288e..368c814f8e0a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -215,54 +215,6 @@ public class DozeMachineTest extends SysuiTestCase {
}
@Test
- public void testScreen_offInDoze() {
- mMachine.requestState(INITIALIZED);
-
- mMachine.requestState(DOZE);
-
- assertEquals(Display.STATE_OFF, mServiceFake.screenState);
- }
-
- @Test
- public void testScreen_onInAod() {
- mMachine.requestState(INITIALIZED);
-
- mMachine.requestState(DOZE_AOD);
-
- assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState);
- }
-
- @Test
- public void testScreen_onInPulse() {
- mMachine.requestState(INITIALIZED);
-
- mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
- mMachine.requestState(DOZE_PULSING);
-
- assertEquals(Display.STATE_ON, mServiceFake.screenState);
- }
-
- @Test
- public void testScreen_offInRequestPulseWithoutAoD() {
- mMachine.requestState(INITIALIZED);
-
- mMachine.requestState(DOZE);
- mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
-
- assertEquals(Display.STATE_OFF, mServiceFake.screenState);
- }
-
- @Test
- public void testScreen_onInRequestPulseWithoutAoD() {
- mMachine.requestState(INITIALIZED);
-
- mMachine.requestState(DOZE_AOD);
- mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
-
- assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState);
- }
-
- @Test
public void testTransitions_canRequestTransitions() {
mMachine.requestState(INITIALIZED);
mMachine.requestState(DOZE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
new file mode 100644
index 000000000000..514dc8b94de5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.doze;
+
+import static com.android.systemui.doze.DozeMachine.State.DOZE;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSING;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_REQUEST_PULSE;
+import static com.android.systemui.doze.DozeMachine.State.FINISH;
+import static com.android.systemui.doze.DozeMachine.State.INITIALIZED;
+import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.PowerManager;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.utils.hardware.FakeSensorManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DozeScreenBrightnessTest extends SysuiTestCase {
+
+ DozeServiceFake mServiceFake;
+ DozeScreenBrightness mScreen;
+ FakeSensorManager.FakeGenericSensor mSensor;
+ FakeSensorManager mSensorManager;
+
+ @Before
+ public void setUp() throws Exception {
+ mServiceFake = new DozeServiceFake();
+ mSensorManager = new FakeSensorManager(mContext);
+ mSensor = mSensorManager.getFakeLightSensor();
+ mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
+ mSensor.getSensor(), null /* handler */);
+ }
+
+ @Test
+ public void testInitialize_setsScreenBrightnessToValidValue() throws Exception {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+
+ assertNotEquals(PowerManager.BRIGHTNESS_DEFAULT, mServiceFake.screenBrightness);
+ assertTrue(mServiceFake.screenBrightness <= PowerManager.BRIGHTNESS_ON);
+ }
+
+ @Test
+ public void testAod_usesLightSensor() throws Exception {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+
+ mSensor.sendSensorEvent(1000);
+
+ assertEquals(1000, mServiceFake.screenBrightness);
+ }
+
+ @Test
+ public void testPausingAod_pausesLightSensor() throws Exception {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+
+ mSensor.sendSensorEvent(1000);
+
+ mScreen.transitionTo(DOZE_AOD, DOZE_AOD_PAUSED);
+
+ mSensor.sendSensorEvent(1001);
+
+ assertNotEquals(1001, mServiceFake.screenBrightness);
+ }
+
+ @Test
+ public void testPausingAod_resetsBrightness() throws Exception {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+
+ mSensor.sendSensorEvent(1000);
+
+ mScreen.transitionTo(DOZE_AOD, DOZE_AOD_PAUSED);
+
+ assertNotEquals(1000, mServiceFake.screenBrightness);
+ }
+
+ @Test
+ public void testPulsing_usesLightSensor() throws Exception {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE);
+ mScreen.transitionTo(DOZE, DOZE_REQUEST_PULSE);
+
+ mSensor.sendSensorEvent(1000);
+
+ assertEquals(1000, mServiceFake.screenBrightness);
+ }
+
+ @Test
+ public void testDozingAfterPulsing_pausesLightSensor() throws Exception {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE);
+ mScreen.transitionTo(DOZE, DOZE_REQUEST_PULSE);
+ mScreen.transitionTo(DOZE_REQUEST_PULSE, DOZE_PULSING);
+ mScreen.transitionTo(DOZE_PULSING, DOZE_PULSE_DONE);
+ mScreen.transitionTo(DOZE_PULSE_DONE, DOZE);
+
+ mSensor.sendSensorEvent(1000);
+
+ assertNotEquals(1000, mServiceFake.screenBrightness);
+ }
+
+ @Test
+ public void testNullSensor() throws Exception {
+ mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
+ null /* sensor */, null /* handler */);
+
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+ mScreen.transitionTo(DOZE_AOD, DOZE_AOD_PAUSED);
+ }
+
+ @Test
+ public void testNoBrightnessDeliveredAfterFinish() throws Exception {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+ mScreen.transitionTo(DOZE_AOD, FINISH);
+
+ mSensor.sendSensorEvent(1000);
+
+ assertNotEquals(1000, mServiceFake.screenBrightness);
+ }
+
+ @Test
+ public void testBrightness_atLeastOne() throws Exception {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+
+ mSensor.sendSensorEvent(0);
+
+ assertTrue("Brightness must be at least 1, but was " + mServiceFake.screenBrightness,
+ mServiceFake.screenBrightness >= 1);
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
new file mode 100644
index 000000000000..203876b9a2f5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.doze;
+
+import static com.android.systemui.doze.DozeMachine.State.DOZE;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSING;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_REQUEST_PULSE;
+import static com.android.systemui.doze.DozeMachine.State.INITIALIZED;
+import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.Display;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DozeScreenStateTest extends SysuiTestCase {
+
+ DozeServiceFake mServiceFake;
+ DozeScreenState mScreen;
+
+ @Before
+ public void setUp() throws Exception {
+ mServiceFake = new DozeServiceFake();
+ mScreen = new DozeScreenState(mServiceFake);
+ }
+
+ @Test
+ public void testScreen_offInDoze() {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE);
+
+ assertEquals(Display.STATE_OFF, mServiceFake.screenState);
+ }
+
+ @Test
+ public void testScreen_onInAod() {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+
+ assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState);
+ }
+
+ @Test
+ public void testScreen_onInPulse() {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE);
+
+ mScreen.transitionTo(DOZE, DOZE_REQUEST_PULSE);
+ mScreen.transitionTo(DOZE_REQUEST_PULSE, DOZE_PULSING);
+
+ assertEquals(Display.STATE_ON, mServiceFake.screenState);
+ }
+
+ @Test
+ public void testScreen_offInRequestPulseWithoutAoD() {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE);
+
+ mScreen.transitionTo(DOZE, DOZE_REQUEST_PULSE);
+
+ assertEquals(Display.STATE_OFF, mServiceFake.screenState);
+ }
+
+ @Test
+ public void testScreen_onInRequestPulseWithAoD() {
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+
+ mScreen.transitionTo(DOZE, DOZE_REQUEST_PULSE);
+
+ assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState);
+ }
+
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java
index c1e7fe46de8e..34026b0b6145 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java
@@ -16,6 +16,7 @@
package com.android.systemui.doze;
+import android.os.PowerManager;
import android.view.Display;
public class DozeServiceFake implements DozeMachine.Service {
@@ -23,6 +24,7 @@ public class DozeServiceFake implements DozeMachine.Service {
public boolean finished;
public int screenState;
public boolean requestedWakeup;
+ public int screenBrightness;
public DozeServiceFake() {
reset();
@@ -38,13 +40,19 @@ public class DozeServiceFake implements DozeMachine.Service {
screenState = state;
}
- public void reset() {
- finished = false;
- screenState = Display.STATE_UNKNOWN;
- }
-
@Override
public void requestWakeUp() {
requestedWakeup = true;
}
+
+ @Override
+ public void setDozeScreenBrightness(int brightness) {
+ screenBrightness = brightness;
+ }
+
+ public void reset() {
+ finished = false;
+ screenState = Display.STATE_UNKNOWN;
+ screenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 8641faca5d6e..a8ea1c0770da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -23,6 +23,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AlarmManager;
import android.app.Instrumentation;
import android.os.Handler;
import android.os.Looper;
@@ -56,6 +57,7 @@ public class DozeTriggersTest extends SysuiTestCase {
private Handler mHandler;
private WakeLock mWakeLock;
private Instrumentation mInstrumentation;
+ private AlarmManager mAlarmManager;
@BeforeClass
public static void setupSuite() {
@@ -67,6 +69,7 @@ public class DozeTriggersTest extends SysuiTestCase {
public void setUp() throws Exception {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mMachine = mock(DozeMachine.class);
+ mAlarmManager = mock(AlarmManager.class);
mHost = new DozeHostFake();
mConfig = DozeConfigurationUtil.createMockConfig();
mParameters = DozeConfigurationUtil.createMockParameters();
@@ -75,7 +78,7 @@ public class DozeTriggersTest extends SysuiTestCase {
mWakeLock = new WakeLockFake();
mInstrumentation.runOnMainSync(() -> {
- mTriggers = new DozeTriggers(mContext, mMachine, mHost,
+ mTriggers = new DozeTriggers(mContext, mMachine, mHost, mAlarmManager,
mConfig, mParameters, mSensors, mHandler, mWakeLock, true);
});
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java
new file mode 100644
index 000000000000..40f8059fecbf
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import static com.android.systemui.statusbar.phone.AutoTileManager.INVERSION;
+import static com.android.systemui.statusbar.phone.AutoTileManager.SAVER;
+import static com.android.systemui.statusbar.phone.AutoTileManager.WORK;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.provider.Settings.Secure;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.systemui.Prefs;
+import com.android.systemui.Prefs.Key;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class AutoAddTrackerTest extends SysuiTestCase {
+
+ private AutoAddTracker mAutoTracker;
+
+ @Test
+ public void testMigration() {
+ Prefs.putBoolean(mContext, Key.QS_DATA_SAVER_ADDED, true);
+ Prefs.putBoolean(mContext, Key.QS_WORK_ADDED, true);
+ mAutoTracker = new AutoAddTracker(mContext);
+
+ assertTrue(mAutoTracker.isAdded(SAVER));
+ assertTrue(mAutoTracker.isAdded(WORK));
+ assertFalse(mAutoTracker.isAdded(INVERSION));
+
+ assertFalse(Prefs.getBoolean(mContext, Key.QS_DATA_SAVER_ADDED, false));
+ assertFalse(Prefs.getBoolean(mContext, Key.QS_WORK_ADDED, false));
+
+ mAutoTracker.destroy();
+ }
+
+ @Test
+ public void testChangeFromBackup() {
+ mAutoTracker = new AutoAddTracker(mContext);
+
+ assertFalse(mAutoTracker.isAdded(SAVER));
+
+ Secure.putString(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES, SAVER);
+ mAutoTracker.mObserver.onChange(false);
+
+ assertTrue(mAutoTracker.isAdded(SAVER));
+
+ mAutoTracker.destroy();
+ }
+
+ @Test
+ public void testSetAdded() {
+ mAutoTracker = new AutoAddTracker(mContext);
+
+ assertFalse(mAutoTracker.isAdded(SAVER));
+ mAutoTracker.setTileAdded(SAVER);
+
+ assertTrue(mAutoTracker.isAdded(SAVER));
+
+ mAutoTracker.destroy();
+ }
+
+ @Test
+ public void testPersist() {
+ mAutoTracker = new AutoAddTracker(mContext);
+
+ assertFalse(mAutoTracker.isAdded(SAVER));
+ mAutoTracker.setTileAdded(SAVER);
+
+ mAutoTracker.destroy();
+ mAutoTracker = new AutoAddTracker(mContext);
+
+ assertTrue(mAutoTracker.isAdded(SAVER));
+
+ mAutoTracker.destroy();
+ }
+
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
index d25bbe1e4904..703b4d5e22ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterImplTest.java
@@ -42,9 +42,9 @@ import org.junit.runner.RunWith;
@RunWithLooper
@SmallTest
@Ignore("failing")
-public class QSFooterTest extends LeakCheckedTest {
+public class QSFooterImplTest extends LeakCheckedTest {
- private QSFooter mFooter;
+ private QSFooterImpl mFooter;
private ActivityStarter mActivityStarter;
private DeviceProvisionedController mDeviceProvisionedController;
@@ -54,9 +54,9 @@ public class QSFooterTest extends LeakCheckedTest {
mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class);
mDeviceProvisionedController = mDependency.injectMockDependency(
DeviceProvisionedController.class);
- TestableLooper.get(this).runWithLooper(() -> {
- mFooter = (QSFooter) LayoutInflater.from(mContext).inflate(R.layout.qs_footer, null);
- });
+ TestableLooper.get(this).runWithLooper(
+ () -> mFooter = (QSFooterImpl) LayoutInflater.from(mContext).inflate(
+ R.layout.qs_footer_impl, null));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/car/CarQsFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/car/CarQsFragmentTest.java
new file mode 100644
index 000000000000..4f87b02ed35f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/car/CarQsFragmentTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.android.systemui.qs.car;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.content.Context;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.LayoutInflaterBuilder;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.keyguard.CarrierText;
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiBaseFragmentTest;
+import com.android.systemui.statusbar.policy.Clock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link CarQSFragment}.
+ */
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class CarQsFragmentTest extends SysuiBaseFragmentTest {
+ public CarQsFragmentTest() {
+ super(CarQSFragment.class);
+ }
+
+ @Before
+ public void initDependencies() {
+ mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE,
+ new LayoutInflaterBuilder(mContext)
+ .replace("com.android.systemui.statusbar.policy.SplitClockView",
+ FrameLayout.class)
+ .replace("TextClock", View.class)
+ .replace(CarrierText.class, View.class)
+ .replace(Clock.class, View.class)
+ .build());
+
+ mDependency.injectTestDependency(Dependency.BG_LOOPER,
+ TestableLooper.get(this).getLooper());
+ }
+
+ @Test
+ public void testLayoutInflation() {
+ CarQSFragment fragment = (CarQSFragment) mFragment;
+ mFragments.dispatchResume();
+
+ assertNotNull(fragment.getHeader());
+ assertNotNull(fragment.getFooter());
+ }
+
+ @Test
+ public void testListening() {
+ CarQSFragment qs = (CarQSFragment) mFragment;
+ mFragments.dispatchResume();
+ processAllMessages();
+
+ qs.setListening(true);
+ processAllMessages();
+
+ qs.setListening(false);
+ processAllMessages();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java b/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java
index 30be6658d4b6..a4ae166d0675 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java
@@ -30,13 +30,15 @@ import android.os.MemoryFile;
import android.os.SystemClock;
import android.util.ArraySet;
-import com.google.android.collect.Lists;
+import com.android.internal.util.Preconditions;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
/**
* Rudimentary fake for SensorManager
@@ -49,6 +51,8 @@ import java.util.List;
public class FakeSensorManager extends SensorManager {
private final MockProximitySensor mMockProximitySensor;
+ private final FakeGenericSensor mFakeLightSensor;
+ private final FakeGenericSensor[] mSensors;
public FakeSensorManager(Context context) throws Exception {
Sensor proxSensor = context.getSystemService(SensorManager.class)
@@ -57,13 +61,21 @@ public class FakeSensorManager extends SensorManager {
// No prox? Let's create a fake one!
proxSensor = createSensor(Sensor.TYPE_PROXIMITY);
}
- mMockProximitySensor = new MockProximitySensor(proxSensor);
+
+ mSensors = new FakeGenericSensor[]{
+ mMockProximitySensor = new MockProximitySensor(proxSensor),
+ mFakeLightSensor = new FakeGenericSensor(createSensor(Sensor.TYPE_LIGHT)),
+ };
}
public MockProximitySensor getMockProximitySensor() {
return mMockProximitySensor;
}
+ public FakeGenericSensor getFakeLightSensor() {
+ return mFakeLightSensor;
+ }
+
@Override
public Sensor getDefaultSensor(int type) {
Sensor s = super.getDefaultSensor(type);
@@ -77,7 +89,10 @@ public class FakeSensorManager extends SensorManager {
@Override
protected List<Sensor> getFullSensorList() {
- return Lists.newArrayList(mMockProximitySensor.sensor);
+ return Arrays
+ .stream(mSensors)
+ .map(i -> i.mSensor)
+ .collect(Collectors.toList());
}
@Override
@@ -87,8 +102,11 @@ public class FakeSensorManager extends SensorManager {
@Override
protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
- if (sensor == mMockProximitySensor.sensor || sensor == null) {
- mMockProximitySensor.listeners.remove(listener);
+ Preconditions.checkNotNull(listener);
+ for (FakeGenericSensor s : mSensors) {
+ if (sensor == null || s.mSensor == sensor) {
+ s.mListeners.remove(listener);
+ }
}
}
@@ -96,9 +114,13 @@ public class FakeSensorManager extends SensorManager {
protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
int delayUs,
Handler handler, int maxReportLatencyUs, int reservedFlags) {
- if (sensor == mMockProximitySensor.sensor) {
- mMockProximitySensor.listeners.add(listener);
- return true;
+ Preconditions.checkNotNull(sensor);
+ Preconditions.checkNotNull(listener);
+ for (FakeGenericSensor s : mSensors) {
+ if (s.mSensor == sensor) {
+ s.mListeners.add(listener);
+ return true;
+ }
}
return false;
}
@@ -196,18 +218,35 @@ public class FakeSensorManager extends SensorManager {
setter.invoke(sensor, type);
}
- public class MockProximitySensor {
- final Sensor sensor;
- final ArraySet<SensorEventListener> listeners = new ArraySet<>();
+ public class MockProximitySensor extends FakeGenericSensor {
private MockProximitySensor(Sensor sensor) {
- this.sensor = sensor;
+ super(sensor);
}
public void sendProximityResult(boolean far) {
- SensorEvent event = createSensorEvent(1);
- event.values[0] = far ? sensor.getMaximumRange() : 0;
- for (SensorEventListener listener : listeners) {
+ sendSensorEvent(far ? getSensor().getMaximumRange() : 0);
+ }
+ }
+
+ public class FakeGenericSensor {
+
+ private final Sensor mSensor;
+ private final ArraySet<SensorEventListener> mListeners = new ArraySet<>();
+
+ public FakeGenericSensor(
+ Sensor sensor) {
+ this.mSensor = sensor;
+ }
+
+ public Sensor getSensor() {
+ return mSensor;
+ }
+
+ public void sendSensorEvent(float... values) {
+ SensorEvent event = createSensorEvent(values.length);
+ System.arraycopy(values, 0, event.values, 0, values.length);
+ for (SensorEventListener listener : mListeners) {
listener.onSensorChanged(event);
}
}
@@ -222,7 +261,7 @@ public class FakeSensorManager extends SensorManager {
} catch (Exception e) {
throw new RuntimeException(e);
}
- event.sensor = sensor;
+ event.sensor = mSensor;
event.timestamp = SystemClock.elapsedRealtimeNanos();
return event;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java
index 51e35cc3915e..3f952c3cbca9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java
@@ -47,6 +47,11 @@ public class FakeKeyguardMonitor implements KeyguardMonitor {
}
@Override
+ public boolean isOccluded() {
+ return false;
+ }
+
+ @Override
public boolean isKeyguardFadingAway() {
return false;
}
diff --git a/packages/VpnDialogs/res/values-ar/strings.xml b/packages/VpnDialogs/res/values-ar/strings.xml
index d29c40715a21..e36eef4a0b83 100644
--- a/packages/VpnDialogs/res/values-ar/strings.xml
+++ b/packages/VpnDialogs/res/values-ar/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">"‏يريد <xliff:g id="APP">%s</xliff:g> إعداد الاتصال بالشبكة الظاهرية الخاصة التي تتيح له مراقبة حركة المرور على الشبكة. فلا توافق إلا إذا كنت تثق في المصدر. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; يظهر في الجزء العلوي من الشاشة عندما تكون الشبكة الظاهرية الخاصة نشطة."</string>
+ <string name="warning" msgid="809658604548412033">"‏يريد <xliff:g id="APP">%s</xliff:g> إعداد الاتصال بالشبكة الافتراضية الخاصة التي تتيح له مراقبة حركة المرور على الشبكة. فلا توافق إلا إذا كنت تثق في المصدر. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; يظهر في الجزء العلوي من الشاشة عندما تكون الشبكة الافتراضية الخاصة نشطة."</string>
<string name="legacy_title" msgid="192936250066580964">"‏VPN متصلة"</string>
<string name="configure" msgid="4905518375574791375">"تهيئة"</string>
<string name="disconnect" msgid="971412338304200056">"قطع الاتصال"</string>
diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values/styles.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values/styles.xml
index 1b70413fde46..0c1b0ef31434 100644
--- a/packages/overlays/SysuiDarkThemeOverlay/res/values/styles.xml
+++ b/packages/overlays/SysuiDarkThemeOverlay/res/values/styles.xml
@@ -1,19 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <style name="DarkQuickSettings" parent="android:Theme.DeviceDefault">
+ <style name="qs_base" parent="android:Theme.DeviceDefault">
<item name="android:colorPrimary">@*android:color/primary_device_default_settings</item>
<item name="android:colorPrimaryDark">@*android:color/primary_dark_device_default_settings</item>
- <!-- textColorPrimaryInverse is used on the lock screen and this means that we can't just
- invert text colors otherwise we won't have contrast on the keyguard -->
- <item name="android:textColorPrimaryInverse">@*android:color/primary_text_material_dark</item>
- <!-- same for textColorSecondaryInverse -->
- <item name="android:textColorSecondaryInverse">@*android:color/secondary_text_material_dark</item>
<item name="android:colorSecondary">@*android:color/secondary_device_default_settings</item>
<item name="android:colorAccent">@*android:color/accent_device_default_dark</item>
<item name="android:colorControlNormal">?android:attr/textColorPrimary</item>
<item name="android:colorBackgroundFloating">#000</item>
</style>
-
- <style name="systemui_base" parent="DarkQuickSettings" />
- <style name="edit_theme" parent="DarkQuickSettings" />
</resources> \ No newline at end of file
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index c6e3ed5f30ae..0a0fa1849de3 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4190,6 +4190,18 @@ message MetricsEvent {
// OS: O DR
FIELD_TIME_ELAPSED_BETWEEN_CHARGE_MS = 1030;
+ // ---- End O-DR1 Constants, all O-DR1 constants go above this line ----
+
+ // ACTION: Settings > Network & Internet > Mobile network > Mobile data
+ // CATEGORY: SETTINGS
+ // OS: O MR
+ ACTION_MOBILE_NETWORK_MOBILE_DATA_TOGGLE = 1081;
+
+ // ACTION: Settings > Network & Internet > Mobile network > Data usage
+ // CATEGORY: SETTINGS
+ // OS: O MR
+ ACTION_MOBILE_NETWORK_DATA_USAGE = 1082;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/Android.mk b/services/Android.mk
index 02af56108885..6a73d5f65351 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -44,6 +44,9 @@ LOCAL_STATIC_JAVA_LIBRARIES := $(addprefix services.,$(services)) \
android.hidl.base-V1.0-java-static \
android.hardware.biometrics.fingerprint-V2.1-java-static
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.manager-V1.0-java
+
ifeq ($(EMMA_INSTRUMENT_FRAMEWORK),true)
LOCAL_EMMA_INSTRUMENT := true
endif
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index aebe92e1687d..5e25dfa49d70 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -430,6 +430,8 @@ final class RemoteFillService implements DeathRecipient {
Slog.w(LOG_TAG, getClass().getSimpleName() + " timed out");
final RemoteFillService remoteService = mWeakService.get();
if (remoteService != null) {
+ Slog.w(LOG_TAG, getClass().getSimpleName() + " timed out after "
+ + TIMEOUT_REMOTE_REQUEST_MILLIS + " ms");
fail(remoteService);
}
};
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 72ad752caf19..25aa0d15b617 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -55,8 +55,10 @@ import android.service.autofill.Dataset;
import android.service.autofill.FillContext;
import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
+import android.service.autofill.InternalValidator;
import android.service.autofill.SaveInfo;
import android.service.autofill.SaveRequest;
+import android.service.autofill.ValueFinder;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
@@ -78,6 +80,7 @@ import com.android.server.autofill.ui.AutoFillUI;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -214,7 +217,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
final int numContexts = mContexts.size();
for (int i = 0; i < numContexts; i++) {
- fillContextWithAllowedValues(mContexts.get(i), flags);
+ fillContextWithAllowedValuesLocked(mContexts.get(i), flags);
}
request = new FillRequest(requestId, mContexts, mClientState, flags);
@@ -227,7 +230,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
/**
* Returns the ids of all entries in {@link #mViewStates} in the same order.
*/
- private AutofillId[] getIdsOfAllViewStates() {
+ private AutofillId[] getIdsOfAllViewStatesLocked() {
final int numViewState = mViewStates.size();
final AutofillId[] ids = new AutofillId[numViewState];
for (int i = 0; i < numViewState; i++) {
@@ -238,6 +241,32 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
/**
+ * Gets the value of a field, using either the {@code viewStates} or the {@code mContexts}, or
+ * {@code null} when not found on either of them.
+ */
+ @Nullable
+ private String getValueAsString(@NonNull AutofillId id) {
+ AutofillValue value = null;
+ synchronized (mLock) {
+ final ViewState state = mViewStates.get(id);
+ if (state == null) {
+ if (sDebug) Slog.d(TAG, "getValue(): no view state for " + id);
+ return null;
+ }
+ value = state.getCurrentValue();
+ if (value == null) {
+ if (sDebug) Slog.d(TAG, "getValue(): no current value for " + id);
+ value = getValueFromContexts(id);
+ }
+ }
+ // TODO(b/62534917): support list values, using the String provided by getAutofillOptions()
+ if (value != null && value.isText()) {
+ return value.getTextValue().toString();
+ }
+ return null;
+ }
+
+ /**
* Updates values of the nodes in the context's structure so that:
* - proper node is focused
* - autofillValue is sent back to service when it was previously autofilled
@@ -246,8 +275,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
* @param fillContext The context to be filled
* @param flags The flags that started the session
*/
- private void fillContextWithAllowedValues(@NonNull FillContext fillContext, int flags) {
- final ViewNode[] nodes = fillContext.findViewNodesByAutofillIds(getIdsOfAllViewStates());
+ private void fillContextWithAllowedValuesLocked(@NonNull FillContext fillContext, int flags) {
+ final ViewNode[] nodes = fillContext
+ .findViewNodesByAutofillIds(getIdsOfAllViewStatesLocked());
final int numViewState = mViewStates.size();
for (int i = 0; i < numViewState; i++) {
@@ -771,6 +801,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
boolean atLeastOneChanged = false;
for (int i = 0; i < requiredIds.length; i++) {
final AutofillId id = requiredIds[i];
+ if (id == null) {
+ Slog.w(TAG, "null autofill id on " + Arrays.toString(requiredIds));
+ continue;
+ }
final ViewState viewState = mViewStates.get(id);
if (viewState == null) {
Slog.w(TAG, "showSaveLocked(): no ViewState for required " + id);
@@ -832,11 +866,22 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
}
if (atLeastOneChanged) {
- if (sDebug) Slog.d(TAG, "at least one field changed - showing save UI");
- mService.setSaveShown(id);
- getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo, mPackageName,
- this);
+ if (sDebug) {
+ Slog.d(TAG, "at least one field changed, validate fields for save UI");
+ }
+ final ValueFinder valueFinder = (id) -> {return getValueAsString(id);};
+ final InternalValidator validator = saveInfo.getValidator();
+ if (validator != null && !validator.isValid(valueFinder)) {
+ // TODO(b/62534917): add CTS test
+ Slog.i(TAG, "not showing save UI because fields failed validation");
+ return true;
+ }
+
+ if (sDebug) Slog.d(TAG, "Good news, everyone! All checks passed, show save UI!");
+ mService.setSaveShown(id);
+ getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo,
+ valueFinder, mPackageName, this);
mIsSaving = true;
return false;
}
@@ -897,7 +942,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
for (int contextNum = 0; contextNum < numContexts; contextNum++) {
final FillContext context = mContexts.get(contextNum);
- final ViewNode[] nodes = context.findViewNodesByAutofillIds(getIdsOfAllViewStates());
+ final ViewNode[] nodes =
+ context.findViewNodesByAutofillIds(getIdsOfAllViewStatesLocked());
if (sVerbose) Slog.v(TAG, "callSaveLocked(): updating " + context);
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 4f90019d32b6..8b15d506dab7 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -28,6 +28,7 @@ import android.os.Handler;
import android.service.autofill.Dataset;
import android.service.autofill.FillResponse;
import android.service.autofill.SaveInfo;
+import android.service.autofill.ValueFinder;
import android.text.TextUtils;
import android.util.Slog;
import android.view.autofill.AutofillId;
@@ -242,7 +243,8 @@ public final class AutoFillUI {
* Shows the UI asking the user to save for autofill.
*/
public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info,
- @NonNull String packageName, @NonNull AutoFillUiCallback callback) {
+ @NonNull ValueFinder valueFinder, @NonNull String packageName,
+ @NonNull AutoFillUiCallback callback) {
if (sVerbose) Slog.v(TAG, "showSaveUi() for " + packageName + ": " + info);
int numIds = 0;
numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length;
@@ -257,8 +259,8 @@ public final class AutoFillUI {
return;
}
hideAllUiThread(callback);
- mSaveUi = new SaveUi(mContext, providerLabel, info,
- mOverlayControl, new SaveUi.OnSaveListener() {
+ mSaveUi = new SaveUi(mContext, providerLabel, info, valueFinder, mOverlayControl,
+ new SaveUi.OnSaveListener() {
@Override
public void onSave() {
log.setType(MetricsProto.MetricsEvent.TYPE_ACTION);
diff --git a/services/autofill/java/com/android/server/autofill/ui/OverlayControl.java b/services/autofill/java/com/android/server/autofill/ui/OverlayControl.java
index fe0611eef0a2..49f4b538448e 100644
--- a/services/autofill/java/com/android/server/autofill/ui/OverlayControl.java
+++ b/services/autofill/java/com/android/server/autofill/ui/OverlayControl.java
@@ -21,6 +21,7 @@ import android.app.AppOpsManager;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
+import android.os.UserHandle;
/**
* This class controls showing/hiding overlays. We don't
@@ -47,10 +48,10 @@ class OverlayControl {
private void setOverlayAllowed(boolean allowed) {
if (mAppOpsManager != null) {
- mAppOpsManager.setUserRestriction(
- AppOpsManager.OP_SYSTEM_ALERT_WINDOW, !allowed, mToken);
- mAppOpsManager.setUserRestriction(
- AppOpsManager.OP_TOAST_WINDOW, !allowed, mToken);
+ mAppOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, !allowed,
+ mToken, null, UserHandle.USER_ALL);
+ mAppOpsManager.setUserRestrictionForUser(AppOpsManager.OP_TOAST_WINDOW, !allowed,
+ mToken, null, UserHandle.USER_ALL);
}
}
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index c9e2a928dee0..e8dc3c1aea06 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -24,13 +24,18 @@ import android.app.Dialog;
import android.content.Context;
import android.content.IntentSender;
import android.os.Handler;
+import android.service.autofill.CustomDescription;
import android.service.autofill.SaveInfo;
+import android.service.autofill.ValueFinder;
import android.text.Html;
+import android.text.method.LinkMovementMethod;
import android.util.ArraySet;
import android.util.Slog;
import android.view.Gravity;
import android.view.Window;
import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
import android.widget.TextView;
import android.view.LayoutInflater;
import android.view.View;
@@ -107,14 +112,15 @@ final class SaveUi {
private boolean mDestroyed;
SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel, @NonNull SaveInfo info,
- @NonNull OverlayControl overlayControl, @NonNull OnSaveListener listener) {
+ @NonNull ValueFinder valueFinder, @NonNull OverlayControl overlayControl,
+ @NonNull OnSaveListener listener) {
mListener = new OneTimeListener(listener);
mOverlayControl = overlayControl;
final LayoutInflater inflater = LayoutInflater.from(context);
final View view = inflater.inflate(R.layout.autofill_save, null);
- final TextView titleView = (TextView) view.findViewById(R.id.autofill_save_title);
+ final TextView titleView = view.findViewById(R.id.autofill_save_title);
final ArraySet<String> types = new ArraySet<>(3);
final int type = info.getType();
@@ -135,6 +141,23 @@ final class SaveUi {
types.add(context.getString(R.string.autofill_save_type_email_address));
}
+ final CustomDescription customDescription = info.getCustomDescription();
+
+ if (customDescription != null) {
+ // TODO(b/62534917): add CTS test
+ if (sDebug) Slog.d(TAG, "Using custom description");
+
+ final RemoteViews presentation = customDescription.getPresentation(valueFinder);
+ if (presentation != null) {
+ final View remote = presentation.apply(context, null);
+ final LinearLayout layout = view.findViewById(R.id.autofill_save_custom_subtitle);
+ layout.addView(remote);
+ layout.setVisibility(View.VISIBLE);
+ } else {
+ Slog.w(TAG, "could not create remote presentation for custom title");
+ }
+ }
+
switch (types.size()) {
case 1:
mTitle = Html.fromHtml(context.getString(R.string.autofill_save_title_with_type,
@@ -162,9 +185,7 @@ final class SaveUi {
subTitleView.setVisibility(View.VISIBLE);
}
- if (sDebug) {
- Slog.d(TAG, "on constructor: title=" + mTitle + ", subTitle=" + mSubTitle);
- }
+ if (sDebug) Slog.d(TAG, "on constructor: title=" + mTitle + ", subTitle=" + mSubTitle);
final TextView noButton = view.findViewById(R.id.autofill_save_no);
if (info.getNegativeActionStyle() == SaveInfo.NEGATIVE_BUTTON_STYLE_REJECT) {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 4810f4fe8c82..f47b0d3c6e73 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -383,7 +383,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
findDeviceCallback,
getServiceCallback());
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ Log.e(LOG_TAG, "Error while initiating device discovery", e);
}
}
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 2e962d534e67..c90b40209fb8 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -26,7 +26,7 @@ LOCAL_JAVA_LIBRARIES := \
LOCAL_STATIC_JAVA_LIBRARIES := \
time_zone_distro \
- tzdata_update2 \
+ time_zone_distro_installer \
android.hidl.base-V1.0-java-static \
android.hardware.weaver-V1.0-java-static \
android.hardware.biometrics.fingerprint-V2.1-java-static \
@@ -46,4 +46,16 @@ LOCAL_JACK_FLAGS := \
-D jack.transformations.boost-locked-region-priority.request=com.android.server.am.ActivityManagerService\#boostPriorityForLockedSection,com.android.server.wm.WindowManagerService\#boostPriorityForLockedSection \
-D jack.transformations.boost-locked-region-priority.reset=com.android.server.am.ActivityManagerService\#resetPriorityAfterLockedSection,com.android.server.wm.WindowManagerService\#resetPriorityAfterLockedSection
+LOCAL_JAR_PROCESSOR := lockedregioncodeinjection
+# Use = instead of := to delay evaluation of ${in} and ${out}
+LOCAL_JAR_PROCESSOR_ARGS = \
+ --targets \
+ "Lcom/android/server/am/ActivityManagerService;,Lcom/android/server/wm/WindowHashMap;" \
+ --pre \
+ "com/android/server/am/ActivityManagerService.boostPriorityForLockedSection,com/android/server/wm/WindowManagerService.boostPriorityForLockedSection" \
+ --post \
+ "com/android/server/am/ActivityManagerService.resetPriorityAfterLockedSection,com/android/server/wm/WindowManagerService.resetPriorityAfterLockedSection" \
+ -o ${out} \
+ -i ${in}
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index c8e6e2efb240..29f8a1130792 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -16,22 +16,6 @@
package com.android.server;
-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.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityThread;
@@ -42,6 +26,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.UserInfo;
import android.media.AudioAttributes;
import android.os.AsyncTask;
import android.os.Binder;
@@ -55,6 +40,7 @@ import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.UserHandle;
+import android.os.UserManager;
import android.os.storage.StorageManagerInternal;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -66,8 +52,8 @@ import android.util.SparseIntArray;
import android.util.TimeUtils;
import android.util.Xml;
-import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsService;
import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
@@ -76,10 +62,27 @@ import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import libcore.util.EmptyArray;
+
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.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
public class AppOpsService extends IAppOpsService.Stub {
static final String TAG = "AppOps";
static final boolean DEBUG = false;
@@ -2526,38 +2529,56 @@ public class AppOpsService extends IAppOpsService.Stub {
perUserRestrictions = new SparseArray<>();
}
- if (perUserRestrictions != null) {
- boolean[] userRestrictions = perUserRestrictions.get(userId);
- if (userRestrictions == null && restricted) {
- userRestrictions = new boolean[AppOpsManager._NUM_OP];
- perUserRestrictions.put(userId, userRestrictions);
- }
- if (userRestrictions != null && userRestrictions[code] != restricted) {
- userRestrictions[code] = restricted;
- if (!restricted && isDefault(userRestrictions)) {
- perUserRestrictions.remove(userId);
- userRestrictions = null;
- }
- changed = true;
+ int[] users;
+ if (userId == UserHandle.USER_ALL) {
+ List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false);
+
+ users = new int[liveUsers.size()];
+ for (int i = 0; i < liveUsers.size(); i++) {
+ users[i] = liveUsers.get(i).id;
}
+ } else {
+ users = new int[]{userId};
+ }
- if (userRestrictions != null) {
- final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
- if (perUserExcludedPackages == null && !noExcludedPackages) {
- perUserExcludedPackages = new SparseArray<>();
+ if (perUserRestrictions != null) {
+ int numUsers = users.length;
+
+ for (int i = 0; i < numUsers; i++) {
+ int thisUserId = users[i];
+
+ boolean[] userRestrictions = perUserRestrictions.get(thisUserId);
+ if (userRestrictions == null && restricted) {
+ userRestrictions = new boolean[AppOpsManager._NUM_OP];
+ perUserRestrictions.put(thisUserId, userRestrictions);
}
- if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
- perUserExcludedPackages.get(userId))) {
- if (noExcludedPackages) {
- perUserExcludedPackages.remove(userId);
- if (perUserExcludedPackages.size() <= 0) {
- perUserExcludedPackages = null;
- }
- } else {
- perUserExcludedPackages.put(userId, excludedPackages);
+ if (userRestrictions != null && userRestrictions[code] != restricted) {
+ userRestrictions[code] = restricted;
+ if (!restricted && isDefault(userRestrictions)) {
+ perUserRestrictions.remove(thisUserId);
+ userRestrictions = null;
}
changed = true;
}
+
+ if (userRestrictions != null) {
+ final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackages);
+ if (perUserExcludedPackages == null && !noExcludedPackages) {
+ perUserExcludedPackages = new SparseArray<>();
+ }
+ if (perUserExcludedPackages != null && !Arrays.equals(excludedPackages,
+ perUserExcludedPackages.get(thisUserId))) {
+ if (noExcludedPackages) {
+ perUserExcludedPackages.remove(thisUserId);
+ if (perUserExcludedPackages.size() <= 0) {
+ perUserExcludedPackages = null;
+ }
+ } else {
+ perUserExcludedPackages.put(thisUserId, excludedPackages);
+ }
+ changed = true;
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 61057dd25444..75206e48aa8b 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -86,6 +86,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private static final int ACTIVE_LOG_MAX_SIZE = 20;
private static final int CRASH_LOG_MAX_SIZE = 100;
private static final String REASON_AIRPLANE_MODE = "airplane mode";
+ private static final String REASON_DISALLOWED = "disallowed by system";
+ private static final String REASON_SHARING_DISALLOWED = "sharing disallowed by system";
private static final String REASON_RESTARTED = "automatic restart";
private static final String REASON_START_CRASH = "turn-on crash";
private static final String REASON_SYSTEM_BOOT = "system boot";
@@ -227,25 +229,26 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
@Override
public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
Bundle prevRestrictions) {
- if (!UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions,
- UserManager.DISALLOW_BLUETOOTH, UserManager.DISALLOW_BLUETOOTH_SHARING)) {
- return; // No relevant changes, nothing to do.
- }
- final boolean disallowed = newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH);
+ if (UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions,
+ UserManager.DISALLOW_BLUETOOTH_SHARING)) {
+ updateOppLauncherComponentState(userId, newRestrictions.getBoolean(
+ UserManager.DISALLOW_BLUETOOTH_SHARING));
+ }
- // DISALLOW_BLUETOOTH is a global restriction that can only be set by DO or PO on the
- // system user, so we only look at the system user.
- if (userId == UserHandle.USER_SYSTEM && disallowed && (mEnable || mEnableExternal)) {
- try {
- disable(null /* packageName */, true /* persist */);
- } catch (RemoteException e) {
- Slog.w(TAG, "Exception when disabling Bluetooth", e);
+ // DISALLOW_BLUETOOTH can only be set by DO or PO on the system user.
+ if (userId == UserHandle.USER_SYSTEM &&
+ UserRestrictionsUtils.restrictionsChanged(
+ prevRestrictions, newRestrictions, UserManager.DISALLOW_BLUETOOTH)) {
+ if (userId == UserHandle.USER_SYSTEM && newRestrictions.getBoolean(
+ UserManager.DISALLOW_BLUETOOTH)) {
+ updateOppLauncherComponentState(userId, true); // Sharing disallowed
+ sendDisableMsg(REASON_DISALLOWED);
+ } else {
+ updateOppLauncherComponentState(userId, newRestrictions.getBoolean(
+ UserManager.DISALLOW_BLUETOOTH_SHARING));
}
}
- final boolean sharingDisallowed = disallowed
- || newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH_SHARING);
- updateOppLauncherComponentState(userId, sharingDisallowed);
}
};
@@ -2118,7 +2121,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
: PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
try {
final IPackageManager imp = AppGlobals.getPackageManager();
- imp.setComponentEnabledSetting(oppLauncherComponent, newState, 0 /* flags */, userId);
+ imp.setComponentEnabledSetting(oppLauncherComponent, newState,
+ PackageManager.DONT_KILL_APP, userId);
} catch (Exception e) {
// The component was not found, do nothing.
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 98389a663f5e..a2ba7aff20c4 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -210,13 +210,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
// See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
private final int mReleasePendingIntentDelayMs;
- // Driver specific constants used to select packets received via
- // WiFi that caused the phone to exit sleep state. Currently there
- // is only one kernel implementation so we can get away with
- // constants.
- private static final int mWakeupPacketMark = 0x80000000;
- private static final int mWakeupPacketMask = 0x80000000;
-
private MockableSystemProperties mSystemProperties;
private Tethering mTethering;
@@ -2282,6 +2275,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
mKeepaliveTracker.handleStopAllKeepalives(nai,
ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
+ for (String iface : nai.linkProperties.getAllInterfaceNames()) {
+ // Disable wakeup packet monitoring for each interface.
+ wakeupModifyInterface(iface, nai.networkCapabilities, false);
+ }
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
mNetworkAgentInfos.remove(msg.replyTo);
updateClat(null, nai.linkProperties, nai);
@@ -3791,6 +3788,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
public void setProvisioningNotificationVisible(boolean visible, int networkType,
String action) {
enforceConnectivityInternalPermission();
+ if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
+ return;
+ }
final long ident = Binder.clearCallingIdentity();
try {
// Concatenate the range of types onto the range of NetIDs.
@@ -4405,22 +4405,35 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void wakeupAddInterface(String iface, NetworkCapabilities caps) throws RemoteException {
+ private void wakeupModifyInterface(String iface, NetworkCapabilities caps, boolean add) {
// Marks are only available on WiFi interaces. Checking for
// marks on unsupported interfaces is harmless.
if (!caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
return;
}
- mNetd.getNetdService().wakeupAddInterface(
- iface, "iface:" + iface, mWakeupPacketMark, mWakeupPacketMask);
- }
- private void wakeupDelInterface(String iface, NetworkCapabilities caps) throws RemoteException {
- if (!caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+ int mark = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_networkWakeupPacketMark);
+ int mask = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_networkWakeupPacketMask);
+
+ // Mask/mark of zero will not detect anything interesting.
+ // Don't install rules unless both values are nonzero.
+ if (mark == 0 || mask == 0) {
return;
}
- mNetd.getNetdService().wakeupDelInterface(
- iface, "iface:" + iface, mWakeupPacketMark, mWakeupPacketMask);
+
+ final String prefix = "iface:" + iface;
+ try {
+ if (add) {
+ mNetd.getNetdService().wakeupAddInterface(iface, prefix, mark, mask);
+ } else {
+ mNetd.getNetdService().wakeupDelInterface(iface, prefix, mark, mask);
+ }
+ } catch (Exception e) {
+ loge("Exception modifying wakeup packet monitoring: " + e);
+ }
+
}
private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId,
@@ -4435,7 +4448,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
try {
if (DBG) log("Adding iface " + iface + " to network " + netId);
mNetd.addInterfaceToNetwork(iface, netId);
- wakeupAddInterface(iface, caps);
+ wakeupModifyInterface(iface, caps, true);
} catch (Exception e) {
loge("Exception adding interface: " + e);
}
@@ -4443,8 +4456,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
for (String iface : interfaceDiff.removed) {
try {
if (DBG) log("Removing iface " + iface + " from network " + netId);
+ wakeupModifyInterface(iface, caps, false);
mNetd.removeInterfaceFromNetwork(iface, netId);
- wakeupDelInterface(iface, caps);
} catch (Exception e) {
loge("Exception removing interface: " + e);
}
@@ -4941,7 +4954,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (newNetwork.getCurrentScore() != score) {
Slog.wtf(TAG, String.format(
"BUG: %s changed score during rematch: %d -> %d",
- score, newNetwork.getCurrentScore()));
+ newNetwork.name(), score, newNetwork.getCurrentScore()));
}
// Second pass: process all listens.
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 4c9495a786c3..a903f3dff0ae 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -57,7 +57,7 @@ import com.android.server.statusbar.StatusBarManagerInternal;
*/
public class GestureLauncherService extends SystemService {
private static final boolean DBG = false;
- private static final boolean DBG_CAMERA_LIFT = true; // false once b/62623620 is fixed
+ private static final boolean DBG_CAMERA_LIFT = false;
private static final String TAG = "GestureLauncherService";
/**
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 098b43c897e7..7a9bf216e863 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -642,57 +642,6 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
}
- @Override
- public void setCurrentSpellChecker(String locale, String sciId) {
- if (!calledFromValidUser()) {
- return;
- }
- synchronized(mSpellCheckerMap) {
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- "Requires permission "
- + android.Manifest.permission.WRITE_SECURE_SETTINGS);
- }
- setCurrentSpellCheckerLocked(sciId);
- }
- }
-
- @Override
- public void setCurrentSpellCheckerSubtype(String locale, int hashCode) {
- if (!calledFromValidUser()) {
- return;
- }
- synchronized(mSpellCheckerMap) {
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- "Requires permission "
- + android.Manifest.permission.WRITE_SECURE_SETTINGS);
- }
- setCurrentSpellCheckerSubtypeLocked(hashCode);
- }
- }
-
- @Override
- public void setSpellCheckerEnabled(boolean enabled) {
- if (!calledFromValidUser()) {
- return;
- }
- synchronized(mSpellCheckerMap) {
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- "Requires permission "
- + android.Manifest.permission.WRITE_SECURE_SETTINGS);
- }
- setSpellCheckerEnabledLocked(enabled);
- }
- }
-
private void setCurrentSpellCheckerLocked(String sciId) {
if (DBG) {
Slog.w(TAG, "setCurrentSpellChecker: " + sciId);
@@ -732,18 +681,6 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
}
- private void setSpellCheckerEnabledLocked(boolean enabled) {
- if (DBG) {
- Slog.w(TAG, "setSpellCheckerEnabled: " + enabled);
- }
- final long ident = Binder.clearCallingIdentity();
- try {
- mSettings.setSpellCheckerEnabled(enabled);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
private boolean isSpellCheckerEnabledLocked() {
final long ident = Binder.clearCallingIdentity();
try {
@@ -1135,10 +1072,6 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
return Settings.Secure.getIntForUser(mResolver, key, defaultValue, mCurrentUserId);
}
- private void putBoolean(final String key, final boolean value) {
- putInt(key, value ? 1 : 0);
- }
-
private boolean getBoolean(final String key, final boolean defaultValue) {
return getInt(key, defaultValue ? 1 : 0) == 1;
}
@@ -1178,10 +1111,6 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
putInt(Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, hashCode);
}
- public void setSpellCheckerEnabled(boolean enabled) {
- putBoolean(Settings.Secure.SPELL_CHECKER_ENABLED, enabled);
- }
-
@NonNull
public String getSelectedSpellChecker() {
return getString(Settings.Secure.SELECTED_SPELL_CHECKER, "");
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index f440100b7621..3a9bf1258d12 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -91,7 +91,6 @@ class ActivityManagerDebugConfig {
static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false;
- static final boolean DEBUG_VISIBLE_BEHIND = DEBUG_ALL_ACTIVITIES || false;
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;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f51947832604..3566c2962727 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -20,6 +20,7 @@ import static android.Manifest.permission.CHANGE_CONFIGURATION;
import static android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
@@ -135,7 +136,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVE
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_URI_PERMISSION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_WHITELISTS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
@@ -1499,11 +1499,7 @@ public class ActivityManagerService extends IActivityManager.Stub
boolean mControllerIsAMonkey = false;
String mProfileApp = null;
ProcessRecord mProfileProc = null;
- String mProfileFile;
- ParcelFileDescriptor mProfileFd;
- int mSamplingInterval = 0;
- boolean mAutoStopProfiler = false;
- boolean mStreamingOutput = false;
+ ProfilerInfo mProfilerInfo = null;
int mProfileType = 0;
final ProcessMap<Pair<Long, String>> mMemWatchProcesses = new ProcessMap<>();
String mMemWatchDumpProcName;
@@ -6909,19 +6905,19 @@ public class ActivityManagerService extends IActivityManager.Stub
mWaitForDebugger = mOrigWaitForDebugger;
}
}
- String profileFile = app.instr != null ? app.instr.mProfileFile : null;
- ParcelFileDescriptor profileFd = null;
- int samplingInterval = 0;
- boolean profileAutoStop = false;
- boolean profileStreamingOutput = false;
+
+ ProfilerInfo profilerInfo = null;
+ String agent = null;
if (mProfileApp != null && mProfileApp.equals(processName)) {
mProfileProc = app;
- profileFile = mProfileFile;
- profileFd = mProfileFd;
- samplingInterval = mSamplingInterval;
- profileAutoStop = mAutoStopProfiler;
- profileStreamingOutput = mStreamingOutput;
+ profilerInfo = (mProfilerInfo != null && mProfilerInfo.profileFile != null) ?
+ new ProfilerInfo(mProfilerInfo) : null;
+ agent = profilerInfo.agent;
+ } else if (app.instr != null && app.instr.mProfileFile != null) {
+ profilerInfo = new ProfilerInfo(app.instr.mProfileFile, null, 0, false, false,
+ null);
}
+
boolean enableTrackAllocation = false;
if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) {
enableTrackAllocation = true;
@@ -6945,12 +6941,10 @@ public class ActivityManagerService extends IActivityManager.Stub
+ processName + " with config " + getGlobalConfiguration());
ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info;
app.compat = compatibilityInfoForPackageLocked(appInfo);
- if (profileFd != null) {
- profileFd = profileFd.dup();
+
+ if (profilerInfo != null && profilerInfo.profileFd != null) {
+ profilerInfo.profileFd = profilerInfo.profileFd.dup();
}
- ProfilerInfo profilerInfo = profileFile == null ? null
- : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop,
- profileStreamingOutput);
// We deprecated Build.SERIAL and it is not accessible to
// apps that target the v2 security sandbox. Since access to
@@ -6990,6 +6984,12 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ // If we were asked to attach an agent on startup, do so now, before we're binding
+ // application code.
+ if (agent != null) {
+ thread.attachAgent(agent);
+ }
+
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
mStackSupervisor.mActivityMetricsLogger.notifyBindApplication(app);
if (app.instr != null) {
@@ -7125,11 +7125,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mStackSupervisor.activityIdleInternalLocked(token, false /* fromTimeout */,
false /* processPausingActivities */, config);
if (stopProfiling) {
- if ((mProfileProc == r.app) && (mProfileFd != null)) {
- try {
- mProfileFd.close();
- } catch (IOException e) {
- }
+ if ((mProfileProc == r.app) && mProfilerInfo != null) {
clearProfilerLocked();
}
}
@@ -7403,21 +7399,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public final void backgroundResourcesReleased(IBinder token) {
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (this) {
- ActivityStack stack = ActivityRecord.getStackLocked(token);
- if (stack != null) {
- stack.backgroundResourcesReleased();
- }
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- @Override
public final void notifyLaunchTaskBehindComplete(IBinder token) {
mStackSupervisor.scheduleLaunchTaskBehindComplete(token);
}
@@ -10320,7 +10301,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void moveStackToDisplay(int stackId, int displayId) {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveStackToDisplay()");
+ enforceCallingPermission(INTERNAL_SYSTEM_WINDOW, "moveStackToDisplay()");
synchronized (this) {
final long ident = Binder.clearCallingIdentity();
@@ -12753,18 +12734,16 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
mProfileApp = processName;
- mProfileFile = profilerInfo.profileFile;
- if (mProfileFd != null) {
- try {
- mProfileFd.close();
- } catch (IOException e) {
+
+ if (mProfilerInfo != null) {
+ if (mProfilerInfo.profileFd != null) {
+ try {
+ mProfilerInfo.profileFd.close();
+ } catch (IOException e) {
+ }
}
- mProfileFd = null;
}
- mProfileFd = profilerInfo.profileFd;
- mSamplingInterval = profilerInfo.samplingInterval;
- mAutoStopProfiler = profilerInfo.autoStopProfiler;
- mStreamingOutput = profilerInfo.streamingOutput;
+ mProfilerInfo = new ProfilerInfo(profilerInfo);
mProfileType = 0;
}
}
@@ -13302,7 +13281,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
final boolean translucentChanged = r.changeWindowTranslucency(true);
if (translucentChanged) {
- r.getStack().releaseBackgroundResources(r);
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
mWindowManager.setAppFullscreen(token, true);
@@ -13342,38 +13320,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public boolean requestVisibleBehind(IBinder token, boolean visible) {
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (this) {
- final ActivityRecord r = ActivityRecord.isInStackLocked(token);
- if (r != null) {
- return mStackSupervisor.requestVisibleBehindLocked(r, visible);
- }
- }
- return false;
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- @Override
- public boolean isBackgroundVisibleBehind(IBinder token) {
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (this) {
- final ActivityStack stack = ActivityRecord.getStackLocked(token);
- final boolean visible = stack == null ? false : stack.hasVisibleBehindActivity();
- if (DEBUG_VISIBLE_BEHIND) Slog.d(TAG_VISIBLE_BEHIND,
- "isBackgroundVisibleBehind: stack=" + stack + " visible=" + visible);
- return visible;
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- @Override
public Bundle getActivityOptions(IBinder token) {
final long origId = Binder.clearCallingIdentity();
try {
@@ -15927,18 +15873,22 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.println(" mTrackAllocationApp=" + mTrackAllocationApp);
}
}
- if (mProfileApp != null || mProfileProc != null || mProfileFile != null
- || mProfileFd != null) {
+ if (mProfileApp != null || mProfileProc != null || (mProfilerInfo != null &&
+ (mProfilerInfo.profileFile != null || mProfilerInfo.profileFd != null))) {
if (dumpPackage == null || dumpPackage.equals(mProfileApp)) {
if (needSep) {
pw.println();
needSep = false;
}
pw.println(" mProfileApp=" + mProfileApp + " mProfileProc=" + mProfileProc);
- pw.println(" mProfileFile=" + mProfileFile + " mProfileFd=" + mProfileFd);
- pw.println(" mSamplingInterval=" + mSamplingInterval + " mAutoStopProfiler="
- + mAutoStopProfiler + " mStreamingOutput=" + mStreamingOutput);
- pw.println(" mProfileType=" + mProfileType);
+ if (mProfilerInfo != null) {
+ pw.println(" mProfileFile=" + mProfilerInfo.profileFile + " mProfileFd=" +
+ mProfilerInfo.profileFd);
+ pw.println(" mSamplingInterval=" + mProfilerInfo.samplingInterval +
+ " mAutoStopProfiler=" + mProfilerInfo.autoStopProfiler +
+ " mStreamingOutput=" + mProfilerInfo.streamingOutput);
+ pw.println(" mProfileType=" + mProfileType);
+ }
}
}
if (mNativeDebuggingApp != null) {
@@ -23257,19 +23207,15 @@ public class ActivityManagerService extends IActivityManager.Stub
}
private void clearProfilerLocked() {
- if (mProfileFd != null) {
+ if (mProfilerInfo !=null && mProfilerInfo.profileFd != null) {
try {
- mProfileFd.close();
+ mProfilerInfo.profileFd.close();
} catch (IOException e) {
}
}
mProfileApp = null;
mProfileProc = null;
- mProfileFile = null;
- mProfileType = 0;
- mAutoStopProfiler = false;
- mStreamingOutput = false;
- mSamplingInterval = 0;
+ mProfilerInfo = null;
}
public boolean profileControl(String process, int userId, boolean start,
@@ -23313,10 +23259,10 @@ public class ActivityManagerService extends IActivityManager.Stub
proc.thread.profilerControl(start, profilerInfo, profileType);
fd = null;
try {
- mProfileFd.close();
+ mProfilerInfo.profileFd.close();
} catch (IOException e) {
}
- mProfileFd = null;
+ mProfilerInfo.profileFd = null;
} else {
stopProfilerLocked(proc, profileType);
if (profilerInfo != null && profilerInfo.profileFd != null) {
@@ -24495,4 +24441,37 @@ public class ActivityManagerService extends IActivityManager.Stub
return mNmi != null;
}
}
+
+ @Override
+ public void setShowWhenLocked(IBinder token, boolean showWhenLocked)
+ throws RemoteException {
+ synchronized (this) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null) {
+ return;
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ r.setShowWhenLocked(showWhenLocked);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
+
+ @Override
+ public void setTurnScreenOn(IBinder token, boolean turnScreenOn) throws RemoteException {
+ synchronized (this) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null) {
+ return;
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ r.setTurnScreenOn(turnScreenOn);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index d7683047143a..f0a886dfcb08 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -114,6 +114,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
private int mSamplingInterval;
private boolean mAutoStop;
private boolean mStreaming; // Streaming the profiling output to a file.
+ private String mAgent; // Agent to attach on startup.
private int mDisplayId;
private int mStackId;
private int mTaskId;
@@ -292,6 +293,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
mSamplingInterval = Integer.parseInt(getNextArgRequired());
} else if (opt.equals("--streaming")) {
mStreaming = true;
+ } else if (opt.equals("--attach-agent")) {
+ mAgent = getNextArgRequired();
} else if (opt.equals("-R")) {
mRepeat = Integer.parseInt(getNextArgRequired());
} else if (opt.equals("-S")) {
@@ -368,13 +371,16 @@ final class ActivityManagerShellCommand extends ShellCommand {
ProfilerInfo profilerInfo = null;
- if (mProfileFile != null) {
- ParcelFileDescriptor fd = openOutputFileForSystem(mProfileFile);
- if (fd == null) {
- return 1;
+ if (mProfileFile != null || mAgent != null) {
+ ParcelFileDescriptor fd = null;
+ if (mProfileFile != null) {
+ fd = openOutputFileForSystem(mProfileFile);
+ if (fd == null) {
+ return 1;
+ }
}
profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop,
- mStreaming);
+ mStreaming, mAgent);
}
pw.println("Starting: " + intent);
@@ -747,7 +753,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
if (fd == null) {
return -1;
}
- profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false, mStreaming);
+ profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false, mStreaming,
+ null);
}
try {
@@ -2490,6 +2497,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" --streaming: stream the profiling output to the specified file");
pw.println(" (use with --start-profiler)");
pw.println(" -P <FILE>: like above, but profiling stops when app goes idle");
+ pw.println(" --attach-agent <agent>: attach the given agent before binding");
pw.println(" -R: repeat the activity launch <COUNT> times. Prior to each repeat,");
pw.println(" the top activity will be finished.");
pw.println(" -S: force stop the target app before starting the activity");
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index c7cac3be5bc9..4b2b6a77deb6 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -47,11 +47,13 @@ import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
import static android.content.pm.ActivityInfo.FLAG_MULTIPROCESS;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED;
+import static android.content.pm.ActivityInfo.FLAG_TURN_SCREEN_ON;
import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
@@ -344,6 +346,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
// handle calculating override configuration from the bounds.
private final Rect mBounds = new Rect();
+ private boolean mShowWhenLocked;
+ private boolean mTurnScreenOn;
+
/**
* Temp configs used in {@link #ensureActivityConfigurationLocked(int, boolean)}
*/
@@ -904,6 +909,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
requestedVrComponent = (aInfo.requestedVrComponent == null) ?
null : ComponentName.unflattenFromString(aInfo.requestedVrComponent);
+
+ mShowWhenLocked = (aInfo.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
+ mTurnScreenOn = (aInfo.flags & FLAG_TURN_SCREEN_ON) != 0;
}
AppWindowContainerController getWindowContainerController() {
@@ -1258,13 +1266,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
}
- /**
- * @return true if the activity contains windows that have
- * {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set
- */
- boolean hasShowWhenLockedWindows() {
- return service.mWindowManager.containsShowWhenLockedWindow(appToken);
- }
/**
* @return true if the activity contains windows that have
@@ -1275,20 +1276,16 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
void makeFinishingLocked() {
- if (!finishing) {
- final ActivityStack stack = getStack();
- if (stack != null && this == stack.getVisibleBehindActivity()) {
- // A finishing activity should not remain as visible in the background
- mStackSupervisor.requestVisibleBehindLocked(this, false);
- }
- finishing = true;
- if (stopped) {
- clearOptionsLocked();
- }
+ if (finishing) {
+ return;
+ }
+ finishing = true;
+ if (stopped) {
+ clearOptionsLocked();
+ }
- if (service != null) {
- service.mTaskChangeNotificationController.notifyTaskStackChanged();
- }
+ if (service != null) {
+ service.mTaskChangeNotificationController.notifyTaskStackChanged();
}
}
@@ -1345,11 +1342,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
intent, getUriPermissionsLocked(), userId);
final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
boolean unsent = true;
- final ActivityStack stack = getStack();
- final boolean isTopActivityInStack =
- stack != null && stack.topRunningActivityLocked() == this;
- final boolean isTopActivityWhileSleeping =
- service.isSleepingLocked() && isTopActivityInStack;
+ final boolean isTopActivityWhileSleeping = service.isSleepingLocked() && isTopRunningActivity();
// We want to immediately deliver the intent to the activity if:
// - It is currently resumed or paused. i.e. it is currently visible to the user and we want
@@ -1621,20 +1614,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
*
* @see {@link ActivityStack#checkKeyguardVisibility}
*/
- boolean shouldBeVisibleIgnoringKeyguard(boolean behindTranslucentActivity,
- boolean stackVisibleBehind, ActivityRecord visibleBehind,
- boolean behindFullscreenActivity) {
+ boolean shouldBeVisibleIgnoringKeyguard(boolean behindFullscreenActivity) {
if (!okToShowLocked()) {
return false;
}
- // mLaunchingBehind: Activities launching behind are at the back of the task stack
- // but must be drawn initially for the animation as though they were visible.
- final boolean activityVisibleBehind =
- (behindTranslucentActivity || stackVisibleBehind) && visibleBehind == this;
-
- boolean isVisible =
- !behindFullscreenActivity || mLaunchTaskBehind || activityVisibleBehind;
+ boolean isVisible = !behindFullscreenActivity || mLaunchTaskBehind;
if (service.mSupportsLeanbackOnly && isVisible && isRecentsActivity()) {
// On devices that support leanback only (Android TV), Recents activity can only be
@@ -1746,11 +1731,14 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
returningOptions = null;
- if (stack.getVisibleBehindActivity() == this) {
- // When resuming an activity, require it to call requestVisibleBehind() again.
- stack.setVisibleBehindActivity(null /* ActivityRecord */);
+ if (canTurnScreenOn()) {
+ mStackSupervisor.wakeUp("turnScreenOnFlag");
+ } else {
+ // If the screen is going to turn on because the caller explicitly requested it and
+ // the keyguard is not showing don't attempt to sleep. Otherwise the Activity will
+ // pause and then resume again later, which will result in a double life-cycle event.
+ mStackSupervisor.checkReadyForSleepLocked();
}
- mStackSupervisor.checkReadyForSleepLocked();
}
final void activityStoppedLocked(Bundle newIcicle, PersistableBundle newPersistentState,
@@ -1783,9 +1771,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
mWindowContainerController.notifyAppStopped();
- if (stack.getVisibleBehindActivity() == this) {
- mStackSupervisor.requestVisibleBehindLocked(this, false /* visible */);
- }
if (finishing) {
clearOptionsLocked();
} else {
@@ -2817,6 +2802,44 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
return info.applicationInfo.uid;
}
+ void setShowWhenLocked(boolean showWhenLocked) {
+ mShowWhenLocked = showWhenLocked;
+ }
+
+ /**
+ * @return true if the activity contains windows that have
+ * {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set or if the activity has set
+ * {@link #mShowWhenLocked}.
+ */
+ boolean canShowWhenLocked() {
+ return mShowWhenLocked || service.mWindowManager.containsShowWhenLockedWindow(appToken);
+ }
+
+ void setTurnScreenOn(boolean turnScreenOn) {
+ mTurnScreenOn = turnScreenOn;
+ }
+
+ /**
+ * Determines whether this ActivityRecord can turn the screen on. It checks whether the flag
+ * {@link #mTurnScreenOn} is set and checks whether the ActivityRecord should be visible
+ * depending on Keyguard state
+ *
+ * @return true if the screen can be turned on, false otherwise.
+ */
+ boolean canTurnScreenOn() {
+ final ActivityStack stack = getStack();
+ return mTurnScreenOn && stack != null &&
+ stack.checkKeyguardVisibility(this, true /* shouldBeVisible */, true /* isTop */);
+ }
+
+ boolean getTurnScreenOnFlag() {
+ return mTurnScreenOn;
+ }
+
+ boolean isTopRunningActivity() {
+ return mStackSupervisor.topRunningActivityLocked() == this;
+ }
+
@Override
public String toString() {
if (stringName != null) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 9cde98598987..77e438a7c610 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -230,9 +230,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
static final int STACK_INVISIBLE = 0;
// Stack is considered visible
static final int STACK_VISIBLE = 1;
- // Stack is considered visible, but only becuase it has activity that is visible behind other
- // activities and there is a specific combination of stacks.
- static final int STACK_VISIBLE_ACTIVITY_BEHIND = 2;
@VisibleForTesting
/* The various modes for the method {@link #removeTask}. */
@@ -365,8 +362,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
static final int STOP_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 4;
static final int DESTROY_ACTIVITIES_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 5;
static final int TRANSLUCENT_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 6;
- static final int RELEASE_BACKGROUND_RESOURCES_TIMEOUT_MSG =
- ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 7;
private static class ScheduleDestroyArgs {
final ProcessRecord mOwner;
@@ -440,15 +435,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
notifyActivityDrawnLocked(null);
}
} break;
- case RELEASE_BACKGROUND_RESOURCES_TIMEOUT_MSG: {
- synchronized (mService) {
- final ActivityRecord r = getVisibleBehindActivity();
- Slog.e(TAG, "Timeout waiting for cancelVisibleBehind player=" + r);
- if (r != null) {
- mService.killAppAtUsersRequest(r.app, null);
- }
- }
- } break;
}
}
}
@@ -1195,15 +1181,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still waiting to pause " + mPausingActivity);
return true;
}
-
- if (hasVisibleBehindActivity()) {
- // Stop visible behind activity before going to sleep.
- final ActivityRecord r = getVisibleBehindActivity();
- mStackSupervisor.mStoppingActivities.add(r);
- if (DEBUG_STATES) Slog.v(TAG_STATES, "Sleep still waiting to stop visible behind " + r);
- return true;
- }
-
return false;
}
@@ -1422,8 +1399,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// We can't clobber it, because the stop confirmation will not be handled.
// We don't need to schedule another stop, we only need to let it happen.
prev.state = STOPPING;
- } else if ((!prev.visible && !hasVisibleBehindActivity())
- || mService.isSleepingOrShuttingDownLocked()) {
+ } else if (!prev.visible || mService.isSleepingOrShuttingDownLocked()) {
// Clear out any deferred client hide we might currently have.
prev.setDeferHidingClient(false);
// If we were visible then resumeTopActivities will release resources before
@@ -1628,8 +1604,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
/**
- * Returns what the stack visibility should be: {@link #STACK_INVISIBLE}, {@link #STACK_VISIBLE}
- * or {@link #STACK_VISIBLE_ACTIVITY_BEHIND}.
+ * Returns what the stack visibility should be: {@link #STACK_INVISIBLE} or
+ * {@link #STACK_VISIBLE}.
*
* @param starting The currently starting activity or null if there is none.
*/
@@ -1654,14 +1630,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
final ActivityStack topStack = getTopStackOnDisplay();
final int topStackId = topStack.mStackId;
- if (StackId.isBackdropToTranslucentActivity(mStackId)
- && hasVisibleBehindActivity() && StackId.isHomeOrRecentsStack(topStackId)
- && (topStack.topActivity() == null || !topStack.topActivity().fullscreen)) {
- // The fullscreen or assistant stack should be visible if it has a visible behind
- // activity behind the home or recents stack that is translucent.
- return STACK_VISIBLE_ACTIVITY_BEHIND;
- }
-
if (mStackId == DOCKED_STACK_ID) {
// If the assistant stack is focused and translucent, then the docked stack is always
// visible
@@ -1780,12 +1748,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
boolean aboveTop = top != null;
final int stackVisibility = shouldBeVisible(starting);
final boolean stackInvisible = stackVisibility != STACK_VISIBLE;
- final boolean stackVisibleBehind = stackVisibility == STACK_VISIBLE_ACTIVITY_BEHIND;
boolean behindFullscreenActivity = stackInvisible;
boolean resumeNextActivity = mStackSupervisor.isFocusedStack(this)
&& (isInStackLocked(starting) == null);
boolean behindTranslucentActivity = false;
- final ActivityRecord visibleBehind = getVisibleBehindActivity();
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
final ArrayList<ActivityRecord> activities = task.mActivities;
@@ -1810,7 +1776,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// Check whether activity should be visible without Keyguard influence
final boolean visibleIgnoringKeyguard = r.shouldBeVisibleIgnoringKeyguard(
- behindTranslucentActivity, stackVisibleBehind, visibleBehind,
behindFullscreenActivity);
r.visibleIgnoringKeyguard = visibleIgnoringKeyguard;
@@ -1862,7 +1827,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
+ stackInvisible + " behindFullscreenActivity="
+ behindFullscreenActivity + " mLaunchTaskBehind="
+ r.mLaunchTaskBehind);
- makeInvisible(r, visibleBehind);
+ makeInvisible(r);
}
}
if (mStackId == FREEFORM_WORKSPACE_STACK_ID) {
@@ -1942,7 +1907,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
final boolean isInPinnedStack = r.getStack().getStackId() == PINNED_STACK_ID;
final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing();
final boolean keyguardLocked = mStackSupervisor.mKeyguardController.isKeyguardLocked();
- final boolean showWhenLocked = r.hasShowWhenLockedWindows() && !isInPinnedStack;
+ final boolean showWhenLocked = r.canShowWhenLocked() && !isInPinnedStack;
final boolean dismissKeyguard = r.hasDismissKeyguardWindows();
if (shouldBeVisible) {
if (dismissKeyguard && mTopDismissingKeyguardActivity == null) {
@@ -2028,7 +1993,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
return false;
}
- private void makeInvisible(ActivityRecord r, ActivityRecord visibleBehind) {
+ // TODO: Should probably be moved into ActivityRecord.
+ private void makeInvisible(ActivityRecord r) {
if (!r.visible) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + r);
return;
@@ -2064,14 +2030,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
case RESUMED:
case PAUSING:
case PAUSED:
- // This case created for transitioning activities from
- // translucent to opaque {@link Activity#convertToOpaque}.
- if (visibleBehind == r) {
- releaseBackgroundResources(r);
- } else {
- addToStopping(r, true /* scheduleIdle */,
- canEnterPictureInPicture /* idleDelayed */);
- }
+ addToStopping(r, true /* scheduleIdle */,
+ canEnterPictureInPicture /* idleDelayed */);
break;
default:
@@ -2216,12 +2176,18 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
+
// When resuming the top activity, it may be necessary to pause the top activity (for
// example, returning to the lock screen. We suppress the normal pause logic in
// {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the end.
// We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here to ensure
- // any necessary pause logic occurs.
- mStackSupervisor.checkReadyForSleepLocked();
+ // any necessary pause logic occurs. In the case where the Activity will be shown regardless
+ // of the lock screen, the call to {@link ActivityStackSupervisor#checkReadyForSleepLocked}
+ // is skipped.
+ final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
+ if (next == null || !next.canTurnScreenOn()) {
+ mStackSupervisor.checkReadyForSleepLocked();
+ }
return result;
}
@@ -3991,10 +3957,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// Get rid of any pending idle timeouts.
removeTimeoutsForActivityLocked(r);
- if (getVisibleBehindActivity() == r) {
- mStackSupervisor.requestVisibleBehindLocked(r, false);
- }
-
// Clean-up activities are no longer relaunching (e.g. app process died). Notify window
// manager so it can update its bookkeeping.
mWindowManager.notifyAppRelaunchesCleared(r.appToken);
@@ -4298,56 +4260,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
}
- void releaseBackgroundResources(ActivityRecord r) {
- if (hasVisibleBehindActivity() &&
- !mHandler.hasMessages(RELEASE_BACKGROUND_RESOURCES_TIMEOUT_MSG)) {
- if (r == topRunningActivityLocked()
- && shouldBeVisible(null) == STACK_VISIBLE) {
- // Don't release the top activity if it has requested to run behind the next
- // activity and the stack is currently visible.
- return;
- }
- if (DEBUG_STATES) Slog.d(TAG_STATES, "releaseBackgroundResources activtyDisplay=" +
- mActivityContainer.mActivityDisplay + " visibleBehind=" + r + " app=" + r.app +
- " thread=" + r.app.thread);
- if (r != null && r.app != null && r.app.thread != null) {
- try {
- r.app.thread.scheduleCancelVisibleBehind(r.appToken);
- } catch (RemoteException e) {
- }
- mHandler.sendEmptyMessageDelayed(RELEASE_BACKGROUND_RESOURCES_TIMEOUT_MSG, 500);
- } else {
- Slog.e(TAG, "releaseBackgroundResources: activity " + r + " no longer running");
- backgroundResourcesReleased();
- }
- }
- }
-
- final void backgroundResourcesReleased() {
- mHandler.removeMessages(RELEASE_BACKGROUND_RESOURCES_TIMEOUT_MSG);
- final ActivityRecord r = getVisibleBehindActivity();
- if (r != null) {
- mStackSupervisor.mStoppingActivities.add(r);
- setVisibleBehindActivity(null);
- mStackSupervisor.scheduleIdleTimeoutLocked(null);
- }
- mStackSupervisor.resumeFocusedStackTopActivityLocked();
- }
-
- boolean hasVisibleBehindActivity() {
- return isAttached() && mActivityContainer.mActivityDisplay.hasVisibleBehindActivity();
- }
-
- void setVisibleBehindActivity(ActivityRecord r) {
- if (isAttached()) {
- mActivityContainer.mActivityDisplay.setVisibleBehindActivity(r);
- }
- }
-
- ActivityRecord getVisibleBehindActivity() {
- return isAttached() ? mActivityContainer.mActivityDisplay.mVisibleBehindActivity : null;
- }
-
private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
ProcessRecord app, String listName) {
int i = list.size();
@@ -4609,28 +4521,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task=" + taskId);
- if (mStackId == HOME_STACK_ID && topTask().isHomeTask()) {
- // For the case where we are moving the home task back and there is an activity visible
- // behind it on the fullscreen or assistant stack, we want to move the focus to the
- // visible behind activity to maintain order with what the user is seeing.
- ActivityRecord visibleBehind = null;
- final ActivityStack fullscreenStack =
- mStackSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID);
- final ActivityStack assistantStack =
- mStackSupervisor.getStack(ASSISTANT_STACK_ID);
- if (fullscreenStack != null && fullscreenStack.hasVisibleBehindActivity()) {
- visibleBehind = fullscreenStack.getVisibleBehindActivity();
- } else if (assistantStack != null && assistantStack.hasVisibleBehindActivity()) {
- visibleBehind = assistantStack.getVisibleBehindActivity();
- }
- if (visibleBehind != null) {
- mStackSupervisor.moveFocusableActivityStackToFrontLocked(visibleBehind,
- "moveTaskToBack");
- mStackSupervisor.resumeFocusedStackTopActivityLocked();
- return true;
- }
- }
-
boolean prevIsHome = false;
// If true, we should resume the home activity next if the task we are moving to the
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index ead8f60c3428..90d9149a2f66 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.START_ANY_ACTIVITY;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
@@ -39,6 +40,7 @@ import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;
+import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_PRIVATE;
@@ -59,7 +61,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONTAINERS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IDLE;
@@ -556,6 +557,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
final KeyguardController mKeyguardController;
+ private PowerManager mPowerManager;
+ private int mDeferResumeCount;
+
/**
* Description of a request to start a new activity, which has been held
* due to app switches being disabled.
@@ -604,9 +608,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
* initialized. So we initialize our wakelocks afterwards.
*/
void initPowerManagement() {
- PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE);
- mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
- mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*launch*");
+ mPowerManager = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE);
+ mGoingToSleep = mPowerManager
+ .newWakeLock(PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
+ mLaunchingActivity = mPowerManager.newWakeLock(PARTIAL_WAKE_LOCK, "*launch*");
mLaunchingActivity.setReferenceCounted(false);
}
@@ -1334,184 +1339,187 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return false;
}
- r.startFreezingScreenLocked(app, 0);
- if (r.getStack().checkKeyguardVisibility(r, true /* shouldBeVisible */, true /* isTop */)) {
- // We only set the visibility to true if the activity is allowed to be visible based on
- // keyguard state. This avoids setting this into motion in window manager that is later
- // cancelled due to later calls to ensure visible activities that set visibility back to
- // false.
- r.setVisibility(true);
- }
+ final TaskRecord task = r.getTask();
+ final ActivityStack stack = task.getStack();
- // schedule launch ticks to collect information about slow apps.
- r.startLaunchTickingLocked();
+ beginDeferResume();
- // Have the window manager re-evaluate the orientation of the screen based on the new
- // activity order. Note that as a result of this, it can call back into the activity
- // manager with a new orientation. We don't care about that, because the activity is not
- // currently running so we are just restarting it anyway.
- if (checkConfig) {
- final int displayId = r.getDisplayId();
- final Configuration config = mWindowManager.updateOrientationFromAppTokens(
- getDisplayOverrideConfiguration(displayId),
- r.mayFreezeScreenLocked(app) ? r.appToken : null, displayId);
- // Deferring resume here because we're going to launch new activity shortly.
- // We don't want to perform a redundant launch of the same record while ensuring
- // configurations and trying to resume top activity of focused stack.
- mService.updateDisplayOverrideConfigurationLocked(config, r, true /* deferResume */,
- displayId);
- }
+ try {
+ r.startFreezingScreenLocked(app, 0);
- if (mKeyguardController.isKeyguardLocked()) {
- r.notifyUnknownVisibilityLaunched();
- }
- final int applicationInfoUid =
- (r.info.applicationInfo != null) ? r.info.applicationInfo.uid : -1;
- if ((r.userId != app.userId) || (r.appInfo.uid != applicationInfoUid)) {
- Slog.wtf(TAG,
- "User ID for activity changing for " + r
- + " appInfo.uid=" + r.appInfo.uid
- + " info.ai.uid=" + applicationInfoUid
- + " old=" + r.app + " new=" + app);
- }
+ // schedule launch ticks to collect information about slow apps.
+ r.startLaunchTickingLocked();
- r.app = app;
- app.waitingToKill = null;
- r.launchCount++;
- r.lastLaunchTime = SystemClock.uptimeMillis();
+ r.app = app;
- if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);
+ // Have the window manager re-evaluate the orientation of the screen based on the new
+ // activity order. Note that as a result of this, it can call back into the activity
+ // manager with a new orientation. We don't care about that, because the activity is
+ // not currently running so we are just restarting it anyway.
+ if (checkConfig) {
+ final int displayId = r.getDisplayId();
+ final Configuration config = mWindowManager.updateOrientationFromAppTokens(
+ getDisplayOverrideConfiguration(displayId),
+ r.mayFreezeScreenLocked(app) ? r.appToken : null, displayId);
+ // Deferring resume here because we're going to launch new activity shortly.
+ // We don't want to perform a redundant launch of the same record while ensuring
+ // configurations and trying to resume top activity of focused stack.
+ mService.updateDisplayOverrideConfigurationLocked(config, r, true /* deferResume */,
+ displayId);
+ }
- int idx = app.activities.indexOf(r);
- if (idx < 0) {
- app.activities.add(r);
- }
- mService.updateLruProcessLocked(app, true, null);
- mService.updateOomAdjLocked();
+ if (r.getStack().checkKeyguardVisibility(r, true /* shouldBeVisible */,
+ true /* isTop */)) {
+ // We only set the visibility to true if the activity is allowed to be visible
+ // based on
+ // keyguard state. This avoids setting this into motion in window manager that is
+ // later cancelled due to later calls to ensure visible activities that set
+ // visibility back to false.
+ r.setVisibility(true);
+ }
- final TaskRecord task = r.getTask();
- if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE ||
- task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV) {
- setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE", false);
- }
+ if (mKeyguardController.isKeyguardLocked()) {
+ r.notifyUnknownVisibilityLaunched();
+ }
+ final int applicationInfoUid =
+ (r.info.applicationInfo != null) ? r.info.applicationInfo.uid : -1;
+ if ((r.userId != app.userId) || (r.appInfo.uid != applicationInfoUid)) {
+ Slog.wtf(TAG,
+ "User ID for activity changing for " + r
+ + " appInfo.uid=" + r.appInfo.uid
+ + " info.ai.uid=" + applicationInfoUid
+ + " old=" + r.app + " new=" + app);
+ }
- final ActivityStack stack = task.getStack();
- try {
- if (app.thread == null) {
- throw new RemoteException();
- }
- List<ResultInfo> results = null;
- List<ReferrerIntent> newIntents = null;
- if (andResume) {
- // We don't need to deliver new intents and/or set results if activity is going
- // to pause immediately after launch.
- results = r.results;
- newIntents = r.newIntents;
- }
- if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
- "Launching: " + r + " icicle=" + r.icicle + " with results=" + results
- + " newIntents=" + newIntents + " andResume=" + andResume);
- EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY, r.userId,
- System.identityHashCode(r), task.taskId, r.shortComponentName);
- if (r.isHomeActivity()) {
- // Home process is the root process of the task.
- mService.mHomeProcess = task.mActivities.get(0).app;
- }
- mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
- PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY);
- r.sleeping = false;
- r.forceNewConfig = false;
- mService.showUnsupportedZoomDialogIfNeededLocked(r);
- mService.showAskCompatModeDialogLocked(r);
- r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
- ProfilerInfo profilerInfo = null;
- if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName)) {
- if (mService.mProfileProc == null || mService.mProfileProc == app) {
- mService.mProfileProc = app;
- final String profileFile = mService.mProfileFile;
- if (profileFile != null) {
- ParcelFileDescriptor profileFd = mService.mProfileFd;
- if (profileFd != null) {
- try {
- profileFd = profileFd.dup();
- } catch (IOException e) {
- if (profileFd != null) {
- try {
- profileFd.close();
- } catch (IOException o) {
- }
- profileFd = null;
+ app.waitingToKill = null;
+ r.launchCount++;
+ r.lastLaunchTime = SystemClock.uptimeMillis();
+
+ if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);
+
+ int idx = app.activities.indexOf(r);
+ if (idx < 0) {
+ app.activities.add(r);
+ }
+ mService.updateLruProcessLocked(app, true, null);
+ mService.updateOomAdjLocked();
+
+ if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE ||
+ task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV) {
+ setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE",
+ false);
+ }
+
+ try {
+ if (app.thread == null) {
+ throw new RemoteException();
+ }
+ List<ResultInfo> results = null;
+ List<ReferrerIntent> newIntents = null;
+ if (andResume) {
+ // We don't need to deliver new intents and/or set results if activity is going
+ // to pause immediately after launch.
+ results = r.results;
+ newIntents = r.newIntents;
+ }
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+ "Launching: " + r + " icicle=" + r.icicle + " with results=" + results
+ + " newIntents=" + newIntents + " andResume=" + andResume);
+ EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY, r.userId,
+ System.identityHashCode(r), task.taskId, r.shortComponentName);
+ if (r.isHomeActivity()) {
+ // Home process is the root process of the task.
+ mService.mHomeProcess = task.mActivities.get(0).app;
+ }
+ mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
+ PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY);
+ r.sleeping = false;
+ r.forceNewConfig = false;
+ mService.showUnsupportedZoomDialogIfNeededLocked(r);
+ mService.showAskCompatModeDialogLocked(r);
+ r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
+ ProfilerInfo profilerInfo = null;
+ if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName)) {
+ if (mService.mProfileProc == null || mService.mProfileProc == app) {
+ mService.mProfileProc = app;
+ ProfilerInfo profilerInfoSvc = mService.mProfilerInfo;
+ if (profilerInfoSvc != null && profilerInfoSvc.profileFile != null) {
+ if (profilerInfoSvc.profileFd != null) {
+ try {
+ profilerInfoSvc.profileFd = profilerInfoSvc.profileFd.dup();
+ } catch (IOException e) {
+ profilerInfoSvc.closeFd();
}
}
- }
- profilerInfo = new ProfilerInfo(profileFile, profileFd,
- mService.mSamplingInterval, mService.mAutoStopProfiler,
- mService.mStreamingOutput);
+ profilerInfo = new ProfilerInfo(profilerInfoSvc);
+ }
}
}
- }
- app.hasShownUi = true;
- app.pendingUiClean = true;
- app.forceProcessStateUpTo(mService.mTopProcessState);
- // Because we could be starting an Activity in the system process this may not go across
- // a Binder interface which would create a new Configuration. Consequently we have to
- // always create a new Configuration here.
-
- final MergedConfiguration mergedConfiguration = new MergedConfiguration(
- mService.getGlobalConfiguration(), r.getMergedOverrideConfiguration());
- r.setLastReportedConfiguration(mergedConfiguration);
-
- logIfTransactionTooLarge(r.intent, r.icicle);
- app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
- System.identityHashCode(r), r.info,
- // TODO: Have this take the merged configuration instead of separate global and
- // override configs.
- mergedConfiguration.getGlobalConfiguration(),
- mergedConfiguration.getOverrideConfiguration(), r.compat,
- r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
- r.persistentState, results, newIntents, !andResume,
- mService.isNextTransitionForward(), profilerInfo);
-
- if ((app.info.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
- // This may be a heavy-weight process! Note that the package
- // manager will ensure that only activity can run in the main
- // process of the .apk, which is the only thing that will be
- // considered heavy-weight.
- if (app.processName.equals(app.info.packageName)) {
- if (mService.mHeavyWeightProcess != null
- && mService.mHeavyWeightProcess != app) {
- Slog.w(TAG, "Starting new heavy weight process " + app
- + " when already running "
- + mService.mHeavyWeightProcess);
+ app.hasShownUi = true;
+ app.pendingUiClean = true;
+ app.forceProcessStateUpTo(mService.mTopProcessState);
+ // Because we could be starting an Activity in the system process this may not go
+ // across a Binder interface which would create a new Configuration. Consequently
+ // we have to always create a new Configuration here.
+
+ final MergedConfiguration mergedConfiguration = new MergedConfiguration(
+ mService.getGlobalConfiguration(), r.getMergedOverrideConfiguration());
+ r.setLastReportedConfiguration(mergedConfiguration);
+
+ logIfTransactionTooLarge(r.intent, r.icicle);
+ app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
+ System.identityHashCode(r), r.info,
+ // TODO: Have this take the merged configuration instead of separate global
+ // and override configs.
+ mergedConfiguration.getGlobalConfiguration(),
+ mergedConfiguration.getOverrideConfiguration(), r.compat,
+ r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
+ r.persistentState, results, newIntents, !andResume,
+ mService.isNextTransitionForward(), profilerInfo);
+
+ if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
+ // This may be a heavy-weight process! Note that the package
+ // manager will ensure that only activity can run in the main
+ // process of the .apk, which is the only thing that will be
+ // considered heavy-weight.
+ if (app.processName.equals(app.info.packageName)) {
+ if (mService.mHeavyWeightProcess != null
+ && mService.mHeavyWeightProcess != app) {
+ Slog.w(TAG, "Starting new heavy weight process " + app
+ + " when already running "
+ + mService.mHeavyWeightProcess);
+ }
+ mService.mHeavyWeightProcess = app;
+ Message msg = mService.mHandler.obtainMessage(
+ ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG);
+ msg.obj = r;
+ mService.mHandler.sendMessage(msg);
}
- mService.mHeavyWeightProcess = app;
- Message msg = mService.mHandler.obtainMessage(
- ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG);
- msg.obj = r;
- mService.mHandler.sendMessage(msg);
}
- }
- } catch (RemoteException e) {
- if (r.launchFailed) {
- // This is the second time we failed -- finish activity
- // and give up.
- Slog.e(TAG, "Second failure launching "
- + r.intent.getComponent().flattenToShortString()
- + ", giving up", e);
- mService.appDiedLocked(app);
- stack.requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
- "2nd-crash", false);
- return false;
- }
+ } catch (RemoteException e) {
+ if (r.launchFailed) {
+ // This is the second time we failed -- finish activity
+ // and give up.
+ Slog.e(TAG, "Second failure launching "
+ + r.intent.getComponent().flattenToShortString()
+ + ", giving up", e);
+ mService.appDiedLocked(app);
+ stack.requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
+ "2nd-crash", false);
+ return false;
+ }
- // This is the first time we failed -- restart process and
- // retry.
- r.launchFailed = true;
- app.activities.remove(r);
- throw e;
+ // This is the first time we failed -- restart process and
+ // retry.
+ r.launchFailed = true;
+ app.activities.remove(r);
+ throw e;
+ }
+ } finally {
+ endDeferResume();
}
r.launchFailed = false;
@@ -1519,7 +1527,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
Slog.w(TAG, "Activity " + r + " being launched, but already in LRU list");
}
- if (andResume) {
+ if (andResume && readyToResume()) {
// As part of the process of launching, ActivityThread also performs
// a resume.
stack.minimalResumeActivityLocked(r);
@@ -1672,8 +1680,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// owner.
final int launchDisplayId = options.getLaunchDisplayId();
if (launchDisplayId != INVALID_DISPLAY
- && !isCallerAllowedToLaunchOnDisplay(callingPid, callingUid, launchDisplayId,
- aInfo)) {
+ && !isCallerAllowedToLaunchOnDisplay(callingPid, callingUid, launchDisplayId)) {
final String msg = "Permission Denial: starting " + intent.toString()
+ " from " + callerApp + " (pid=" + callingPid
+ ", uid=" + callingUid + ") with launchDisplayId="
@@ -1687,8 +1694,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
/** Check if caller is allowed to launch activities on specified display. */
- boolean isCallerAllowedToLaunchOnDisplay(int callingPid, int callingUid, int launchDisplayId,
- ActivityInfo aInfo) {
+ boolean isCallerAllowedToLaunchOnDisplay(int callingPid, int callingUid, int launchDisplayId) {
if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check: displayId=" + launchDisplayId
+ " callingPid=" + callingPid + " callingUid=" + callingUid);
@@ -1699,7 +1705,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
// Check if the caller can manage activity stacks.
- final int startAnyPerm = mService.checkPermission(MANAGE_ACTIVITY_STACKS, callingPid,
+ final int startAnyPerm = mService.checkPermission(INTERNAL_SYSTEM_WINDOW, callingPid,
callingUid);
if (startAnyPerm == PERMISSION_GRANTED) {
if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
@@ -1708,8 +1714,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
if (activityDisplay.mDisplay.getType() == TYPE_VIRTUAL
- && activityDisplay.mDisplay.getOwnerUid() != SYSTEM_UID
- && (aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
+ && activityDisplay.mDisplay.getOwnerUid() != SYSTEM_UID) {
// Limit launching on virtual displays, because their contents can be read from Surface
// by apps that created them.
if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
@@ -2076,9 +2081,15 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
+
+ if (!readyToResume()) {
+ return false;
+ }
+
if (targetStack != null && isFocusedStack(targetStack)) {
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
+
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
if (r == null || r.state != RESUMED) {
mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
@@ -2086,6 +2097,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// Kick off any lingering app transitions form the MoveTaskToFront operation.
mFocusedStack.executeAppTransition(targetOptions);
}
+
return false;
}
@@ -2985,13 +2997,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
try {
final TaskRecord task = r.getTask();
-
- if (r == task.getStack().getVisibleBehindActivity()) {
- // An activity can't be pinned and visible behind at the same time. Go ahead and
- // release it from been visible behind before pinning.
- requestVisibleBehindLocked(r, false);
- }
-
// Resize the pinned stack to match the current size of the task the activity we are
// going to be moving is currently contained in. We do this to have the right starting
// animation bounds for the pinned stack to the desired bounds the caller wants.
@@ -3314,70 +3319,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
}
- boolean requestVisibleBehindLocked(ActivityRecord r, boolean visible) {
- final ActivityStack stack = r.getStack();
- if (stack == null) {
- if (DEBUG_VISIBLE_BEHIND) Slog.d(TAG_VISIBLE_BEHIND,
- "requestVisibleBehind: r=" + r + " visible=" + visible + " stack is null");
- return false;
- }
-
- if (visible && !StackId.activitiesCanRequestVisibleBehind(stack.mStackId)) {
- if (DEBUG_VISIBLE_BEHIND) Slog.d(TAG_VISIBLE_BEHIND, "requestVisibleBehind: r=" + r
- + " visible=" + visible + " stackId=" + stack.mStackId
- + " can't contain visible behind activities");
- return false;
- }
-
- final boolean isVisible = stack.hasVisibleBehindActivity();
- if (DEBUG_VISIBLE_BEHIND) Slog.d(TAG_VISIBLE_BEHIND,
- "requestVisibleBehind r=" + r + " visible=" + visible + " isVisible=" + isVisible);
-
- final ActivityRecord top = topRunningActivityLocked();
- if (top == null || top == r || (visible == isVisible)) {
- if (DEBUG_VISIBLE_BEHIND) Slog.d(TAG_VISIBLE_BEHIND, "requestVisibleBehind: quick return");
- stack.setVisibleBehindActivity(visible ? r : null);
- return true;
- }
-
- // A non-top activity is reporting a visibility change.
- if (visible && top.fullscreen) {
- // Let the caller know that it can't be seen.
- if (DEBUG_VISIBLE_BEHIND) Slog.d(TAG_VISIBLE_BEHIND,
- "requestVisibleBehind: returning top.fullscreen=" + top.fullscreen
- + " top.state=" + top.state + " top.app=" + top.app + " top.app.thread="
- + top.app.thread);
- return false;
- } else if (!visible && stack.getVisibleBehindActivity() != r) {
- // Only the activity set as currently visible behind should actively reset its
- // visible behind state.
- if (DEBUG_VISIBLE_BEHIND) Slog.d(TAG_VISIBLE_BEHIND,
- "requestVisibleBehind: returning visible=" + visible
- + " stack.getVisibleBehindActivity()=" + stack.getVisibleBehindActivity()
- + " r=" + r);
- return false;
- }
-
- stack.setVisibleBehindActivity(visible ? r : null);
- if (!visible) {
- // If there is a translucent home activity, we need to force it stop being translucent,
- // because we can't depend on the application to necessarily perform that operation.
- // Check out b/14469711 for details.
- final ActivityRecord next = stack.findNextTranslucentActivity(r);
- if (next != null && next.isHomeActivity()) {
- mService.convertFromTranslucent(next.appToken);
- }
- }
- if (top.app != null && top.app.thread != null) {
- // Notify the top app of the change.
- try {
- top.app.thread.scheduleBackgroundVisibleBehindChanged(top.appToken, visible);
- } catch (RemoteException e) {
- }
- }
- return true;
- }
-
// Called when WindowManager has finished animating the launchingBehind activity to the back.
private void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
final TaskRecord task = r.getTask();
@@ -4435,6 +4376,31 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mIsDockMinimized = minimized;
}
+ void wakeUp(String reason) {
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.server.am:TURN_ON:" + reason);
+ }
+
+ /**
+ * Begin deferring resume to avoid duplicate resumes in one pass.
+ */
+ private void beginDeferResume() {
+ mDeferResumeCount++;
+ }
+
+ /**
+ * End deferring resume and determine if resume can be called.
+ */
+ private void endDeferResume() {
+ mDeferResumeCount--;
+ }
+
+ /**
+ * @return True if resume can be called.
+ */
+ private boolean readyToResume() {
+ return mDeferResumeCount == 0;
+ }
+
private final class ActivityStackSupervisorHandler extends Handler {
public ActivityStackSupervisorHandler(Looper looper) {
@@ -4965,8 +4931,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
* stacks, bottommost behind. Accessed directly by ActivityManager package classes */
final ArrayList<ActivityStack> mStacks = new ArrayList<>();
- ActivityRecord mVisibleBehindActivity;
-
/** Array of all UIDs that are present on the display. */
private IntArray mDisplayAccessUIDs = new IntArray();
@@ -5000,14 +4964,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mStacks.remove(stack);
}
- void setVisibleBehindActivity(ActivityRecord r) {
- mVisibleBehindActivity = r;
- }
-
- boolean hasVisibleBehindActivity() {
- return mVisibleBehindActivity != null;
- }
-
@Override
public String toString() {
return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index a46c85170ba2..372d80df928f 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -30,7 +30,6 @@ import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AW
import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY;
import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_OCCLUDE;
import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
-import static com.android.server.wm.AppTransition.TRANSIT_NONE;
import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
import android.os.IBinder;
@@ -144,6 +143,13 @@ class KeyguardController {
failCallback(callback);
return;
}
+
+ // If the client has requested to dismiss the keyguard and the Activity has the flag to
+ // turn the screen on, wakeup the screen if it's the top Activity.
+ if (activityRecord.getTurnScreenOnFlag() && activityRecord.isTopRunningActivity()) {
+ mStackSupervisor.wakeUp("dismissKeyguard");
+ }
+
mWindowManager.dismissKeyguard(callback);
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 0ee2a41c5767..d3a93542c740 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -29,6 +29,7 @@ import android.content.IntentFilter;
import android.net.CaptivePortal;
import android.net.ConnectivityManager;
import android.net.ICaptivePortal;
+import android.net.Network;
import android.net.NetworkRequest;
import android.net.ProxyInfo;
import android.net.TrafficStats;
@@ -71,6 +72,9 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
@@ -95,7 +99,7 @@ public class NetworkMonitor extends StateMachine {
"http://play.googleapis.com/generate_204";
private static final String DEFAULT_USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) "
+ "AppleWebKit/537.36 (KHTML, like Gecko) "
- + "Chrome/52.0.2743.82 Safari/537.36";
+ + "Chrome/60.0.3112.32 Safari/537.36";
private static final int SOCKET_TIMEOUT_MS = 10000;
private static final int PROBE_TIMEOUT_MS = 3000;
@@ -228,6 +232,7 @@ public class NetworkMonitor extends StateMachine {
private final Context mContext;
private final Handler mConnectivityServiceHandler;
private final NetworkAgentInfo mNetworkAgentInfo;
+ private final Network mNetwork;
private final int mNetId;
private final TelephonyManager mTelephonyManager;
private final WifiManager mWifiManager;
@@ -286,7 +291,8 @@ public class NetworkMonitor extends StateMachine {
mMetricsLog = logger;
mConnectivityServiceHandler = handler;
mNetworkAgentInfo = networkAgentInfo;
- mNetId = mNetworkAgentInfo.network.netId;
+ mNetwork = new OneAddressPerFamilyNetwork(networkAgentInfo.network);
+ mNetId = mNetwork.netId;
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
@@ -415,7 +421,7 @@ public class NetworkMonitor extends StateMachine {
maybeLogEvaluationResult(
networkEventType(validationStage(), EvaluationResult.VALIDATED));
mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
- NETWORK_TEST_RESULT_VALID, mNetworkAgentInfo.network.netId, null));
+ NETWORK_TEST_RESULT_VALID, mNetId, null));
mValidations++;
}
@@ -440,7 +446,8 @@ public class NetworkMonitor extends StateMachine {
case CMD_LAUNCH_CAPTIVE_PORTAL_APP:
final Intent intent = new Intent(
ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN);
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK, mNetworkAgentInfo.network);
+ // OneAddressPerFamilyNetwork is not parcelable across processes.
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK, new Network(mNetwork));
intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL,
new CaptivePortal(new ICaptivePortal.Stub() {
@Override
@@ -468,8 +475,7 @@ public class NetworkMonitor extends StateMachine {
@Override
public void exit() {
- Message message = obtainMessage(EVENT_PROVISIONING_NOTIFICATION, 0,
- mNetworkAgentInfo.network.netId, null);
+ Message message = obtainMessage(EVENT_PROVISIONING_NOTIFICATION, 0, mNetId, null);
mConnectivityServiceHandler.sendMessage(message);
}
}
@@ -623,7 +629,7 @@ public class NetworkMonitor extends StateMachine {
CustomIntentReceiver(String action, int token, int what) {
mToken = token;
mWhat = what;
- mAction = action + "_" + mNetworkAgentInfo.network.netId + "_" + token;
+ mAction = action + "_" + mNetId + "_" + token;
mContext.registerReceiver(this, new IntentFilter(mAction));
}
public PendingIntent getPendingIntent() {
@@ -659,8 +665,7 @@ public class NetworkMonitor extends StateMachine {
CMD_LAUNCH_CAPTIVE_PORTAL_APP);
}
// Display the sign in notification.
- Message message = obtainMessage(EVENT_PROVISIONING_NOTIFICATION, 1,
- mNetworkAgentInfo.network.netId,
+ Message message = obtainMessage(EVENT_PROVISIONING_NOTIFICATION, 1, mNetId,
mLaunchCaptivePortalAppBroadcastReceiver.getPendingIntent());
mConnectivityServiceHandler.sendMessage(message);
// Retest for captive portal occasionally.
@@ -675,6 +680,31 @@ public class NetworkMonitor extends StateMachine {
}
}
+ // Limits the list of IP addresses returned by getAllByName or tried by openConnection to at
+ // most one per address family. This ensures we only wait up to 20 seconds for TCP connections
+ // to complete, regardless of how many IP addresses a host has.
+ private static class OneAddressPerFamilyNetwork extends Network {
+ public OneAddressPerFamilyNetwork(Network network) {
+ super(network);
+ }
+
+ @Override
+ public InetAddress[] getAllByName(String host) throws UnknownHostException {
+ List<InetAddress> addrs = Arrays.asList(super.getAllByName(host));
+
+ // Ensure the address family of the first address is tried first.
+ LinkedHashMap<Class, InetAddress> addressByFamily = new LinkedHashMap<>();
+ addressByFamily.put(addrs.get(0).getClass(), addrs.get(0));
+ Collections.shuffle(addrs);
+
+ for (InetAddress addr : addrs) {
+ addressByFamily.put(addr.getClass(), addr);
+ }
+
+ return addressByFamily.values().toArray(new InetAddress[addressByFamily.size()]);
+ }
+ }
+
private static String getCaptivePortalServerHttpsUrl(Context context) {
return getSetting(context, Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, DEFAULT_HTTPS_URL);
}
@@ -805,7 +835,7 @@ public class NetworkMonitor extends StateMachine {
int result;
String connectInfo;
try {
- InetAddress[] addresses = mNetworkAgentInfo.network.getAllByName(host);
+ InetAddress[] addresses = mNetwork.getAllByName(host);
StringBuffer buffer = new StringBuffer();
for (InetAddress address : addresses) {
buffer.append(',').append(address.getHostAddress());
@@ -834,7 +864,7 @@ public class NetworkMonitor extends StateMachine {
final Stopwatch probeTimer = new Stopwatch().start();
final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
try {
- urlConnection = (HttpURLConnection) mNetworkAgentInfo.network.openConnection(url);
+ urlConnection = (HttpURLConnection) mNetwork.openConnection(url);
urlConnection.setInstanceFollowRedirects(probeType == ValidationProbeEvent.PROBE_PAC);
urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index e5fc4b1d1775..b6573352a482 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -16,6 +16,7 @@
package com.android.server.connectivity;
+import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
import static android.net.ConnectivityManager.getNetworkTypeName;
@@ -47,6 +48,7 @@ import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
+import android.net.IpPrefix;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -107,6 +109,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
@@ -213,7 +216,7 @@ public class Tethering extends BaseNetworkObserver {
mContext.getContentResolver(),
mLog);
mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
- mContext, mTetherMasterSM, TetherMasterSM.EVENT_UPSTREAM_CALLBACK, mLog);
+ mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK );
mForwardedDownstreams = new HashSet<>();
mSimChange = new SimChangeListener(
mContext, mTetherMasterSM.getHandler(), () -> reevaluateSimCardProvisioning());
@@ -701,7 +704,7 @@ public class Tethering extends BaseNetworkObserver {
private void showTetheredNotification(int id) {
NotificationManager notificationManager =
- (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager == null) {
return;
}
@@ -762,7 +765,7 @@ public class Tethering extends BaseNetworkObserver {
private void clearTetheredNotification() {
NotificationManager notificationManager =
- (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null && mLastNotificationId != 0) {
notificationManager.cancelAsUser(null, mLastNotificationId,
UserHandle.ALL);
@@ -801,11 +804,37 @@ public class Tethering extends BaseNetworkObserver {
private void handleUsbAction(Intent intent) {
final boolean usbConnected = intent.getBooleanExtra(USB_CONNECTED, false);
+ final boolean usbConfigured = intent.getBooleanExtra(USB_CONFIGURED, false);
final boolean rndisEnabled = intent.getBooleanExtra(USB_FUNCTION_RNDIS, false);
+
+ mLog.log(String.format("USB bcast connected:%s configured:%s rndis:%s",
+ usbConnected, usbConfigured, rndisEnabled));
+
+ // There are three types of ACTION_USB_STATE:
+ //
+ // - DISCONNECTED (USB_CONNECTED and USB_CONFIGURED are 0)
+ // Meaning: USB connection has ended either because of
+ // software reset or hard unplug.
+ //
+ // - CONNECTED (USB_CONNECTED is 1, USB_CONFIGURED is 0)
+ // Meaning: the first stage of USB protocol handshake has
+ // occurred but it is not complete.
+ //
+ // - CONFIGURED (USB_CONNECTED and USB_CONFIGURED are 1)
+ // Meaning: the USB handshake is completely done and all the
+ // functions are ready to use.
+ //
+ // For more explanation, see b/62552150 .
+ if (usbConnected && !usbConfigured) {
+ // Nothing for us to do here.
+ // TODO: consider ignoring DISCONNECTED broadcasts as well.
+ return;
+ }
+
synchronized (Tethering.this.mPublicSync) {
mRndisEnabled = rndisEnabled;
// start tethering if we have a request pending
- if (usbConnected && mRndisEnabled && mUsbTetherRequested) {
+ if (usbConfigured && mRndisEnabled && mUsbTetherRequested) {
tetherMatchingInterfaces(
IControlsTethering.STATE_TETHERED,
ConnectivityManager.TETHERING_USB);
@@ -981,7 +1010,7 @@ public class Tethering extends BaseNetworkObserver {
public int setUsbTethering(boolean enable) {
if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
- UsbManager usbManager = mContext.getSystemService(UsbManager.class);
+ UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
synchronized (mPublicSync) {
if (enable) {
@@ -1076,7 +1105,7 @@ public class Tethering extends BaseNetworkObserver {
// Needed because the canonical source of upstream truth is just the
// upstream interface name, |mCurrentUpstreamIface|. This is ripe for
// future simplification, once the upstream Network is canonical.
- boolean pertainsToCurrentUpstream(NetworkState ns) {
+ private boolean pertainsToCurrentUpstream(NetworkState ns) {
if (ns != null && ns.linkProperties != null && mCurrentUpstreamIface != null) {
for (String ifname : ns.linkProperties.getAllInterfaceNames()) {
if (mCurrentUpstreamIface.equals(ifname)) {
@@ -1110,6 +1139,12 @@ public class Tethering extends BaseNetworkObserver {
}
}
+ private void startOffloadController() {
+ mOffloadController.start();
+ mOffloadController.updateExemptPrefixes(
+ mUpstreamNetworkMonitor.getOffloadExemptPrefixes());
+ }
+
class TetherMasterSM extends StateMachine {
private static final int BASE_MASTER = Protocol.BASE_TETHERING;
// an interface SM has requested Tethering/Local Hotspot
@@ -1203,146 +1238,138 @@ public class Tethering extends BaseNetworkObserver {
}
}
- class TetherMasterUtilState extends State {
- @Override
- public boolean processMessage(Message m) {
+ protected boolean turnOnMasterTetherSettings() {
+ final TetheringConfiguration cfg = mConfig;
+ try {
+ mNMService.setIpForwardingEnabled(true);
+ } catch (Exception e) {
+ mLog.e(e);
+ transitionTo(mSetIpForwardingEnabledErrorState);
return false;
}
-
- protected boolean turnOnMasterTetherSettings() {
- final TetheringConfiguration cfg = mConfig;
- try {
- mNMService.setIpForwardingEnabled(true);
- } catch (Exception e) {
- mLog.e(e);
- transitionTo(mSetIpForwardingEnabledErrorState);
- return false;
- }
- // TODO: Randomize DHCPv4 ranges, especially in hotspot mode.
- try {
- // TODO: Find a more accurate method name (startDHCPv4()?).
- mNMService.startTethering(cfg.dhcpRanges);
- } catch (Exception e) {
- try {
- mNMService.stopTethering();
- mNMService.startTethering(cfg.dhcpRanges);
- } catch (Exception ee) {
- mLog.e(ee);
- transitionTo(mStartTetheringErrorState);
- return false;
- }
- }
- mLog.log("SET master tether settings: ON");
- return true;
- }
-
- protected boolean turnOffMasterTetherSettings() {
+ // TODO: Randomize DHCPv4 ranges, especially in hotspot mode.
+ try {
+ // TODO: Find a more accurate method name (startDHCPv4()?).
+ mNMService.startTethering(cfg.dhcpRanges);
+ } catch (Exception e) {
try {
mNMService.stopTethering();
- } catch (Exception e) {
- mLog.e(e);
- transitionTo(mStopTetheringErrorState);
- return false;
- }
- try {
- mNMService.setIpForwardingEnabled(false);
- } catch (Exception e) {
- mLog.e(e);
- transitionTo(mSetIpForwardingDisabledErrorState);
+ mNMService.startTethering(cfg.dhcpRanges);
+ } catch (Exception ee) {
+ mLog.e(ee);
+ transitionTo(mStartTetheringErrorState);
return false;
}
- transitionTo(mInitialState);
- mLog.log("SET master tether settings: OFF");
- return true;
}
+ mLog.log("SET master tether settings: ON");
+ return true;
+ }
- protected void chooseUpstreamType(boolean tryCell) {
- updateConfiguration(); // TODO - remove?
+ protected boolean turnOffMasterTetherSettings() {
+ try {
+ mNMService.stopTethering();
+ } catch (Exception e) {
+ mLog.e(e);
+ transitionTo(mStopTetheringErrorState);
+ return false;
+ }
+ try {
+ mNMService.setIpForwardingEnabled(false);
+ } catch (Exception e) {
+ mLog.e(e);
+ transitionTo(mSetIpForwardingDisabledErrorState);
+ return false;
+ }
+ transitionTo(mInitialState);
+ mLog.log("SET master tether settings: OFF");
+ return true;
+ }
- final NetworkState ns = mUpstreamNetworkMonitor.selectPreferredUpstreamType(
- mConfig.preferredUpstreamIfaceTypes);
- if (ns == null) {
- if (tryCell) {
- mUpstreamNetworkMonitor.registerMobileNetworkRequest();
- // We think mobile should be coming up; don't set a retry.
- } else {
- sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
- }
- }
- setUpstreamNetwork(ns);
- }
-
- protected void setUpstreamNetwork(NetworkState ns) {
- String iface = null;
- if (ns != null && ns.linkProperties != null) {
- // Find the interface with the default IPv4 route. It may be the
- // interface described by linkProperties, or one of the interfaces
- // stacked on top of it.
- Log.i(TAG, "Finding IPv4 upstream interface on: " + ns.linkProperties);
- RouteInfo ipv4Default = RouteInfo.selectBestRoute(
- ns.linkProperties.getAllRoutes(), Inet4Address.ANY);
- if (ipv4Default != null) {
- iface = ipv4Default.getInterface();
- Log.i(TAG, "Found interface " + ipv4Default.getInterface());
- } else {
- Log.i(TAG, "No IPv4 upstream interface, giving up.");
- }
- }
+ protected void chooseUpstreamType(boolean tryCell) {
+ updateConfiguration(); // TODO - remove?
- if (iface != null) {
- setDnsForwarders(ns.network, ns.linkProperties);
+ final NetworkState ns = mUpstreamNetworkMonitor.selectPreferredUpstreamType(
+ mConfig.preferredUpstreamIfaceTypes);
+ if (ns == null) {
+ if (tryCell) {
+ mUpstreamNetworkMonitor.registerMobileNetworkRequest();
+ // We think mobile should be coming up; don't set a retry.
+ } else {
+ sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
}
- notifyTetheredOfNewUpstreamIface(iface);
- if (ns != null && pertainsToCurrentUpstream(ns)) {
- // If we already have NetworkState for this network examine
- // it immediately, because there likely will be no second
- // EVENT_ON_AVAILABLE (it was already received).
- handleNewUpstreamNetworkState(ns);
- } else if (mCurrentUpstreamIface == null) {
- // There are no available upstream networks, or none that
- // have an IPv4 default route (current metric for success).
- handleNewUpstreamNetworkState(null);
+ }
+ setUpstreamNetwork(ns);
+ }
+
+ protected void setUpstreamNetwork(NetworkState ns) {
+ String iface = null;
+ if (ns != null && ns.linkProperties != null) {
+ // Find the interface with the default IPv4 route. It may be the
+ // interface described by linkProperties, or one of the interfaces
+ // stacked on top of it.
+ Log.i(TAG, "Finding IPv4 upstream interface on: " + ns.linkProperties);
+ RouteInfo ipv4Default = RouteInfo.selectBestRoute(
+ ns.linkProperties.getAllRoutes(), Inet4Address.ANY);
+ if (ipv4Default != null) {
+ iface = ipv4Default.getInterface();
+ Log.i(TAG, "Found interface " + ipv4Default.getInterface());
+ } else {
+ Log.i(TAG, "No IPv4 upstream interface, giving up.");
}
}
- protected void setDnsForwarders(final Network network, final LinkProperties lp) {
- // TODO: Set v4 and/or v6 DNS per available connectivity.
- String[] dnsServers = mConfig.defaultIPv4DNS;
- final Collection<InetAddress> dnses = lp.getDnsServers();
- // TODO: Properly support the absence of DNS servers.
- if (dnses != null && !dnses.isEmpty()) {
- // TODO: remove this invocation of NetworkUtils.makeStrings().
- dnsServers = NetworkUtils.makeStrings(dnses);
- }
- try {
- mNMService.setDnsForwarders(network, dnsServers);
- mLog.log(String.format(
- "SET DNS forwarders: network=%s dnsServers=%s",
- network, Arrays.toString(dnsServers)));
- } catch (Exception e) {
- // TODO: Investigate how this can fail and what exactly
- // happens if/when such failures occur.
- mLog.e("setting DNS forwarders failed, " + e);
- transitionTo(mSetDnsForwardersErrorState);
- }
+ if (iface != null) {
+ setDnsForwarders(ns.network, ns.linkProperties);
}
+ notifyTetheredOfNewUpstreamIface(iface);
+ if (ns != null && pertainsToCurrentUpstream(ns)) {
+ // If we already have NetworkState for this network examine
+ // it immediately, because there likely will be no second
+ // EVENT_ON_AVAILABLE (it was already received).
+ handleNewUpstreamNetworkState(ns);
+ } else if (mCurrentUpstreamIface == null) {
+ // There are no available upstream networks, or none that
+ // have an IPv4 default route (current metric for success).
+ handleNewUpstreamNetworkState(null);
+ }
+ }
- protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
- if (DBG) Log.d(TAG, "Notifying tethered with upstream=" + ifaceName);
- mCurrentUpstreamIface = ifaceName;
- for (TetherInterfaceStateMachine sm : mNotifyList) {
- sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
- ifaceName);
- }
+ protected void setDnsForwarders(final Network network, final LinkProperties lp) {
+ // TODO: Set v4 and/or v6 DNS per available connectivity.
+ String[] dnsServers = mConfig.defaultIPv4DNS;
+ final Collection<InetAddress> dnses = lp.getDnsServers();
+ // TODO: Properly support the absence of DNS servers.
+ if (dnses != null && !dnses.isEmpty()) {
+ // TODO: remove this invocation of NetworkUtils.makeStrings().
+ dnsServers = NetworkUtils.makeStrings(dnses);
+ }
+ try {
+ mNMService.setDnsForwarders(network, dnsServers);
+ mLog.log(String.format(
+ "SET DNS forwarders: network=%s dnsServers=%s",
+ network, Arrays.toString(dnsServers)));
+ } catch (Exception e) {
+ // TODO: Investigate how this can fail and what exactly
+ // happens if/when such failures occur.
+ mLog.e("setting DNS forwarders failed, " + e);
+ transitionTo(mSetDnsForwardersErrorState);
}
+ }
- protected void handleNewUpstreamNetworkState(NetworkState ns) {
- mIPv6TetheringCoordinator.updateUpstreamNetworkState(ns);
- mOffloadController.setUpstreamLinkProperties(
- (ns != null) ? ns.linkProperties : null);
+ protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
+ if (DBG) Log.d(TAG, "Notifying tethered with upstream=" + ifaceName);
+ mCurrentUpstreamIface = ifaceName;
+ for (TetherInterfaceStateMachine sm : mNotifyList) {
+ sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
+ ifaceName);
}
}
+ protected void handleNewUpstreamNetworkState(NetworkState ns) {
+ mIPv6TetheringCoordinator.updateUpstreamNetworkState(ns);
+ mOffloadController.setUpstreamLinkProperties((ns != null) ? ns.linkProperties : null);
+ }
+
private void handleInterfaceServingStateActive(int mode, TetherInterfaceStateMachine who) {
if (mNotifyList.indexOf(who) < 0) {
mNotifyList.add(who);
@@ -1389,7 +1416,61 @@ public class Tethering extends BaseNetworkObserver {
}
}
- class TetherModeAliveState extends TetherMasterUtilState {
+ private void handleUpstreamNetworkMonitorCallback(int arg1, Object o) {
+ if (arg1 == UpstreamNetworkMonitor.NOTIFY_EXEMPT_PREFIXES) {
+ mOffloadController.updateExemptPrefixes((Set<IpPrefix>) o);
+ return;
+ }
+
+ final NetworkState ns = (NetworkState) o;
+
+ if (ns == null || !pertainsToCurrentUpstream(ns)) {
+ // TODO: In future, this is where upstream evaluation and selection
+ // could be handled for notifications which include sufficient data.
+ // For example, after CONNECTIVITY_ACTION listening is removed, here
+ // is where we could observe a Wi-Fi network becoming available and
+ // passing validation.
+ if (mCurrentUpstreamIface == null) {
+ // If we have no upstream interface, try to run through upstream
+ // selection again. If, for example, IPv4 connectivity has shown up
+ // after IPv6 (e.g., 464xlat became available) we want the chance to
+ // notice and act accordingly.
+ chooseUpstreamType(false);
+ }
+ return;
+ }
+
+ switch (arg1) {
+ case UpstreamNetworkMonitor.EVENT_ON_AVAILABLE:
+ // The default network changed, or DUN connected
+ // before this callback was processed. Updates
+ // for the current NetworkCapabilities and
+ // LinkProperties have been requested (default
+ // request) or are being sent shortly (DUN). Do
+ // nothing until they arrive; if no updates
+ // arrive there's nothing to do.
+ break;
+ case UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES:
+ handleNewUpstreamNetworkState(ns);
+ break;
+ case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES:
+ setDnsForwarders(ns.network, ns.linkProperties);
+ handleNewUpstreamNetworkState(ns);
+ break;
+ case UpstreamNetworkMonitor.EVENT_ON_LOST:
+ // TODO: Re-evaluate possible upstreams. Currently upstream
+ // reevaluation is triggered via received CONNECTIVITY_ACTION
+ // broadcasts that result in being passed a
+ // TetherMasterSM.CMD_UPSTREAM_CHANGED.
+ handleNewUpstreamNetworkState(null);
+ break;
+ default:
+ mLog.e("Unknown arg1 value: " + arg1);
+ break;
+ }
+ }
+
+ class TetherModeAliveState extends State {
boolean mUpstreamWanted = false;
boolean mTryCell = true;
@@ -1407,7 +1488,7 @@ public class Tethering extends BaseNetworkObserver {
// TODO: De-duplicate with updateUpstreamWanted() below.
if (upstreamWanted()) {
mUpstreamWanted = true;
- mOffloadController.start();
+ startOffloadController();
chooseUpstreamType(true);
mTryCell = false;
}
@@ -1427,7 +1508,7 @@ public class Tethering extends BaseNetworkObserver {
mUpstreamWanted = upstreamWanted();
if (mUpstreamWanted != previousUpstreamWanted) {
if (mUpstreamWanted) {
- mOffloadController.start();
+ startOffloadController();
} else {
mOffloadController.stop();
}
@@ -1507,52 +1588,8 @@ public class Tethering extends BaseNetworkObserver {
break;
case EVENT_UPSTREAM_CALLBACK: {
updateUpstreamWanted();
- if (!mUpstreamWanted) break;
-
- final NetworkState ns = (NetworkState) message.obj;
-
- if (ns == null || !pertainsToCurrentUpstream(ns)) {
- // TODO: In future, this is where upstream evaluation and selection
- // could be handled for notifications which include sufficient data.
- // For example, after CONNECTIVITY_ACTION listening is removed, here
- // is where we could observe a Wi-Fi network becoming available and
- // passing validation.
- if (mCurrentUpstreamIface == null) {
- // If we have no upstream interface, try to run through upstream
- // selection again. If, for example, IPv4 connectivity has shown up
- // after IPv6 (e.g., 464xlat became available) we want the chance to
- // notice and act accordingly.
- chooseUpstreamType(false);
- }
- break;
- }
-
- switch (message.arg1) {
- case UpstreamNetworkMonitor.EVENT_ON_AVAILABLE:
- // The default network changed, or DUN connected
- // before this callback was processed. Updates
- // for the current NetworkCapabilities and
- // LinkProperties have been requested (default
- // request) or are being sent shortly (DUN). Do
- // nothing until they arrive; if no updates
- // arrive there's nothing to do.
- break;
- case UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES:
- handleNewUpstreamNetworkState(ns);
- break;
- case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES:
- setDnsForwarders(ns.network, ns.linkProperties);
- handleNewUpstreamNetworkState(ns);
- break;
- case UpstreamNetworkMonitor.EVENT_ON_LOST:
- // TODO: Re-evaluate possible upstreams. Currently upstream
- // reevaluation is triggered via received CONNECTIVITY_ACTION
- // broadcasts that result in being passed a
- // TetherMasterSM.CMD_UPSTREAM_CHANGED.
- handleNewUpstreamNetworkState(null);
- break;
- default:
- break;
+ if (mUpstreamWanted) {
+ handleUpstreamNetworkMonitorCallback(message.arg1, message.obj);
}
break;
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index 08deef84f3ae..78487b713f2e 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -19,6 +19,7 @@ package com.android.server.connectivity.tethering;
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
import android.content.ContentResolver;
+import android.net.IpPrefix;
import android.net.LinkProperties;
import android.net.RouteInfo;
import android.net.util.SharedLog;
@@ -28,6 +29,7 @@ import android.provider.Settings;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.ArrayList;
+import java.util.Set;
/**
* A class to encapsulate the business logic of programming the tethering
@@ -45,6 +47,7 @@ public class OffloadController {
private boolean mConfigInitialized;
private boolean mControlInitialized;
private LinkProperties mUpstreamLinkProperties;
+ private Set<IpPrefix> mExemptPrefixes;
public OffloadController(Handler h, OffloadHardwareInterface hwi,
ContentResolver contentResolver, SharedLog log) {
@@ -108,6 +111,17 @@ public class OffloadController {
pushUpstreamParameters();
}
+ public void updateExemptPrefixes(Set<IpPrefix> exemptPrefixes) {
+ if (!started()) return;
+
+ mExemptPrefixes = exemptPrefixes;
+ // TODO:
+ // - add IP addresses from all downstream link properties
+ // - add routes from all non-tethering downstream link properties
+ // - remove any 64share prefixes
+ // - push this to the HAL
+ }
+
public void notifyDownstreamLinkProperties(LinkProperties lp) {
if (!started()) return;
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 1fc16841e355..09fd96b4966e 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -76,6 +76,10 @@ public class OffloadHardwareInterface {
}
}
+ final String logmsg = String.format("initOffloadControl(%s)",
+ (controlCb == null) ? "null"
+ : "0x" + Integer.toHexString(System.identityHashCode(controlCb)));
+
mTetheringOffloadCallback = new TetheringOffloadCallback(mHandler, mControlCallback);
final CbResults results = new CbResults();
try {
@@ -86,11 +90,11 @@ public class OffloadHardwareInterface {
results.errMsg = errMsg;
});
} catch (RemoteException e) {
- mLog.e("failed to initOffload: " + e);
+ record(logmsg, e);
return false;
}
- if (!results.success) mLog.e("initOffload failed: " + results.errMsg);
+ record(logmsg, results);
return results.success;
}
@@ -108,14 +112,18 @@ public class OffloadHardwareInterface {
mOffloadControl = null;
mTetheringOffloadCallback = null;
mControlCallback = null;
+ mLog.log("stopOffloadControl()");
}
public boolean setUpstreamParameters(
String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
- iface = iface != null ? iface : NO_INTERFACE_NAME;
- v4addr = v4addr != null ? v4addr : NO_IPV4_ADDRESS;
- v4gateway = v4gateway != null ? v4gateway : NO_IPV4_GATEWAY;
- v6gws = v6gws != null ? v6gws : new ArrayList<>();
+ iface = (iface != null) ? iface : NO_INTERFACE_NAME;
+ v4addr = (v4addr != null) ? v4addr : NO_IPV4_ADDRESS;
+ v4gateway = (v4gateway != null) ? v4gateway : NO_IPV4_GATEWAY;
+ v6gws = (v6gws != null) ? v6gws : new ArrayList<>();
+
+ final String logmsg = String.format("setUpstreamParameters(%s, %s, %s, [%s])",
+ iface, v4addr, v4gateway, String.join(",", v6gws));
final CbResults results = new CbResults();
try {
@@ -126,14 +134,27 @@ public class OffloadHardwareInterface {
results.errMsg = errMsg;
});
} catch (RemoteException e) {
- mLog.e("failed to setUpstreamParameters: " + e);
+ record(logmsg, e);
return false;
}
- if (!results.success) mLog.e("setUpstreamParameters failed: " + results.errMsg);
+ record(logmsg, results);
return results.success;
}
+ private void record(String msg, Throwable t) {
+ mLog.e(msg + " -> exception: " + t);
+ }
+
+ private void record(String msg, CbResults results) {
+ final String logmsg = msg + " -> " + results;
+ if (!results.success) {
+ mLog.e(logmsg);
+ } else {
+ mLog.log(logmsg);
+ }
+ }
+
private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub {
public final Handler handler;
public final ControlCallback controlCb;
@@ -162,5 +183,13 @@ public class OffloadHardwareInterface {
private static class CbResults {
boolean success;
String errMsg;
+
+ public String toString() {
+ if (success) {
+ return "ok";
+ } else {
+ return "fail: " + errMsg;
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 9ebfaf7b3893..eb66767bfdfa 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -26,18 +26,24 @@ import android.os.Handler;
import android.os.Looper;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.NetworkState;
+import android.net.util.NetworkConstants;
import android.net.util.SharedLog;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.StateMachine;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
/**
@@ -66,10 +72,16 @@ public class UpstreamNetworkMonitor {
private static final boolean DBG = false;
private static final boolean VDBG = false;
+ private static final IpPrefix[] MINIMUM_LOCAL_PREFIXES_SET = {
+ prefix("127.0.0.0/8"), prefix("169.254.0.0/16"),
+ prefix("::/3"), prefix("fe80::/64"), prefix("fc00::/7"), prefix("ff00::/8"),
+ };
+
public static final int EVENT_ON_AVAILABLE = 1;
public static final int EVENT_ON_CAPABILITIES = 2;
public static final int EVENT_ON_LINKPROPERTIES = 3;
public static final int EVENT_ON_LOST = 4;
+ public static final int NOTIFY_EXEMPT_PREFIXES = 10;
private static final int CALLBACK_LISTEN_ALL = 1;
private static final int CALLBACK_TRACK_DEFAULT = 2;
@@ -81,6 +93,7 @@ public class UpstreamNetworkMonitor {
private final Handler mHandler;
private final int mWhat;
private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
+ private HashSet<IpPrefix> mOffloadExemptPrefixes;
private ConnectivityManager mCM;
private NetworkCallback mListenAllCallback;
private NetworkCallback mDefaultNetworkCallback;
@@ -88,18 +101,19 @@ public class UpstreamNetworkMonitor {
private boolean mDunRequired;
private Network mCurrentDefault;
- public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what, SharedLog log) {
+ public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, SharedLog log, int what) {
mContext = ctx;
mTarget = tgt;
mHandler = mTarget.getHandler();
- mWhat = what;
mLog = log.forSubComponent(TAG);
+ mWhat = what;
+ mOffloadExemptPrefixes = allOffloadExemptPrefixes(mNetworkMap.values());
}
@VisibleForTesting
public UpstreamNetworkMonitor(
- StateMachine tgt, int what, ConnectivityManager cm, SharedLog log) {
- this(null, tgt, what, log);
+ ConnectivityManager cm, StateMachine tgt, SharedLog log, int what) {
+ this((Context) null, tgt, log, what);
mCM = cm;
}
@@ -209,6 +223,10 @@ public class UpstreamNetworkMonitor {
return typeStatePair.ns;
}
+ public Set<IpPrefix> getOffloadExemptPrefixes() {
+ return (Set<IpPrefix>) mOffloadExemptPrefixes.clone();
+ }
+
private void handleAvailable(int callbackType, Network network) {
if (VDBG) Log.d(TAG, "EVENT_ON_AVAILABLE for " + network);
@@ -342,6 +360,14 @@ public class UpstreamNetworkMonitor {
notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network));
}
+ private void recomputeOffloadExemptPrefixes() {
+ final HashSet<IpPrefix> exemptPrefixes = allOffloadExemptPrefixes(mNetworkMap.values());
+ if (!mOffloadExemptPrefixes.equals(exemptPrefixes)) {
+ mOffloadExemptPrefixes = exemptPrefixes;
+ notifyTarget(NOTIFY_EXEMPT_PREFIXES, exemptPrefixes.clone());
+ }
+ }
+
// Fetch (and cache) a ConnectivityManager only if and when we need one.
private ConnectivityManager cm() {
if (mCM == null) {
@@ -376,6 +402,7 @@ public class UpstreamNetworkMonitor {
@Override
public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
handleLinkProp(network, newLp);
+ recomputeOffloadExemptPrefixes();
}
// TODO: Handle onNetworkSuspended();
@@ -384,6 +411,7 @@ public class UpstreamNetworkMonitor {
@Override
public void onLost(Network network) {
handleLost(mCallbackType, network);
+ recomputeOffloadExemptPrefixes();
}
}
@@ -395,16 +423,16 @@ public class UpstreamNetworkMonitor {
notifyTarget(which, mNetworkMap.get(network));
}
- private void notifyTarget(int which, NetworkState netstate) {
- mTarget.sendMessage(mWhat, which, 0, netstate);
+ private void notifyTarget(int which, Object obj) {
+ mTarget.sendMessage(mWhat, which, 0, obj);
}
- static private class TypeStatePair {
+ private static class TypeStatePair {
public int type = TYPE_NONE;
public NetworkState ns = null;
}
- static private TypeStatePair findFirstAvailableUpstreamByType(
+ private static TypeStatePair findFirstAvailableUpstreamByType(
Iterable<NetworkState> netStates, Iterable<Integer> preferredTypes) {
final TypeStatePair result = new TypeStatePair();
@@ -431,4 +459,36 @@ public class UpstreamNetworkMonitor {
return result;
}
+
+ private static HashSet<IpPrefix> allOffloadExemptPrefixes(Iterable<NetworkState> netStates) {
+ final HashSet<IpPrefix> prefixSet = new HashSet<>();
+
+ addDefaultLocalPrefixes(prefixSet);
+
+ for (NetworkState ns : netStates) {
+ addOffloadExemptPrefixes(prefixSet, ns.linkProperties);
+ }
+
+ return prefixSet;
+ }
+
+ private static void addDefaultLocalPrefixes(Set<IpPrefix> prefixSet) {
+ Collections.addAll(prefixSet, MINIMUM_LOCAL_PREFIXES_SET);
+ }
+
+ private static void addOffloadExemptPrefixes(Set<IpPrefix> prefixSet, LinkProperties lp) {
+ if (lp == null) return;
+
+ for (LinkAddress linkAddr : lp.getAllLinkAddresses()) {
+ prefixSet.add(new IpPrefix(linkAddr.getAddress(), linkAddr.getPrefixLength()));
+ }
+
+ // TODO: Consider adding other non-default routes associated with this
+ // network. Traffic to these destinations should perhaps not go through
+ // the Internet (upstream).
+ }
+
+ private static IpPrefix prefix(String prefixStr) {
+ return new IpPrefix(prefixStr);
+ }
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 468cb2990b67..ad74ff88e80f 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -102,6 +102,22 @@ public final class ContentService extends IContentService.Stub {
}
}
+
+ @Override
+ public void onStartUser(int userHandle) {
+ mService.onStartUser(userHandle);
+ }
+
+ @Override
+ public void onUnlockUser(int userHandle) {
+ mService.onUnlockUser(userHandle);
+ }
+
+ @Override
+ public void onStopUser(int userHandle) {
+ mService.onStopUser(userHandle);
+ }
+
@Override
public void onCleanupUser(int userHandle) {
synchronized (mService.mCache) {
@@ -162,6 +178,18 @@ public final class ContentService extends IContentService.Stub {
}
}
+ void onStartUser(int userHandle) {
+ if (mSyncManager != null) mSyncManager.onStartUser(userHandle);
+ }
+
+ void onUnlockUser(int userHandle) {
+ if (mSyncManager != null) mSyncManager.onUnlockUser(userHandle);
+ }
+
+ void onStopUser(int userHandle) {
+ if (mSyncManager != null) mSyncManager.onStopUser(userHandle);
+ }
+
@Override
protected synchronized void dump(FileDescriptor fd, PrintWriter pw_, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw_)) return;
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 35591420af50..c250005204ba 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -405,6 +405,7 @@ public class SyncManager {
public void onReceive(Context context, Intent intent) {
Log.w(TAG, "Writing sync state before shutdown...");
getSyncStorageEngine().writeAllState();
+ mLogger.log("Shutting down.");
}
};
@@ -674,8 +675,23 @@ public class SyncManager {
// before we started checking for account access because they already know
// the account (they run before) which is the genie is out of the bottle.
whiteListExistingSyncAdaptersIfNeeded();
+
+ mLogger.log("Sync manager initialized.");
+ }
+
+ public void onStartUser(int userHandle) {
+ mLogger.log("onStartUser: user=", userHandle);
+ }
+
+ public void onUnlockUser(int userHandle) {
+ mLogger.log("onUnlockUser: user=", userHandle);
+ }
+
+ public void onStopUser(int userHandle) {
+ mLogger.log("onStopUser: user=", userHandle);
}
+
private void whiteListExistingSyncAdaptersIfNeeded() {
if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) {
return;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index ab3aff99937d..8269042da24a 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -132,7 +132,7 @@ public final class DisplayManagerService extends SystemService {
private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
- private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER = 1;
+ private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1;
private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2;
private static final int MSG_DELIVER_DISPLAY_EVENT = 3;
private static final int MSG_REQUEST_TRAVERSAL = 4;
@@ -266,7 +266,6 @@ public final class DisplayManagerService extends SystemService {
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
-
}
public void setupSchedulerPolicies() {
@@ -284,9 +283,9 @@ public final class DisplayManagerService extends SystemService {
// We need to pre-load the persistent data store so it's ready before the default display
// adapter is up so that we have it's configuration. We could load it lazily, but since
// we're going to have to read it in eventually we may as well do it here rather than after
- // we've waited for the diplay to register itself with us.
+ // we've waited for the display to register itself with us.
mPersistentDataStore.loadIfNeeded();
- mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
+ mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS);
publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
true /*allowIsolated*/);
@@ -298,12 +297,16 @@ public final class DisplayManagerService extends SystemService {
public void onBootPhase(int phase) {
if (phase == PHASE_WAIT_FOR_DEFAULT_DISPLAY) {
synchronized (mSyncRoot) {
- long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
- while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) {
+ long timeout = SystemClock.uptimeMillis()
+ + mInjector.getDefaultDisplayDelayTimeout();
+ while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null ||
+ mVirtualDisplayAdapter == null) {
long delay = timeout - SystemClock.uptimeMillis();
if (delay <= 0) {
throw new RuntimeException("Timeout waiting for default display "
- + "to be initialized.");
+ + "to be initialized. DefaultDisplay="
+ + mLogicalDisplays.get(Display.DEFAULT_DISPLAY)
+ + ", mVirtualDisplayAdapter=" + mVirtualDisplayAdapter);
}
if (DEBUG) {
Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay);
@@ -685,11 +688,23 @@ public final class DisplayManagerService extends SystemService {
}
}
- private void registerDefaultDisplayAdapter() {
- // Register default display adapter.
+ private void registerDefaultDisplayAdapters() {
+ // Register default display adapters.
synchronized (mSyncRoot) {
+ // main display adapter
registerDisplayAdapterLocked(new LocalDisplayAdapter(
mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
+
+ // Standalone VR devices rely on a virtual display as their primary display for
+ // 2D UI. We register virtual display adapter along side the main display adapter
+ // here so that it is ready by the time the system sends the home Intent for
+ // early apps like SetupWizard/Launcher. In particular, SUW is displayed using
+ // the virtual display inside VR before any VR-specific apps even run.
+ mVirtualDisplayAdapter = mInjector.getVirtualDisplayAdapter(mSyncRoot, mContext,
+ mHandler, mDisplayAdapterListener);
+ if (mVirtualDisplayAdapter != null) {
+ registerDisplayAdapterLocked(mVirtualDisplayAdapter);
+ }
}
}
@@ -698,7 +713,6 @@ public final class DisplayManagerService extends SystemService {
if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
registerOverlayDisplayAdapterLocked();
registerWifiDisplayAdapterLocked();
- registerVirtualDisplayAdapterLocked();
}
}
}
@@ -719,12 +733,6 @@ public final class DisplayManagerService extends SystemService {
}
}
- private void registerVirtualDisplayAdapterLocked() {
- mVirtualDisplayAdapter = mInjector.getVirtualDisplayAdapter(mSyncRoot, mContext, mHandler,
- mDisplayAdapterListener);
- registerDisplayAdapterLocked(mVirtualDisplayAdapter);
- }
-
private boolean shouldRegisterNonEssentialDisplayAdaptersLocked() {
// In safe mode, we disable non-essential display adapters to give the user
// an opportunity to fix broken settings or other problems that might affect
@@ -1219,6 +1227,10 @@ public final class DisplayManagerService extends SystemService {
Handler handler, DisplayAdapter.Listener displayAdapterListener) {
return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener);
}
+
+ long getDefaultDisplayDelayTimeout() {
+ return WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
+ }
}
@VisibleForTesting
@@ -1241,8 +1253,8 @@ public final class DisplayManagerService extends SystemService {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER:
- registerDefaultDisplayAdapter();
+ case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS:
+ registerDefaultDisplayAdapters();
break;
case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS:
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 553e3c6691e9..2d645c0eea90 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2680,11 +2680,6 @@ public class UserManagerService extends IUserManager.Stub {
addRemovingUserIdLocked(userHandle);
}
- try {
- mAppOpsService.removeUser(userHandle);
- } catch (RemoteException e) {
- Log.w(LOG_TAG, "Unable to notify AppOpsService of removing user", e);
- }
// Set this to a partially created user, so that the user will be purged
// on next startup, in case the runtime stops now before stopping and
// removing the user completely.
@@ -2694,6 +2689,11 @@ public class UserManagerService extends IUserManager.Stub {
userData.info.flags |= UserInfo.FLAG_DISABLED;
writeUserLP(userData);
}
+ try {
+ mAppOpsService.removeUser(userHandle);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Unable to notify AppOpsService of removing user", e);
+ }
if (userData.info.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
&& userData.info.isManagedProfile()) {
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index ebb945023caf..c6ec287d9c6a 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -19,6 +19,7 @@ package com.android.server.policy;
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
+import android.app.ActivityThread;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -79,7 +80,7 @@ public class ImmersiveModeConfirmation {
boolean mVrModeEnabled = false;
public ImmersiveModeConfirmation(Context context) {
- mContext = context;
+ mContext = ActivityThread.currentActivityThread().getSystemUiContext();
mHandler = new H();
mShowDelayMs = getNavBarExitDuration() * 3;
mPanicThresholdMs = context.getResources()
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 89dbc2a1c1c4..5d2d4b6d6090 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1677,8 +1677,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
boolean isUserSetupComplete() {
- return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ boolean isSetupComplete = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
+ if (mHasFeatureLeanback) {
+ isSetupComplete &= isTvUserSetupComplete();
+ }
+ return isSetupComplete;
+ }
+
+ private boolean isTvUserSetupComplete() {
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.TV_USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
}
private void handleShortPressOnHome() {
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 02f2afcb0be8..56612ad21398 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -23,14 +23,17 @@ import android.app.IActivityManager;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.IBluetoothManager;
-import android.media.AudioAttributes;
-import android.nfc.NfcAdapter;
-import android.nfc.INfcAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.om.IOverlayManager;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.media.AudioAttributes;
+import android.nfc.INfcAdapter;
+import android.nfc.NfcAdapter;
import android.os.FileUtils;
import android.os.Handler;
import android.os.PowerManager;
@@ -39,24 +42,21 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.SystemVibrator;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
-import android.os.SystemVibrator;
-import android.os.storage.IStorageShutdownObserver;
import android.os.storage.IStorageManager;
-import android.system.ErrnoException;
-import android.system.Os;
-
-import com.android.internal.telephony.ITelephony;
-import com.android.server.pm.PackageManagerService;
-
+import android.os.storage.IStorageShutdownObserver;
import android.util.Log;
+import android.view.ViewGroup;
import android.view.WindowManager;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import com.android.internal.telephony.ITelephony;
+import com.android.server.pm.PackageManagerService;
-import java.io.BufferedReader;
import java.io.File;
-import java.io.FileReader;
import java.io.IOException;
public final class ShutdownThread extends Thread {
@@ -243,15 +243,7 @@ public final class ShutdownThread extends Thread {
shutdownInner(context, confirm);
}
- private static void beginShutdownSequence(Context context) {
- synchronized (sIsStartedGuard) {
- if (sIsStarted) {
- Log.d(TAG, "Shutdown sequence already running, returning.");
- return;
- }
- sIsStarted = true;
- }
-
+ private static ProgressDialog showShutdownDialog(Context context) {
// Throw up a system dialog to indicate the device is rebooting / shutting down.
ProgressDialog pd = new ProgressDialog(context);
@@ -303,6 +295,32 @@ public final class ShutdownThread extends Thread {
pd.setMessage(context.getText(
com.android.internal.R.string.reboot_to_reset_message));
pd.setIndeterminate(true);
+ } else if (mReason != null && mReason.equals(PowerManager.SHUTDOWN_USER_REQUESTED)) {
+ Dialog d = new Dialog(context);
+ d.setContentView(com.android.internal.R.layout.shutdown_dialog);
+ d.setCancelable(false);
+
+ int color = Color.WHITE;
+ try {
+ IOverlayManager service = IOverlayManager.Stub.asInterface(
+ ServiceManager.getService(Context.OVERLAY_SERVICE));
+ if (service.getOverlayInfo("com.android.systemui.theme.lightwallpaper", 0).isEnabled()) {
+ color = Color.BLACK;
+ }
+ } catch (Exception e) {
+ // Shutdown UI really shouldn't crash or have strict dependencies on other services.
+ Log.w(TAG, "Problem getting overlay state", e);
+ }
+ ProgressBar bar = d.findViewById(com.android.internal.R.id.progress);
+ bar.getIndeterminateDrawable().setTint(color);
+ ((TextView) d.findViewById(com.android.internal.R.id.text1)).setTextColor(color);
+ d.getWindow().getAttributes().width = ViewGroup.LayoutParams.MATCH_PARENT;
+ d.getWindow().getAttributes().height = ViewGroup.LayoutParams.MATCH_PARENT;
+ d.getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+ d.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+ d.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+ d.show();
+ return null;
} else {
pd.setTitle(context.getText(com.android.internal.R.string.power_off));
pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
@@ -312,8 +330,19 @@ public final class ShutdownThread extends Thread {
pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
pd.show();
+ return pd;
+ }
+
+ private static void beginShutdownSequence(Context context) {
+ synchronized (sIsStartedGuard) {
+ if (sIsStarted) {
+ Log.d(TAG, "Shutdown sequence already running, returning.");
+ return;
+ }
+ sIsStarted = true;
+ }
- sInstance.mProgressDialog = pd;
+ sInstance.mProgressDialog = showShutdownDialog(context);
sInstance.mContext = context;
sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
diff --git a/services/core/java/com/android/server/timezone/PackageStatusStorage.java b/services/core/java/com/android/server/timezone/PackageStatusStorage.java
index 05e97c7ef1e9..fe82dc4f1572 100644
--- a/services/core/java/com/android/server/timezone/PackageStatusStorage.java
+++ b/services/core/java/com/android/server/timezone/PackageStatusStorage.java
@@ -32,6 +32,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
+import java.io.PrintWriter;
import static com.android.server.timezone.PackageStatus.CHECK_COMPLETED_FAILURE;
import static com.android.server.timezone.PackageStatus.CHECK_COMPLETED_SUCCESS;
@@ -375,4 +376,8 @@ final class PackageStatusStorage {
}
return value;
}
+
+ public void dump(PrintWriter printWriter) {
+ printWriter.println("Package status: " + getPackageStatus());
+ }
}
diff --git a/services/core/java/com/android/server/timezone/PackageTracker.java b/services/core/java/com/android/server/timezone/PackageTracker.java
index f9af2eae92cd..e8dfd779a715 100644
--- a/services/core/java/com/android/server/timezone/PackageTracker.java
+++ b/services/core/java/com/android/server/timezone/PackageTracker.java
@@ -26,6 +26,7 @@ import android.provider.TimeZoneRulesDataContract;
import android.util.Slog;
import java.io.File;
+import java.io.PrintWriter;
/**
* Monitors the installed applications associated with time zone updates. If the app packages are
@@ -510,4 +511,23 @@ public class PackageTracker implements IntentHelper.Listener {
Slog.wtf(TAG, message, cause);
throw new RuntimeException(message, cause);
}
+
+ public void dump(PrintWriter fout) {
+ fout.println("PackageTrackerState: " + toString());
+ mPackageStatusStorage.dump(fout);
+ }
+
+ @Override
+ public String toString() {
+ return "PackageTracker{" +
+ "mTrackingEnabled=" + mTrackingEnabled +
+ ", mUpdateAppPackageName='" + mUpdateAppPackageName + '\'' +
+ ", mDataAppPackageName='" + mDataAppPackageName + '\'' +
+ ", mCheckTimeAllowedMillis=" + mCheckTimeAllowedMillis +
+ ", mFailedCheckRetryCount=" + mFailedCheckRetryCount +
+ ", mLastTriggerTimestamp=" + mLastTriggerTimestamp +
+ ", mCheckTriggered=" + mCheckTriggered +
+ ", mCheckFailureCount=" + mCheckFailureCount +
+ '}';
+ }
}
diff --git a/services/core/java/com/android/server/timezone/PermissionHelper.java b/services/core/java/com/android/server/timezone/PermissionHelper.java
index ba91c7f7b7ab..2ec31e2f5dfc 100644
--- a/services/core/java/com/android/server/timezone/PermissionHelper.java
+++ b/services/core/java/com/android/server/timezone/PermissionHelper.java
@@ -16,10 +16,14 @@
package com.android.server.timezone;
+import java.io.PrintWriter;
+
/**
* An easy-to-mock interface around permission checks for use by {@link RulesManagerService}.
*/
public interface PermissionHelper {
void enforceCallerHasPermission(String requiredPermission) throws SecurityException;
+
+ boolean checkDumpPermission(String tag, PrintWriter printWriter);
}
diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
index 804a8b79310e..3d60dcf6ac8e 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerService.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerService.java
@@ -22,6 +22,7 @@ import com.android.timezone.distro.DistroException;
import com.android.timezone.distro.DistroVersion;
import com.android.timezone.distro.StagedDistroOperation;
import com.android.timezone.distro.TimeZoneDistro;
+import com.android.timezone.distro.installer.TimeZoneDistroInstaller;
import android.app.timezone.Callback;
import android.app.timezone.DistroFormatVersion;
@@ -36,13 +37,24 @@ import android.os.RemoteException;
import android.util.Slog;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.PrintWriter;
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
-import libcore.tzdata.update2.TimeZoneDistroInstaller;
+import libcore.icu.ICU;
+import libcore.util.ZoneInfoDB;
+
+import static android.app.timezone.RulesState.DISTRO_STATUS_INSTALLED;
+import static android.app.timezone.RulesState.DISTRO_STATUS_NONE;
+import static android.app.timezone.RulesState.DISTRO_STATUS_UNKNOWN;
+import static android.app.timezone.RulesState.STAGED_OPERATION_INSTALL;
+import static android.app.timezone.RulesState.STAGED_OPERATION_NONE;
+import static android.app.timezone.RulesState.STAGED_OPERATION_UNINSTALL;
+import static android.app.timezone.RulesState.STAGED_OPERATION_UNKNOWN;
// TODO(nfuller) Add EventLog calls where useful in the system server.
// TODO(nfuller) Check logging best practices in the system server.
@@ -113,6 +125,11 @@ public final class RulesManagerService extends IRulesManager.Stub {
public RulesState getRulesState() {
mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
+ return getRulesStateInternal();
+ }
+
+ /** Like {@link #getRulesState()} without the permission check. */
+ private RulesState getRulesStateInternal() {
synchronized(this) {
String systemRulesVersion;
try {
@@ -126,18 +143,18 @@ public final class RulesManagerService extends IRulesManager.Stub {
// Determine the staged operation status, if possible.
DistroRulesVersion stagedDistroRulesVersion = null;
- int stagedOperationStatus = RulesState.STAGED_OPERATION_UNKNOWN;
+ int stagedOperationStatus = STAGED_OPERATION_UNKNOWN;
if (!operationInProgress) {
StagedDistroOperation stagedDistroOperation;
try {
stagedDistroOperation = mInstaller.getStagedDistroOperation();
if (stagedDistroOperation == null) {
- stagedOperationStatus = RulesState.STAGED_OPERATION_NONE;
+ stagedOperationStatus = STAGED_OPERATION_NONE;
} else if (stagedDistroOperation.isUninstall) {
- stagedOperationStatus = RulesState.STAGED_OPERATION_UNINSTALL;
+ stagedOperationStatus = STAGED_OPERATION_UNINSTALL;
} else {
// Must be an install.
- stagedOperationStatus = RulesState.STAGED_OPERATION_INSTALL;
+ stagedOperationStatus = STAGED_OPERATION_INSTALL;
DistroVersion stagedDistroVersion = stagedDistroOperation.distroVersion;
stagedDistroRulesVersion = new DistroRulesVersion(
stagedDistroVersion.rulesVersion,
@@ -150,16 +167,16 @@ public final class RulesManagerService extends IRulesManager.Stub {
// Determine the installed distro state, if possible.
DistroVersion installedDistroVersion;
- int distroStatus = RulesState.DISTRO_STATUS_UNKNOWN;
+ int distroStatus = DISTRO_STATUS_UNKNOWN;
DistroRulesVersion installedDistroRulesVersion = null;
if (!operationInProgress) {
try {
installedDistroVersion = mInstaller.getInstalledDistroVersion();
if (installedDistroVersion == null) {
- distroStatus = RulesState.DISTRO_STATUS_NONE;
+ distroStatus = DISTRO_STATUS_NONE;
installedDistroRulesVersion = null;
} else {
- distroStatus = RulesState.DISTRO_STATUS_INSTALLED;
+ distroStatus = DISTRO_STATUS_INSTALLED;
installedDistroRulesVersion = new DistroRulesVersion(
installedDistroVersion.rulesVersion,
installedDistroVersion.revision);
@@ -358,6 +375,87 @@ public final class RulesManagerService extends IRulesManager.Stub {
mPackageTracker.recordCheckResult(checkToken, success);
}
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!mPermissionHelper.checkDumpPermission(TAG, pw)) {
+ return;
+ }
+
+ RulesState rulesState = getRulesStateInternal();
+ if (args != null && args.length == 2) {
+ // Formatting options used for automated tests. The format is less free-form than
+ // the -format options, which are intended to be easier to parse.
+ if ("-format_state".equals(args[0]) && args[1] != null) {
+ for (char c : args[1].toCharArray()) {
+ switch (c) {
+ case 'p': // Report operation in progress
+ pw.println("Operation in progress: "
+ + rulesState.isOperationInProgress());
+ break;
+ case 's': // Report system image rules version
+ pw.println("System rules version: "
+ + rulesState.getSystemRulesVersion());
+ break;
+ case 'c': // Report current installation state
+ pw.println("Current install state: "
+ + distroStatusToString(rulesState.getDistroStatus()));
+ break;
+ case 'i': // Report currently installed version
+ DistroRulesVersion installedRulesVersion =
+ rulesState.getInstalledDistroRulesVersion();
+ pw.print("Installed rules version: ");
+ if (installedRulesVersion == null) {
+ pw.println("<None>");
+ } else {
+ pw.println(installedRulesVersion.toDumpString());
+ }
+ break;
+ case 'o': // Report staged operation type
+ int stagedOperationType = rulesState.getStagedOperationType();
+ pw.println("Staged operation: "
+ + stagedOperationToString(stagedOperationType));
+ break;
+ case 't':
+ // Report staged version (i.e. the one that will be installed next boot
+ // if the staged operation is an install).
+ pw.print("Staged rules version: ");
+ DistroRulesVersion stagedDistroRulesVersion =
+ rulesState.getStagedDistroRulesVersion();
+ if (stagedDistroRulesVersion == null) {
+ pw.println("<None>");
+ } else {
+ pw.println("Staged install version: "
+ + stagedDistroRulesVersion.toDumpString());
+ }
+ break;
+ case 'a':
+ // Report the active rules version (i.e. the rules in use by the current
+ // process).
+ pw.println("Active rules version (ICU, libcore): "
+ + ICU.getTZDataVersion() + ","
+ + ZoneInfoDB.getInstance().getVersion());
+ break;
+ default:
+ pw.println("Unknown option: " + c);
+ }
+ }
+ return;
+ }
+ }
+
+ pw.println("RulesManagerService state: " + toString());
+ pw.println("Active rules version (ICU, libcore): " + ICU.getTZDataVersion() + ","
+ + ZoneInfoDB.getInstance().getVersion());
+ mPackageTracker.dump(pw);
+ }
+
+ @Override
+ public String toString() {
+ return "RulesManagerService{" +
+ "mOperationInProgress=" + mOperationInProgress +
+ '}';
+ }
+
private static CheckToken createCheckTokenOrThrow(byte[] checkTokenBytes) {
CheckToken checkToken;
try {
@@ -368,4 +466,30 @@ public final class RulesManagerService extends IRulesManager.Stub {
}
return checkToken;
}
+
+ private static String distroStatusToString(int distroStatus) {
+ switch(distroStatus) {
+ case DISTRO_STATUS_NONE:
+ return "None";
+ case DISTRO_STATUS_INSTALLED:
+ return "Installed";
+ case DISTRO_STATUS_UNKNOWN:
+ default:
+ return "Unknown";
+ }
+ }
+
+ private static String stagedOperationToString(int stagedOperationType) {
+ switch(stagedOperationType) {
+ case STAGED_OPERATION_NONE:
+ return "None";
+ case STAGED_OPERATION_UNINSTALL:
+ return "Uninstall";
+ case STAGED_OPERATION_INSTALL:
+ return "Install";
+ case STAGED_OPERATION_UNKNOWN:
+ default:
+ return "Unknown";
+ }
+ }
}
diff --git a/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java b/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
index 482d8e2c8014..767f0e0993ef 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
@@ -17,10 +17,13 @@
package com.android.server.timezone;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.ParcelFileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.concurrent.Executor;
import libcore.io.Streams;
@@ -40,6 +43,19 @@ final class RulesManagerServiceHelperImpl implements PermissionHelper, Executor
mContext.enforceCallingPermission(requiredPermission, null /* message */);
}
+ @Override
+ public boolean checkDumpPermission(String tag, PrintWriter pw) {
+ // TODO(nfuller): Switch to DumpUtils.checkDumpPermission() when it is available in AOSP.
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump LocationManagerService from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return false;
+ }
+ return true;
+ }
+
// TODO Wake lock required?
@Override
public void execute(Runnable runnable) {
diff --git a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
index 2be69ac68219..cabce183a1a4 100644
--- a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
@@ -17,12 +17,12 @@
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;
-import libcore.tzdata.update2.TimeZoneDistroInstaller;
/**
* An install receiver responsible for installing timezone data updates.
diff --git a/services/core/java/com/android/server/vr/Vr2dDisplay.java b/services/core/java/com/android/server/vr/Vr2dDisplay.java
index 8335243d590f..b1c1df14feeb 100644
--- a/services/core/java/com/android/server/vr/Vr2dDisplay.java
+++ b/services/core/java/com/android/server/vr/Vr2dDisplay.java
@@ -35,7 +35,6 @@ class Vr2dDisplay {
private final static String TAG = "Vr2dDisplay";
private final static boolean DEBUG = false;
- // TODO: Go over these values and figure out what is best
private int mVirtualDisplayHeight;
private int mVirtualDisplayWidth;
private int mVirtualDisplayDpi;
@@ -55,17 +54,17 @@ class Vr2dDisplay {
/**
* The default width of the VR virtual display
*/
- public static final int DEFAULT_VR_DISPLAY_WIDTH = 1400;
+ public static final int DEFAULT_VIRTUAL_DISPLAY_WIDTH = 1400;
/**
* The default height of the VR virtual display
*/
- public static final int DEFAULT_VR_DISPLAY_HEIGHT = 1800;
+ public static final int DEFAULT_VIRTUAL_DISPLAY_HEIGHT = 1400;
/**
* The default height of the VR virtual dpi.
*/
- public static final int DEFAULT_VR_DISPLAY_DPI = 320;
+ public static final int DEFAULT_VIRTUAL_DISPLAY_DPI = 320;
/**
* The minimum height, width and dpi of VR virtual display.
@@ -87,8 +86,8 @@ class Vr2dDisplay {
new IPersistentVrStateCallbacks.Stub() {
@Override
public void onPersistentVrStateChanged(boolean enabled) {
- if (enabled != mIsVrModeEnabled) {
- mIsVrModeEnabled = enabled;
+ if (enabled != mIsPersistentVrModeEnabled) {
+ mIsPersistentVrModeEnabled = enabled;
updateVirtualDisplay();
}
}
@@ -98,25 +97,33 @@ class Vr2dDisplay {
private Surface mSurface;
private ImageReader mImageReader;
private Runnable mStopVDRunnable;
- private boolean mIsVrModeOverrideEnabled;
- private boolean mIsVrModeEnabled;
+ private boolean mIsVrModeOverrideEnabled; // debug override to set vr mode.
+ private boolean mIsVirtualDisplayAllowed = true; // Virtual-display feature toggle
+ private boolean mIsPersistentVrModeEnabled; // indicates we are in vr persistent mode.
+ private boolean mBootsToVr = false; // The device boots into VR (standalone VR device)
public Vr2dDisplay(DisplayManager displayManager,
ActivityManagerInternal activityManagerInternal, IVrManager vrManager) {
mDisplayManager = displayManager;
mActivityManagerInternal = activityManagerInternal;
mVrManager = vrManager;
- mVirtualDisplayWidth = DEFAULT_VR_DISPLAY_WIDTH;
- mVirtualDisplayHeight = DEFAULT_VR_DISPLAY_HEIGHT;
- mVirtualDisplayDpi = DEFAULT_VR_DISPLAY_DPI;
+ mVirtualDisplayWidth = DEFAULT_VIRTUAL_DISPLAY_WIDTH;
+ mVirtualDisplayHeight = DEFAULT_VIRTUAL_DISPLAY_HEIGHT;
+ mVirtualDisplayDpi = DEFAULT_VIRTUAL_DISPLAY_DPI;
}
/**
* Initializes the compabilitiy display by listening to VR mode changes.
*/
- public void init(Context context) {
+ public void init(Context context, boolean bootsToVr) {
startVrModeListener();
startDebugOnlyBroadcastReceiver(context);
+ mBootsToVr = bootsToVr;
+ if (mBootsToVr) {
+ // If we are booting into VR, we need to start the virtual display immediately. This
+ // ensures that the virtual display is up by the time Setup Wizard is started.
+ updateVirtualDisplay();
+ }
}
/**
@@ -124,10 +131,13 @@ class Vr2dDisplay {
*/
private void updateVirtualDisplay() {
if (DEBUG) {
- Log.i(TAG, "isVrMode: " + mIsVrModeEnabled + ", override: " + mIsVrModeOverrideEnabled);
+ Log.i(TAG, "isVrMode: " + mIsPersistentVrModeEnabled + ", override: "
+ + mIsVrModeOverrideEnabled + ", isAllowed: " + mIsVirtualDisplayAllowed
+ + ", bootsToVr: " + mBootsToVr);
}
- if (mIsVrModeEnabled || mIsVrModeOverrideEnabled) {
+ if (shouldRunVirtualDisplay()) {
+ Log.i(TAG, "Attempting to start virtual display");
// TODO: Consider not creating the display until ActivityManager needs one on
// which to display a 2D application.
startVirtualDisplay();
@@ -190,33 +200,43 @@ class Vr2dDisplay {
*
* <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
*
- * @param compatDisplayProperties Properties of the virtual display for 2D applications
+ * @param displayProperties Properties of the virtual display for 2D applications
* in VR mode.
*/
- public void setVirtualDisplayProperties(Vr2dDisplayProperties compatDisplayProperties) {
+ public void setVirtualDisplayProperties(Vr2dDisplayProperties displayProperties) {
synchronized(mVdLock) {
if (DEBUG) {
- Log.i(TAG, "VD setVirtualDisplayProperties: res = "
- + compatDisplayProperties.getWidth() + "X"
- + compatDisplayProperties.getHeight() + ", dpi = "
- + compatDisplayProperties.getDpi());
+ Log.i(TAG, "VD setVirtualDisplayProperties: " +
+ displayProperties.toString());
}
- if (compatDisplayProperties.getWidth() < MIN_VR_DISPLAY_WIDTH ||
- compatDisplayProperties.getHeight() < MIN_VR_DISPLAY_HEIGHT ||
- compatDisplayProperties.getDpi() < MIN_VR_DISPLAY_DPI) {
- throw new IllegalArgumentException (
- "Illegal argument: height, width, dpi cannot be negative. res = "
- + compatDisplayProperties.getWidth() + "X"
- + compatDisplayProperties.getHeight()
- + ", dpi = " + compatDisplayProperties.getDpi());
+ int width = displayProperties.getWidth();
+ int height = displayProperties.getHeight();
+ int dpi = displayProperties.getDpi();
+ boolean resized = false;
+
+ if (width < MIN_VR_DISPLAY_WIDTH || height < MIN_VR_DISPLAY_HEIGHT ||
+ dpi < MIN_VR_DISPLAY_DPI) {
+ Log.i(TAG, "Ignoring Width/Height/Dpi values of " + width + "," + height + ","
+ + dpi);
+ } else {
+ Log.i(TAG, "Setting width/height/dpi to " + width + "," + height + "," + dpi);
+ mVirtualDisplayWidth = width;
+ mVirtualDisplayHeight = height;
+ mVirtualDisplayDpi = dpi;
+ resized = true;
}
- mVirtualDisplayWidth = compatDisplayProperties.getWidth();
- mVirtualDisplayHeight = compatDisplayProperties.getHeight();
- mVirtualDisplayDpi = compatDisplayProperties.getDpi();
+ if ((displayProperties.getFlags() & Vr2dDisplayProperties.FLAG_VIRTUAL_DISPLAY_ENABLED)
+ == Vr2dDisplayProperties.FLAG_VIRTUAL_DISPLAY_ENABLED) {
+ mIsVirtualDisplayAllowed = true;
+ } else if ((displayProperties.getRemovedFlags() &
+ Vr2dDisplayProperties.FLAG_VIRTUAL_DISPLAY_ENABLED)
+ == Vr2dDisplayProperties.FLAG_VIRTUAL_DISPLAY_ENABLED) {
+ mIsVirtualDisplayAllowed = false;
+ }
- if (mVirtualDisplay != null) {
+ if (mVirtualDisplay != null && resized && mIsVirtualDisplayAllowed) {
mVirtualDisplay.resize(mVirtualDisplayWidth, mVirtualDisplayHeight,
mVirtualDisplayDpi);
ImageReader oldImageReader = mImageReader;
@@ -224,6 +244,9 @@ class Vr2dDisplay {
startImageReader();
oldImageReader.close();
}
+
+ // Start/Stop the virtual display in case the updates indicated that we should.
+ updateVirtualDisplay();
}
}
@@ -297,7 +320,7 @@ class Vr2dDisplay {
mStopVDRunnable = new Runnable() {
@Override
public void run() {
- if (mIsVrModeEnabled) {
+ if (shouldRunVirtualDisplay()) {
Log.i(TAG, "Virtual Display destruction stopped: VrMode is back on.");
} else {
Log.i(TAG, "Stopping Virtual Display");
@@ -366,4 +389,14 @@ class Vr2dDisplay {
mImageReader = null;
}
}
+
+ private boolean shouldRunVirtualDisplay() {
+ // Virtual Display should run whenever:
+ // * Virtual Display is allowed/enabled AND
+ // (1) BootsToVr is set indicating the device never leaves VR
+ // (2) VR (persistent) mode is enabled
+ // (3) VR mode is overridden to be enabled.
+ return mIsVirtualDisplayAllowed &&
+ (mBootsToVr || mIsPersistentVrModeEnabled || mIsVrModeOverrideEnabled);
+ }
}
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 3c537713012e..b10c9a3fd2ac 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -625,7 +625,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC
(DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class);
mVr2dDisplay = new Vr2dDisplay(dm, ami, mVrManager);
- mVr2dDisplay.init(getContext());
+ mVr2dDisplay.init(getContext(), mBootsToVr);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 929f28da66f3..dfcc1665bfc4 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -379,54 +379,31 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
/**
* We can easily extract colors from an ImageWallpaper since it's only a bitmap.
- * In this case, using the crop is more than enough.
- *
- * In case of a live wallpaper, the best we can do is to extract colors from its
- * preview image. Anyway, the live wallpaper can also implement the wallpaper colors API
- * to report when colors change.
+ * In this case, using the crop is more than enough. Live wallpapers are just ignored.
*
* @param wallpaper a wallpaper representation
*/
private void extractColors(WallpaperData wallpaper) {
String cropFile = null;
- Drawable thumbnail = null;
- // This represents a maximum pixel count in an image.
- // It prevents color extraction on big bitmaps.
- int wallpaperId = -1;
+ int wallpaperId;
- boolean imageWallpaper = false;
synchronized (mLock) {
- imageWallpaper = mImageWallpaper.equals(wallpaper.wallpaperComponent)
+ // Not having a wallpaperComponent means it's a lock screen wallpaper.
+ final boolean imageWallpaper = mImageWallpaper.equals(wallpaper.wallpaperComponent)
|| wallpaper.wallpaperComponent == null;
- if (imageWallpaper) {
- if (wallpaper.cropFile != null && wallpaper.cropFile.exists()) {
- cropFile = wallpaper.cropFile.getAbsolutePath();
- }
- } else {
- if (wallpaper.connection == null) {
- Slog.w(TAG, "Can't extract colors, wallpaper not connected. " +
- wallpaper.wallpaperId);
- return;
- }
- WallpaperInfo info = wallpaper.connection.mInfo;
- if (info == null) {
- Slog.w(TAG, "Something is really wrong, live wallpaper doesn't have " +
- "a WallpaperInfo object! " + wallpaper.wallpaperId);
- return;
- }
- thumbnail = info.loadThumbnail(mContext.getPackageManager());
+ if (imageWallpaper && wallpaper.cropFile != null && wallpaper.cropFile.exists()) {
+ cropFile = wallpaper.cropFile.getAbsolutePath();
}
-
wallpaperId = wallpaper.wallpaperId;
}
WallpaperColors colors = null;
if (cropFile != null) {
Bitmap bitmap = BitmapFactory.decodeFile(cropFile);
- colors = WallpaperColors.fromBitmap(bitmap);
- bitmap.recycle();
- } else if (thumbnail != null) {
- colors = WallpaperColors.fromDrawable(thumbnail);
+ if (bitmap != null) {
+ colors = WallpaperColors.fromBitmap(bitmap);
+ bitmap.recycle();
+ }
}
if (colors == null) {
@@ -434,16 +411,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
return;
}
- // Even though we can extract colors from live wallpaper thumbnails,
- // it's risky to assume that it might support dark text on top of it:
- // • Thumbnail might not be accurate.
- // • Colors might change over time.
- if (!imageWallpaper) {
- int colorHints = colors.getColorHints();
- colorHints &= ~WallpaperColors.HINT_SUPPORTS_DARK_TEXT;
- colors.setColorHints(colorHints);
- }
-
synchronized (mLock) {
if (wallpaper.wallpaperId == wallpaperId) {
wallpaper.primaryColors = colors;
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 5f34c6067997..4e4398ee9d91 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -614,7 +614,7 @@ public class AppWindowContainerController
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
} else if (taskSwitch && allowTaskSnapshot) {
return snapshot == null ? STARTING_WINDOW_TYPE_NONE
- : snapshotOrientationSameAsDisplay(snapshot) || fromRecents
+ : snapshotOrientationSameAsTask(snapshot) || fromRecents
? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
} else {
return STARTING_WINDOW_TYPE_NONE;
@@ -640,24 +640,11 @@ public class AppWindowContainerController
return true;
}
- private boolean snapshotOrientationSameAsDisplay(TaskSnapshot snapshot) {
+ private boolean snapshotOrientationSameAsTask(TaskSnapshot snapshot) {
if (snapshot == null) {
return false;
}
- final Rect rect = new Rect(0, 0, snapshot.getSnapshot().getWidth(),
- snapshot.getSnapshot().getHeight());
- rect.inset(snapshot.getContentInsets());
- final Rect taskBoundsWithoutInsets = new Rect();
- mContainer.getTask().getBounds(taskBoundsWithoutInsets);
- final DisplayInfo di = mContainer.getDisplayContent().getDisplayInfo();
- final Rect displayBounds = new Rect(0, 0, di.logicalWidth, di.logicalHeight);
- final Rect stableInsets = new Rect();
- mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
- stableInsets);
- displayBounds.inset(stableInsets);
- final boolean snapshotInLandscape = rect.width() >= rect.height();
- final boolean displayInLandscape = displayBounds.width() >= displayBounds.height();
- return snapshotInLandscape == displayInLandscape;
+ return mContainer.getTask().getConfiguration().orientation == snapshot.getOrientation();
}
public void removeStartingWindow() {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index bd379344e18b..ad3ad5082a96 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -937,8 +937,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
// Update keyguard flags upon finishing relaunch.
checkKeyguardFlagsChanged();
}
-
- updateAllDrawn();
}
void clearRelaunching() {
@@ -1344,6 +1342,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
}
}
+ /**
+ * Determines if the token has finished drawing. This should only be called from
+ * {@link DisplayContent#applySurfaceChangesTransaction}
+ */
void updateAllDrawn() {
if (!allDrawn) {
// Number of drawn windows can be less when a window is being relaunched, wait for
@@ -1571,6 +1573,17 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
return null;
}
+ int getLowestAnimLayer() {
+ for (int i = 0; i < mChildren.size(); i++) {
+ final WindowState w = mChildren.get(i);
+ if (w.mRemoved) {
+ continue;
+ }
+ return w.mWinAnimator.mAnimLayer;
+ }
+ return Integer.MAX_VALUE;
+ }
+
WindowState getHighestAnimLayerWindow(WindowState currentTarget) {
WindowState candidate = null;
for (int i = mChildren.indexOf(currentTarget); i >= 0; i--) {
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index 015c08466708..708973d5d4f2 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -81,6 +81,12 @@ public class DimLayer {
boolean isAttachedToDisplay();
/** Gets the bounds of the dim layer user. */
void getDimBounds(Rect outBounds);
+ /** Returns the layer to place a dim layer. */
+ default int getLayerForDim(WindowStateAnimator animator, int layerOffset,
+ int defaultLayer) {
+ return defaultLayer;
+ }
+
String toShortString();
}
/** The user of this dim layer. */
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index d44cd13f8ed5..49f5ee646efa 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -261,7 +261,8 @@ class DimLayerController {
dimLayer = state.animator.mAnimLayer + LAYER_OFFSET_DIM;
dimAmount = DEFAULT_DIM_AMOUNT_DEAD_WINDOW;
} else {
- dimLayer = state.animator.mAnimLayer - LAYER_OFFSET_DIM;
+ dimLayer = dimLayerUser.getLayerForDim(state.animator, LAYER_OFFSET_DIM,
+ state.animator.mAnimLayer - LAYER_OFFSET_DIM);
dimAmount = state.animator.mWin.mAttrs.dimAmount;
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index c98d60dcad93..9fe73815b380 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1183,6 +1183,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
final int dh = displayInfo.logicalHeight;
config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
Configuration.ORIENTATION_LANDSCAPE;
+ config.setRotation(displayInfo.rotation);
+
config.screenWidthDp =
(int)(mService.mPolicy.getConfigDisplayWidth(dw, dh, displayInfo.rotation,
config.uiMode, mDisplayId) / mDisplayMetrics.density);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 22b0f5bcdf07..7a8c2f91b4e9 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
@@ -82,6 +83,7 @@ public class Session extends IWindowSession.Stub
// Set of visible alert window surfaces connected to this session.
private final Set<WindowSurfaceController> mAlertWindowSurfaces = new HashSet<>();
final boolean mCanAddInternalSystemWindow;
+ final boolean mCanHideNonSystemOverlayWindows;
private AlertWindowNotification mAlertWindowNotification;
private boolean mShowingAlertWindowNotificationAllowed;
private boolean mClientDead = false;
@@ -99,6 +101,8 @@ public class Session extends IWindowSession.Stub
mLastReportedAnimatorScale = service.getCurrentAnimatorScale();
mCanAddInternalSystemWindow = service.mContext.checkCallingOrSelfPermission(
INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED;
+ mCanHideNonSystemOverlayWindows = service.mContext.checkCallingOrSelfPermission(
+ HIDE_NON_SYSTEM_OVERLAY_WINDOWS) == PERMISSION_GRANTED;
mShowingAlertWindowNotificationAllowed = mService.mShowAlertWindowNotifications;
StringBuilder sb = new StringBuilder();
sb.append("Session{");
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index bfebca869554..cc3b146e8e0d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -23,6 +23,8 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSC
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+
import static com.android.server.EventLogTags.WM_TASK_REMOVED;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -39,6 +41,7 @@ import android.view.DisplayInfo;
import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.wm.DimLayer.DimLayerUser;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -637,6 +640,18 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
return isFullscreen();
}
+ @Override
+ public int getLayerForDim(WindowStateAnimator animator, int layerOffset, int defaultLayer) {
+ // If the dim layer is for a starting window, move the dim layer back in the z-order behind
+ // the lowest activity window to ensure it does not occlude the main window if it is
+ // translucent
+ final AppWindowToken appToken = animator.mWin.mAppToken;
+ if (animator.mAttrType == TYPE_APPLICATION_STARTING && hasChild(appToken) ) {
+ return Math.min(defaultLayer, appToken.getLowestAnimLayer() - layerOffset);
+ }
+ return defaultLayer;
+ }
+
boolean isFullscreen() {
if (useCurrentBounds()) {
return mFillsParent;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index a96d22412918..802f9edc92dc 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -20,6 +20,7 @@ import static android.graphics.Color.WHITE;
import static android.graphics.Color.alpha;
import static android.view.SurfaceControl.HIDDEN;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE;
@@ -32,7 +33,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TASK_SNAPSHOT;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
@@ -159,13 +159,13 @@ class TaskSnapshotSurface implements StartingSurface {
windowFlags = mainWindow.getAttrs().flags;
windowPrivateFlags = mainWindow.getAttrs().privateFlags;
+ layoutParams.dimAmount = mainWindow.getAttrs().dimAmount;
layoutParams.type = TYPE_APPLICATION_STARTING;
layoutParams.format = snapshot.getSnapshot().getFormat();
layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
| FLAG_NOT_FOCUSABLE
| FLAG_NOT_TOUCHABLE;
- layoutParams.privateFlags = PRIVATE_FLAG_TASK_SNAPSHOT
- | (windowPrivateFlags & PRIVATE_FLAG_INHERITS);
+ layoutParams.privateFlags = windowPrivateFlags & PRIVATE_FLAG_INHERITS;
layoutParams.token = token.token;
layoutParams.width = LayoutParams.MATCH_PARENT;
layoutParams.height = LayoutParams.MATCH_PARENT;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a95a0cf9808c..20d9286781bb 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -19,16 +19,17 @@ package com.android.server.wm;
import static android.Manifest.permission.MANAGE_APP_TOKENS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
+import static android.Manifest.permission.RESTRICTED_VR_ACCESS;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.StatusBarManager.DISABLE_MASK;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_USER_HANDLE;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.ROOT_UID;
import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID;
-import static android.os.Process.THREAD_PRIORITY_DISPLAY;
import static android.os.Process.myPid;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.os.UserHandle.USER_NULL;
@@ -48,7 +49,6 @@ import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHA
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TASK_SNAPSHOT;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -231,7 +231,6 @@ import com.android.server.DisplayThread;
import com.android.server.EventLogTags;
import com.android.server.FgThread;
import com.android.server.LocalServices;
-import com.android.server.ThreadPriorityBooster;
import com.android.server.UiThread;
import com.android.server.Watchdog;
import com.android.server.input.InputManagerService;
@@ -496,12 +495,15 @@ public class WindowManagerService extends IWindowManager.Stub
*/
Runnable mWaitingForDrawnCallback;
+ /** List of window currently causing non-system overlay windows to be hidden. */
+ private ArrayList<WindowState> mHidingNonSystemOverlayWindows = new ArrayList<>();
+
/**
* Stores for each user whether screencapture is disabled
* This array is essentially a cache for all userId for
* {@link android.app.admin.DevicePolicyManager#getScreenCaptureDisabled}
*/
- SparseArray<Boolean> mScreenCaptureDisabled = new SparseArray<>();
+ private SparseArray<Boolean> mScreenCaptureDisabled = new SparseArray<>();
IInputMethodManager mInputMethodManager;
@@ -1716,6 +1718,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
mPendingRemove.remove(win);
mResizingWindows.remove(win);
+ updateNonSystemOverlayWindowsVisibilityIfNeeded(win, false /* surfaceShown */);
mWindowsChanged = true;
if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Final remove of window: " + win);
@@ -2018,8 +2021,7 @@ public class WindowManagerService extends IWindowManager.Stub
win.setDisplayLayoutNeeded();
mWindowPlacerLocked.performSurfacePlacement(true);
}
- result = win.relayoutVisibleWindow(mergedConfiguration, result, attrChanges,
- oldVisibility);
+ result = win.relayoutVisibleWindow(result, attrChanges, oldVisibility);
try {
result = createSurfaceControl(outSurface, result, win, winAnimator);
@@ -2157,6 +2159,15 @@ public class WindowManagerService extends IWindowManager.Stub
if (!win.isGoneForLayoutLw()) {
win.mResizedWhileGone = false;
}
+
+ // We must always send the latest {@link MergedConfiguration}, regardless of whether we
+ // have already reported it. The client might not have processed the previous value yet
+ // and needs process it before handling the corresponding window frame. the variable
+ // {@code mergedConfiguration} is an out parameter that will be passed back to the
+ // client over IPC and checked there.
+ win.getMergedConfiguration(mergedConfiguration);
+ win.setReportedConfiguration(mergedConfiguration);
+
outFrame.set(win.mCompatFrame);
outOverscanInsets.set(win.mOverscanInsets);
outContentInsets.set(win.mContentInsets);
@@ -6305,6 +6316,9 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public Region getCurrentImeTouchRegion() {
+ if (mContext.checkCallingOrSelfPermission(RESTRICTED_VR_ACCESS) != PERMISSION_GRANTED) {
+ throw new SecurityException("getCurrentImeTouchRegion is restricted to VR services");
+ }
synchronized (mWindowMap) {
final Region r = new Region();
if (mInputMethodWindow != null) {
@@ -6474,6 +6488,21 @@ public class WindowManagerService extends IWindowManager.Stub
ArrayList<WindowState> windows) {
mRoot.dumpWindowsNoHeader(pw, dumpAll, windows);
+ if (!mHidingNonSystemOverlayWindows.isEmpty()) {
+ pw.println();
+ pw.println(" Hiding System Alert Windows:");
+ for (int i = mHidingNonSystemOverlayWindows.size() - 1; i >= 0; i--) {
+ final WindowState w = mHidingNonSystemOverlayWindows.get(i);
+ pw.print(" #"); pw.print(i); pw.print(' ');
+ pw.print(w);
+ if (dumpAll) {
+ pw.println(":");
+ w.dump(pw, " ", true);
+ } else {
+ pw.println();
+ }
+ }
+ }
if (mPendingRemove.size() > 0) {
pw.println();
pw.println(" Remove pending for:");
@@ -7588,4 +7617,28 @@ public class WindowManagerService extends IWindowManager.Stub
boolean hasWideColorGamutSupport() {
return mHasWideColorGamutSupport;
}
+
+ void updateNonSystemOverlayWindowsVisibilityIfNeeded(WindowState win, boolean surfaceShown) {
+ if (!win.hideNonSystemOverlayWindowsWhenVisible()) {
+ return;
+ }
+ final boolean systemAlertWindowsHidden = !mHidingNonSystemOverlayWindows.isEmpty();
+ if (surfaceShown) {
+ if (!mHidingNonSystemOverlayWindows.contains(win)) {
+ mHidingNonSystemOverlayWindows.add(win);
+ }
+ } else {
+ mHidingNonSystemOverlayWindows.remove(win);
+ }
+
+ final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty();
+
+ if (systemAlertWindowsHidden == hideSystemAlertWindows) {
+ return;
+ }
+
+ mRoot.forAllWindows((w) -> {
+ w.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);
+ }, false /* traverseTopToBottom */);
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f74948f8e7f0..001019b43f9c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -46,6 +46,7 @@ import static android.view.WindowManager.LayoutParams.FORMAT_CHANGED;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
@@ -59,7 +60,9 @@ import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
@@ -208,6 +211,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
boolean mPolicyVisibilityAfterAnim = true;
private boolean mAppOpVisibility = true;
boolean mPermanentlyHidden; // the window should never be shown again
+ // This is a non-system overlay window that is currently force hidden.
+ private boolean mForceHideNonSystemOverlayWindow;
boolean mAppFreezing;
boolean mHidden; // Used to determine if to show child windows.
boolean mWallpaperVisible; // for wallpaper, what was last vis report?
@@ -2207,8 +2212,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- void prepareWindowToDisplayDuringRelayout(MergedConfiguration mergedConfiguration,
- boolean wasVisible) {
+ void prepareWindowToDisplayDuringRelayout(boolean wasVisible) {
// We need to turn on screen regardless of visibility.
if ((mAttrs.flags & FLAG_TURN_SCREEN_ON) != 0) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "Relayout window turning screen on: " + this);
@@ -2230,16 +2234,16 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (isDrawnLw() && mService.okToDisplay()) {
mWinAnimator.applyEnterAnimationLocked();
}
+ }
- if (isConfigChanged()) {
- final Configuration globalConfig = mService.mRoot.getConfiguration();
- final Configuration overrideConfig = getMergedOverrideConfiguration();
- mergedConfiguration.setConfiguration(globalConfig, overrideConfig);
- if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + this
- + " visible with new global config: " + globalConfig
- + " merged override config: " + overrideConfig);
- mLastReportedConfiguration.setTo(getConfiguration());
- }
+ void getMergedConfiguration(MergedConfiguration outConfiguration) {
+ final Configuration globalConfig = mService.mRoot.getConfiguration();
+ final Configuration overrideConfig = getMergedOverrideConfiguration();
+ outConfiguration.setConfiguration(globalConfig, overrideConfig);
+ }
+
+ void setReportedConfiguration(MergedConfiguration config) {
+ mLastReportedConfiguration.setTo(config.getMergedConfiguration());
}
void adjustStartingWindowFlags() {
@@ -2371,6 +2375,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// to handle their windows being removed from under them.
return false;
}
+ if (mForceHideNonSystemOverlayWindow) {
+ // This is an alert window that is currently force hidden.
+ return false;
+ }
if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
// Already showing.
return false;
@@ -2447,6 +2455,22 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return true;
}
+ void setForceHideNonSystemOverlayWindowIfNeeded(boolean forceHide) {
+ if (mOwnerCanAddInternalSystemWindow
+ || (!isSystemAlertWindowType(mAttrs.type) && mAttrs.type != TYPE_TOAST)) {
+ return;
+ }
+ if (mForceHideNonSystemOverlayWindow == forceHide) {
+ return;
+ }
+ mForceHideNonSystemOverlayWindow = forceHide;
+ if (forceHide) {
+ hideLw(true /* doAnimation */, true /* requestAnim */);
+ } else {
+ showLw(true /* doAnimation */, true /* requestAnim */);
+ }
+ }
+
public void setAppOpVisibilityLw(boolean state) {
if (mAppOpVisibility != state) {
mAppOpVisibility = state;
@@ -3005,14 +3029,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
try {
if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
+ ": " + mCompatFrame);
- final MergedConfiguration mergedConfiguration;
- if (isConfigChanged()) {
- mergedConfiguration = new MergedConfiguration(mService.mRoot.getConfiguration(),
- getMergedOverrideConfiguration());
- mLastReportedConfiguration.setTo(mergedConfiguration.getMergedConfiguration());
- } else {
- mergedConfiguration = null;
- }
+ final MergedConfiguration mergedConfiguration =
+ new MergedConfiguration(mService.mRoot.getConfiguration(),
+ getMergedOverrideConfiguration());
+
+ setReportedConfiguration(mergedConfiguration);
+
if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == DRAW_PENDING)
Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");
@@ -3330,7 +3352,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
pw.println(Integer.toHexString(mSystemUiVisibility));
}
if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || !mAppOpVisibility
- || isParentWindowHidden()|| mPermanentlyHidden) {
+ || isParentWindowHidden()|| mPermanentlyHidden || mForceHideNonSystemOverlayWindow) {
pw.print(prefix); pw.print("mPolicyVisibility=");
pw.print(mPolicyVisibility);
pw.print(" mPolicyVisibilityAfterAnim=");
@@ -3338,7 +3360,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
pw.print(" mAppOpVisibility=");
pw.print(mAppOpVisibility);
pw.print(" parentHidden="); pw.print(isParentWindowHidden());
- pw.print(" mPermanentlyHidden="); pw.println(mPermanentlyHidden);
+ pw.print(" mPermanentlyHidden="); pw.print(mPermanentlyHidden);
+ pw.print(" mForceHideNonSystemOverlayWindow="); pw.println(
+ mForceHideNonSystemOverlayWindow);
}
if (!mRelayoutCalled || mLayoutNeeded) {
pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled);
@@ -3593,6 +3617,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
&& (mAttrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) != 0;
}
+ /**
+ * Returns true if any window added by an application process that if of type
+ * {@link android.view.WindowManager.LayoutParams#TYPE_TOAST} or that requires that requires
+ * {@link android.app.AppOpsManager#OP_SYSTEM_ALERT_WINDOW} permission should be hidden when
+ * this window is visible.
+ */
+ boolean hideNonSystemOverlayWindowsWhenVisible() {
+ return (mAttrs.privateFlags & PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0
+ && mSession.mCanHideNonSystemOverlayWindows;
+ }
+
/** Returns the parent window if this is a child of another window, else null. */
WindowState getParentWindow() {
// NOTE: We are not calling getParent() directly as the WindowState might be a child of a
@@ -4342,8 +4377,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return !mLastSurfaceInsets.equals(mAttrs.surfaceInsets);
}
- int relayoutVisibleWindow(MergedConfiguration mergedConfiguration, int result, int attrChanges,
- int oldVisibility) {
+ int relayoutVisibleWindow(int result, int attrChanges, int oldVisibility) {
final boolean wasVisible = isVisibleLw();
result |= (!wasVisible || !isDrawnLw()) ? RELAYOUT_RES_FIRST_TIME : 0;
@@ -4366,7 +4400,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mWinAnimator.mEnteringAnimation = true;
- prepareWindowToDisplayDuringRelayout(mergedConfiguration, wasVisible);
+ prepareWindowToDisplayDuringRelayout(wasVisible);
if ((attrChanges & FORMAT_CHANGED) != 0) {
// If the format can't be changed in place, preserve the old surface until the app draws
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 27927e6c0693..1728cfbb6ef0 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -24,10 +24,8 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static android.view.Surface.SCALING_MODE_FREEZE;
import static android.view.Surface.SCALING_MODE_SCALE_TO_WINDOW;
-import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -514,6 +512,8 @@ class WindowSurfaceController {
void setShown(boolean surfaceShown) {
mSurfaceShown = surfaceShown;
+ mService.updateNonSystemOverlayWindowsVisibilityIfNeeded(mAnimator.mWin, surfaceShown);
+
if (mWindowSession != null) {
mWindowSession.onWindowSurfaceVisibilityChanged(this, mSurfaceShown, mWindowType);
}
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index fdcf9df50426..c8c629fd5ea5 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -33,6 +33,7 @@ LOCAL_SRC_FILES += \
$(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \
$(LOCAL_REL_DIR)/com_android_server_vr_VrManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_UsbDescriptorParser.cpp \
$(LOCAL_REL_DIR)/com_android_server_UsbMidiDevice.cpp \
$(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
$(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
diff --git a/services/core/jni/com_android_server_GraphicsStatsService.cpp b/services/core/jni/com_android_server_GraphicsStatsService.cpp
index 5d5728da61af..61c53e6d30b3 100644
--- a/services/core/jni/com_android_server_GraphicsStatsService.cpp
+++ b/services/core/jni/com_android_server_GraphicsStatsService.cpp
@@ -43,8 +43,9 @@ static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jstrin
std::string path;
const ProfileData* data = nullptr;
LOG_ALWAYS_FATAL_IF(jdata == nullptr && jpath == nullptr, "Path and data can't both be null");
+ ScopedByteArrayRO buffer{env};
if (jdata != nullptr) {
- ScopedByteArrayRO buffer(env, jdata);
+ buffer.reset(jdata);
LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
"Buffer size %zu doesn't match expected %zu!", buffer.size(), sizeof(ProfileData));
data = reinterpret_cast<const ProfileData*>(buffer.get());
diff --git a/services/core/jni/com_android_server_UsbDescriptorParser.cpp b/services/core/jni/com_android_server_UsbDescriptorParser.cpp
new file mode 100644
index 000000000000..98c5ec1bd4d5
--- /dev/null
+++ b/services/core/jni/com_android_server_UsbDescriptorParser.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "UsbHostManagerJNI"
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include <usbhost/usbhost.h>
+
+#define MAX_DESCRIPTORS_LENGTH 16384
+
+// com.android.server.usb.descriptors
+extern "C" {
+jbyteArray JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getRawDescriptors(
+ JNIEnv* env, jobject thiz, jstring deviceAddr) {
+ const char *deviceAddrStr = env->GetStringUTFChars(deviceAddr, NULL);
+ struct usb_device* device = usb_device_open(deviceAddrStr);
+ env->ReleaseStringUTFChars(deviceAddr, deviceAddrStr);
+
+ if (!device) {
+ ALOGE("usb_device_open failed");
+ return NULL;
+ }
+
+ int fd = usb_device_get_fd(device);
+ if (fd < 0) {
+ return NULL;
+ }
+
+ // from android_hardware_UsbDeviceConnection_get_desc()
+ jbyte buffer[MAX_DESCRIPTORS_LENGTH];
+ lseek(fd, 0, SEEK_SET);
+ int numBytes = read(fd, buffer, sizeof(buffer));
+
+ usb_device_close(device);
+
+ jbyteArray ret = NULL;
+ if (numBytes != 0) {
+ ret = env->NewByteArray(numBytes);
+ env->SetByteArrayRegion(ret, 0, numBytes, buffer);
+ }
+ return ret;
+}
+
+} // extern "C"
+
+
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 804cd17fc27c..cb8416b36be5 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -42,107 +42,121 @@ using IVibrator_1_1 = android::hardware::vibrator::V1_1::IVibrator;
namespace android
{
-static sp<IVibrator> mHal;
+static constexpr int NUM_TRIES = 2;
+
+// Creates a Return<R> with STATUS::EX_NULL_POINTER.
+template<class R>
+inline Return<R> NullptrStatus() {
+ using ::android::hardware::Status;
+ return Return<R>{Status::fromExceptionCode(Status::EX_NULL_POINTER)};
+}
+
+// Helper used to transparently deal with the vibrator HAL becoming unavailable.
+template<class R, class I, class... Args0, class... Args1>
+Return<R> halCall(Return<R> (I::* fn)(Args0...), Args1&&... args1) {
+ // Assume that if getService returns a nullptr, HAL is not available on the
+ // device.
+ static sp<I> sHal = I::getService();
+ static bool sAvailable = sHal != nullptr;
+
+ if (!sAvailable) {
+ return NullptrStatus<R>();
+ }
+
+ // Return<R> doesn't have a default constructor, so make a Return<R> with
+ // STATUS::EX_NONE.
+ using ::android::hardware::Status;
+ Return<R> ret{Status::fromExceptionCode(Status::EX_NONE)};
+
+ // Note that ret is guaranteed to be changed after this loop.
+ for (int i = 0; i < NUM_TRIES; ++i) {
+ ret = (sHal == nullptr) ? NullptrStatus<R>()
+ : (*sHal.*fn)(std::forward<Args1>(args1)...);
+
+ if (!ret.isOk()) {
+ ALOGE("Failed to issue command to vibrator HAL. Retrying.");
+ // Restoring connection to the HAL.
+ sHal = I::tryGetService();
+ }
+ }
+ return ret;
+}
static void vibratorInit(JNIEnv /* env */, jobject /* clazz */)
{
- /* TODO(b/31632518) */
- if (mHal != nullptr) {
- return;
- }
- mHal = IVibrator::getService();
+ halCall(&IVibrator::ping).isOk();
}
static jboolean vibratorExists(JNIEnv* /* env */, jobject /* clazz */)
{
- if (mHal != nullptr) {
- return JNI_TRUE;
- } else {
- return JNI_FALSE;
- }
+ return halCall(&IVibrator::ping).isOk() ? JNI_TRUE : JNI_FALSE;
}
static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms)
{
- if (mHal != nullptr) {
- Status retStatus = mHal->on(timeout_ms);
- if (retStatus != Status::OK) {
- ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
- }
- } else {
- ALOGW("Tried to vibrate but there is no vibrator device.");
+ Status retStatus = halCall(&IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR);
+ if (retStatus != Status::OK) {
+ ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
}
}
static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */)
{
- if (mHal != nullptr) {
- Status retStatus = mHal->off();
- if (retStatus != Status::OK) {
- ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
- }
- } else {
- ALOGW("Tried to stop vibrating but there is no vibrator device.");
+ Status retStatus = halCall(&IVibrator::off).withDefault(Status::UNKNOWN_ERROR);
+ if (retStatus != Status::OK) {
+ ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
}
}
static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jobject) {
- if (mHal != nullptr) {
- return mHal->supportsAmplitudeControl();
- } else {
- ALOGW("Unable to get max vibration amplitude, there is no vibrator device.");
- }
- return false;
+ return halCall(&IVibrator::supportsAmplitudeControl).withDefault(false);
}
static void vibratorSetAmplitude(JNIEnv*, jobject, jint amplitude) {
- if (mHal != nullptr) {
- Status status = mHal->setAmplitude(static_cast<uint32_t>(amplitude));
- if (status != Status::OK) {
- ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").",
- static_cast<uint32_t>(status));
- }
- } else {
- ALOGW("Unable to set vibration amplitude, there is no vibrator device.");
+ Status status = halCall(&IVibrator::setAmplitude, static_cast<uint32_t>(amplitude))
+ .withDefault(Status::UNKNOWN_ERROR);
+ if (status != Status::OK) {
+ ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").",
+ static_cast<uint32_t>(status));
}
}
static jlong vibratorPerformEffect(JNIEnv*, jobject, jlong effect, jint strength) {
- if (mHal != nullptr) {
- Status status;
- uint32_t lengthMs;
- auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) {
- status = retStatus;
- lengthMs = retLengthMs;
- };
- EffectStrength effectStrength(static_cast<EffectStrength>(strength));
-
- if (effect < 0 || effect > static_cast<uint32_t>(Effect_1_1::TICK)) {
- ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")",
+ Status status;
+ uint32_t lengthMs;
+ auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) {
+ status = retStatus;
+ lengthMs = retLengthMs;
+ };
+ EffectStrength effectStrength(static_cast<EffectStrength>(strength));
+
+ if (effect < 0 || effect > static_cast<uint32_t>(Effect_1_1::TICK)) {
+ ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")",
+ static_cast<int32_t>(effect));
+ } else if (effect == static_cast<uint32_t>(Effect_1_1::TICK)) {
+ auto ret = halCall(&IVibrator_1_1::perform_1_1, static_cast<Effect_1_1>(effect),
+ effectStrength, callback);
+ if (!ret.isOk()) {
+ ALOGW("Failed to perform effect (%" PRId32 "), insufficient HAL version",
static_cast<int32_t>(effect));
- } else if (effect == static_cast<uint32_t>(Effect_1_1::TICK)) {
- sp<IVibrator_1_1> hal_1_1 = IVibrator_1_1::castFrom(mHal);
- if (hal_1_1 != nullptr) {
- hal_1_1->perform_1_1(static_cast<Effect_1_1>(effect), effectStrength, callback);
- } else {
- ALOGW("Failed to perform effect (%" PRId32 "), insufficient HAL version",
- static_cast<int32_t>(effect));
- }
- } else {
- mHal->perform(static_cast<Effect>(effect), effectStrength, callback);
- }
- if (status == Status::OK) {
- return lengthMs;
- } else if (status != Status::UNSUPPORTED_OPERATION) {
- // Don't warn on UNSUPPORTED_OPERATION, that's a normal even and just means the motor
- // doesn't have a pre-defined waveform to perform for it, so we should just fall back
- // to the framework waveforms.
- ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32
- ", error=%" PRIu32 ").", static_cast<int64_t>(effect),
- static_cast<int32_t>(strength), static_cast<uint32_t>(status));
}
} else {
- ALOGW("Unable to perform haptic effect, there is no vibrator device.");
+ auto ret = halCall(&IVibrator::perform, static_cast<Effect>(effect), effectStrength,
+ callback);
+ if (!ret.isOk()) {
+ ALOGW("Failed to perform effect (%" PRId32 ")", static_cast<int32_t>(effect));
+ }
+ }
+
+ if (status == Status::OK) {
+ return lengthMs;
+ } else if (status != Status::UNSUPPORTED_OPERATION) {
+ // Don't warn on UNSUPPORTED_OPERATION, that's a normal even and just means the motor
+ // doesn't have a pre-defined waveform to perform for it, so we should just fall back
+ // to the framework waveforms.
+ ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32
+ ", error=%" PRIu32 ").", static_cast<int64_t>(effect),
+ static_cast<int32_t>(strength), static_cast<uint32_t>(status));
}
return -1;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8cac6e051e6b..68349a1a4013 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2020,12 +2020,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void setDeviceOwnerSystemPropertyLocked() {
final boolean deviceProvisioned =
mInjector.settingsGlobalGetInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+ final boolean hasDeviceOwner = mOwners.hasDeviceOwner();
// If the device is not provisioned and there is currently no device owner, do not set the
- // read-only system property yet, since Device owner may still be provisioned. For Wear
- // devices, if there is already a device owner then it's OK to set the property to true now,
- // regardless the provision state.
- final boolean isWatchWithDeviceOwner = mIsWatch && mOwners.hasDeviceOwner();
- if (!isWatchWithDeviceOwner && !deviceProvisioned) {
+ // read-only system property yet, since Device owner may still be provisioned.
+ if (!hasDeviceOwner && !deviceProvisioned) {
return;
}
// Still at the first stage of CryptKeeper double bounce, mOwners.hasDeviceOwner is
@@ -2034,20 +2032,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return;
}
- if (!TextUtils.isEmpty(mInjector.systemPropertiesGet(PROPERTY_DEVICE_OWNER_PRESENT))) {
+ if (!mInjector.systemPropertiesGet(PROPERTY_DEVICE_OWNER_PRESENT, "").isEmpty()) {
Slog.w(LOG_TAG, "Trying to set ro.device_owner, but it has already been set?");
} else {
- if (mOwners.hasDeviceOwner()) {
- mInjector.systemPropertiesSet(PROPERTY_DEVICE_OWNER_PRESENT, "true");
- Slog.i(LOG_TAG, "Set ro.device_owner property to true");
+ final String value = Boolean.toString(hasDeviceOwner);
+ mInjector.systemPropertiesSet(PROPERTY_DEVICE_OWNER_PRESENT, value);
+ Slog.i(LOG_TAG, "Set ro.device_owner property to " + value);
- if (mInjector.securityLogGetLoggingEnabledProperty()) {
- mSecurityLogMonitor.start();
- maybePauseDeviceWideLoggingLocked();
- }
- } else {
- mInjector.systemPropertiesSet(PROPERTY_DEVICE_OWNER_PRESENT, "false");
- Slog.i(LOG_TAG, "Set ro.device_owner property to false");
+ if (hasDeviceOwner && mInjector.securityLogGetLoggingEnabledProperty()) {
+ mSecurityLogMonitor.start();
+ maybePauseDeviceWideLoggingLocked();
}
}
}
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index a94536ceaab4..48fa9707976c 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -35,6 +35,7 @@ import android.net.dhcp.DhcpClient;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.IpManagerEvent;
import android.net.util.MultinetworkPolicyTracker;
+import android.net.util.SharedLog;
import android.os.INetworkManagementService;
import android.os.Message;
import android.os.RemoteException;
@@ -187,7 +188,7 @@ public class IpManager extends StateMachine {
}
private void log(String msg) {
- mLocalLog.log(PREFIX + msg);
+ mLog.log(PREFIX + msg);
}
@Override
@@ -414,7 +415,7 @@ public class IpManager extends StateMachine {
private final WakeupMessage mProvisioningTimeoutAlarm;
private final WakeupMessage mDhcpActionTimeoutAlarm;
private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
- private final LocalLog mLocalLog;
+ private final SharedLog mLog;
private final LocalLog mConnectivityPacketLog;
private final MessageHandlingLogger mMsgStateLogger;
private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
@@ -455,7 +456,7 @@ public class IpManager extends StateMachine {
mCallback = new LoggingCallbackWrapper(callback);
mNwService = nwService;
- mLocalLog = new LocalLog(MAX_LOG_RECORDS);
+ mLog = new SharedLog(MAX_LOG_RECORDS, mTag);
mConnectivityPacketLog = new LocalLog(MAX_PACKET_RECORDS);
mMsgStateLogger = new MessageHandlingLogger();
@@ -500,7 +501,7 @@ public class IpManager extends StateMachine {
private void logMsg(String msg) {
Log.d(mTag, msg);
- getHandler().post(() -> { mLocalLog.log("OBSERVED " + msg); });
+ getHandler().post(() -> { mLog.log("OBSERVED " + msg); });
}
};
@@ -508,7 +509,7 @@ public class IpManager extends StateMachine {
mLinkProperties.setInterfaceName(mInterfaceName);
mMultinetworkPolicyTracker = new MultinetworkPolicyTracker(mContext, getHandler(),
- () -> { mLocalLog.log("OBSERVED AvoidBadWifi changed"); });
+ () -> { mLog.log("OBSERVED AvoidBadWifi changed"); });
mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT);
@@ -658,7 +659,7 @@ public class IpManager extends StateMachine {
pw.println();
pw.println(mTag + " StateMachine dump:");
pw.increaseIndent();
- mLocalLog.readOnlyLocalLog().dump(fd, pw, args);
+ mLog.dump(fd, pw, args);
pw.decreaseIndent();
pw.println();
@@ -693,7 +694,7 @@ public class IpManager extends StateMachine {
msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger);
final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
- mLocalLog.log(richerLogLine);
+ mLog.log(richerLogLine);
if (VDBG) {
Log.d(mTag, richerLogLine);
}
@@ -717,7 +718,7 @@ public class IpManager extends StateMachine {
private void logError(String fmt, Object... args) {
final String msg = "ERROR " + String.format(fmt, args);
Log.e(mTag, msg);
- mLocalLog.log(msg);
+ mLog.log(msg);
}
private void getNetworkInterface() {
@@ -1088,6 +1089,7 @@ public class IpManager extends StateMachine {
mIpReachabilityMonitor = new IpReachabilityMonitor(
mContext,
mInterfaceName,
+ mLog,
new IpReachabilityMonitor.Callback() {
@Override
public void notifyLost(InetAddress ip, String logMsg) {
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index d13449a4c8c6..97c9d82e8e31 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -35,6 +35,7 @@ import android.net.netlink.StructNdaCacheInfo;
import android.net.netlink.StructNdMsg;
import android.net.netlink.StructNlMsgHdr;
import android.net.util.MultinetworkPolicyTracker;
+import android.net.util.SharedLog;
import android.os.PowerManager;
import android.os.SystemClock;
import android.system.ErrnoException;
@@ -150,6 +151,7 @@ public class IpReachabilityMonitor {
private final PowerManager.WakeLock mWakeLock;
private final String mInterfaceName;
private final int mInterfaceIndex;
+ private final SharedLog mLog;
private final Callback mCallback;
private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
private final NetlinkSocketObserver mNetlinkSocketObserver;
@@ -221,11 +223,11 @@ public class IpReachabilityMonitor {
return errno;
}
- public IpReachabilityMonitor(Context context, String ifName, Callback callback) {
- this(context, ifName, callback, null);
+ public IpReachabilityMonitor(Context context, String ifName, SharedLog log, Callback callback) {
+ this(context, ifName, log, callback, null);
}
- public IpReachabilityMonitor(Context context, String ifName, Callback callback,
+ public IpReachabilityMonitor(Context context, String ifName, SharedLog log, Callback callback,
MultinetworkPolicyTracker tracker) throws IllegalArgumentException {
mInterfaceName = ifName;
int ifIndex = -1;
@@ -237,6 +239,7 @@ public class IpReachabilityMonitor {
}
mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, TAG + "." + mInterfaceName);
+ mLog = log.forSubComponent(TAG);
mCallback = callback;
mMultinetworkPolicyTracker = tracker;
mNetlinkSocketObserver = new NetlinkSocketObserver();
@@ -403,6 +406,8 @@ public class IpReachabilityMonitor {
break;
}
final int returnValue = probeNeighbor(mInterfaceIndex, target);
+ mLog.log(String.format("put neighbor %s into NUD_PROBE state (rval=%d)",
+ target.getHostAddress(), returnValue));
logEvent(IpReachabilityEvent.PROBE, returnValue);
}
mLastProbeTimeMs = SystemClock.elapsedRealtime();
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 711c36b8b1d4..48464e5e0248 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -98,25 +98,4 @@ public class ActivityStackTests extends ActivityTestsBase {
testStack.stopActivityLocked(activityRecord);
}
-
- /**
- * This test verifies that {@link ActivityStack#STACK_VISIBLE_ACTIVITY_BEHIND} is returned from
- * {@link ActivityStack#shouldBeVisible(ActivityRecord)} from a fullscreen workspace stack with
- * a visible behind activity when top focused stack is the home stack.
- */
- @Test
- public void testShouldBeVisibleWithVisibleBehindActivity() throws Exception {
- final ActivityManagerService service = createActivityManagerService();
- final TaskRecord task = createTask(service, testActivityComponent,
- ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID);
- final ActivityStack fullscreenWorkspaceStackId = task.getStack();
- final ActivityStack homeStack = service.mStackSupervisor.getStack(
- ActivityManager.StackId.HOME_STACK_ID, true /*createStaticStackIfNeeded*/,
- true /*onTop*/);
- final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task);
- service.mStackSupervisor.setFocusStackUnchecked("testEmptyStackShouldBeVisible", homeStack);
- service.mStackSupervisor.requestVisibleBehindLocked(activityRecord, true);
- assertEquals(ActivityStack.STACK_VISIBLE_ACTIVITY_BEHIND,
- fullscreenWorkspaceStackId.shouldBeVisible(null /*starting*/));
- }
}
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 c58b733b8b54..faa91b875df6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -2307,11 +2307,6 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// restore to the debuggable build state
getServices().buildMock.isDebuggable = true;
- // Always return the default (second arg) when getting system property for long type
- when(getServices().systemProperties.getLong(anyString(), anyLong())).thenAnswer(
- invocation -> invocation.getArguments()[1]
- );
-
// reset to default (0 means the admin is not participating, so default should be returned)
dpm.setRequiredStrongAuthTimeout(admin1, 0);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index e0ea5734d3b8..0c8a7879ef5e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -16,9 +16,13 @@
package com.android.server.devicepolicy;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
@@ -62,6 +66,7 @@ public abstract class DpmTestBase extends AndroidTestCase {
adminAnotherPackage = new ComponentName(DpmMockContext.ANOTHER_PACKAGE_NAME,
"whatever.random.class");
adminNoPerm = new ComponentName(mRealTestContext, DummyDeviceAdmins.AdminNoPerm.class);
+ mockSystemPropertiesToReturnDefault();
}
@Override
@@ -213,4 +218,25 @@ public abstract class DpmTestBase extends AndroidTestCase {
// Set up getPackageInfo().
markPackageAsInstalled(admin.getPackageName(), ai, UserHandle.getUserId(packageUid));
}
+
+ /**
+ * By default, system properties are mocked to return default value. Override the mock if you
+ * want a specific value.
+ */
+ private void mockSystemPropertiesToReturnDefault() {
+ when(getServices().systemProperties.get(
+ anyString(), anyString())).thenAnswer(
+ invocation -> invocation.getArguments()[1]
+ );
+
+ when(getServices().systemProperties.getBoolean(
+ anyString(), anyBoolean())).thenAnswer(
+ invocation -> invocation.getArguments()[1]
+ );
+
+ when(getServices().systemProperties.getLong(
+ anyString(), anyLong())).thenAnswer(
+ invocation -> invocation.getArguments()[1]
+ );
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index e3ce17bcd2d8..61df22ecda9c 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -29,9 +29,11 @@ import android.view.SurfaceControl;
import android.view.WindowManagerInternal;
import com.android.server.LocalServices;
+import com.android.server.SystemService;
import com.android.server.display.DisplayDeviceInfo;
import com.android.server.display.DisplayManagerService.SyncRoot;
import com.android.server.display.VirtualDisplayAdapter.SurfaceControlDisplayFactory;
+import com.android.server.lights.LightsManager;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -45,35 +47,51 @@ import static org.mockito.Mockito.when;
@SmallTest
public class DisplayManagerServiceTest extends AndroidTestCase {
- private Handler mHandler;
- private DisplayManagerService mDisplayManager;
+ private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1;
+ private static final long SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS = 10;
+
+ private final DisplayManagerService.Injector mShortMockedInjector =
+ new DisplayManagerService.Injector() {
+ @Override
+ VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot,
+ Context context, Handler handler, DisplayAdapter.Listener listener) {
+ return mMockVirtualDisplayAdapter;
+ }
+
+ @Override
+ long getDefaultDisplayDelayTimeout() {
+ return SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS;
+ }
+ };
+ private final DisplayManagerService.Injector mBasicInjector =
+ new DisplayManagerService.Injector() {
+ @Override
+ VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot,
+ Context context, Handler handler,
+ DisplayAdapter.Listener displayAdapterListener) {
+ return new VirtualDisplayAdapter(syncRoot, context, handler,
+ displayAdapterListener,
+ (String name, boolean secure) -> mMockDisplayToken);
+ }
+ };
+
@Mock InputManagerInternal mMockInputManagerInternal;
@Mock IVirtualDisplayCallback.Stub mMockAppToken;
@Mock WindowManagerInternal mMockWindowManagerInternal;
+ @Mock LightsManager mMockLightsManager;
@Mock VirtualDisplayAdapter mMockVirtualDisplayAdapter;
@Mock IBinder mMockDisplayToken;
@Override
protected void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mDisplayManager = new DisplayManagerService(mContext,
- new DisplayManagerService.Injector() {
- @Override
- VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, Context context,
- Handler handler, DisplayAdapter.Listener displayAdapterListener) {
- return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener,
- (String name, boolean secure) -> mMockDisplayToken);
- }
- });
- mHandler = mDisplayManager.getDisplayHandler();
LocalServices.removeServiceForTest(InputManagerInternal.class);
LocalServices.addService(InputManagerInternal.class, mMockInputManagerInternal);
LocalServices.removeServiceForTest(WindowManagerInternal.class);
LocalServices.addService(WindowManagerInternal.class, mMockWindowManagerInternal);
-
- mDisplayManager.systemReady(false /* safeMode */, false /* onlyCore */);
- mDisplayManager.windowManagerAndInputReady();
+ LocalServices.removeServiceForTest(LightsManager.class);
+ LocalServices.addService(LightsManager.class, mMockLightsManager);
super.setUp();
}
@@ -83,8 +101,14 @@ public class DisplayManagerServiceTest extends AndroidTestCase {
}
public void testCreateVirtualDisplay_sentToInputManager() throws Exception {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mBasicInjector);
+ registerDefaultDisplays(displayManager);
+ displayManager.systemReady(false /* safeMode */, true /* onlyCore */);
+ displayManager.windowManagerAndInputReady();
+
// This is effectively the DisplayManager service published to ServiceManager.
- DisplayManagerService.BinderService bs = mDisplayManager.new BinderService();
+ DisplayManagerService.BinderService bs = displayManager.new BinderService();
String uniqueId = "uniqueId --- Test";
String uniqueIdPrefix = "virtual:" + mContext.getPackageName() + ":";
@@ -99,10 +123,10 @@ public class DisplayManagerServiceTest extends AndroidTestCase {
"Test Virtual Display", width, height, dpi, null /* surface */, flags /* flags */,
uniqueId);
- mDisplayManager.performTraversalInTransactionFromWindowManagerInternal();
+ displayManager.performTraversalInTransactionFromWindowManagerInternal();
// flush the handler
- mHandler.runWithScissors(() -> {}, 0 /* now */);
+ displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
ArgumentCaptor<List<DisplayViewport>> virtualViewportCaptor =
ArgumentCaptor.forClass(List.class);
@@ -118,8 +142,12 @@ public class DisplayManagerServiceTest extends AndroidTestCase {
}
public void testCreateVirtualDisplayRotatesWithContent() throws Exception {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mBasicInjector);
+ registerDefaultDisplays(displayManager);
+
// This is effectively the DisplayManager service published to ServiceManager.
- DisplayManagerService.BinderService bs = mDisplayManager.new BinderService();
+ DisplayManagerService.BinderService bs = displayManager.new BinderService();
String uniqueId = "uniqueId --- Rotates With Content Test";
int width = 600;
@@ -133,13 +161,76 @@ public class DisplayManagerServiceTest extends AndroidTestCase {
"Test Virtual Display", width, height, dpi, null /* surface */, flags /* flags */,
uniqueId);
- mDisplayManager.performTraversalInTransactionFromWindowManagerInternal();
+ displayManager.performTraversalInTransactionFromWindowManagerInternal();
// flush the handler
- mHandler.runWithScissors(() -> {}, 0 /* now */);
+ displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
- DisplayDeviceInfo ddi = mDisplayManager.getDisplayDeviceInfoInternal(displayId);
+ DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
assertNotNull(ddi);
assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0);
}
+
+ /**
+ * Tests that the virtual display is created along-side the default display.
+ */
+ public void testStartVirtualDisplayWithDefaultDisplay_Succeeds() throws Exception {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mShortMockedInjector);
+ registerDefaultDisplays(displayManager);
+ displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+ }
+
+ /**
+ * Tests that we get a Runtime exception when we cannot initialize the default display.
+ */
+ public void testStartVirtualDisplayWithDefDisplay_NoDefaultDisplay() throws Exception {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mShortMockedInjector);
+ Handler handler = displayManager.getDisplayHandler();
+ handler.runWithScissors(() -> {}, 0 /* now */);
+
+ try {
+ displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+ } catch (RuntimeException e) {
+ return;
+ }
+ fail("Expected DisplayManager to throw RuntimeException when it cannot initialize the"
+ + " default display");
+ }
+
+ /**
+ * Tests that we get a Runtime exception when we cannot initialize the virtual display.
+ */
+ public void testStartVirtualDisplayWithDefDisplay_NoVirtualDisplayAdapter() throws Exception {
+ DisplayManagerService displayManager = new DisplayManagerService(mContext,
+ new DisplayManagerService.Injector() {
+ @Override
+ VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot,
+ Context context, Handler handler, DisplayAdapter.Listener listener) {
+ return null; // return null for the adapter. This should cause a failure.
+ }
+
+ @Override
+ long getDefaultDisplayDelayTimeout() {
+ return SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS;
+ }
+ });
+ try {
+ displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+ } catch (RuntimeException e) {
+ return;
+ }
+ fail("Expected DisplayManager to throw RuntimeException when it cannot initialize the"
+ + " virtual display adapter");
+ }
+
+ private void registerDefaultDisplays(DisplayManagerService displayManager) {
+ Handler handler = displayManager.getDisplayHandler();
+ // Would prefer to call displayManager.onStart() directly here but it performs binderService
+ // registration which triggers security exceptions when running from a test.
+ handler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS);
+ // flush the handler
+ handler.runWithScissors(() -> {}, 0 /* now */);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index 84cca0eb050b..e9674f015de3 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -20,6 +20,7 @@ import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -30,8 +31,10 @@ import android.content.ComponentName;
import android.content.pm.UserInfo;
import android.os.FileUtils;
import android.os.IProgressListener;
+import android.os.RemoteException;
import android.os.UserManager;
import android.os.storage.StorageManager;
+import android.os.storage.IStorageManager;
import android.security.KeyStore;
import android.test.AndroidTestCase;
@@ -67,7 +70,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase {
MockGateKeeperService mGateKeeperService;
NotificationManager mNotificationManager;
UserManager mUserManager;
- MockStorageManager mStorageManager;
+ FakeStorageManager mStorageManager;
IActivityManager mActivityManager;
DevicePolicyManager mDevicePolicyManager;
KeyStore mKeyStore;
@@ -81,7 +84,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase {
mGateKeeperService = new MockGateKeeperService();
mNotificationManager = mock(NotificationManager.class);
mUserManager = mock(UserManager.class);
- mStorageManager = new MockStorageManager();
+ mStorageManager = new FakeStorageManager();
mActivityManager = mock(IActivityManager.class);
mDevicePolicyManager = mock(DevicePolicyManager.class);
@@ -97,8 +100,8 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase {
}
mSpManager = new MockSyntheticPasswordManager(mStorage, mGateKeeperService, mUserManager);
- mService = new LockSettingsServiceTestable(mContext, mLockPatternUtils,
- mStorage, mGateKeeperService, mKeyStore, mStorageManager, mActivityManager,
+ mService = new LockSettingsServiceTestable(mContext, mLockPatternUtils, mStorage,
+ mGateKeeperService, mKeyStore, setUpStorageManagerMock(), mActivityManager,
mSpManager);
when(mUserManager.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(PRIMARY_USER_INFO);
mPrimaryUserProfiles.add(PRIMARY_USER_INFO);
@@ -145,6 +148,33 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase {
return userInfo;
}
+ private IStorageManager setUpStorageManagerMock() throws RemoteException {
+ final IStorageManager sm = mock(IStorageManager.class);
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ mStorageManager.addUserKeyAuth((int) args[0] /* userId */,
+ (int) args[1] /* serialNumber */,
+ (byte[]) args[2] /* token */,
+ (byte[]) args[3] /* secret */);
+ return null;
+ }
+ }).when(sm).addUserKeyAuth(anyInt(), anyInt(), any(), any());
+
+ doAnswer(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ mStorageManager.fixateNewestUserKeyAuth((int) args[0] /* userId */);
+ return null;
+ }
+ }).when(sm).fixateNewestUserKeyAuth(anyInt());
+ return sm;
+ }
+
@Override
protected void tearDown() throws Exception {
super.tearDown();
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java b/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java
new file mode 100644
index 000000000000..dbdb41bc71b1
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.locksettings;
+
+import android.os.IProgressListener;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Pair;
+
+
+import junit.framework.AssertionFailedError;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class FakeStorageManager {
+
+ private ArrayMap<Integer, ArrayList<Pair<byte[], byte[]>>> mAuth = new ArrayMap<>();
+ private boolean mIgnoreBadUnlock;
+
+ public void addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
+ getUserAuth(userId).add(new Pair<>(token, secret));
+ }
+
+ public void fixateNewestUserKeyAuth(int userId) {
+ ArrayList<Pair<byte[], byte[]>> auths = mAuth.get(userId);
+ Pair<byte[], byte[]> latest = auths.get(auths.size() - 1);
+ auths.clear();
+ auths.add(latest);
+ }
+
+ private ArrayList<Pair<byte[], byte[]>> getUserAuth(int userId) {
+ if (!mAuth.containsKey(userId)) {
+ ArrayList<Pair<byte[], byte[]>> auths = new ArrayList<Pair<byte[], byte[]>>();
+ auths.add(new Pair(null, null));
+ mAuth.put(userId, auths);
+ }
+ return mAuth.get(userId);
+ }
+
+ public byte[] getUserUnlockToken(int userId) {
+ ArrayList<Pair<byte[], byte[]>> auths = getUserAuth(userId);
+ if (auths.size() != 1) {
+ throw new AssertionFailedError("More than one secret exists");
+ }
+ return auths.get(0).second;
+ }
+
+ public void unlockUser(int userId, byte[] secret, IProgressListener listener)
+ throws RemoteException {
+ listener.onStarted(userId, null);
+ listener.onFinished(userId, null);
+ ArrayList<Pair<byte[], byte[]>> auths = getUserAuth(userId);
+ if (secret != null) {
+ if (auths.size() > 1) {
+ throw new AssertionFailedError("More than one secret exists");
+ }
+ Pair<byte[], byte[]> auth = auths.get(0);
+ if ((!mIgnoreBadUnlock) && auth.second != null && !Arrays.equals(secret, auth.second)) {
+ throw new AssertionFailedError("Invalid secret to unlock user");
+ }
+ } else {
+ if (auths != null && auths.size() > 0) {
+ throw new AssertionFailedError("Cannot unlock encrypted user with empty token");
+ }
+ }
+ }
+
+ public void setIgnoreBadUnlock(boolean ignore) {
+ mIgnoreBadUnlock = ignore;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java b/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java
deleted file mode 100644
index 40e114bfaef2..000000000000
--- a/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java
+++ /dev/null
@@ -1,507 +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.locksettings;
-
-import android.content.pm.IPackageMoveObserver;
-import android.os.IBinder;
-import android.os.IProgressListener;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.os.storage.DiskInfo;
-import android.os.storage.IObbActionListener;
-import android.os.storage.IStorageEventListener;
-import android.os.storage.IStorageManager;
-import android.os.storage.IStorageShutdownObserver;
-import android.os.storage.StorageVolume;
-import android.os.storage.VolumeInfo;
-import android.os.storage.VolumeRecord;
-import android.util.ArrayMap;
-import android.util.Pair;
-
-import com.android.internal.os.AppFuseMount;
-
-import junit.framework.AssertionFailedError;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-public class MockStorageManager implements IStorageManager {
-
- private ArrayMap<Integer, ArrayList<Pair<byte[], byte[]>>> mAuth = new ArrayMap<>();
- private boolean mIgnoreBadUnlock;
-
- @Override
- public void addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret)
- throws RemoteException {
- getUserAuth(userId).add(new Pair<>(token, secret));
- }
-
- @Override
- public void fixateNewestUserKeyAuth(int userId) throws RemoteException {
- ArrayList<Pair<byte[], byte[]>> auths = mAuth.get(userId);
- Pair<byte[], byte[]> latest = auths.get(auths.size() - 1);
- auths.clear();
- auths.add(latest);
- }
-
- private ArrayList<Pair<byte[], byte[]>> getUserAuth(int userId) {
- if (!mAuth.containsKey(userId)) {
- ArrayList<Pair<byte[], byte[]>> auths = new ArrayList<Pair<byte[], byte[]>>();
- auths.add(new Pair(null, null));
- mAuth.put(userId, auths);
- }
- return mAuth.get(userId);
- }
-
- public byte[] getUserUnlockToken(int userId) {
- ArrayList<Pair<byte[], byte[]>> auths = getUserAuth(userId);
- if (auths.size() != 1) {
- throw new AssertionFailedError("More than one secret exists");
- }
- return auths.get(0).second;
- }
-
- public void unlockUser(int userId, byte[] secret, IProgressListener listener)
- throws RemoteException {
- listener.onStarted(userId, null);
- listener.onFinished(userId, null);
- ArrayList<Pair<byte[], byte[]>> auths = getUserAuth(userId);
- if (secret != null) {
- if (auths.size() > 1) {
- throw new AssertionFailedError("More than one secret exists");
- }
- Pair<byte[], byte[]> auth = auths.get(0);
- if ((!mIgnoreBadUnlock) && auth.second != null && !Arrays.equals(secret, auth.second)) {
- throw new AssertionFailedError("Invalid secret to unlock user");
- }
- } else {
- if (auths != null && auths.size() > 0) {
- throw new AssertionFailedError("Cannot unlock encrypted user with empty token");
- }
- }
- }
-
- public void setIgnoreBadUnlock(boolean ignore) {
- mIgnoreBadUnlock = ignore;
- }
-
- @Override
- public IBinder asBinder() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void registerListener(IStorageEventListener listener) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void unregisterListener(IStorageEventListener listener) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isUsbMassStorageConnected() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setUsbMassStorageEnabled(boolean enable) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isUsbMassStorageEnabled() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int mountVolume(String mountPoint) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void unmountVolume(String mountPoint, boolean force, boolean removeEncryption)
- throws RemoteException {
- throw new UnsupportedOperationException();
-
- }
-
- @Override
- public int formatVolume(String mountPoint) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int[] getStorageUsers(String path) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getVolumeState(String mountPoint) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int createSecureContainer(String id, int sizeMb, String fstype, String key, int ownerUid,
- boolean external) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int finalizeSecureContainer(String id) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int destroySecureContainer(String id, boolean force) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly)
- throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int unmountSecureContainer(String id, boolean force) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isSecureContainerMounted(String id) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int renameSecureContainer(String oldId, String newId) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getSecureContainerPath(String id) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String[] getSecureContainerList() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void shutdown(IStorageShutdownObserver observer) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void finishMediaUpdate() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void mountObb(String rawPath, String canonicalPath, String key, IObbActionListener token,
- int nonce) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce)
- throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isObbMounted(String rawPath) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getMountedObbPath(String rawPath) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isExternalStorageEmulated() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int decryptStorage(String password) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int encryptStorage(int type, String password) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int changeEncryptionPassword(int type, String password) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public StorageVolume[] getVolumeList(int uid, String packageName, int flags)
- throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getSecureContainerFilesystemPath(String cid) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int getEncryptionState() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int verifyEncryptionPassword(String password) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int fixPermissionsSecureContainer(String id, int gid, String filename)
- throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int mkdirs(String callingPkg, String path) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int getPasswordType() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getPassword() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void clearPassword() throws RemoteException {
- throw new UnsupportedOperationException();
-
- }
-
- @Override
- public void setField(String field, String contents) throws RemoteException {
- throw new UnsupportedOperationException();
-
- }
-
- @Override
- public String getField(String field) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int resizeSecureContainer(String id, int sizeMb, String key) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public long lastMaintenance() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void runMaintenance() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void waitForAsecScan() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public DiskInfo[] getDisks() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public VolumeInfo[] getVolumes(int flags) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public VolumeRecord[] getVolumeRecords(int flags) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void mount(String volId) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void unmount(String volId) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void format(String volId) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void partitionPublic(String diskId) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void partitionPrivate(String diskId) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void partitionMixed(String diskId, int ratio) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setVolumeNickname(String fsUuid, String nickname) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setVolumeUserFlags(String fsUuid, int flags, int mask) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void forgetVolume(String fsUuid) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void forgetAllVolumes() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getPrimaryStorageUuid() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
- throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public long benchmark(String volId) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setDebugFlags(int flags, int mask) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void createUserKey(int userId, int serialNumber, boolean ephemeral)
- throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void destroyUserKey(int userId) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret)
- throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void lockUserKey(int userId) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isUserKeyUnlocked(int userId) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags)
- throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void destroyUserStorage(String volumeUuid, int userId, int flags)
- throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isConvertibleToFBE() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void fstrim(int flags) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public AppFuseMount mountProxyFileDescriptorBridge() throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public ParcelFileDescriptor openProxyFileDescriptor(int mountPointId, int fileId, int mode)
- throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public long getCacheQuotaBytes(String volumeUuid, int uid) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public long getCacheSizeBytes(String volumeUuid, int uid) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public long getAllocatableBytes(String path, int flags, String callingPackage) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void allocateBytes(String path, long bytes, int flags, String callingPackage) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void secdiscard(String path) throws RemoteException {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/timezone/PackageStatusStorageTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageStatusStorageTest.java
index dd56072372af..b57cac06ce6e 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/PackageStatusStorageTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/PackageStatusStorageTest.java
@@ -25,6 +25,8 @@ import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
@@ -228,4 +230,27 @@ public class PackageStatusStorageTest {
assertFalse(writeOk2);
assertEquals(expectedPackageStatus, mPackageStatusStorage.getPackageStatus());
}
+
+ @Test
+ public void dump() {
+ StringWriter stringWriter = new StringWriter();
+ PrintWriter printWriter = new PrintWriter(stringWriter);
+
+ // Dump initial state.
+ mPackageStatusStorage.dump(printWriter);
+
+ // No crash and it does something.
+ assertFalse(stringWriter.toString().isEmpty());
+
+ // Reset
+ stringWriter.getBuffer().setLength(0);
+ assertTrue(stringWriter.toString().isEmpty());
+
+ // Store something.
+ mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
+
+ mPackageStatusStorage.dump(printWriter);
+
+ assertFalse(stringWriter.toString().isEmpty());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
index 4c7680b1edef..a972e4f84204 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
@@ -30,6 +30,9 @@ import android.provider.TimeZoneRulesDataContract;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -1174,6 +1177,16 @@ public class PackageTrackerTest {
assertFalse(token1.equals(token2));
}
+ @Test
+ public void dump() {
+ StringWriter stringWriter = new StringWriter();
+ PrintWriter printWriter = new PrintWriter(stringWriter);
+
+ mPackageTracker.dump(printWriter);
+
+ assertFalse(stringWriter.toString().isEmpty());
+ }
+
private void simulatePackageInstallation(PackageVersions packageVersions) throws Exception {
configureApplicationsValidManifests(packageVersions);
diff --git a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
index 3b76d5e05e0e..2887e3bb520f 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
@@ -19,6 +19,7 @@ package com.android.server.timezone;
import com.android.timezone.distro.DistroVersion;
import com.android.timezone.distro.StagedDistroOperation;
import com.android.timezone.distro.TimeZoneDistro;
+import com.android.timezone.distro.installer.TimeZoneDistroInstaller;
import org.junit.Before;
import org.junit.Test;
@@ -31,11 +32,14 @@ import android.app.timezone.RulesState;
import android.os.ParcelFileDescriptor;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.concurrent.Executor;
import javax.annotation.Nullable;
-import libcore.tzdata.update2.TimeZoneDistroInstaller;
+
+import libcore.io.IoUtils;
import static com.android.server.timezone.RulesManagerService.REQUIRED_UPDATER_PERMISSION;
import static org.junit.Assert.assertEquals;
@@ -52,6 +56,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
/**
@@ -724,6 +729,97 @@ public class RulesManagerServiceTest {
verifyPackageTrackerCalled(null /* token */, true /* success */);
}
+ @Test
+ public void dump_noPermission() throws Exception {
+ when(mMockPermissionHelper.checkDumpPermission(any(String.class), any(PrintWriter.class)))
+ .thenReturn(false);
+
+ doDumpCallAndCapture(mRulesManagerService, null);
+ verifyZeroInteractions(mMockPackageTracker, mMockTimeZoneDistroInstaller);
+ }
+
+ @Test
+ public void dump_emptyArgs() throws Exception {
+ doSuccessfulDumpCall(mRulesManagerService, new String[0]);
+
+ // Verify the package tracker was consulted.
+ verify(mMockPackageTracker).dump(any(PrintWriter.class));
+ }
+
+ @Test
+ public void dump_nullArgs() throws Exception {
+ doSuccessfulDumpCall(mRulesManagerService, null);
+ // Verify the package tracker was consulted.
+ verify(mMockPackageTracker).dump(any(PrintWriter.class));
+ }
+
+ @Test
+ public void dump_unknownArgs() throws Exception {
+ String dumpedTextUnknownArgs = doSuccessfulDumpCall(
+ mRulesManagerService, new String[] { "foo", "bar"});
+
+ // Verify the package tracker was consulted.
+ verify(mMockPackageTracker).dump(any(PrintWriter.class));
+
+ String dumpedTextZeroArgs = doSuccessfulDumpCall(mRulesManagerService, null);
+ assertEquals(dumpedTextZeroArgs, dumpedTextUnknownArgs);
+ }
+
+ @Test
+ public void dump_formatState() throws Exception {
+ // Just expect these to not throw exceptions, not return nothing, and not interact with the
+ // package tracker.
+ doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("p"));
+ doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("s"));
+ doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("c"));
+ doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("i"));
+ doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("o"));
+ doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("t"));
+ doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("a"));
+ doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("z" /* Unknown */));
+ doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("piscotz"));
+
+ verifyZeroInteractions(mMockPackageTracker);
+ }
+
+ private static String[] dumpFormatArgs(String argsString) {
+ return new String[] { "-format_state", argsString};
+ }
+
+ private String doSuccessfulDumpCall(RulesManagerService rulesManagerService, String[] args)
+ throws Exception {
+ when(mMockPermissionHelper.checkDumpPermission(any(String.class), any(PrintWriter.class)))
+ .thenReturn(true);
+
+ // Set up the mocks to return (arbitrary) information about the current device state.
+ when(mMockTimeZoneDistroInstaller.getSystemRulesVersion()).thenReturn("2017a");
+ when(mMockTimeZoneDistroInstaller.getInstalledDistroVersion()).thenReturn(
+ new DistroVersion(2, 3, "2017b", 4));
+ when(mMockTimeZoneDistroInstaller.getStagedDistroOperation()).thenReturn(
+ StagedDistroOperation.install(new DistroVersion(5, 6, "2017c", 7)));
+
+ // Do the dump call.
+ String dumpedOutput = doDumpCallAndCapture(rulesManagerService, args);
+
+ assertFalse(dumpedOutput.isEmpty());
+
+ return dumpedOutput;
+ }
+
+ private static String doDumpCallAndCapture(
+ RulesManagerService rulesManagerService, String[] args) throws IOException {
+ File file = File.createTempFile("dump", null);
+ try {
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ FileDescriptor fd = fos.getFD();
+ rulesManagerService.dump(fd, args);
+ }
+ return IoUtils.readFileAsString(file.getAbsolutePath());
+ } finally {
+ file.delete();
+ }
+ }
+
private void verifyNoPackageTrackerCallsMade() {
verifyNoMoreInteractions(mMockPackageTracker);
reset(mMockPackageTracker);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index c809c325726f..67db5f4d12dd 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -218,8 +218,7 @@ public class WindowStateTests extends WindowTestsBase {
root.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
root.mTurnOnScreen = false;
- root.prepareWindowToDisplayDuringRelayout(new MergedConfiguration(),
- wasVisible /*wasVisible*/);
+ root.prepareWindowToDisplayDuringRelayout(wasVisible /*wasVisible*/);
assertTrue(root.mTurnOnScreen);
}
}
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index d315b181c357..68c1d5f6ec7f 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -65,6 +65,9 @@ public final class UsbAlsaManager {
private final HashMap<UsbDevice,UsbAudioDevice>
mAudioDevices = new HashMap<UsbDevice,UsbAudioDevice>();
+ private boolean mIsInputHeadset; // as reported by UsbDescriptorParser
+ private boolean mIsOutputHeadset; // as reported by UsbDescriptorParser
+
private final HashMap<UsbDevice,UsbMidiDevice>
mMidiDevices = new HashMap<UsbDevice,UsbMidiDevice>();
@@ -184,9 +187,14 @@ public final class UsbAlsaManager {
try {
// Playback Device
if (audioDevice.mHasPlayback) {
- int device = (audioDevice == mAccessoryAudioDevice ?
- AudioSystem.DEVICE_OUT_USB_ACCESSORY :
- AudioSystem.DEVICE_OUT_USB_DEVICE);
+ int device;
+ if (mIsOutputHeadset) {
+ device = AudioSystem.DEVICE_OUT_USB_HEADSET;
+ } else {
+ device = (audioDevice == mAccessoryAudioDevice
+ ? AudioSystem.DEVICE_OUT_USB_ACCESSORY
+ : AudioSystem.DEVICE_OUT_USB_DEVICE);
+ }
if (DEBUG) {
Slog.i(TAG, "pre-call device:0x" + Integer.toHexString(device) +
" addr:" + address + " name:" + audioDevice.getDeviceName());
@@ -197,9 +205,14 @@ public final class UsbAlsaManager {
// Capture Device
if (audioDevice.mHasCapture) {
- int device = (audioDevice == mAccessoryAudioDevice ?
- AudioSystem.DEVICE_IN_USB_ACCESSORY :
- AudioSystem.DEVICE_IN_USB_DEVICE);
+ int device;
+ if (mIsInputHeadset) {
+ device = AudioSystem.DEVICE_IN_USB_HEADSET;
+ } else {
+ device = (audioDevice == mAccessoryAudioDevice
+ ? AudioSystem.DEVICE_IN_USB_ACCESSORY
+ : AudioSystem.DEVICE_IN_USB_DEVICE);
+ }
mAudioService.setWiredDeviceConnectionState(
device, state, address, audioDevice.getDeviceName(), TAG);
}
@@ -343,12 +356,16 @@ public final class UsbAlsaManager {
return selectAudioCard(mCardsParser.getDefaultCard());
}
- /* package */ void usbDeviceAdded(UsbDevice usbDevice) {
- if (DEBUG) {
- Slog.d(TAG, "deviceAdded(): " + usbDevice.getManufacturerName() +
- " nm:" + usbDevice.getProductName());
+ /* package */ void usbDeviceAdded(UsbDevice usbDevice,
+ boolean isInputHeadset, boolean isOutputHeadset) {
+ if (DEBUG) {
+ Slog.d(TAG, "deviceAdded(): " + usbDevice.getManufacturerName()
+ + " nm:" + usbDevice.getProductName());
}
+ mIsInputHeadset = isInputHeadset;
+ mIsOutputHeadset = isOutputHeadset;
+
// Is there an audio interface in there?
boolean isAudioDevice = false;
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 1a24d9571e72..a7180c989a6e 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -683,8 +683,9 @@ public class UsbDeviceManager {
// Set the new USB configuration.
setUsbConfig(oemFunctions);
- if (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
- || UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP)) {
+ if (mBootCompleted
+ && (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
+ || UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) {
// Start up dependent services.
updateUsbStateBroadcastIfNeeded(true);
}
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 737b572d9f29..66292f80e903 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -31,6 +31,7 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.descriptors.UsbDescriptorParser;
import java.util.ArrayList;
import java.util.HashMap;
@@ -257,7 +258,14 @@ public class UsbHostManager {
getCurrentUserSettings().deviceAttachedForFixedHandler(mNewDevice,
usbDeviceConnectionHandler);
}
- mUsbAlsaManager.usbDeviceAdded(mNewDevice);
+ // deviceName is something like: "/dev/bus/usb/001/001"
+ UsbDescriptorParser parser = new UsbDescriptorParser();
+ if (parser.parseDevice(mNewDevice.getDeviceName())) {
+ Slog.i(TAG, "---- isHeadset[in:" + parser.isInputHeadset()
+ + " , out:" + parser.isOutputHeadset() + "]");
+ mUsbAlsaManager.usbDeviceAdded(mNewDevice,
+ parser.isInputHeadset(), parser.isOutputHeadset());
+ }
} else {
Slog.e(TAG, "mNewDevice is null in endUsbDeviceAdded");
}
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 9d800ad5c479..e28513a29a3a 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -692,12 +692,7 @@ public class UsbPortManager {
// Guard against possible reentrance by posting the broadcast from the handler
// instead of from within the critical section.
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
- }
- });
+ mHandler.post(() -> mContext.sendBroadcastAsUser(intent, UserHandle.ALL));
}
private static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) {
diff --git a/services/usb/java/com/android/server/usb/descriptors/ByteStream.java b/services/usb/java/com/android/server/usb/descriptors/ByteStream.java
new file mode 100644
index 000000000000..d678931fd01a
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/ByteStream.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+import android.annotation.NonNull;
+
+/**
+ * @hide
+ * A stream interface wrapping a byte array. Very much like a java.io.ByteArrayInputStream
+ * but with the capability to "back up" in situations where the parser discovers that a
+ * UsbDescriptor has overrun its length.
+ */
+public class ByteStream {
+ private static final String TAG = "ByteStream";
+
+ /** The byte array being wrapped */
+ @NonNull
+ private final byte[] mBytes; // this is never null.
+
+ /**
+ * The index into the byte array to be read next.
+ * This value is altered by reading data out of the stream
+ * (using either the getByte() or unpack*() methods), or alternatively
+ * by explicitly offseting the stream position with either
+ * advance() or reverse().
+ */
+ private int mIndex;
+
+ /*
+ * This member used with resetReadCount() & getReadCount() can be used to determine how many
+ * bytes a UsbDescriptor subclass ACTUALLY reads (as opposed to what its length field says).
+ * using this info, the parser can mark a descriptor as valid or invalid and correct the stream
+ * position with advance() & reverse() to keep from "getting lost" in the descriptor stream.
+ */
+ private int mReadCount;
+
+ /**
+ * Create a ByteStream object wrapping the specified byte array.
+ *
+ * @param bytes The byte array containing the raw descriptor information retrieved from
+ * the USB device.
+ * @throws IllegalArgumentException
+ */
+ public ByteStream(@NonNull byte[] bytes) {
+ if (bytes == null) {
+ throw new IllegalArgumentException();
+ }
+ mBytes = bytes;
+ }
+
+ /**
+ * Resets the running count of bytes read so that later we can see how much more has been read.
+ */
+ public void resetReadCount() {
+ mReadCount = 0;
+ }
+
+ /**
+ * Retrieves the running count of bytes read from the stream.
+ */
+ public int getReadCount() {
+ return mReadCount;
+ }
+
+ /**
+ * @return The value of the next byte in the stream without advancing the stream.
+ * Does not affect the running count as the byte hasn't been "consumed".
+ * @throws IndexOutOfBoundsException
+ */
+ public byte peekByte() {
+ if (available() > 0) {
+ return mBytes[mIndex + 1];
+ } else {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * @return the next byte from the stream and advances the stream and the read count. Note
+ * that this is a signed byte (as is the case of byte in Java). The user may need to understand
+ * from context if it should be interpreted as an unsigned value.
+ * @throws IndexOutOfBoundsException
+ */
+ public byte getByte() {
+ if (available() > 0) {
+ mReadCount++;
+ return mBytes[mIndex++];
+ } else {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Reads 2 bytes in *little endian format* from the stream and composes a 16-bit integer.
+ * As we are storing the 2-byte value in a 4-byte integer, the upper 2 bytes are always
+ * 0, essentially making the returned value *unsigned*.
+ * @return The 16-bit integer (packed into the lower 2 bytes of an int) encoded by the
+ * next 2 bytes in the stream.
+ * @throws IndexOutOfBoundsException
+ */
+ public int unpackUsbWord() {
+ if (available() >= 2) {
+ int b0 = getByte();
+ int b1 = getByte();
+ return ((b1 << 8) & 0x0000FF00) | (b0 & 0x000000FF);
+ } else {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Reads 3 bytes in *little endian format* from the stream and composes a 24-bit integer.
+ * As we are storing the 3-byte value in a 4-byte integer, the upper byte is always
+ * 0, essentially making the returned value *unsigned*.
+ * @return The 24-bit integer (packed into the lower 3 bytes of an int) encoded by the
+ * next 3 bytes in the stream.
+ * @throws IndexOutOfBoundsException
+ */
+ public int unpackUsbTriple() {
+ if (available() >= 3) {
+ int b0 = getByte();
+ int b1 = getByte();
+ int b2 = getByte();
+ return ((b2 << 16) & 0x00FF0000) | ((b1 << 8) & 0x0000FF00) | (b0 & 0x000000FF);
+ } else {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Advances the logical position in the stream. Affects the running count also.
+ * @param numBytes The number of bytes to advance.
+ * @throws IndexOutOfBoundsException
+ * @throws IllegalArgumentException
+ */
+ public void advance(int numBytes) {
+ if (numBytes < 0) {
+ // Positive offsets only
+ throw new IllegalArgumentException();
+ }
+ // do arithmetic and comparison in long to ovoid potention integer overflow
+ long longNewIndex = (long) mIndex + (long) numBytes;
+ if (longNewIndex < (long) mBytes.length) {
+ mReadCount += numBytes;
+ mIndex += numBytes;
+ } else {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Reverse the logical position in the stream. Affects the running count also.
+ * @param numBytes The (positive) number of bytes to reverse.
+ * @throws IndexOutOfBoundsException
+ * @throws IllegalArgumentException
+ */
+ public void reverse(int numBytes) {
+ if (numBytes < 0) {
+ // Positive (reverse) offsets only
+ throw new IllegalArgumentException();
+ }
+ if (mIndex >= numBytes) {
+ mReadCount -= numBytes;
+ mIndex -= numBytes;
+ } else {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * @return The number of bytes available to be read in the stream.
+ */
+ public int available() {
+ return mBytes.length - mIndex;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java b/services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java
new file mode 100644
index 000000000000..96fcc6a0b8db
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific Audio Control Endpoint.
+ * audio10.pdf section 4.4.2.1
+ */
+public class UsbACAudioControlEndpoint extends UsbACEndpoint {
+ private static final String TAG = "ACAudioControlEndpoint";
+
+ private byte mAddress; // 2:1 The address of the endpoint on the USB device.
+ // D7: Direction. 1 = IN endpoint
+ // D6..4: Reserved, reset to zero
+ // D3..0: The endpoint number.
+ private byte mAttribs; // 3:1 (see ATTRIBSMASK_* below
+ private int mMaxPacketSize; // 4:2 Maximum packet size this endpoint is capable of sending
+ // or receiving when this configuration is selected.
+ private byte mInterval; // 6:1
+
+ static final byte ADDRESSMASK_DIRECTION = (byte) 0x80;
+ static final byte ADDRESSMASK_ENDPOINT = 0x0F;
+
+ static final byte ATTRIBSMASK_SYNC = 0x0C;
+ static final byte ATTRIBMASK_TRANS = 0x03;
+
+ public UsbACAudioControlEndpoint(int length, byte type, byte subclass) {
+ super(length, type, subclass);
+ }
+
+ public byte getAddress() {
+ return mAddress;
+ }
+
+ public byte getAttribs() {
+ return mAttribs;
+ }
+
+ public int getMaxPacketSize() {
+ return mMaxPacketSize;
+ }
+
+ public byte getInterval() {
+ return mInterval;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ super.parseRawDescriptors(stream);
+
+ mAddress = stream.getByte();
+ mAttribs = stream.getByte();
+ mMaxPacketSize = stream.unpackUsbWord();
+ mInterval = stream.getByte();
+
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java b/services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java
new file mode 100644
index 000000000000..d387883d3049
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific Streaming Endpoint
+ * see audio10.pdf section 3.7.2
+ */
+public class UsbACAudioStreamEndpoint extends UsbACEndpoint {
+ private static final String TAG = "ACAudioStreamEndpoint";
+
+ //TODO data fields...
+ public UsbACAudioStreamEndpoint(int length, byte type, byte subclass) {
+ super(length, type, subclass);
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ super.parseRawDescriptors(stream);
+
+ //TODO Read fields
+ stream.advance(mLength - stream.getReadCount());
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java b/services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java
new file mode 100644
index 000000000000..223496ab016e
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+import android.util.Log;
+
+/**
+ * @hide
+ * An audio class-specific Endpoint
+ * see audio10.pdf section 4.4.1.2
+ */
+abstract class UsbACEndpoint extends UsbDescriptor {
+ private static final String TAG = "ACEndpoint";
+
+ protected final byte mSubclass; // from the mSubclass member of the "enclosing"
+ // Interface Descriptor, not the stream.
+ protected byte mSubtype; // 2:1 HEADER descriptor subtype
+
+ UsbACEndpoint(int length, byte type, byte subclass) {
+ super(length, type);
+ mSubclass = subclass;
+ }
+
+ public byte getSubclass() {
+ return mSubclass;
+ }
+
+ public byte getSubtype() {
+ return mSubtype;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mSubtype = stream.getByte();
+
+ return mLength;
+ }
+
+ public static UsbDescriptor allocDescriptor(UsbDescriptorParser parser,
+ int length, byte type) {
+ UsbInterfaceDescriptor interfaceDesc = parser.getCurInterface();
+ byte subClass = interfaceDesc.getUsbSubclass();
+ switch (subClass) {
+ case AUDIO_AUDIOCONTROL:
+ return new UsbACAudioControlEndpoint(length, type, subClass);
+
+ case AUDIO_AUDIOSTREAMING:
+ return new UsbACAudioStreamEndpoint(length, type, subClass);
+
+ case AUDIO_MIDISTREAMING:
+ return new UsbACMidiEndpoint(length, type, subClass);
+
+ default:
+ Log.w(TAG, "Unknown Audio Class Endpoint id:0x" + Integer.toHexString(subClass));
+ return null;
+ }
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.java b/services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.java
new file mode 100644
index 000000000000..739fe5503a1d
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.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.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific Feature Unit Interface
+ * see audio10.pdf section 3.5.5
+ */
+public class UsbACFeatureUnit extends UsbACInterface {
+ private static final String TAG = "ACFeatureUnit";
+
+ // audio10.pdf section 4.3.2.5
+ public static final int CONTROL_MASK_MUTE = 0x0001;
+ public static final int CONTROL_MASK_VOL = 0x0002;
+ public static final int CONTROL_MASK_BASS = 0x0004;
+ public static final int CONTROL_MASK_MID = 0x0008;
+ public static final int CONTROL_MASK_TREB = 0x0010;
+ public static final int CONTROL_MASK_EQ = 0x0020;
+ public static final int CONTROL_MASK_AGC = 0x0040;
+ public static final int CONTROL_MASK_DELAY = 0x0080;
+ public static final int CONTROL_MASK_BOOST = 0x0100; // BASS boost
+ public static final int CONTROL_MASK_LOUD = 0x0200; // LOUDNESS
+
+ private int mNumChannels;
+
+ private byte mUnitID; // 3:1 Constant uniquely identifying the Unit within the audio function.
+ // This value is used in all requests to address this Unit
+ private byte mSourceID; // 4:1 ID of the Unit or Terminal to which this Feature Unit
+ // is connected.
+ private byte mControlSize; // 5:1 Size in bytes of an element of the mControls array: n
+ private int[] mControls; // 6:? bitmask (see above) of supported controls in a given
+ // logical channel
+ private byte mUnitName; // ?:1 Index of a string descriptor, describing this Feature Unit.
+
+ public UsbACFeatureUnit(int length, byte type, byte subtype, byte subClass) {
+ super(length, type, subtype, subClass);
+ }
+
+ public int getNumChannels() {
+ return mNumChannels;
+ }
+
+ public byte getUnitID() {
+ return mUnitID;
+ }
+
+ public byte getSourceID() {
+ return mSourceID;
+ }
+
+ public byte getControlSize() {
+ return mControlSize;
+ }
+
+ public int[] getControls() {
+ return mControls;
+ }
+
+ public byte getUnitName() {
+ return mUnitName;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACHeader.java b/services/usb/java/com/android/server/usb/descriptors/UsbACHeader.java
new file mode 100644
index 000000000000..e31438c58e06
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACHeader.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific Interface Header.
+ * see audio10.pdf section 4.3.2
+ */
+public class UsbACHeader extends UsbACInterface {
+ private static final String TAG = "ACHeader";
+
+ private int mADCRelease; // 3:2 Audio Device Class Specification Release (BCD).
+ private int mTotalLength; // 5:2 Total number of bytes returned for the class-specific
+ // AudioControl interface descriptor. Includes the combined length
+ // of this descriptor header and all Unit and Terminal descriptors.
+ private byte mNumInterfaces = 0; // 7:1 The number of AudioStreaming and MIDIStreaming
+ // interfaces in the Audio Interface Collection to which this
+ // AudioControl interface belongs: n
+ private byte[] mInterfaceNums = null; // 8:n List of Audio/MIDI streaming interface
+ // numbers associate with this endpoint
+ private byte mControls; // Vers 2.0 thing
+
+ public UsbACHeader(int length, byte type, byte subtype, byte subclass) {
+ super(length, type, subtype, subclass);
+ }
+
+ public int getADCRelease() {
+ return mADCRelease;
+ }
+
+ public int getTotalLength() {
+ return mTotalLength;
+ }
+
+ public byte getNumInterfaces() {
+ return mNumInterfaces;
+ }
+
+ public byte[] getInterfaceNums() {
+ return mInterfaceNums;
+ }
+
+ public byte getControls() {
+ return mControls;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mADCRelease = stream.unpackUsbWord();
+
+ mTotalLength = stream.unpackUsbWord();
+ if (mADCRelease >= 0x200) {
+ mControls = stream.getByte();
+ } else {
+ mNumInterfaces = stream.getByte();
+ mInterfaceNums = new byte[mNumInterfaces];
+ for (int index = 0; index < mNumInterfaces; index++) {
+ mInterfaceNums[index] = stream.getByte();
+ }
+ }
+
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACInputTerminal.java b/services/usb/java/com/android/server/usb/descriptors/UsbACInputTerminal.java
new file mode 100644
index 000000000000..653a7de5457e
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACInputTerminal.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.server.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific Input Terminal interface.
+ * see audio10.pdf section 4.3.2.1
+ */
+public class UsbACInputTerminal extends UsbACTerminal {
+ private static final String TAG = "ACInputTerminal";
+
+ private byte mNrChannels; // 7:1 1 Channel (0x01)
+ // Number of logical output channels in the
+ // Terminal’s output audio channel cluster
+ private int mChannelConfig; // 8:2 Mono (0x0000)
+ private byte mChannelNames; // 10:1 Unused (0x00)
+ private byte mTerminal; // 11:1 Unused (0x00)
+
+ public UsbACInputTerminal(int length, byte type, byte subtype, byte subclass) {
+ super(length, type, subtype, subclass);
+ }
+
+ public byte getNrChannels() {
+ return mNrChannels;
+ }
+
+ public int getChannelConfig() {
+ return mChannelConfig;
+ }
+
+ public byte getChannelNames() {
+ return mChannelNames;
+ }
+
+ public byte getTerminal() {
+ return mTerminal;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ super.parseRawDescriptors(stream);
+
+ mNrChannels = stream.getByte();
+ mChannelConfig = stream.unpackUsbWord();
+ mChannelNames = stream.getByte();
+ mTerminal = stream.getByte();
+
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java b/services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java
new file mode 100644
index 000000000000..0ab7fccd2c3b
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.usb.descriptors;
+
+import android.util.Log;
+
+/**
+ * @hide
+ * An audio class-specific Interface.
+ * see audio10.pdf section 4.3.2
+ */
+public abstract class UsbACInterface extends UsbDescriptor {
+ private static final String TAG = "ACInterface";
+
+ // Audio Control Subtypes
+ public static final byte ACI_UNDEFINED = 0;
+ public static final byte ACI_HEADER = 1;
+ public static final byte ACI_INPUT_TERMINAL = 2;
+ public static final byte ACI_OUTPUT_TERMINAL = 3;
+ public static final byte ACI_MIXER_UNIT = 4;
+ public static final byte ACI_SELECTOR_UNIT = 5;
+ public static final byte ACI_FEATURE_UNIT = 6;
+ public static final byte ACI_PROCESSING_UNIT = 7;
+ public static final byte ACI_EXTENSION_UNIT = 8;
+
+ // Audio Streaming Subtypes
+ public static final byte ASI_UNDEFINED = 0;
+ public static final byte ASI_GENERAL = 1;
+ public static final byte ASI_FORMAT_TYPE = 2;
+ public static final byte ASI_FORMAT_SPECIFIC = 3;
+
+ // MIDI Streaming Subtypes
+ public static final byte MSI_UNDEFINED = 0;
+ public static final byte MSI_HEADER = 1;
+ public static final byte MSI_IN_JACK = 2;
+ public static final byte MSI_OUT_JACK = 3;
+ public static final byte MSI_ELEMENT = 4;
+
+ // Sample format IDs (encodings)
+ // FORMAT_I
+ public static final int FORMAT_I_UNDEFINED = 0x0000;
+ public static final int FORMAT_I_PCM = 0x0001;
+ public static final int FORMAT_I_PCM8 = 0x0002;
+ public static final int FORMAT_I_IEEE_FLOAT = 0x0003;
+ public static final int FORMAT_I_ALAW = 0x0004;
+ public static final int FORMAT_I_MULAW = 0x0005;
+ // FORMAT_II
+ public static final int FORMAT_II_UNDEFINED = 0x1000;
+ public static final int FORMAT_II_MPEG = 0x1001;
+ public static final int FORMAT_II_AC3 = 0x1002;
+ // FORMAT_III
+ public static final int FORMAT_III_UNDEFINED = 0x2000;
+ public static final int FORMAT_III_IEC1937AC3 = 0x2001;
+ public static final int FORMAT_III_IEC1937_MPEG1_Layer1 = 0x2002;
+ public static final int FORMAT_III_IEC1937_MPEG1_Layer2 = 0x2003;
+ public static final int FORMAT_III_IEC1937_MPEG2_EXT = 0x2004;
+ public static final int FORMAT_III_IEC1937_MPEG2_Layer1LS = 0x2005;
+
+ protected final byte mSubtype; // 2:1 HEADER descriptor subtype
+ protected final byte mSubclass; // from the mSubclass member of the
+ // "enclosing" Interface Descriptor
+
+ public UsbACInterface(int length, byte type, byte subtype, byte subclass) {
+ super(length, type);
+ mSubtype = subtype;
+ mSubclass = subclass;
+ }
+
+ public byte getSubtype() {
+ return mSubtype;
+ }
+
+ public byte getSubclass() {
+ return mSubclass;
+ }
+
+ private static UsbDescriptor allocAudioControlDescriptor(ByteStream stream,
+ int length, byte type, byte subtype, byte subClass) {
+ switch (subtype) {
+ case ACI_HEADER:
+ return new UsbACHeader(length, type, subtype, subClass);
+
+ case ACI_INPUT_TERMINAL:
+ return new UsbACInputTerminal(length, type, subtype, subClass);
+
+ case ACI_OUTPUT_TERMINAL:
+ return new UsbACOutputTerminal(length, type, subtype, subClass);
+
+ case ACI_SELECTOR_UNIT:
+ return new UsbACSelectorUnit(length, type, subtype, subClass);
+
+ case ACI_FEATURE_UNIT:
+ return new UsbACFeatureUnit(length, type, subtype, subClass);
+
+ case ACI_MIXER_UNIT:
+ return new UsbACMixerUnit(length, type, subtype, subClass);
+
+ case ACI_PROCESSING_UNIT:
+ case ACI_EXTENSION_UNIT:
+ case ACI_UNDEFINED:
+ // break; Fall through until we implement this descriptor
+ default:
+ Log.w(TAG, "Unknown Audio Class Interface subtype:0x"
+ + Integer.toHexString(subtype));
+ return null;
+ }
+ }
+
+ private static UsbDescriptor allocAudioStreamingDescriptor(ByteStream stream,
+ int length, byte type, byte subtype, byte subClass) {
+ switch (subtype) {
+ case ASI_GENERAL:
+ return new UsbASGeneral(length, type, subtype, subClass);
+
+ case ASI_FORMAT_TYPE:
+ return UsbASFormat.allocDescriptor(stream, length, type, subtype, subClass);
+
+ case ASI_FORMAT_SPECIFIC:
+ case ASI_UNDEFINED:
+ // break; Fall through until we implement this descriptor
+ default:
+ Log.w(TAG, "Unknown Audio Streaming Interface subtype:0x"
+ + Integer.toHexString(subtype));
+ return null;
+ }
+ }
+
+ private static UsbDescriptor allocMidiStreamingDescriptor(int length, byte type,
+ byte subtype, byte subClass) {
+ switch (subtype) {
+ case MSI_HEADER:
+ return new UsbMSMidiHeader(length, type, subtype, subClass);
+
+ case MSI_IN_JACK:
+ return new UsbMSMidiInputJack(length, type, subtype, subClass);
+
+ case MSI_OUT_JACK:
+ return new UsbMSMidiOutputJack(length, type, subtype, subClass);
+
+ case MSI_ELEMENT:
+ // break;
+ // Fall through until we implement that descriptor
+
+ case MSI_UNDEFINED:
+ // break; Fall through until we implement this descriptor
+ default:
+ Log.w(TAG, "Unknown MIDI Streaming Interface subtype:0x"
+ + Integer.toHexString(subtype));
+ return null;
+ }
+ }
+
+ /**
+ * Allocates an audio class interface subtype based on subtype and subclass.
+ */
+ public static UsbDescriptor allocDescriptor(UsbDescriptorParser parser, ByteStream stream,
+ int length, byte type) {
+ byte subtype = stream.getByte();
+ UsbInterfaceDescriptor interfaceDesc = parser.getCurInterface();
+ byte subClass = interfaceDesc.getUsbSubclass();
+ switch (subClass) {
+ case AUDIO_AUDIOCONTROL:
+ return allocAudioControlDescriptor(stream, length, type, subtype, subClass);
+
+ case AUDIO_AUDIOSTREAMING:
+ return allocAudioStreamingDescriptor(stream, length, type, subtype, subClass);
+
+ case AUDIO_MIDISTREAMING:
+ return allocMidiStreamingDescriptor(length, type, subtype, subClass);
+
+ default:
+ Log.w(TAG, "Unknown Audio Class Interface Subclass: 0x"
+ + Integer.toHexString(subClass));
+ return null;
+ }
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java b/services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java
new file mode 100644
index 000000000000..9c072426cc49
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific Midi Endpoint.
+ * see midi10.pdf section 6.2.2
+ */
+public class UsbACMidiEndpoint extends UsbACEndpoint {
+ private static final String TAG = "ACMidiEndpoint";
+
+ private byte mNumJacks;
+ private byte[] mJackIds;
+
+ public UsbACMidiEndpoint(int length, byte type, byte subclass) {
+ super(length, type, subclass);
+ }
+
+ public byte getNumJacks() {
+ return mNumJacks;
+ }
+
+ public byte[] getJackIds() {
+ return mJackIds;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ super.parseRawDescriptors(stream);
+
+ mNumJacks = stream.getByte();
+ mJackIds = new byte[mNumJacks];
+ for (int jack = 0; jack < mNumJacks; jack++) {
+ mJackIds[jack] = stream.getByte();
+ }
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java b/services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java
new file mode 100644
index 000000000000..552b5ae308d6
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific Mixer Interface.
+ * see audio10.pdf section 4.3.2.3
+ */
+public class UsbACMixerUnit extends UsbACInterface {
+ private static final String TAG = "ACMixerUnit";
+
+ private byte mUnitID; // 3:1
+ private byte mNumInputs; // 4:1 Number of Input Pins of this Unit.
+ private byte[] mInputIDs; // 5...:1 ID of the Unit or Terminal to which the Input Pins
+ // are connected.
+ private byte mNumOutputs; // The number of output channels
+ private int mChannelConfig; // Spacial location of output channels
+ private byte mChanNameID; // First channel name string descriptor ID
+ private byte[] mControls; // bitmasks of which controls are present for each channel
+ private byte mNameID; // string descriptor ID of mixer name
+
+ public UsbACMixerUnit(int length, byte type, byte subtype, byte subClass) {
+ super(length, type, subtype, subClass);
+ }
+
+ public byte getUnitID() {
+ return mUnitID;
+ }
+
+ public byte getNumInputs() {
+ return mNumInputs;
+ }
+
+ public byte[] getInputIDs() {
+ return mInputIDs;
+ }
+
+ public byte getNumOutputs() {
+ return mNumOutputs;
+ }
+
+ public int getChannelConfig() {
+ return mChannelConfig;
+ }
+
+ public byte getChanNameID() {
+ return mChanNameID;
+ }
+
+ public byte[] getControls() {
+ return mControls;
+ }
+
+ public byte getNameID() {
+ return mNameID;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mUnitID = stream.getByte();
+ mNumInputs = stream.getByte();
+ mInputIDs = new byte[mNumInputs];
+ for (int input = 0; input < mNumInputs; input++) {
+ mInputIDs[input] = stream.getByte();
+ }
+ mNumOutputs = stream.getByte();
+ mChannelConfig = stream.unpackUsbWord();
+ mChanNameID = stream.getByte();
+
+ int controlArraySize;
+ int totalChannels = mNumInputs * mNumOutputs;
+ if (totalChannels % 8 == 0) {
+ controlArraySize = totalChannels / 8;
+ } else {
+ controlArraySize = totalChannels / 8 + 1;
+ }
+ mControls = new byte[controlArraySize];
+ for (int index = 0; index < controlArraySize; index++) {
+ mControls[index] = stream.getByte();
+ }
+
+ mNameID = stream.getByte();
+
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACOutputTerminal.java b/services/usb/java/com/android/server/usb/descriptors/UsbACOutputTerminal.java
new file mode 100644
index 000000000000..f957e3dbe217
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACOutputTerminal.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 com.android.server.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific Output Terminal Interface.
+ * see audio10.pdf section 4.3.2.2
+ */
+public class UsbACOutputTerminal extends UsbACTerminal {
+ private static final String TAG = "ACOutputTerminal";
+
+ private byte mSourceID; // 7:1 From Input Terminal. (0x01)
+ private byte mTerminal; // 8:1 Unused.
+
+ public UsbACOutputTerminal(int length, byte type, byte subtype, byte subClass) {
+ super(length, type, subtype, subClass);
+ }
+
+ public byte getSourceID() {
+ return mSourceID;
+ }
+
+ public byte getTerminal() {
+ return mTerminal;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ super.parseRawDescriptors(stream);
+
+ mSourceID = stream.getByte();
+ mTerminal = stream.getByte();
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java b/services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java
new file mode 100644
index 000000000000..b1f60bdcf6ed
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific Selector Unit Interface.
+ * see audio10.pdf section 4.3.2.4
+ */
+public class UsbACSelectorUnit extends UsbACInterface {
+ private static final String TAG = "ACSelectorUnit";
+
+ private byte mUnitID; // 3:1 Constant uniquely identifying the Unit within the audio function.
+ // This value is used in all requests to address this Unit.
+ private byte mNumPins; // 4:1 Number of input pins in this unit
+ private byte[] mSourceIDs; // 5+mNumPins:1 ID of the Unit or Terminal to which the first
+ // Input Pin of this Selector Unit is connected.
+ private byte mNameIndex; // Index of a string descriptor, describing the Selector Unit.
+
+ public UsbACSelectorUnit(int length, byte type, byte subtype, byte subClass) {
+ super(length, type, subtype, subClass);
+ }
+
+ public byte getUnitID() {
+ return mUnitID;
+ }
+
+ public byte getNumPins() {
+ return mNumPins;
+ }
+
+ public byte[] getSourceIDs() {
+ return mSourceIDs;
+ }
+
+ public byte getNameIndex() {
+ return mNameIndex;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mUnitID = stream.getByte();
+ mNumPins = stream.getByte();
+ mSourceIDs = new byte[mNumPins];
+ for (int index = 0; index < mNumPins; index++) {
+ mSourceIDs[index] = stream.getByte();
+ }
+ mNameIndex = stream.getByte();
+
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java b/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java
new file mode 100644
index 000000000000..ea80208ee3f3
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.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.usb.descriptors;
+
+/**
+ * @hide
+ */
+public abstract class UsbACTerminal extends UsbACInterface {
+ // Note that these fields are the same for both the
+ // audio class-specific Output Terminal Interface.(audio10.pdf section 4.3.2.2)
+ // and audio class-specific Input Terminal interface.(audio10.pdf section 4.3.2.1)
+ // so we may as well unify the parsing here.
+ protected byte mTerminalID; // 3:1 ID of this Output Terminal. (0x02)
+ protected int mTerminalType; // 4:2 USB Streaming. (0x0101)
+ protected byte mAssocTerminal; // 6:1 Unused (0x00)
+
+ public UsbACTerminal(int length, byte type, byte subtype, byte subclass) {
+ super(length, type, subtype, subclass);
+ }
+
+ public byte getTerminalID() {
+ return mTerminalID;
+ }
+
+ public int getTerminalType() {
+ return mTerminalType;
+ }
+
+ public byte getAssocTerminal() {
+ return mAssocTerminal;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mTerminalID = stream.getByte();
+ mTerminalType = stream.unpackUsbWord();
+ mAssocTerminal = stream.getByte();
+
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbASFormat.java b/services/usb/java/com/android/server/usb/descriptors/UsbASFormat.java
new file mode 100644
index 000000000000..d7c84c6a0965
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbASFormat.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.server.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific Format Interface.
+ * Subclasses: UsbACFormatI and UsbACFormatII.
+ * see audio10.pdf section 4.5.3 & & Frmts10.pdf
+ */
+public abstract class UsbASFormat extends UsbACInterface {
+ private static final String TAG = "ASFormat";
+
+ private final byte mFormatType; // 3:1 FORMAT_TYPE_*
+
+ public static final byte FORMAT_TYPE_I = 1;
+ public static final byte FORMAT_TYPE_II = 2;
+
+ public UsbASFormat(int length, byte type, byte subtype, byte formatType, byte mSubclass) {
+ super(length, type, subtype, mSubclass);
+ mFormatType = formatType;
+ }
+
+ public byte getFormatType() {
+ return mFormatType;
+ }
+
+ /**
+ * Allocates the audio-class format subtype associated with the format type read from the
+ * stream.
+ */
+ public static UsbDescriptor allocDescriptor(ByteStream stream, int length, byte type,
+ byte subtype, byte subclass) {
+
+ byte formatType = stream.getByte();
+ //TODO
+ // There is an issue parsing format descriptors on (some) USB 2.0 pro-audio interfaces
+ // Since we don't need this info for headset detection, just skip these descriptors
+ // for now to avoid the (low) possibility of an IndexOutOfBounds exception.
+ switch (formatType) {
+// case FORMAT_TYPE_I:
+// return new UsbASFormatI(length, type, subtype, formatType, subclass);
+//
+// case FORMAT_TYPE_II:
+// return new UsbASFormatII(length, type, subtype, formatType, subclass);
+
+ default:
+ return null;
+ }
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbASFormatI.java b/services/usb/java/com/android/server/usb/descriptors/UsbASFormatI.java
new file mode 100644
index 000000000000..347a6cffb525
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbASFormatI.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific Format I interface.
+ * see Frmts10.pdf section 2.2
+ */
+public class UsbASFormatI extends UsbASFormat {
+ private static final String TAG = "ASFormatI";
+
+ private byte mNumChannels; // 4:1
+ private byte mSubframeSize; // 5:1 frame size in bytes
+ private byte mBitResolution; // 6:1 sample size in bits
+ private byte mSampleFreqType; // 7:1
+ private int[] mSampleRates; // if mSamFreqType == 0, there will be 2 values: the
+ // min & max rates otherwise mSamFreqType rates.
+ // All 3-byte values. All rates in Hz
+
+ public UsbASFormatI(int length, byte type, byte subtype, byte formatType, byte subclass) {
+ super(length, type, subtype, formatType, subclass);
+ }
+
+ public byte getNumChannels() {
+ return mNumChannels;
+ }
+
+ public byte getSubframeSize() {
+ return mSubframeSize;
+ }
+
+ public byte getBitResolution() {
+ return mBitResolution;
+ }
+
+ public byte getSampleFreqType() {
+ return mSampleFreqType;
+ }
+
+ public int[] getSampleRates() {
+ return mSampleRates;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mNumChannels = stream.getByte();
+ mSubframeSize = stream.getByte();
+ mBitResolution = stream.getByte();
+ mSampleFreqType = stream.getByte();
+ if (mSampleFreqType == 0) {
+ mSampleRates = new int[2];
+ mSampleRates[0] = stream.unpackUsbTriple();
+ mSampleRates[1] = stream.unpackUsbTriple();
+ } else {
+ mSampleRates = new int[mSampleFreqType];
+ for (int index = 0; index < mSampleFreqType; index++) {
+ mSampleRates[index] = stream.unpackUsbTriple();
+ }
+ }
+
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbASFormatII.java b/services/usb/java/com/android/server/usb/descriptors/UsbASFormatII.java
new file mode 100644
index 000000000000..abdc62145aa2
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbASFormatII.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific Format II interface.
+ * see Frmts10.pdf section 2.3
+ */
+public class UsbASFormatII extends UsbASFormat {
+ private static final String TAG = "ASFormatII";
+
+ private int mMaxBitRate; // 4:2 Indicates the maximum number of bits per second this
+ // interface can handle. Expressed in kbits/s.
+ private int mSamplesPerFrame; // 6:2 Indicates the number of PCM audio samples contained
+ // in one encoded audio frame.
+ private byte mSamFreqType; // Indicates how the sampling frequency can be programmed:
+ // 0: Continuous sampling frequency
+ // 1..255: The number of discrete sampling frequencies supported
+ // by the isochronous data endpoint of the AudioStreaming
+ // interface (ns)
+ private int[] mSampleRates; // if mSamFreqType == 0, there will be 2 values:
+ // the min & max rates. otherwise mSamFreqType rates.
+ // All 3-byte values. All rates in Hz
+
+ public UsbASFormatII(int length, byte type, byte subtype, byte formatType, byte subclass) {
+ super(length, type, subtype, formatType, subclass);
+ }
+
+ public int getMaxBitRate() {
+ return mMaxBitRate;
+ }
+
+ public int getSamplesPerFrame() {
+ return mSamplesPerFrame;
+ }
+
+ public byte getSamFreqType() {
+ return mSamFreqType;
+ }
+
+ public int[] getSampleRates() {
+ return mSampleRates;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mMaxBitRate = stream.unpackUsbWord();
+ mSamplesPerFrame = stream.unpackUsbWord();
+ mSamFreqType = stream.getByte();
+ int numFreqs = mSamFreqType == 0 ? 2 : mSamFreqType;
+ mSampleRates = new int[numFreqs];
+ for (int index = 0; index < numFreqs; index++) {
+ mSampleRates[index] = stream.unpackUsbTriple();
+ }
+
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbASGeneral.java b/services/usb/java/com/android/server/usb/descriptors/UsbASGeneral.java
new file mode 100644
index 000000000000..c4f42d318213
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbASGeneral.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific General interface.
+ * see audio10.pdf section 4.5.2
+ */
+public class UsbASGeneral extends UsbACInterface {
+ private static final String TAG = "ACGeneral";
+
+ // audio10.pdf - section 4.5.2
+ private byte mTerminalLink; // 3:1 The Terminal ID of the Terminal to which the endpoint
+ // of this interface is connected.
+ private byte mDelay; // 4:1 Delay introduced by the data path (see Section 3.4,
+ // “Inter Channel Synchronization”). Expressed in number of frames.
+ private int mFormatTag; // 5:2 The Audio Data Format that has to be used to communicate
+ // with this interface.
+
+ public UsbASGeneral(int length, byte type, byte subtype, byte subclass) {
+ super(length, type, subtype, subclass);
+ }
+
+ public byte getTerminalLink() {
+ return mTerminalLink;
+ }
+
+ public byte getDelay() {
+ return mDelay;
+ }
+
+ public int getFormatTag() {
+ return mFormatTag;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mTerminalLink = stream.getByte();
+ mDelay = stream.getByte();
+ mFormatTag = stream.unpackUsbWord();
+
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbBinaryParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbBinaryParser.java
new file mode 100644
index 000000000000..185cee20b090
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbBinaryParser.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.usb.descriptors;
+
+import android.hardware.usb.UsbDeviceConnection;
+import android.util.Log;
+
+import com.android.server.usb.descriptors.report.UsbStrings;
+
+/**
+ * @hide
+ * A class that just walks the descriptors and does a hex dump of the contained values.
+ * Usefull as a debugging tool.
+ */
+public class UsbBinaryParser {
+ private static final String TAG = "UsbBinaryParser";
+ private static final boolean LOGGING = false;
+
+ private void dumpDescriptor(ByteStream stream, int length, byte type, StringBuilder builder) {
+
+ // Log
+ if (LOGGING) {
+ Log.i(TAG, "l:" + length + " t:" + Integer.toHexString(type) + " "
+ + UsbStrings.getDescriptorName(type));
+ StringBuilder sb = new StringBuilder();
+ for (int index = 2; index < length; index++) {
+ sb.append("0x" + Integer.toHexString(stream.getByte() & 0xFF) + " ");
+ }
+ Log.i(TAG, sb.toString());
+ } else {
+ // Screen Dump
+ builder.append("<p>");
+ builder.append("<b> l:" + length
+ + " t:0x" + Integer.toHexString(type) + " "
+ + UsbStrings.getDescriptorName(type) + "</b><br>");
+ for (int index = 2; index < length; index++) {
+ builder.append("0x" + Integer.toHexString(stream.getByte() & 0xFF) + " ");
+ }
+ builder.append("</p>");
+ }
+ }
+
+ /**
+ * Walk through descriptor stream and generate an HTML text report of the contents.
+ * TODO: This should be done in the model of UsbDescriptorsParser/Reporter model.
+ */
+ public void parseDescriptors(UsbDeviceConnection connection, byte[] descriptors,
+ StringBuilder builder) {
+
+ builder.append("<tt>");
+ ByteStream stream = new ByteStream(descriptors);
+ while (stream.available() > 0) {
+ int length = (int) stream.getByte() & 0x000000FF;
+ byte type = stream.getByte();
+ dumpDescriptor(stream, length, type, builder);
+ }
+ builder.append("</tt>");
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
new file mode 100644
index 000000000000..8ae6d0f1ee7e
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.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.server.usb.descriptors;
+
+/**
+ * @hide
+ * An USB Config Descriptor.
+ * see usb11.pdf section 9.6.2
+ */
+public class UsbConfigDescriptor extends UsbDescriptor {
+ private static final String TAG = "Config";
+
+ private int mTotalLength; // 2:2 Total length in bytes of data returned
+ private byte mNumInterfaces; // 4:1 Number of Interfaces
+ private byte mConfigValue; // 5:1 Value to use as an argument to select this configuration
+ private byte mConfigIndex; // 6:1 Index of String Descriptor describing this configuration
+ private byte mAttribs; // 7:1 D7 Reserved, set to 1. (USB 1.0 Bus Powered)
+ // D6 Self Powered
+ // D5 Remote Wakeup
+ // D4..0 Reserved, set to 0.
+ private byte mMaxPower; // 8:1 Maximum Power Consumption in 2mA units
+
+ UsbConfigDescriptor(int length, byte type) {
+ super(length, type);
+ }
+
+ public int getTotalLength() {
+ return mTotalLength;
+ }
+
+ public byte getNumInterfaces() {
+ return mNumInterfaces;
+ }
+
+ public byte getConfigValue() {
+ return mConfigValue;
+ }
+
+ public byte getConfigIndex() {
+ return mConfigIndex;
+ }
+
+ public byte getAttribs() {
+ return mAttribs;
+ }
+
+ public byte getMaxPower() {
+ return mMaxPower;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mTotalLength = stream.unpackUsbWord();
+ mNumInterfaces = stream.getByte();
+ mConfigValue = stream.getByte();
+ mConfigIndex = stream.getByte();
+ mAttribs = stream.getByte();
+ mMaxPower = stream.getByte();
+
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.java
new file mode 100644
index 000000000000..63b2d7f6aed7
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.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.server.usb.descriptors;
+
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDeviceConnection;
+import android.util.Log;
+
+/*
+ * Some notes about UsbDescriptor and its subclasses.
+ *
+ * It is assumed that the user of the UsbDescriptorParser knows what they are doing
+ * so NO PROTECTION is implemented against "improper" use. Such uses are specifically:
+ * allocating a UsbDescriptor (subclass) object outside of the context of parsing/reading
+ * a rawdescriptor stream and perhaps accessing fields which have not been inialized (by
+ * parsing/reading or course).
+ */
+
+/**
+ * @hide
+ * Common superclass for all USB Descriptors.
+ */
+public abstract class UsbDescriptor {
+ private static final String TAG = "Descriptor";
+
+ protected final int mLength; // 0:1 bLength Number Size of the Descriptor in Bytes (18 bytes)
+ // we store this as an int because Java bytes are SIGNED.
+ protected final byte mType; // 1:1 bDescriptorType Constant Device Descriptor (0x01)
+
+ private byte[] mRawData;
+
+ private static final int SIZE_STRINGBUFFER = 256;
+ private static byte[] sStringBuffer = new byte[SIZE_STRINGBUFFER];
+
+ // Status
+ public static final int STATUS_UNPARSED = 0;
+ public static final int STATUS_PARSED_OK = 1;
+ public static final int STATUS_PARSED_UNDERRUN = 2;
+ public static final int STATUS_PARSED_OVERRUN = 3;
+ private int mStatus = STATUS_UNPARSED;
+
+ private static String[] sStatusStrings = {
+ "UNPARSED", "PARSED - OK", "PARSED - UNDERRUN", "PARSED - OVERRUN"};
+
+ // Descriptor Type IDs
+ public static final byte DESCRIPTORTYPE_DEVICE = 0x01; // 1
+ public static final byte DESCRIPTORTYPE_CONFIG = 0x02; // 2
+ public static final byte DESCRIPTORTYPE_STRING = 0x03; // 3
+ public static final byte DESCRIPTORTYPE_INTERFACE = 0x04; // 4
+ public static final byte DESCRIPTORTYPE_ENDPOINT = 0x05; // 5
+ public static final byte DESCRIPTORTYPE_INTERFACEASSOC = 0x0B; // 11
+ public static final byte DESCRIPTORTYPE_BOS = 0x0F; // 15
+ public static final byte DESCRIPTORTYPE_CAPABILITY = 0x10; // 16
+
+ public static final byte DESCRIPTORTYPE_HID = 0x21; // 33
+ public static final byte DESCRIPTORTYPE_REPORT = 0x22; // 34
+ public static final byte DESCRIPTORTYPE_PHYSICAL = 0x23; // 35
+ public static final byte DESCRIPTORTYPE_AUDIO_INTERFACE = 0x24; // 36
+ public static final byte DESCRIPTORTYPE_AUDIO_ENDPOINT = 0x25; // 37
+ public static final byte DESCRIPTORTYPE_HUB = 0x29; // 41
+ public static final byte DESCRIPTORTYPE_SUPERSPEED_HUB = 0x2A; // 42
+ public static final byte DESCRIPTORTYPE_ENDPOINT_COMPANION = 0x30; // 48
+
+ // Class IDs
+ public static final byte CLASSID_DEVICE = 0x00;
+ public static final byte CLASSID_AUDIO = 0x01;
+ public static final byte CLASSID_COM = 0x02;
+ public static final byte CLASSID_HID = 0x03;
+ // public static final byte CLASSID_??? = 0x04;
+ public static final byte CLASSID_PHYSICAL = 0x05;
+ public static final byte CLASSID_IMAGE = 0x06;
+ public static final byte CLASSID_PRINTER = 0x07;
+ public static final byte CLASSID_STORAGE = 0x08;
+ public static final byte CLASSID_HUB = 0x09;
+ public static final byte CLASSID_CDC_CONTROL = 0x0A;
+ public static final byte CLASSID_SMART_CARD = 0x0B;
+ //public static final byte CLASSID_??? = 0x0C;
+ public static final byte CLASSID_SECURITY = 0x0D;
+ public static final byte CLASSID_VIDEO = 0x0E;
+ public static final byte CLASSID_HEALTHCARE = 0x0F;
+ public static final byte CLASSID_AUDIOVIDEO = 0x10;
+ public static final byte CLASSID_BILLBOARD = 0x11;
+ public static final byte CLASSID_TYPECBRIDGE = 0x12;
+ public static final byte CLASSID_DIAGNOSTIC = (byte) 0xDC;
+ public static final byte CLASSID_WIRELESS = (byte) 0xE0;
+ public static final byte CLASSID_MISC = (byte) 0xEF;
+ public static final byte CLASSID_APPSPECIFIC = (byte) 0xFE;
+ public static final byte CLASSID_VENDSPECIFIC = (byte) 0xFF;
+
+ // Audio Subclass codes
+ public static final byte AUDIO_SUBCLASS_UNDEFINED = 0x00;
+ public static final byte AUDIO_AUDIOCONTROL = 0x01;
+ public static final byte AUDIO_AUDIOSTREAMING = 0x02;
+ public static final byte AUDIO_MIDISTREAMING = 0x03;
+
+ // Request IDs
+ public static final int REQUEST_GET_STATUS = 0x00;
+ public static final int REQUEST_CLEAR_FEATURE = 0x01;
+ public static final int REQUEST_SET_FEATURE = 0x03;
+ public static final int REQUEST_GET_ADDRESS = 0x05;
+ public static final int REQUEST_GET_DESCRIPTOR = 0x06;
+ public static final int REQUEST_SET_DESCRIPTOR = 0x07;
+ public static final int REQUEST_GET_CONFIGURATION = 0x08;
+ public static final int REQUEST_SET_CONFIGURATION = 0x09;
+
+ /**
+ * @throws IllegalArgumentException
+ */
+ UsbDescriptor(int length, byte type) {
+ // a descriptor has at least a length byte and type byte
+ // one could imagine an empty one otherwise
+ if (length < 2) {
+ // huh?
+ throw new IllegalArgumentException();
+ }
+
+ mLength = length;
+ mType = type;
+ }
+
+ public int getLength() {
+ return mLength;
+ }
+
+ public byte getType() {
+ return mType;
+ }
+
+ public int getStatus() {
+ return mStatus;
+ }
+
+ public void setStatus(int status) {
+ mStatus = status;
+ }
+
+ public String getStatusString() {
+ return sStatusStrings[mStatus];
+ }
+
+ public byte[] getRawData() {
+ return mRawData;
+ }
+
+ /**
+ * Called by the parser for any necessary cleanup.
+ */
+ public void postParse(ByteStream stream) {
+ // Status
+ int bytesRead = stream.getReadCount();
+ if (bytesRead < mLength) {
+ // Too cold...
+ stream.advance(mLength - bytesRead);
+ mStatus = STATUS_PARSED_UNDERRUN;
+ Log.w(TAG, "UNDERRUN t:0x" + Integer.toHexString(mType)
+ + " r:" + bytesRead + " < l:" + mLength);
+ } else if (bytesRead > mLength) {
+ // Too hot...
+ stream.reverse(bytesRead - mLength);
+ mStatus = STATUS_PARSED_OVERRUN;
+ Log.w(TAG, "OVERRRUN t:0x" + Integer.toHexString(mType)
+ + " r:" + bytesRead + " > l:" + mLength);
+ } else {
+ // Just right!
+ mStatus = STATUS_PARSED_OK;
+ }
+ }
+
+ /**
+ * Reads data fields from specified raw-data stream.
+ */
+ public int parseRawDescriptors(ByteStream stream) {
+ int numRead = stream.getReadCount();
+ int dataLen = mLength - numRead;
+ if (dataLen > 0) {
+ mRawData = new byte[dataLen];
+ for (int index = 0; index < dataLen; index++) {
+ mRawData[index] = stream.getByte();
+ }
+ }
+ return mLength;
+ }
+
+ /**
+ * Gets a string for the specified index from the USB Device's string descriptors.
+ */
+ public static String getUsbDescriptorString(UsbDeviceConnection connection, byte strIndex) {
+ String usbStr = "";
+ if (strIndex != 0) {
+ try {
+ int rdo = connection.controlTransfer(
+ UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_STANDARD,
+ REQUEST_GET_DESCRIPTOR,
+ (DESCRIPTORTYPE_STRING << 8) | strIndex,
+ 0,
+ sStringBuffer,
+ 0xFF,
+ 0);
+ if (rdo >= 0) {
+ usbStr = new String(sStringBuffer, 2, rdo - 2, "UTF-16LE");
+ } else {
+ usbStr = "?";
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Can not communicate with USB device", e);
+ }
+ }
+ return usbStr;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
new file mode 100644
index 000000000000..7c074dadadf9
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.usb.descriptors;
+
+import android.util.Log;
+
+import java.util.ArrayList;
+
+/**
+ * @hide
+ * Class for parsing a binary stream of USB Descriptors.
+ */
+public class UsbDescriptorParser {
+ private static final String TAG = "DescriptorParser";
+
+ // Descriptor Objects
+ private ArrayList<UsbDescriptor> mDescriptors = new ArrayList<UsbDescriptor>();
+
+ private UsbDeviceDescriptor mDeviceDescriptor;
+ private UsbInterfaceDescriptor mCurInterfaceDescriptor;
+
+ public UsbDescriptorParser() {}
+
+ /**
+ * The probability (as returned by getHeadsetProbability() at which we conclude
+ * the peripheral is a headset.
+ */
+ private static final float IN_HEADSET_TRIGGER = 0.75f;
+ private static final float OUT_HEADSET_TRIGGER = 0.75f;
+
+ private UsbDescriptor allocDescriptor(ByteStream stream) {
+ stream.resetReadCount();
+
+ int length = (int) stream.getByte() & 0x000000FF;
+ byte type = stream.getByte();
+
+ UsbDescriptor descriptor = null;
+ switch (type) {
+ /*
+ * Standard
+ */
+ case UsbDescriptor.DESCRIPTORTYPE_DEVICE:
+ descriptor = mDeviceDescriptor = new UsbDeviceDescriptor(length, type);
+ break;
+
+ case UsbDescriptor.DESCRIPTORTYPE_CONFIG:
+ descriptor = new UsbConfigDescriptor(length, type);
+ break;
+
+ case UsbDescriptor.DESCRIPTORTYPE_INTERFACE:
+ descriptor = mCurInterfaceDescriptor = new UsbInterfaceDescriptor(length, type);
+ break;
+
+ case UsbDescriptor.DESCRIPTORTYPE_ENDPOINT:
+ descriptor = new UsbEndpointDescriptor(length, type);
+ break;
+
+ /*
+ * HID
+ */
+ case UsbDescriptor.DESCRIPTORTYPE_HID:
+ descriptor = new UsbHIDDescriptor(length, type);
+ break;
+
+ /*
+ * Other
+ */
+ case UsbDescriptor.DESCRIPTORTYPE_INTERFACEASSOC:
+ descriptor = new UsbInterfaceAssoc(length, type);
+ break;
+
+ /*
+ * Audio Class Specific
+ */
+ case UsbDescriptor.DESCRIPTORTYPE_AUDIO_INTERFACE:
+ descriptor = UsbACInterface.allocDescriptor(this, stream, length, type);
+ break;
+
+ case UsbDescriptor.DESCRIPTORTYPE_AUDIO_ENDPOINT:
+ descriptor = UsbACEndpoint.allocDescriptor(this, length, type);
+ break;
+
+ default:
+ break;
+ }
+
+ if (descriptor == null) {
+ // Unknown Descriptor
+ Log.i(TAG, "Unknown Descriptor len:" + length + " type:0x"
+ + Integer.toHexString(type));
+ descriptor = new UsbUnknown(length, type);
+ }
+
+ return descriptor;
+ }
+
+ public UsbDeviceDescriptor getDeviceDescriptor() {
+ return mDeviceDescriptor;
+ }
+
+ public UsbInterfaceDescriptor getCurInterface() {
+ return mCurInterfaceDescriptor;
+ }
+
+ /**
+ * @hide
+ */
+ public boolean parseDescriptors(byte[] descriptors) {
+ try {
+ mDescriptors.clear();
+
+ ByteStream stream = new ByteStream(descriptors);
+ while (stream.available() > 0) {
+ UsbDescriptor descriptor = allocDescriptor(stream);
+ if (descriptor != null) {
+ // Parse
+ descriptor.parseRawDescriptors(stream);
+ mDescriptors.add(descriptor);
+
+ // Clean up
+ descriptor.postParse(stream);
+ }
+ }
+ return true;
+ } catch (Exception ex) {
+ Log.e(TAG, "Exception parsing USB descriptors.", ex);
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ public boolean parseDevice(String deviceAddr) {
+ byte[] rawDescriptors = getRawDescriptors(deviceAddr);
+ return rawDescriptors != null && parseDescriptors(rawDescriptors);
+ }
+
+ private native byte[] getRawDescriptors(String deviceAddr);
+
+ public int getParsingSpec() {
+ return mDeviceDescriptor != null ? mDeviceDescriptor.getSpec() : 0;
+ }
+
+ public ArrayList<UsbDescriptor> getDescriptors() {
+ return mDescriptors;
+ }
+
+ /**
+ * @hide
+ */
+ public ArrayList<UsbDescriptor> getDescriptors(byte type) {
+ ArrayList<UsbDescriptor> list = new ArrayList<UsbDescriptor>();
+ for (UsbDescriptor descriptor : mDescriptors) {
+ if (descriptor.getType() == type) {
+ list.add(descriptor);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * @hide
+ */
+ public ArrayList<UsbDescriptor> getInterfaceDescriptorsForClass(byte usbClass) {
+ ArrayList<UsbDescriptor> list = new ArrayList<UsbDescriptor>();
+ for (UsbDescriptor descriptor : mDescriptors) {
+ // ensure that this isn't an unrecognized DESCRIPTORTYPE_INTERFACE
+ if (descriptor.getType() == UsbDescriptor.DESCRIPTORTYPE_INTERFACE) {
+ if (descriptor instanceof UsbInterfaceDescriptor) {
+ UsbInterfaceDescriptor intrDesc = (UsbInterfaceDescriptor) descriptor;
+ if (intrDesc.getUsbClass() == usbClass) {
+ list.add(descriptor);
+ }
+ } else {
+ Log.w(TAG, "Unrecognized Interface l:" + descriptor.getLength()
+ + " t:0x" + Integer.toHexString(descriptor.getType()));
+ }
+ }
+ }
+ return list;
+ }
+
+ /**
+ * @hide
+ */
+ public ArrayList<UsbDescriptor> getACInterfaceDescriptors(byte subtype, byte subclass) {
+ ArrayList<UsbDescriptor> list = new ArrayList<UsbDescriptor>();
+ for (UsbDescriptor descriptor : mDescriptors) {
+ if (descriptor.getType() == UsbDescriptor.DESCRIPTORTYPE_AUDIO_INTERFACE) {
+ // ensure that this isn't an unrecognized DESCRIPTORTYPE_AUDIO_INTERFACE
+ if (descriptor instanceof UsbACInterface) {
+ UsbACInterface acDescriptor = (UsbACInterface) descriptor;
+ if (acDescriptor.getSubtype() == subtype
+ && acDescriptor.getSubclass() == subclass) {
+ list.add(descriptor);
+ }
+ } else {
+ Log.w(TAG, "Unrecognized Audio Interface l:" + descriptor.getLength()
+ + " t:0x" + Integer.toHexString(descriptor.getType()));
+ }
+ }
+ }
+ return list;
+ }
+
+ /**
+ * @hide
+ */
+ public boolean hasHIDDescriptor() {
+ ArrayList<UsbDescriptor> descriptors =
+ getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_HID);
+ return !descriptors.isEmpty();
+ }
+
+ /**
+ * @hide
+ */
+ public boolean hasMIDIInterface() {
+ ArrayList<UsbDescriptor> descriptors =
+ getInterfaceDescriptorsForClass(UsbDescriptor.CLASSID_AUDIO);
+ for (UsbDescriptor descriptor : descriptors) {
+ // enusure that this isn't an unrecognized interface descriptor
+ if (descriptor instanceof UsbInterfaceDescriptor) {
+ UsbInterfaceDescriptor interfaceDescr = (UsbInterfaceDescriptor) descriptor;
+ if (interfaceDescr.getUsbSubclass() == UsbDescriptor.AUDIO_MIDISTREAMING) {
+ return true;
+ }
+ } else {
+ Log.w(TAG, "Undefined Audio Class Interface l:" + descriptor.getLength()
+ + " t:0x" + Integer.toHexString(descriptor.getType()));
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ public float getInputHeadsetProbability() {
+ if (hasMIDIInterface()) {
+ return 0.0f;
+ }
+
+ float probability = 0.0f;
+ ArrayList<UsbDescriptor> acDescriptors;
+
+ // Look for a microphone
+ boolean hasMic = false;
+ acDescriptors = getACInterfaceDescriptors(UsbACInterface.ACI_INPUT_TERMINAL,
+ UsbACInterface.AUDIO_AUDIOCONTROL);
+ for (UsbDescriptor descriptor : acDescriptors) {
+ if (descriptor instanceof UsbACInputTerminal) {
+ UsbACInputTerminal inDescr = (UsbACInputTerminal) descriptor;
+ if (inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_IN_MIC
+ || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET
+ || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED
+ || inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_EXTERN_LINE) {
+ hasMic = true;
+ break;
+ }
+ } else {
+ Log.w(TAG, "Undefined Audio Input terminal l:" + descriptor.getLength()
+ + " t:0x" + Integer.toHexString(descriptor.getType()));
+ }
+ }
+
+ // Look for a "speaker"
+ boolean hasSpeaker = false;
+ acDescriptors =
+ getACInterfaceDescriptors(UsbACInterface.ACI_OUTPUT_TERMINAL,
+ UsbACInterface.AUDIO_AUDIOCONTROL);
+ for (UsbDescriptor descriptor : acDescriptors) {
+ if (descriptor instanceof UsbACOutputTerminal) {
+ UsbACOutputTerminal outDescr = (UsbACOutputTerminal) descriptor;
+ if (outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_SPEAKER
+ || outDescr.getTerminalType()
+ == UsbTerminalTypes.TERMINAL_OUT_HEADPHONES
+ || outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET) {
+ hasSpeaker = true;
+ break;
+ }
+ } else {
+ Log.w(TAG, "Undefined Audio Output terminal l:" + descriptor.getLength()
+ + " t:0x" + Integer.toHexString(descriptor.getType()));
+ }
+ }
+
+ if (hasMic && hasSpeaker) {
+ probability += 0.75f;
+ }
+
+ if (hasMic && hasHIDDescriptor()) {
+ probability += 0.25f;
+ }
+
+ return probability;
+ }
+
+ /**
+ * getInputHeadsetProbability() reports a probability of a USB Input peripheral being a
+ * headset. The probability range is between 0.0f (definitely NOT a headset) and
+ * 1.0f (definitely IS a headset). A probability of 0.75f seems sufficient
+ * to count on the peripheral being a headset.
+ */
+ public boolean isInputHeadset() {
+ return getInputHeadsetProbability() >= IN_HEADSET_TRIGGER;
+ }
+
+ /**
+ * @hide
+ */
+ public float getOutputHeadsetProbability() {
+ if (hasMIDIInterface()) {
+ return 0.0f;
+ }
+
+ float probability = 0.0f;
+ ArrayList<UsbDescriptor> acDescriptors;
+
+ // Look for a "speaker"
+ boolean hasSpeaker = false;
+ acDescriptors =
+ getACInterfaceDescriptors(UsbACInterface.ACI_OUTPUT_TERMINAL,
+ UsbACInterface.AUDIO_AUDIOCONTROL);
+ for (UsbDescriptor descriptor : acDescriptors) {
+ if (descriptor instanceof UsbACOutputTerminal) {
+ UsbACOutputTerminal outDescr = (UsbACOutputTerminal) descriptor;
+ if (outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_SPEAKER
+ || outDescr.getTerminalType()
+ == UsbTerminalTypes.TERMINAL_OUT_HEADPHONES
+ || outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET) {
+ hasSpeaker = true;
+ break;
+ }
+ } else {
+ Log.w(TAG, "Undefined Audio Output terminal l:" + descriptor.getLength()
+ + " t:0x" + Integer.toHexString(descriptor.getType()));
+ }
+ }
+
+ if (hasSpeaker) {
+ probability += 0.75f;
+ }
+
+ if (hasSpeaker && hasHIDDescriptor()) {
+ probability += 0.25f;
+ }
+
+ return probability;
+ }
+
+ /**
+ * getOutputHeadsetProbability() reports a probability of a USB Output peripheral being a
+ * headset. The probability range is between 0.0f (definitely NOT a headset) and
+ * 1.0f (definitely IS a headset). A probability of 0.75f seems sufficient
+ * to count on the peripheral being a headset.
+ */
+ public boolean isOutputHeadset() {
+ return getOutputHeadsetProbability() >= OUT_HEADSET_TRIGGER;
+ }
+
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
new file mode 100644
index 000000000000..90848caba852
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+/**
+ * @hide
+ * A USB Device Descriptor.
+ * see usb11.pdf section 9.6.1
+ */
+/* public */ public class UsbDeviceDescriptor extends UsbDescriptor {
+ private static final String TAG = "Device";
+
+ private int mSpec; // 2:2 bcdUSB 2 BCD USB Specification Number - BCD
+ private byte mDevClass; // 4:1 class code
+ private byte mDevSubClass; // 5:1 subclass code
+ private byte mProtocol; // 6:1 protocol
+ private byte mPacketSize; // 7:1 Maximum Packet Size for Zero Endpoint.
+ // Valid Sizes are 8, 16, 32, 64
+ private int mVendorID; // 8:2 vendor ID
+ private int mProductID; // 10:2 product ID
+ private int mDeviceRelease; // 12:2 Device Release number - BCD
+ private byte mMfgIndex; // 14:1 Index of Manufacturer String Descriptor
+ private byte mProductIndex; // 15:1 Index of Product String Descriptor
+ private byte mSerialNum; // 16:1 Index of Serial Number String Descriptor
+ private byte mNumConfigs; // 17:1 Number of Possible Configurations
+
+ UsbDeviceDescriptor(int length, byte type) {
+ super(length, type);
+ }
+
+ public int getSpec() {
+ return mSpec;
+ }
+
+ public byte getDevClass() {
+ return mDevClass;
+ }
+
+ public byte getDevSubClass() {
+ return mDevSubClass;
+ }
+
+ public byte getProtocol() {
+ return mProtocol;
+ }
+
+ public byte getPacketSize() {
+ return mPacketSize;
+ }
+
+ public int getVendorID() {
+ return mVendorID;
+ }
+
+ public int getProductID() {
+ return mProductID;
+ }
+
+ public int getDeviceRelease() {
+ return mDeviceRelease;
+ }
+
+ public byte getMfgIndex() {
+ return mMfgIndex;
+ }
+
+ public byte getProductIndex() {
+ return mProductIndex;
+ }
+
+ public byte getSerialNum() {
+ return mSerialNum;
+ }
+
+ public byte getNumConfigs() {
+ return mNumConfigs;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mSpec = stream.unpackUsbWord();
+ mDevClass = stream.getByte();
+ mDevSubClass = stream.getByte();
+ mProtocol = stream.getByte();
+ mPacketSize = stream.getByte();
+ mVendorID = stream.unpackUsbWord();
+ mProductID = stream.unpackUsbWord();
+ mDeviceRelease = stream.unpackUsbWord();
+ mMfgIndex = stream.getByte();
+ mProductIndex = stream.getByte();
+ mSerialNum = stream.getByte();
+ mNumConfigs = stream.getByte();
+
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
new file mode 100644
index 000000000000..def670093e6e
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+/**
+ * @hide
+ * A Usb Endpoint Descriptor.
+ * see usb11.pdf section 9.6.4
+ */
+public class UsbEndpointDescriptor extends UsbDescriptor {
+ private static final String TAG = "EndPoint";
+
+ public static final byte MASK_ENDPOINT_ADDRESS = 0b0001111;
+ public static final byte MASK_ENDPOINT_DIRECTION = (byte) 0b10000000;
+ public static final byte DIRECTION_OUTPUT = 0x00;
+ public static final byte DIRECTION_INPUT = (byte) 0x80;
+
+ public static final byte MASK_ATTRIBS_TRANSTYPE = 0b00000011;
+ public static final byte TRANSTYPE_CONTROL = 0x00;
+ public static final byte TRANSTYPE_ISO = 0x01;
+ public static final byte TRANSTYPE_BULK = 0x02;
+ public static final byte TRANSTYPE_INTERRUPT = 0x03;
+
+ public static final byte MASK_ATTRIBS_SYNCTYPE = 0b00001100;
+ public static final byte SYNCTYPE_NONE = 0b00000000;
+ public static final byte SYNCTYPE_ASYNC = 0b00000100;
+ public static final byte SYNCTYPE_ADAPTSYNC = 0b00001000;
+ public static final byte SYNCTYPE_RESERVED = 0b00001100;
+
+ public static final byte MASK_ATTRIBS_USEAGE = 0b00110000;
+ public static final byte USEAGE_DATA = 0b00000000;
+ public static final byte USEAGE_FEEDBACK = 0b00010000;
+ public static final byte USEAGE_EXPLICIT = 0b00100000;
+ public static final byte USEAGE_RESERVED = 0b00110000;
+
+ private byte mEndpointAddress; // 2:1 Endpoint Address
+ // Bits 0..3b Endpoint Number.
+ // Bits 4..6b Reserved. Set to Zero
+ // Bits 7 Direction 0 = Out, 1 = In
+ // (Ignored for Control Endpoints)
+ private byte mAttributes; // 3:1 Various flags
+ // Bits 0..1 Transfer Type:
+ // 00 = Control, 01 = Isochronous, 10 = Bulk, 11 = Interrupt
+ // Bits 2..7 are reserved. If Isochronous endpoint,
+ // Bits 3..2 = Synchronisation Type (Iso Mode)
+ // 00 = No Synchonisation
+ // 01 = Asynchronous
+ // 10 = Adaptive
+ // 11 = Synchronous
+ // Bits 5..4 = Usage Type (Iso Mode)
+ // 00: Data Endpoint
+ // 01:Feedback Endpoint 10
+ // Explicit Feedback Data Endpoint
+ // 11: Reserved
+ private int mPacketSize; // 4:2 Maximum Packet Size this endpoint is capable of
+ // sending or receiving
+ private byte mInterval; // 6:1 Interval for polling endpoint data transfers. Value in
+ // frame counts.
+ // Ignored for Bulk & Control Endpoints. Isochronous must equal
+ // 1 and field may range from 1 to 255 for interrupt endpoints.
+ private byte mRefresh;
+ private byte mSyncAddress;
+
+ public UsbEndpointDescriptor(int length, byte type) {
+ super(length, type);
+ }
+
+ public byte getEndpointAddress() {
+ return mEndpointAddress;
+ }
+
+ public byte getAttributes() {
+ return mAttributes;
+ }
+
+ public int getPacketSize() {
+ return mPacketSize;
+ }
+
+ public byte getInterval() {
+ return mInterval;
+ }
+
+ public byte getRefresh() {
+ return mRefresh;
+ }
+
+ public byte getSyncAddress() {
+ return mSyncAddress;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mEndpointAddress = stream.getByte();
+ mAttributes = stream.getByte();
+ mPacketSize = stream.unpackUsbWord();
+ mInterval = stream.getByte();
+ if (mLength == 9) {
+ mRefresh = stream.getByte();
+ mSyncAddress = stream.getByte();
+ }
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbHIDDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbHIDDescriptor.java
new file mode 100644
index 000000000000..56c07ec9a071
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbHIDDescriptor.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+/**
+ * @hide
+ * A USB HID (Human Interface Descriptor).
+ * see HID1_11.pdf - 6.2.1
+ */
+public class UsbHIDDescriptor extends UsbDescriptor {
+ private static final String TAG = "HID";
+
+ private int mRelease; // 2:2 the HID Class Specification release.
+ private byte mCountryCode; // 4:1 country code of the localized hardware.
+ private byte mNumDescriptors; // number of descriptors (always at least one
+ // i.e. Report descriptor.)
+ private byte mDescriptorType; // 6:1 type of class descriptor.
+ // See Section 7.1.2: Set_Descriptor
+ // Request for a table of class descriptor constants.
+ private int mDescriptorLen; // 7:2 Numeric expression that is the total size of
+ // the Report descriptor.
+
+ public UsbHIDDescriptor(int length, byte type) {
+ super(length, type);
+ }
+
+ public int getRelease() {
+ return mRelease;
+ }
+
+ public byte getCountryCode() {
+ return mCountryCode;
+ }
+
+ public byte getNumDescriptors() {
+ return mNumDescriptors;
+ }
+
+ public byte getDescriptorType() {
+ return mDescriptorType;
+ }
+
+ public int getDescriptorLen() {
+ return mDescriptorLen;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mRelease = stream.unpackUsbWord();
+ mCountryCode = stream.getByte();
+ mNumDescriptors = stream.getByte();
+ mDescriptorType = stream.getByte();
+ mDescriptorLen = stream.unpackUsbWord();
+
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceAssoc.java b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceAssoc.java
new file mode 100644
index 000000000000..4b18a01b1c8b
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceAssoc.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.server.usb.descriptors;
+
+/**
+ * @hide
+ * A USB Interface Association Descriptor.
+ * found this one here: http://www.usb.org/developers/docs/whitepapers/iadclasscode_r10.pdf
+ * also: https://msdn.microsoft.com/en-us/library/windows/hardware/ff540054(v=vs.85).aspx
+ */
+public class UsbInterfaceAssoc extends UsbDescriptor {
+ private static final String TAG = "InterfaceAssoc";
+
+ private byte mFirstInterface;
+ private byte mInterfaceCount;
+ private byte mFunctionClass;
+ private byte mFunctionSubClass;
+ private byte mFunctionProtocol;
+ private byte mFunction;
+
+ public UsbInterfaceAssoc(int length, byte type) {
+ super(length, type);
+ }
+
+ public byte getFirstInterface() {
+ return mFirstInterface;
+ }
+
+ public byte getInterfaceCount() {
+ return mInterfaceCount;
+ }
+
+ public byte getFunctionClass() {
+ return mFunctionClass;
+ }
+
+ public byte getFunctionSubClass() {
+ return mFunctionSubClass;
+ }
+
+ public byte getFunctionProtocol() {
+ return mFunctionProtocol;
+ }
+
+ public byte getFunction() {
+ return mFunction;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mFirstInterface = stream.getByte();
+ mInterfaceCount = stream.getByte();
+ mFunctionClass = stream.getByte();
+ mFunctionSubClass = stream.getByte();
+ mFunctionProtocol = stream.getByte();
+ mFunction = stream.getByte();
+
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
new file mode 100644
index 000000000000..21b5e0cbaa1b
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.usb.descriptors;
+
+/**
+ * @hide
+ * A common super-class for all USB Interface Descritor subtypes.
+ * see usb11.pdf section 9.6.3
+ */
+public class UsbInterfaceDescriptor extends UsbDescriptor {
+ private static final String TAG = "Interface";
+
+ protected byte mInterfaceNumber; // 2:1 Number of Interface
+ protected byte mAlternateSetting; // 3:1 Value used to select alternative setting
+ protected byte mNumEndpoints; // 4:1 Number of Endpoints used for this interface
+ protected byte mUsbClass; // 5:1 Class Code
+ protected byte mUsbSubclass; // 6:1 Subclass Code
+ protected byte mProtocol; // 7:1 Protocol Code
+ protected byte mDescrIndex; // 8:1 Index of String Descriptor Describing this interface
+
+ UsbInterfaceDescriptor(int length, byte type) {
+ super(length, type);
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mInterfaceNumber = stream.getByte();
+ mAlternateSetting = stream.getByte();
+ mNumEndpoints = stream.getByte();
+ mUsbClass = stream.getByte();
+ mUsbSubclass = stream.getByte();
+ mProtocol = stream.getByte();
+ mDescrIndex = stream.getByte();
+
+ return mLength;
+ }
+
+ public byte getInterfaceNumber() {
+ return mInterfaceNumber;
+ }
+
+ public byte getAlternateSetting() {
+ return mAlternateSetting;
+ }
+
+ public byte getNumEndpoints() {
+ return mNumEndpoints;
+ }
+
+ public byte getUsbClass() {
+ return mUsbClass;
+ }
+
+ public byte getUsbSubclass() {
+ return mUsbSubclass;
+ }
+
+ public byte getProtocol() {
+ return mProtocol;
+ }
+
+ public byte getDescrIndex() {
+ return mDescrIndex;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.java b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.java
new file mode 100644
index 000000000000..4452b23cb6ae
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.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 com.android.server.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific Midi Streaming Interface.
+ * see midi10.pdf section 6.1.2.1
+ */
+public class UsbMSMidiHeader extends UsbACInterface {
+ private static final String TAG = "MSMidiHeader";
+
+ public UsbMSMidiHeader(int length, byte type, byte subtype, byte subclass) {
+ super(length, type, subtype, subclass);
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ // TODO - read data memebers
+ stream.advance(mLength - stream.getReadCount());
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.java b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.java
new file mode 100644
index 000000000000..2d33ba7727dd
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.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 com.android.server.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific Midi Input Jack Interface.
+ * see midi10.pdf section B.4.3
+ */
+public class UsbMSMidiInputJack extends UsbACInterface {
+ private static final String TAG = "MSMidiInputJack";
+
+ UsbMSMidiInputJack(int length, byte type, byte subtype, byte subclass) {
+ super(length, type, subtype, subclass);
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ // TODO - read data memebers
+ stream.advance(mLength - stream.getReadCount());
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.java b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.java
new file mode 100644
index 000000000000..bd2dc11d57df
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.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 com.android.server.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific Midi Output Jack Interface.
+ * see midi10.pdf section B.4.4
+ */
+public class UsbMSMidiOutputJack extends UsbACInterface {
+ private static final String TAG = "MSMidiOutputJack";
+
+ public UsbMSMidiOutputJack(int length, byte type, byte subtype, byte subclass) {
+ super(length, type, subtype, subclass);
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ // TODO - read data memebers
+ stream.advance(mLength - stream.getReadCount());
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java b/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java
new file mode 100644
index 000000000000..b5214625126a
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.usb.descriptors;
+
+/**
+ * @hide
+ * A class for decoding information in Terminal Descriptors.
+ * see termt10.pdf
+ */
+public class UsbTerminalTypes {
+ private static final String TAG = "TerminalTypes";
+
+ // USB
+ public static final int TERMINAL_USB_STREAMING = 0x0101;
+
+ // Inputs
+ public static final int TERMINAL_IN_UNDEFINED = 0x0200;
+ public static final int TERMINAL_IN_MIC = 0x0201;
+ public static final int TERMINAL_IN_DESKTOP_MIC = 0x0202;
+ public static final int TERMINAL_IN_PERSONAL_MIC = 0x0203;
+ public static final int TERMINAL_IN_OMNI_MIC = 0x0204;
+ public static final int TERMINAL_IN_MIC_ARRAY = 0x0205;
+ public static final int TERMINAL_IN_PROC_MIC_ARRAY = 0x0206;
+
+ // Outputs
+ public static final int TERMINAL_OUT_UNDEFINED = 0x0300;
+ public static final int TERMINAL_OUT_SPEAKER = 0x0301;
+ public static final int TERMINAL_OUT_HEADPHONES = 0x0302;
+ public static final int TERMINAL_OUT_HEADMOUNTED = 0x0303;
+ public static final int TERMINAL_OUT_DESKTOPSPEAKER = 0x0304;
+ public static final int TERMINAL_OUT_ROOMSPEAKER = 0x0305;
+ public static final int TERMINAL_OUT_COMSPEAKER = 0x0306;
+ public static final int TERMINAL_OUT_LFSPEAKER = 0x0307;
+
+ // Bi-directional
+ public static final int TERMINAL_BIDIR_UNDEFINED = 0x0400;
+ public static final int TERMINAL_BIDIR_HANDSET = 0x0401;
+ public static final int TERMINAL_BIDIR_HEADSET = 0x0402;
+ public static final int TERMINAL_BIDIR_SKRPHONE = 0x0403;
+ public static final int TERMINAL_BIDIR_SKRPHONE_SUPRESS = 0x0404;
+ public static final int TERMINAL_BIDIR_SKRPHONE_CANCEL = 0x0405;
+
+ // Telephony
+ public static final int TERMINAL_TELE_UNDEFINED = 0x0500;
+ public static final int TERMINAL_TELE_PHONELINE = 0x0501;
+ public static final int TERMINAL_TELE_PHONE = 0x0502;
+ public static final int TERMINAL_TELE_DOWNLINEPHONE = 0x0503;
+
+ // External
+ public static final int TERMINAL_EXTERN_UNDEFINED = 0x0600;
+ public static final int TERMINAL_EXTERN_ANALOG = 0x0601;
+ public static final int TERMINAL_EXTERN_DIGITAL = 0x0602;
+ public static final int TERMINAL_EXTERN_LINE = 0x0603;
+ public static final int TERMINAL_EXTERN_LEGACY = 0x0604;
+ public static final int TERMINAL_EXTERN_SPIDF = 0x0605;
+ public static final int TERMINAL_EXTERN_1394DA = 0x0606;
+ public static final int TERMINAL_EXTERN_1394DV = 0x0607;
+
+ public static final int TERMINAL_EMBED_UNDEFINED = 0x0700;
+ public static final int TERMINAL_EMBED_CALNOISE = 0x0701;
+ public static final int TERMINAL_EMBED_EQNOISE = 0x0702;
+ public static final int TERMINAL_EMBED_CDPLAYER = 0x0703;
+ public static final int TERMINAL_EMBED_DAT = 0x0704;
+ public static final int TERMINAL_EMBED_DCC = 0x0705;
+ public static final int TERMINAL_EMBED_MINIDISK = 0x0706;
+ public static final int TERMINAL_EMBED_ANALOGTAPE = 0x0707;
+ public static final int TERMINAL_EMBED_PHONOGRAPH = 0x0708;
+ public static final int TERMINAL_EMBED_VCRAUDIO = 0x0709;
+ public static final int TERMINAL_EMBED_VIDDISKAUDIO = 0x070A;
+ public static final int TERMINAL_EMBED_DVDAUDIO = 0x070B;
+ public static final int TERMINAL_EMBED_TVAUDIO = 0x070C;
+ public static final int TERMINAL_EMBED_SATELLITEAUDIO = 0x070D;
+ public static final int TERMINAL_EMBED_CABLEAUDIO = 0x070E;
+ public static final int TERMINAL_EMBED_DSSAUDIO = 0x070F;
+ public static final int TERMINAL_EMBED_RADIOAUDIO = 0x0710;
+ public static final int TERMINAL_EMBED_RADIOTRANSMITTER = 0x0711;
+ public static final int TERMINAL_EMBED_MULTITRACK = 0x0712;
+ public static final int TERMINAL_EMBED_SYNTHESIZER = 0x0713;
+
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbUnknown.java b/services/usb/java/com/android/server/usb/descriptors/UsbUnknown.java
new file mode 100644
index 000000000000..a6fe8bba3508
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbUnknown.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.server.usb.descriptors;
+
+/**
+ * @hide
+ * A holder for any unrecognized descriptor encountered in the descriptor stream.
+ */
+public class UsbUnknown extends UsbDescriptor {
+ static final String TAG = "Unknown";
+
+ public UsbUnknown(int length, byte type) {
+ super(length, type);
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/HTMLReporter.java b/services/usb/java/com/android/server/usb/descriptors/report/HTMLReporter.java
new file mode 100644
index 000000000000..c98789d880a0
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/report/HTMLReporter.java
@@ -0,0 +1,572 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.usb.descriptors.report;
+
+import android.hardware.usb.UsbDeviceConnection;
+
+import com.android.server.usb.descriptors.UsbACAudioControlEndpoint;
+import com.android.server.usb.descriptors.UsbACAudioStreamEndpoint;
+import com.android.server.usb.descriptors.UsbACFeatureUnit;
+import com.android.server.usb.descriptors.UsbACHeader;
+import com.android.server.usb.descriptors.UsbACInputTerminal;
+import com.android.server.usb.descriptors.UsbACInterface;
+import com.android.server.usb.descriptors.UsbACMidiEndpoint;
+import com.android.server.usb.descriptors.UsbACMixerUnit;
+import com.android.server.usb.descriptors.UsbACOutputTerminal;
+import com.android.server.usb.descriptors.UsbACSelectorUnit;
+import com.android.server.usb.descriptors.UsbACTerminal;
+import com.android.server.usb.descriptors.UsbASFormat;
+import com.android.server.usb.descriptors.UsbASFormatI;
+import com.android.server.usb.descriptors.UsbASFormatII;
+import com.android.server.usb.descriptors.UsbASGeneral;
+import com.android.server.usb.descriptors.UsbConfigDescriptor;
+import com.android.server.usb.descriptors.UsbDescriptor;
+import com.android.server.usb.descriptors.UsbDeviceDescriptor;
+import com.android.server.usb.descriptors.UsbEndpointDescriptor;
+import com.android.server.usb.descriptors.UsbHIDDescriptor;
+import com.android.server.usb.descriptors.UsbInterfaceAssoc;
+import com.android.server.usb.descriptors.UsbInterfaceDescriptor;
+import com.android.server.usb.descriptors.UsbMSMidiHeader;
+import com.android.server.usb.descriptors.UsbMSMidiInputJack;
+import com.android.server.usb.descriptors.UsbMSMidiOutputJack;
+import com.android.server.usb.descriptors.UsbUnknown;
+
+/**
+ * Implements the Reporter inteface to provide HTML reporting for UsbDescriptor subclasses.
+ */
+public class HTMLReporter implements Reporter {
+ private final StringBuilder mStringBuilder;
+ private final UsbDeviceConnection mConnection;
+
+ public HTMLReporter(StringBuilder stringBuilder, UsbDeviceConnection connection) {
+ mStringBuilder = stringBuilder;
+ mConnection = connection;
+ }
+
+ /*
+ * HTML Helpers
+ */
+ private void writeHeader(int level, String text) {
+ mStringBuilder
+ .append("<h").append(level).append('>')
+ .append(text)
+ .append("</h").append(level).append('>');
+ }
+
+ private void openParagraph() {
+ mStringBuilder.append("<p>");
+ }
+
+ private void closeParagraph() {
+ mStringBuilder.append("</p>");
+ }
+
+ private void writeParagraph(String text) {
+ openParagraph();
+ mStringBuilder.append(text);
+ closeParagraph();
+ }
+
+ private void openList() {
+ mStringBuilder.append("<ul>");
+ }
+
+ private void closeList() {
+ mStringBuilder.append("</ul>");
+ }
+
+ private void openListItem() {
+ mStringBuilder.append("<li>");
+ }
+
+ private void closeListItem() {
+ mStringBuilder.append("</li>");
+ }
+
+ private void writeListItem(String text) {
+ openListItem();
+ mStringBuilder.append(text);
+ closeListItem();
+ }
+
+ /*
+ * Data Formating Helpers
+ */
+ private static String getHexString(byte value) {
+ return "0x" + Integer.toHexString(((int) value) & 0xFF).toUpperCase();
+ }
+
+ private static String getBCDString(int value) {
+ int major = value >> 8;
+ int minor = (value >> 4) & 0x0F;
+ int subminor = value & 0x0F;
+
+ return "" + major + "." + minor + subminor;
+ }
+
+ private static String getHexString(int value) {
+ int intValue = value & 0xFFFF;
+ return "0x" + Integer.toHexString(intValue).toUpperCase();
+ }
+
+ private void dumpHexArray(byte[] rawData, StringBuilder builder) {
+ if (rawData != null) {
+ // Assume the type and Length and perhaps sub-type have been displayed
+ openParagraph();
+ for (int index = 0; index < rawData.length; index++) {
+ builder.append(getHexString(rawData[index]) + " ");
+ }
+ closeParagraph();
+ }
+ }
+
+ /**
+ * Decode ACTUAL UsbDescriptor sub classes and call type-specific report methods.
+ */
+ @Override
+ public void report(UsbDescriptor descriptor) {
+ if (descriptor instanceof UsbDeviceDescriptor) {
+ tsReport((UsbDeviceDescriptor) descriptor);
+ } else if (descriptor instanceof UsbConfigDescriptor) {
+ tsReport((UsbConfigDescriptor) descriptor);
+ } else if (descriptor instanceof UsbInterfaceDescriptor) {
+ tsReport((UsbInterfaceDescriptor) descriptor);
+ } else if (descriptor instanceof UsbEndpointDescriptor) {
+ tsReport((UsbEndpointDescriptor) descriptor);
+ } else if (descriptor instanceof UsbHIDDescriptor) {
+ tsReport((UsbHIDDescriptor) descriptor);
+ } else if (descriptor instanceof UsbACAudioControlEndpoint) {
+ tsReport((UsbACAudioControlEndpoint) descriptor);
+ } else if (descriptor instanceof UsbACAudioStreamEndpoint) {
+ tsReport((UsbACAudioStreamEndpoint) descriptor);
+ } else if (descriptor instanceof UsbACHeader) {
+ tsReport((UsbACHeader) descriptor);
+ } else if (descriptor instanceof UsbACFeatureUnit) {
+ tsReport((UsbACFeatureUnit) descriptor);
+ } else if (descriptor instanceof UsbACInputTerminal) {
+ tsReport((UsbACInputTerminal) descriptor);
+ } else if (descriptor instanceof UsbACOutputTerminal) {
+ tsReport((UsbACOutputTerminal) descriptor);
+ } else if (descriptor instanceof UsbACMidiEndpoint) {
+ tsReport((UsbACMidiEndpoint) descriptor);
+ } else if (descriptor instanceof UsbACMixerUnit) {
+ tsReport((UsbACMixerUnit) descriptor);
+ } else if (descriptor instanceof UsbACSelectorUnit) {
+ tsReport((UsbACSelectorUnit) descriptor);
+ } else if (descriptor instanceof UsbASFormatI) {
+ tsReport((UsbASFormatI) descriptor);
+ } else if (descriptor instanceof UsbASFormatII) {
+ tsReport((UsbASFormatII) descriptor);
+ } else if (descriptor instanceof UsbASFormat) {
+ tsReport((UsbASFormat) descriptor);
+ } else if (descriptor instanceof UsbASGeneral) {
+ tsReport((UsbASGeneral) descriptor);
+ } else if (descriptor instanceof UsbInterfaceAssoc) {
+ tsReport((UsbInterfaceAssoc) descriptor);
+ } else if (descriptor instanceof UsbMSMidiHeader) {
+ tsReport((UsbMSMidiHeader) descriptor);
+ } else if (descriptor instanceof UsbMSMidiInputJack) {
+ tsReport((UsbMSMidiInputJack) descriptor);
+ } else if (descriptor instanceof UsbMSMidiOutputJack) {
+ tsReport((UsbMSMidiOutputJack) descriptor);
+ } else if (descriptor instanceof UsbUnknown) {
+ tsReport((UsbUnknown) descriptor);
+ } else if (descriptor instanceof UsbACInterface) {
+ tsReport((UsbACInterface) descriptor);
+ } else if (descriptor instanceof UsbDescriptor) {
+ tsReport((UsbDescriptor) descriptor);
+ }
+ }
+
+ //
+ // Type-specific report() implementations
+ //
+ private void tsReport(UsbDescriptor descriptor) {
+ int length = descriptor.getLength();
+ byte type = descriptor.getType();
+ int status = descriptor.getStatus();
+
+ String descTypeStr = UsbStrings.getDescriptorName(type);
+ writeParagraph(descTypeStr + ":" + type + " l:" + length + " s:" + status);
+ }
+
+ private void tsReport(UsbDeviceDescriptor descriptor) {
+ writeHeader(1, "Device len:" + descriptor.getLength());
+ openList();
+
+ int spec = descriptor.getSpec();
+ writeListItem("spec:" + getBCDString(spec));
+
+ byte devClass = descriptor.getDevClass();
+ String classStr = UsbStrings.getClassName(devClass);
+ byte devSubClass = descriptor.getDevSubClass();
+ String subClasStr = UsbStrings.getClassName(devSubClass);
+ writeListItem("class " + devClass + ":" + classStr + " subclass"
+ + devSubClass + ":" + subClasStr);
+ writeListItem("vendorID:" + descriptor.getVendorID()
+ + " prodID:" + descriptor.getProductID()
+ + " prodRel:" + getBCDString(descriptor.getDeviceRelease()));
+
+ byte mfgIndex = descriptor.getMfgIndex();
+ String manufacturer = UsbDescriptor.getUsbDescriptorString(mConnection, mfgIndex);
+ byte productIndex = descriptor.getProductIndex();
+ String product = UsbDescriptor.getUsbDescriptorString(mConnection, productIndex);
+
+ writeListItem("mfg " + mfgIndex + ":" + manufacturer
+ + " prod " + productIndex + ":" + product);
+ closeList();
+ }
+
+ private void tsReport(UsbConfigDescriptor descriptor) {
+ writeHeader(2, "Config #" + descriptor.getConfigValue()
+ + " len:" + descriptor.getLength());
+
+ openList();
+ writeListItem(descriptor.getNumInterfaces() + " interfaces.");
+ writeListItem("attribs:" + getHexString(descriptor.getAttribs()));
+ closeList();
+ }
+
+ private void tsReport(UsbInterfaceDescriptor descriptor) {
+ byte usbClass = descriptor.getUsbClass();
+ byte usbSubclass = descriptor.getUsbSubclass();
+ String descr = UsbStrings.getDescriptorName(descriptor.getType());
+ String className = UsbStrings.getClassName(usbClass);
+ String subclassName = "";
+ if (usbClass == UsbDescriptor.CLASSID_AUDIO) {
+ subclassName = UsbStrings.getAudioSubclassName(usbSubclass);
+ }
+
+ writeHeader(2, descr + " #" + descriptor.getInterfaceNumber()
+ + " len:" + descriptor.getLength());
+ String descrStr =
+ UsbDescriptor.getUsbDescriptorString(mConnection, descriptor.getDescrIndex());
+ if (descrStr.length() > 0) {
+ mStringBuilder.append("<br>" + descrStr);
+ }
+ openList();
+ writeListItem("class " + getHexString(usbClass) + ":" + className
+ + " subclass " + getHexString(usbSubclass) + ":" + subclassName);
+ writeListItem("" + descriptor.getNumEndpoints() + " endpoints");
+ closeList();
+ }
+
+ private void tsReport(UsbEndpointDescriptor descriptor) {
+ writeHeader(3, "Endpoint " + getHexString(descriptor.getType())
+ + " len:" + descriptor.getLength());
+ openList();
+
+ byte address = descriptor.getEndpointAddress();
+ writeListItem("address:"
+ + getHexString(address & UsbEndpointDescriptor.MASK_ENDPOINT_ADDRESS)
+ + ((address & UsbEndpointDescriptor.MASK_ENDPOINT_DIRECTION)
+ == UsbEndpointDescriptor.DIRECTION_OUTPUT ? " [out]" : " [in]"));
+
+ byte attributes = descriptor.getAttributes();
+ openListItem();
+ mStringBuilder.append("attribs:" + getHexString(attributes) + " ");
+ switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_TRANSTYPE) {
+ case UsbEndpointDescriptor.TRANSTYPE_CONTROL:
+ mStringBuilder.append("Control");
+ break;
+ case UsbEndpointDescriptor.TRANSTYPE_ISO:
+ mStringBuilder.append("Iso");
+ break;
+ case UsbEndpointDescriptor.TRANSTYPE_BULK:
+ mStringBuilder.append("Bulk");
+ break;
+ case UsbEndpointDescriptor.TRANSTYPE_INTERRUPT:
+ mStringBuilder.append("Interrupt");
+ break;
+ }
+ closeListItem();
+
+ // These flags are only relevant for ISO transfer type
+ if ((attributes & UsbEndpointDescriptor.MASK_ATTRIBS_TRANSTYPE)
+ == UsbEndpointDescriptor.TRANSTYPE_ISO) {
+ openListItem();
+ mStringBuilder.append("sync:");
+ switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_SYNCTYPE) {
+ case UsbEndpointDescriptor.SYNCTYPE_NONE:
+ mStringBuilder.append("NONE");
+ break;
+ case UsbEndpointDescriptor.SYNCTYPE_ASYNC:
+ mStringBuilder.append("ASYNC");
+ break;
+ case UsbEndpointDescriptor.SYNCTYPE_ADAPTSYNC:
+ mStringBuilder.append("ADAPTIVE ASYNC");
+ break;
+ }
+ closeListItem();
+
+ openListItem();
+ mStringBuilder.append("useage:");
+ switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_USEAGE) {
+ case UsbEndpointDescriptor.USEAGE_DATA:
+ mStringBuilder.append("DATA");
+ break;
+ case UsbEndpointDescriptor.USEAGE_FEEDBACK:
+ mStringBuilder.append("FEEDBACK");
+ break;
+ case UsbEndpointDescriptor.USEAGE_EXPLICIT:
+ mStringBuilder.append("EXPLICIT FEEDBACK");
+ break;
+ case UsbEndpointDescriptor.USEAGE_RESERVED:
+ mStringBuilder.append("RESERVED");
+ break;
+ }
+ closeListItem();
+ }
+ writeListItem("package size:" + descriptor.getPacketSize());
+ writeListItem("interval:" + descriptor.getInterval());
+ closeList();
+ }
+
+ private void tsReport(UsbHIDDescriptor descriptor) {
+ String descr = UsbStrings.getDescriptorName(descriptor.getType());
+ writeHeader(2, descr + " len:" + descriptor.getLength());
+ openList();
+ writeListItem("spec:" + getBCDString(descriptor.getRelease()));
+ writeListItem("type:" + getBCDString(descriptor.getDescriptorType()));
+ writeListItem("descriptor.getNumDescriptors() descriptors len:"
+ + descriptor.getDescriptorLen());
+ closeList();
+ }
+
+ private void tsReport(UsbACAudioControlEndpoint descriptor) {
+ writeHeader(3, "AC Audio Control Endpoint:" + getHexString(descriptor.getType())
+ + " length:" + descriptor.getLength());
+ }
+
+ private void tsReport(UsbACAudioStreamEndpoint descriptor) {
+ writeHeader(3, "AC Audio Streaming Endpoint:"
+ + getHexString(descriptor.getType())
+ + " length:" + descriptor.getLength());
+ }
+
+ private void tsReport(UsbACHeader descriptor) {
+ tsReport((UsbACInterface) descriptor);
+
+ openList();
+ writeListItem("spec:" + getBCDString(descriptor.getADCRelease()));
+ int numInterfaces = descriptor.getNumInterfaces();
+ writeListItem("" + numInterfaces + " interfaces");
+ if (numInterfaces > 0) {
+ openListItem();
+ mStringBuilder.append("[");
+ byte[] interfaceNums = descriptor.getInterfaceNums();
+ if (numInterfaces != 0 && interfaceNums != null) {
+ for (int index = 0; index < numInterfaces; index++) {
+ mStringBuilder.append("" + interfaceNums[index]);
+ if (index < numInterfaces - 1) {
+ mStringBuilder.append(" ");
+ }
+ }
+ }
+ mStringBuilder.append("]");
+ closeListItem();
+ }
+ writeListItem("controls:" + getHexString(descriptor.getControls()));
+ closeList();
+ }
+
+ private void tsReport(UsbACFeatureUnit descriptor) {
+ tsReport((UsbACInterface) descriptor);
+ }
+
+ private void tsReport(UsbACInterface descriptor) {
+ String subClassName =
+ descriptor.getSubclass() == UsbDescriptor.AUDIO_AUDIOCONTROL
+ ? "AC Control"
+ : "AC Streaming";
+ byte subtype = descriptor.getSubtype();
+ String subTypeStr = UsbStrings.getACControlInterfaceName(subtype);
+ writeHeader(4, subClassName + " - " + getHexString(subtype)
+ + ":" + subTypeStr + " len:" + descriptor.getLength());
+ }
+
+ private void tsReport(UsbACTerminal descriptor) {
+ tsReport((UsbACInterface) descriptor);
+ }
+
+ private void tsReport(UsbACInputTerminal descriptor) {
+ tsReport((UsbACTerminal) descriptor);
+
+ openList();
+ writeListItem("ID:" + getHexString(descriptor.getTerminalID()));
+ int terminalType = descriptor.getTerminalType();
+ writeListItem("Type:<b>" + getHexString(terminalType) + ":"
+ + UsbStrings.getTerminalName(terminalType) + "</b>");
+ writeListItem("AssocTerminal:" + getHexString(descriptor.getAssocTerminal()));
+ writeListItem("" + descriptor.getNrChannels() + " chans. config:"
+ + getHexString(descriptor.getChannelConfig()));
+ closeList();
+ }
+
+ private void tsReport(UsbACOutputTerminal descriptor) {
+ tsReport((UsbACTerminal) descriptor);
+
+ openList();
+ writeListItem("ID:" + getHexString(descriptor.getTerminalID()));
+ int terminalType = descriptor.getTerminalType();
+ writeListItem("Type:<b>" + getHexString(terminalType) + ":"
+ + UsbStrings.getTerminalName(terminalType) + "</b>");
+ writeListItem("AssocTerminal:" + getHexString(descriptor.getAssocTerminal()));
+ writeListItem("Source:" + getHexString(descriptor.getSourceID()));
+ closeList();
+ }
+
+ private void tsReport(UsbACMidiEndpoint descriptor) {
+ writeHeader(3, "AC Midi Endpoint:" + getHexString(descriptor.getType())
+ + " length:" + descriptor.getLength());
+ openList();
+ writeListItem("" + descriptor.getNumJacks() + " jacks.");
+ closeList();
+ }
+
+ private void tsReport(UsbACMixerUnit descriptor) {
+ tsReport((UsbACInterface) descriptor);
+ openList();
+
+ writeListItem("Unit ID:" + getHexString(descriptor.getUnitID()));
+ byte numInputs = descriptor.getNumInputs();
+ byte[] inputIDs = descriptor.getInputIDs();
+ openListItem();
+ mStringBuilder.append("Num Inputs:" + numInputs + " [");
+ for (int input = 0; input < numInputs; input++) {
+ mStringBuilder.append("" + getHexString(inputIDs[input]));
+ if (input < numInputs - 1) {
+ mStringBuilder.append(" ");
+ }
+ }
+ mStringBuilder.append("]");
+ closeListItem();
+
+ writeListItem("Num Outputs:" + descriptor.getNumOutputs());
+ writeListItem("Chan Config:" + getHexString(descriptor.getChannelConfig()));
+
+ byte[] controls = descriptor.getControls();
+ openListItem();
+ mStringBuilder.append("controls:" + controls.length + " [");
+ for (int ctrl = 0; ctrl < controls.length; ctrl++) {
+ mStringBuilder.append("" + controls[ctrl]);
+ if (ctrl < controls.length - 1) {
+ mStringBuilder.append(" ");
+ }
+ }
+ mStringBuilder.append("]");
+ closeListItem();
+ closeList();
+ // byte mChanNameID; // First channel name string descriptor ID
+ // byte mNameID; // string descriptor ID of mixer name
+ }
+
+ private void tsReport(UsbACSelectorUnit descriptor) {
+ tsReport((UsbACInterface) descriptor);
+ }
+
+ private void tsReport(UsbASFormat descriptor) {
+ writeHeader(4, "AC Streaming Format "
+ + (descriptor.getFormatType() == UsbASFormat.FORMAT_TYPE_I ? "I" : "II")
+ + " - " + getHexString(descriptor.getSubtype()) + ":"
+ + " len:" + descriptor.getLength());
+ }
+
+ private void tsReport(UsbASFormatI descriptor) {
+ tsReport((UsbASFormat) descriptor);
+ openList();
+ writeListItem("chans:" + descriptor.getNumChannels());
+ writeListItem("subframe size:" + descriptor.getSubframeSize());
+ writeListItem("bit resolution:" + descriptor.getBitResolution());
+ byte sampleFreqType = descriptor.getSampleFreqType();
+ int[] sampleRates = descriptor.getSampleRates();
+ writeListItem("sample freq type:" + sampleFreqType);
+ if (sampleFreqType == 0) {
+ openList();
+ writeListItem("min:" + sampleRates[0]);
+ writeListItem("max:" + sampleRates[1]);
+ closeList();
+ } else {
+ openList();
+ for (int index = 0; index < sampleFreqType; index++) {
+ writeListItem("" + sampleRates[index]);
+ }
+ closeList();
+ }
+ closeList();
+ }
+
+ private void tsReport(UsbASFormatII descriptor) {
+ tsReport((UsbASFormat) descriptor);
+ openList();
+ writeListItem("max bit rate:" + descriptor.getMaxBitRate());
+ writeListItem("samples per frame:" + descriptor.getMaxBitRate());
+ byte sampleFreqType = descriptor.getSamFreqType();
+ int[] sampleRates = descriptor.getSampleRates();
+ writeListItem("sample freq type:" + sampleFreqType);
+ if (sampleFreqType == 0) {
+ openList();
+ writeListItem("min:" + sampleRates[0]);
+ writeListItem("max:" + sampleRates[1]);
+ closeList();
+ } else {
+ openList();
+ for (int index = 0; index < sampleFreqType; index++) {
+ writeListItem("" + sampleRates[index]);
+ }
+ closeList();
+ }
+
+ closeList();
+ }
+
+ private void tsReport(UsbASGeneral descriptor) {
+ tsReport((UsbACInterface) descriptor);
+ openList();
+ int formatTag = descriptor.getFormatTag();
+ writeListItem("fmt:" + UsbStrings.getAudioFormatName(formatTag) + " - "
+ + getHexString(formatTag));
+ closeList();
+ }
+
+ private void tsReport(UsbInterfaceAssoc descriptor) {
+ tsReport((UsbDescriptor) descriptor);
+ }
+
+ private void tsReport(UsbMSMidiHeader descriptor) {
+ writeHeader(3, "MS Midi Header:" + getHexString(descriptor.getType())
+ + " subType:" + getHexString(descriptor.getSubclass())
+ + " length:" + descriptor.getSubclass());
+ }
+
+ private void tsReport(UsbMSMidiInputJack descriptor) {
+ writeHeader(3, "MS Midi Input Jack:" + getHexString(descriptor.getType())
+ + " subType:" + getHexString(descriptor.getSubclass())
+ + " length:" + descriptor.getSubclass());
+ }
+
+ private void tsReport(UsbMSMidiOutputJack descriptor) {
+ writeHeader(3, "MS Midi Output Jack:" + getHexString(descriptor.getType())
+ + " subType:" + getHexString(descriptor.getSubclass())
+ + " length:" + descriptor.getSubclass());
+ }
+
+ private void tsReport(UsbUnknown descriptor) {
+ writeParagraph("<i><b>Unknown Descriptor " + getHexString(descriptor.getType())
+ + " len:" + descriptor.getLength() + "</b></i>");
+ dumpHexArray(descriptor.getRawData(), mStringBuilder);
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/Reporter.java b/services/usb/java/com/android/server/usb/descriptors/report/Reporter.java
new file mode 100644
index 000000000000..2944c10796f6
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/report/Reporter.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors.report;
+
+import com.android.server.usb.descriptors.UsbDescriptor;
+
+/**
+ * Declares the Reporter interface to provide HTML reporting for UsbDescriptor (sub)classes.
+ *
+ * NOTE: It is the responsibility of the implementor of this interface to correctly
+ * interpret/decode the SPECIFIC UsbDescriptor subclass (perhaps with 'instanceof') that is
+ * passed and handle that in the appropriate manner. This appears to be a
+ * not very object-oriented approach, and that is true. This approach DOES however move the
+ * complexity and 'plumbing' of reporting into the Reporter implementation and avoids needing
+ * a (trivial) type-specific call to 'report()' in each UsbDescriptor (sub)class, instead
+ * having just one in the top-level UsbDescriptor class. It also removes the need to add new
+ * type-specific 'report()' methods to be added to Reporter interface whenever a
+ * new UsbDescriptor subclass is defined. This seems like a pretty good trade-off.
+ *
+ * See HTMLReporter.java in this package for an example of type decoding.
+ */
+public interface Reporter {
+ /**
+ * Generate report for this UsbDescriptor descriptor
+ */
+ void report(UsbDescriptor descriptor);
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/Reporting.java b/services/usb/java/com/android/server/usb/descriptors/report/Reporting.java
new file mode 100644
index 000000000000..c13111b3e81c
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/report/Reporting.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.usb.descriptors.report;
+
+/**
+ * Declares the interface for classes that provide reporting functionality.
+ * (This is the double-indirection aspect of the "Visitor" pattern.
+ */
+public interface Reporting {
+ /**
+ * Declares the report method that UsbDescriptor subclasses call.
+ */
+ void report(Reporter reporter);
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java b/services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java
new file mode 100644
index 000000000000..0461150abd27
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors.report;
+
+import com.android.server.usb.descriptors.UsbACInterface;
+import com.android.server.usb.descriptors.UsbDescriptor;
+import com.android.server.usb.descriptors.UsbTerminalTypes;
+
+import java.util.HashMap;
+
+/**
+ * @hide
+ * A class to provide human-readable strings for various USB constants.
+ */
+public class UsbStrings {
+ private static final String TAG = "UsbStrings";
+
+ private static HashMap<Byte, String> sDescriptorNames;
+ private static HashMap<Byte, String> sACControlInterfaceNames;
+ private static HashMap<Byte, String> sACStreamingInterfaceNames;
+ private static HashMap<Byte, String> sClassNames;
+ private static HashMap<Byte, String> sAudioSubclassNames;
+ private static HashMap<Integer, String> sAudioEncodingNames;
+ private static HashMap<Integer, String> sTerminalNames;
+
+ private static void initDescriptorNames() {
+ sDescriptorNames = new HashMap<Byte, String>();
+ sDescriptorNames.put(UsbDescriptor.DESCRIPTORTYPE_DEVICE, "Device");
+ sDescriptorNames.put(UsbDescriptor.DESCRIPTORTYPE_CONFIG, "Config");
+ sDescriptorNames.put(UsbDescriptor.DESCRIPTORTYPE_STRING, "String");
+ sDescriptorNames.put(UsbDescriptor.DESCRIPTORTYPE_INTERFACE, "Interface");
+ sDescriptorNames.put(UsbDescriptor.DESCRIPTORTYPE_ENDPOINT, "Endpoint");
+ sDescriptorNames.put(UsbDescriptor.DESCRIPTORTYPE_BOS, "BOS (whatever that means)");
+ sDescriptorNames.put(UsbDescriptor.DESCRIPTORTYPE_INTERFACEASSOC,
+ "Interface Association");
+ sDescriptorNames.put(UsbDescriptor.DESCRIPTORTYPE_CAPABILITY, "Capability");
+ sDescriptorNames.put(UsbDescriptor.DESCRIPTORTYPE_HID, "HID");
+ sDescriptorNames.put(UsbDescriptor.DESCRIPTORTYPE_REPORT, "Report");
+ sDescriptorNames.put(UsbDescriptor.DESCRIPTORTYPE_PHYSICAL, "Physical");
+ sDescriptorNames.put(UsbDescriptor.DESCRIPTORTYPE_AUDIO_INTERFACE,
+ "Audio Class Interface");
+ sDescriptorNames.put(UsbDescriptor.DESCRIPTORTYPE_AUDIO_ENDPOINT, "Audio Class Endpoint");
+ sDescriptorNames.put(UsbDescriptor.DESCRIPTORTYPE_HUB, "Hub");
+ sDescriptorNames.put(UsbDescriptor.DESCRIPTORTYPE_SUPERSPEED_HUB, "Superspeed Hub");
+ sDescriptorNames.put(UsbDescriptor.DESCRIPTORTYPE_ENDPOINT_COMPANION,
+ "Endpoint Companion");
+ }
+
+ private static void initACControlInterfaceNames() {
+ sACControlInterfaceNames = new HashMap<Byte, String>();
+ sACControlInterfaceNames.put(UsbACInterface.ACI_UNDEFINED, "Undefined");
+ sACControlInterfaceNames.put(UsbACInterface.ACI_HEADER, "Header");
+ sACControlInterfaceNames.put(UsbACInterface.ACI_INPUT_TERMINAL, "Input Terminal");
+ sACControlInterfaceNames.put(UsbACInterface.ACI_OUTPUT_TERMINAL, "Output Terminal");
+ sACControlInterfaceNames.put(UsbACInterface.ACI_MIXER_UNIT, "Mixer Unit");
+ sACControlInterfaceNames.put(UsbACInterface.ACI_SELECTOR_UNIT, "Selector Unit");
+ sACControlInterfaceNames.put(UsbACInterface.ACI_FEATURE_UNIT, "Feature Unit");
+ sACControlInterfaceNames.put(UsbACInterface.ACI_PROCESSING_UNIT, "Processing Unit");
+ sACControlInterfaceNames.put(UsbACInterface.ACI_EXTENSION_UNIT, "Extension Unit");
+ }
+
+ private static void initACStreamingInterfaceNames() {
+ sACStreamingInterfaceNames = new HashMap<Byte, String>();
+ sACStreamingInterfaceNames.put(UsbACInterface.ASI_UNDEFINED, "Undefined");
+ sACStreamingInterfaceNames.put(UsbACInterface.ASI_GENERAL, "General");
+ sACStreamingInterfaceNames.put(UsbACInterface.ASI_FORMAT_TYPE, "Format Type");
+ sACStreamingInterfaceNames.put(UsbACInterface.ASI_FORMAT_SPECIFIC, "Format Specific");
+ }
+
+ private static void initClassNames() {
+ sClassNames = new HashMap<Byte, String>();
+ sClassNames.put(UsbDescriptor.CLASSID_DEVICE, "Device");
+ sClassNames.put(UsbDescriptor.CLASSID_AUDIO, "Audio");
+ sClassNames.put(UsbDescriptor.CLASSID_COM, "Communications");
+ sClassNames.put(UsbDescriptor.CLASSID_HID, "HID");
+ sClassNames.put(UsbDescriptor.CLASSID_PHYSICAL, "Physical");
+ sClassNames.put(UsbDescriptor.CLASSID_IMAGE, "Image");
+ sClassNames.put(UsbDescriptor.CLASSID_PRINTER, "Printer");
+ sClassNames.put(UsbDescriptor.CLASSID_STORAGE, "Storage");
+ sClassNames.put(UsbDescriptor.CLASSID_HUB, "Hub");
+ sClassNames.put(UsbDescriptor.CLASSID_CDC_CONTROL, "CDC Control");
+ sClassNames.put(UsbDescriptor.CLASSID_SMART_CARD, "Smart Card");
+ sClassNames.put(UsbDescriptor.CLASSID_SECURITY, "Security");
+ sClassNames.put(UsbDescriptor.CLASSID_VIDEO, "Video");
+ sClassNames.put(UsbDescriptor.CLASSID_HEALTHCARE, "Healthcare");
+ sClassNames.put(UsbDescriptor.CLASSID_AUDIOVIDEO, "Audio/Video");
+ sClassNames.put(UsbDescriptor.CLASSID_BILLBOARD, "Billboard");
+ sClassNames.put(UsbDescriptor.CLASSID_TYPECBRIDGE, "Type C Bridge");
+ sClassNames.put(UsbDescriptor.CLASSID_DIAGNOSTIC, "Diagnostic");
+ sClassNames.put(UsbDescriptor.CLASSID_WIRELESS, "Wireless");
+ sClassNames.put(UsbDescriptor.CLASSID_MISC, "Misc");
+ sClassNames.put(UsbDescriptor.CLASSID_APPSPECIFIC, "Application Specific");
+ sClassNames.put(UsbDescriptor.CLASSID_VENDSPECIFIC, "Vendor Specific");
+ }
+
+ private static void initAudioSubclassNames() {
+ sAudioSubclassNames = new HashMap<Byte, String>();
+ sAudioSubclassNames.put(UsbDescriptor.AUDIO_SUBCLASS_UNDEFINED, "Undefinded");
+ sAudioSubclassNames.put(UsbDescriptor.AUDIO_AUDIOCONTROL, "Audio Control");
+ sAudioSubclassNames.put(UsbDescriptor.AUDIO_AUDIOSTREAMING, "Audio Streaming");
+ sAudioSubclassNames.put(UsbDescriptor.AUDIO_MIDISTREAMING, "MIDI Streaming");
+ }
+
+ private static void initAudioEncodingNames() {
+ sAudioEncodingNames = new HashMap<Integer, String>();
+ sAudioEncodingNames.put(UsbACInterface.FORMAT_I_UNDEFINED, "Format I Undefined");
+ sAudioEncodingNames.put(UsbACInterface.FORMAT_I_PCM, "Format I PCM");
+ sAudioEncodingNames.put(UsbACInterface.FORMAT_I_PCM8, "Format I PCM8");
+ sAudioEncodingNames.put(UsbACInterface.FORMAT_I_IEEE_FLOAT, "Format I FLOAT");
+ sAudioEncodingNames.put(UsbACInterface.FORMAT_I_ALAW, "Format I ALAW");
+ sAudioEncodingNames.put(UsbACInterface.FORMAT_I_MULAW, "Format I MuLAW");
+ sAudioEncodingNames.put(UsbACInterface.FORMAT_II_UNDEFINED, "FORMAT_II Undefined");
+ sAudioEncodingNames.put(UsbACInterface.FORMAT_II_MPEG, "FORMAT_II MPEG");
+ sAudioEncodingNames.put(UsbACInterface.FORMAT_II_AC3, "FORMAT_II AC3");
+ sAudioEncodingNames.put(UsbACInterface.FORMAT_III_UNDEFINED, "FORMAT_III Undefined");
+ sAudioEncodingNames.put(UsbACInterface.FORMAT_III_IEC1937AC3, "FORMAT_III IEC1937 AC3");
+ sAudioEncodingNames.put(UsbACInterface.FORMAT_III_IEC1937_MPEG1_Layer1,
+ "FORMAT_III MPEG1 Layer 1");
+ sAudioEncodingNames.put(UsbACInterface.FORMAT_III_IEC1937_MPEG1_Layer2,
+ "FORMAT_III MPEG1 Layer 2");
+ sAudioEncodingNames.put(UsbACInterface.FORMAT_III_IEC1937_MPEG2_EXT,
+ "FORMAT_III MPEG2 EXT");
+ sAudioEncodingNames.put(UsbACInterface.FORMAT_III_IEC1937_MPEG2_Layer1LS,
+ "FORMAT_III MPEG2 Layer1LS");
+ }
+
+ private static void initTerminalNames() {
+ sTerminalNames = new HashMap<Integer, String>();
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_USB_STREAMING, "USB Streaming");
+
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_IN_UNDEFINED, "Undefined");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_IN_MIC, "Microphone");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_IN_DESKTOP_MIC, "Desktop Microphone");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_IN_PERSONAL_MIC,
+ "Personal (headset) Microphone");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_IN_OMNI_MIC, "Omni Microphone");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_IN_MIC_ARRAY, "Microphone Array");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_IN_PROC_MIC_ARRAY,
+ "Proecessing Microphone Array");
+
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_OUT_UNDEFINED, "Undefined");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_OUT_SPEAKER, "Speaker");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_OUT_HEADPHONES, "Headphones");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_OUT_HEADMOUNTED, "Head Mounted Speaker");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_OUT_DESKTOPSPEAKER, "Desktop Speaker");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_OUT_ROOMSPEAKER, "Room Speaker");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_OUT_COMSPEAKER, "Communications Speaker");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_OUT_LFSPEAKER, "Low Frequency Speaker");
+
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED, "Undefined");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_BIDIR_HANDSET, "Handset");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_BIDIR_HEADSET, "Headset");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_BIDIR_SKRPHONE, "Speaker Phone");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_BIDIR_SKRPHONE_SUPRESS,
+ "Speaker Phone (echo supressing)");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_BIDIR_SKRPHONE_CANCEL,
+ "Speaker Phone (echo canceling)");
+
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_TELE_UNDEFINED, "Undefined");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_TELE_PHONELINE, "Phone Line");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_TELE_PHONE, "Telephone");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_TELE_DOWNLINEPHONE, "Down Line Phone");
+
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EXTERN_UNDEFINED, "Undefined");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EXTERN_ANALOG, "Analog Connector");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EXTERN_DIGITAL, "Digital Connector");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EXTERN_LINE, "Line Connector");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EXTERN_LEGACY, "Legacy Audio Connector");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EXTERN_SPIDF, "S/PIDF Interface");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EXTERN_1394DA, "1394 Audio");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EXTERN_1394DV, "1394 Audio/Video");
+
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_UNDEFINED, "Undefined");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_CALNOISE, "Calibration Nose");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_EQNOISE, "EQ Noise");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_CDPLAYER, "CD Player");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_DAT, "DAT");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_DCC, "DCC");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_MINIDISK, "Mini Disk");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_ANALOGTAPE, "Analog Tap");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_PHONOGRAPH, "Phonograph");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_VCRAUDIO, "VCR Audio");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_VIDDISKAUDIO, "Video Disk Audio");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_DVDAUDIO, "DVD Audio");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_TVAUDIO, "TV Audio");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_SATELLITEAUDIO, "Satellite Audio");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_CABLEAUDIO, "Cable Tuner Audio");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_DSSAUDIO, "DSS Audio");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_RADIOTRANSMITTER, "Radio Transmitter");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_MULTITRACK, "Multitrack Recorder");
+ sTerminalNames.put(UsbTerminalTypes.TERMINAL_EMBED_SYNTHESIZER, "Synthesizer");
+ }
+
+ /**
+ * Retrieves the terminal name for the specified terminal type ID.
+ */
+ public static String getTerminalName(int terminalType) {
+ String name = sTerminalNames.get(terminalType);
+ return name != null
+ ? name
+ : "Unknown Terminal Type 0x" + Integer.toHexString(terminalType);
+ }
+ /**
+ * Initializes string tables.
+ */
+ public static void allocUsbStrings() {
+ initDescriptorNames();
+ initACControlInterfaceNames();
+ initACStreamingInterfaceNames();
+ initClassNames();
+ initAudioSubclassNames();
+ initAudioEncodingNames();
+ initTerminalNames();
+ }
+
+ /**
+ * Initializes string tables.
+ */
+ public static void releaseUsbStrings() {
+ sDescriptorNames = null;
+ sACControlInterfaceNames = null;
+ sACStreamingInterfaceNames = null;
+ sClassNames = null;
+ sAudioSubclassNames = null;
+ sAudioEncodingNames = null;
+ sTerminalNames = null;
+ }
+
+ /**
+ * Retrieves the name for the specified descriptor ID.
+ */
+ public static String getDescriptorName(byte descriptorID) {
+ String name = sDescriptorNames.get(descriptorID);
+ int iDescriptorID = descriptorID & 0xFF;
+ return name != null
+ ? name
+ : "Unknown Descriptor [0x" + Integer.toHexString(iDescriptorID)
+ + ":" + iDescriptorID + "]";
+ }
+
+ /**
+ * Retrieves the audio-class control interface name for the specified audio-class subtype.
+ */
+ public static String getACControlInterfaceName(byte subtype) {
+ String name = sACControlInterfaceNames.get(subtype);
+ int iSubType = subtype & 0xFF;
+ return name != null
+ ? name
+ : "Unknown subtype [0x" + Integer.toHexString(iSubType)
+ + ":" + iSubType + "]";
+ }
+
+ /**
+ * Retrieves the audio-class streaming interface name for the specified audio-class subtype.
+ */
+ public static String getACStreamingInterfaceName(byte subtype) {
+ String name = sACStreamingInterfaceNames.get(subtype);
+ int iSubType = subtype & 0xFF;
+ return name != null
+ ? name
+ : "Unknown Subtype [0x" + Integer.toHexString(iSubType) + ":"
+ + iSubType + "]";
+ }
+
+ /**
+ * Retrieves the name for the specified USB class ID.
+ */
+ public static String getClassName(byte classID) {
+ String name = sClassNames.get(classID);
+ int iClassID = classID & 0xFF;
+ return name != null
+ ? name
+ : "Unknown Class ID [0x" + Integer.toHexString(iClassID) + ":"
+ + iClassID + "]";
+ }
+
+ /**
+ * Retrieves the name for the specified USB audio subclass ID.
+ */
+ public static String getAudioSubclassName(byte subClassID) {
+ String name = sAudioSubclassNames.get(subClassID);
+ int iSubclassID = subClassID & 0xFF;
+ return name != null
+ ? name
+ : "Unknown Audio Subclass [0x" + Integer.toHexString(iSubclassID) + ":"
+ + iSubclassID + "]";
+ }
+
+ /**
+ * Retrieves the name for the specified USB audio format ID.
+ */
+ public static String getAudioFormatName(int formatID) {
+ String name = sAudioEncodingNames.get(formatID);
+ return name != null
+ ? name
+ : "Unknown Format (encoding) ID [0x" + Integer.toHexString(formatID) + ":"
+ + formatID + "]";
+ }
+}
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 31bb0647c9d7..691e7cf1d34f 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -127,6 +127,8 @@ public final class PhoneAccount implements Parcelable {
/**
* Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
* indicates whether a Self-Managed {@link PhoneAccount} should log its calls to the call log.
+ * Self-Managed {@link PhoneAccount}s are responsible for their own notifications, so the system
+ * will not create a notification when a missed call is logged.
* <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.
diff --git a/telephony/java/android/telephony/MbmsDownloadManager.java b/telephony/java/android/telephony/MbmsDownloadManager.java
index 14ba7e5d274a..b3f46c22ba0a 100644
--- a/telephony/java/android/telephony/MbmsDownloadManager.java
+++ b/telephony/java/android/telephony/MbmsDownloadManager.java
@@ -194,27 +194,23 @@ public class MbmsDownloadManager {
private AtomicReference<IMbmsDownloadService> mService = new AtomicReference<>(null);
private final IMbmsDownloadManagerCallback mCallback;
- private final String mDownloadAppName;
- private MbmsDownloadManager(Context context, IMbmsDownloadManagerCallback callback,
- String downloadAppName, int subId) {
+ private MbmsDownloadManager(Context context, IMbmsDownloadManagerCallback callback, int subId) {
mContext = context;
mCallback = callback;
- mDownloadAppName = downloadAppName;
mSubscriptionId = subId;
}
/**
* Create a new MbmsDownloadManager using the system default data subscription ID.
- * See {@link #create(Context, IMbmsDownloadManagerCallback, String, int)}
+ * See {@link #create(Context, IMbmsDownloadManagerCallback, int)}
*
* @hide
*/
public static MbmsDownloadManager create(Context context,
- IMbmsDownloadManagerCallback listener, String downloadAppName)
+ IMbmsDownloadManagerCallback listener)
throws MbmsException {
- return create(context, listener, downloadAppName,
- SubscriptionManager.getDefaultSubscriptionId());
+ return create(context, listener, SubscriptionManager.getDefaultSubscriptionId());
}
/**
@@ -229,15 +225,13 @@ public class MbmsDownloadManager {
*
* @param context The instance of {@link Context} to use
* @param listener A callback to get asynchronous error messages and file service updates.
- * @param downloadAppName The app name, as negotiated with the eMBMS provider
* @param subscriptionId The data subscription ID to use
* @hide
*/
public static MbmsDownloadManager create(Context context,
- IMbmsDownloadManagerCallback listener, String downloadAppName, int subscriptionId)
+ IMbmsDownloadManagerCallback listener, int subscriptionId)
throws MbmsException {
- MbmsDownloadManager mdm = new MbmsDownloadManager(context, listener, downloadAppName,
- subscriptionId);
+ MbmsDownloadManager mdm = new MbmsDownloadManager(context, listener, subscriptionId);
mdm.bindAndInitialize();
return mdm;
}
@@ -250,8 +244,7 @@ public class MbmsDownloadManager {
IMbmsDownloadService downloadService =
IMbmsDownloadService.Stub.asInterface(service);
try {
- downloadService.initialize(
- mDownloadAppName, mSubscriptionId, mCallback);
+ downloadService.initialize(mSubscriptionId, mCallback);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Service died before initialization");
return;
@@ -293,8 +286,7 @@ public class MbmsDownloadManager {
throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
}
try {
- int returnCode = downloadService.getFileServices(
- mDownloadAppName, mSubscriptionId, classList);
+ int returnCode = downloadService.getFileServices(mSubscriptionId, classList);
if (returnCode != MbmsException.SUCCESS) {
throw new MbmsException(returnCode);
}
@@ -345,8 +337,7 @@ public class MbmsDownloadManager {
}
try {
- int result = downloadService.setTempFileRootDirectory(
- mDownloadAppName, mSubscriptionId, filePath);
+ int result = downloadService.setTempFileRootDirectory(mSubscriptionId, filePath);
if (result != MbmsException.SUCCESS) {
throw new MbmsException(result);
}
@@ -396,7 +387,6 @@ public class MbmsDownloadManager {
tempRootDirectory.mkdirs();
setTempFileRootDirectory(tempRootDirectory);
}
- request.setAppName(mDownloadAppName);
checkValidDownloadDestination(request);
writeDownloadRequestToken(request);
@@ -404,6 +394,7 @@ public class MbmsDownloadManager {
downloadService.download(request, callback);
} catch (RemoteException e) {
mService.set(null);
+ throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
}
}
@@ -422,18 +413,31 @@ public class MbmsDownloadManager {
}
/**
- * Attempts to cancel the specified DownloadRequest.
+ * Attempts to cancel the specified {@link DownloadRequest}.
*
- * May throw a RemoteException.
+ * If the middleware is not aware of the specified download request, an MbmsException will be
+ * thrown with error code {@link MbmsException#ERROR_UNKNOWN_DOWNLOAD_REQUEST}.
*
- * Synchronous responses may include
- * <li>SUCCESS</li>
- * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
- * <li>ERROR_MSDC_UNKNOWN_REQUEST</li>
+ * If this method returns without throwing an exception, you may assume that cancellation
+ * was successful.
+ * @param downloadRequest The download request that you wish to cancel.
*/
- public int cancelDownload(DownloadRequest downloadRequest) {
- // TODO: don't forget to delete the token
- return 0;
+ public void cancelDownload(DownloadRequest downloadRequest) throws MbmsException {
+ IMbmsDownloadService downloadService = mService.get();
+ if (downloadService == null) {
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
+ }
+
+ try {
+ int result = downloadService.cancelDownload(downloadRequest);
+ if (result != MbmsException.SUCCESS) {
+ throw new MbmsException(result);
+ }
+ } catch (RemoteException e) {
+ mService.set(null);
+ throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ }
+ deleteDownloadRequestToken(downloadRequest);
}
/**
@@ -472,6 +476,21 @@ public class MbmsDownloadManager {
return 0;
}
+ public void dispose() {
+ try {
+ IMbmsDownloadService downloadService = mService.get();
+ if (downloadService == null) {
+ Log.i(LOG_TAG, "Service already dead");
+ return;
+ }
+ downloadService.dispose(mSubscriptionId);
+ mService.set(null);
+ } catch (RemoteException e) {
+ // Ignore
+ Log.i(LOG_TAG, "Remote exception while disposing of service");
+ }
+ }
+
/**
* Retrieves the {@link ComponentName} for the {@link android.content.BroadcastReceiver} that
* the various intents from the middleware should be targeted towards.
@@ -502,32 +521,13 @@ public class MbmsDownloadManager {
return null;
}
- public void dispose() {
- try {
- IMbmsDownloadService downloadService = mService.get();
- if (downloadService == null) {
- Log.i(LOG_TAG, "Service already dead");
- return;
- }
- downloadService.dispose(mDownloadAppName, mSubscriptionId);
- mService.set(null);
- } catch (RemoteException e) {
- // Ignore
- Log.i(LOG_TAG, "Remote exception while disposing of service");
- }
- }
-
private void writeDownloadRequestToken(DownloadRequest request) {
- File tempFileLocation = MbmsUtils.getEmbmsTempFileDirForService(mContext,
- request.getFileServiceInfo());
- if (!tempFileLocation.exists()) {
- tempFileLocation.mkdirs();
+ File token = getDownloadRequestTokenPath(request);
+ if (!token.getParentFile().exists()) {
+ token.getParentFile().mkdirs();
}
- String downloadTokenFileName = request.getHash()
- + MbmsDownloadReceiver.DOWNLOAD_TOKEN_SUFFIX;
- File token = new File(tempFileLocation, downloadTokenFileName);
if (token.exists()) {
- Log.w(LOG_TAG, "Download token " + downloadTokenFileName + " already exists");
+ Log.w(LOG_TAG, "Download token " + token.getName() + " already exists");
return;
}
try {
@@ -541,6 +541,25 @@ public class MbmsDownloadManager {
}
}
+ private void deleteDownloadRequestToken(DownloadRequest request) {
+ File token = getDownloadRequestTokenPath(request);
+ if (!token.isFile()) {
+ Log.w(LOG_TAG, "Attempting to delete non-existent download token at " + token);
+ return;
+ }
+ if (!token.delete()) {
+ Log.w(LOG_TAG, "Couldn't delete download token at " + token);
+ }
+ }
+
+ private File getDownloadRequestTokenPath(DownloadRequest request) {
+ File tempFileLocation = MbmsUtils.getEmbmsTempFileDirForService(mContext,
+ request.getFileServiceInfo());
+ String downloadTokenFileName = request.getHash()
+ + MbmsDownloadReceiver.DOWNLOAD_TOKEN_SUFFIX;
+ return new File(tempFileLocation, downloadTokenFileName);
+ }
+
/**
* Verifies the following:
* If a request is multi-part,
diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingManager.java
index af7f333390d8..fb3d5025dafa 100644
--- a/telephony/java/android/telephony/MbmsStreamingManager.java
+++ b/telephony/java/android/telephony/MbmsStreamingManager.java
@@ -43,16 +43,14 @@ public class MbmsStreamingManager {
private AtomicReference<IMbmsStreamingService> mService = new AtomicReference<>(null);
private MbmsStreamingManagerCallback mCallbackToApp;
- private final String mAppName;
private final Context mContext;
private int mSubscriptionId = INVALID_SUBSCRIPTION_ID;
/** @hide */
private MbmsStreamingManager(Context context, MbmsStreamingManagerCallback listener,
- String streamingAppName, int subscriptionId) {
+ int subscriptionId) {
mContext = context;
- mAppName = streamingAppName;
mCallbackToApp = listener;
mSubscriptionId = subscriptionId;
}
@@ -67,27 +65,24 @@ public class MbmsStreamingManager {
* @param context The {@link Context} to use.
* @param listener A callback object on which you wish to receive results of asynchronous
* operations.
- * @param streamingAppName The name of the streaming app, as specified by the carrier.
* @param subscriptionId The subscription ID to use.
*/
public static MbmsStreamingManager create(Context context,
- MbmsStreamingManagerCallback listener, String streamingAppName, int subscriptionId)
+ MbmsStreamingManagerCallback listener, int subscriptionId)
throws MbmsException {
- MbmsStreamingManager manager = new MbmsStreamingManager(context, listener,
- streamingAppName, subscriptionId);
+ MbmsStreamingManager manager = new MbmsStreamingManager(context, listener, subscriptionId);
manager.bindAndInitialize();
return manager;
}
/**
* Create a new MbmsStreamingManager using the system default data subscription ID.
- * See {@link #create(Context, MbmsStreamingManagerCallback, String, int)}.
+ * See {@link #create(Context, MbmsStreamingManagerCallback, int)}.
*/
public static MbmsStreamingManager create(Context context,
- MbmsStreamingManagerCallback listener, String streamingAppName)
+ MbmsStreamingManagerCallback listener)
throws MbmsException {
- return create(context, listener, streamingAppName,
- SubscriptionManager.getDefaultSubscriptionId());
+ return create(context, listener, SubscriptionManager.getDefaultSubscriptionId());
}
/**
@@ -101,7 +96,7 @@ public class MbmsStreamingManager {
return;
}
try {
- streamingService.dispose(mAppName, mSubscriptionId);
+ streamingService.dispose(mSubscriptionId);
} catch (RemoteException e) {
// Ignore for now
}
@@ -132,8 +127,7 @@ public class MbmsStreamingManager {
throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
}
try {
- int returnCode = streamingService.getStreamingServices(
- mAppName, mSubscriptionId, classList);
+ int returnCode = streamingService.getStreamingServices(mSubscriptionId, classList);
if (returnCode != MbmsException.SUCCESS) {
throw new MbmsException(returnCode);
}
@@ -168,7 +162,7 @@ public class MbmsStreamingManager {
try {
int returnCode = streamingService.startStreaming(
- mAppName, mSubscriptionId, serviceInfo.getServiceId(), listener);
+ mSubscriptionId, serviceInfo.getServiceId(), listener);
if (returnCode != MbmsException.SUCCESS) {
throw new MbmsException(returnCode);
}
@@ -178,8 +172,7 @@ public class MbmsStreamingManager {
throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
}
- return new StreamingService(
- mAppName, mSubscriptionId, streamingService, serviceInfo, listener);
+ return new StreamingService(mSubscriptionId, streamingService, serviceInfo, listener);
}
private void bindAndInitialize() throws MbmsException {
@@ -190,12 +183,12 @@ public class MbmsStreamingManager {
IMbmsStreamingService streamingService =
IMbmsStreamingService.Stub.asInterface(service);
try {
- streamingService.initialize(mCallbackToApp, mAppName, mSubscriptionId);
+ streamingService.initialize(mCallbackToApp, mSubscriptionId);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Service died before initialization");
return;
}
- mService.set(null);
+ mService.set(streamingService);
}
@Override
diff --git a/telephony/java/android/telephony/mbms/DownloadRequest.java b/telephony/java/android/telephony/mbms/DownloadRequest.java
index 907b0cbd8004..345729d82dea 100644
--- a/telephony/java/android/telephony/mbms/DownloadRequest.java
+++ b/telephony/java/android/telephony/mbms/DownloadRequest.java
@@ -22,11 +22,11 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.Base64;
-import java.lang.IllegalStateException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.util.Objects;
/**
* A Parcelable class describing a pending Cell-Broadcast download request
@@ -83,7 +83,7 @@ public class DownloadRequest implements Parcelable {
public DownloadRequest build() {
return new DownloadRequest(id, serviceInfo, source, dest,
- subscriptionId, appIntent, null, version);
+ subscriptionId, appIntent, version);
}
}
@@ -94,18 +94,16 @@ public class DownloadRequest implements Parcelable {
private final int subscriptionId;
private final String serializedResultIntentForApp;
private final int version;
- private String appName; // not the Android app Name, the embms app name
private DownloadRequest(int id, FileServiceInfo serviceInfo,
Uri source, Uri dest,
- int sub, String appIntent, String name, int version) {
+ int sub, String appIntent, int version) {
downloadId = id;
fileServiceInfo = serviceInfo;
sourceUri = source;
destinationUri = dest;
subscriptionId = sub;
serializedResultIntentForApp = appIntent;
- appName = name;
this.version = version;
}
@@ -120,7 +118,6 @@ public class DownloadRequest implements Parcelable {
destinationUri = dr.destinationUri;
subscriptionId = dr.subscriptionId;
serializedResultIntentForApp = dr.serializedResultIntentForApp;
- appName = dr.appName;
version = dr.version;
}
@@ -131,7 +128,6 @@ public class DownloadRequest implements Parcelable {
destinationUri = in.readParcelable(getClass().getClassLoader());
subscriptionId = in.readInt();
serializedResultIntentForApp = in.readString();
- appName = in.readString();
version = in.readInt();
}
@@ -146,7 +142,6 @@ public class DownloadRequest implements Parcelable {
out.writeParcelable(destinationUri, flags);
out.writeInt(subscriptionId);
out.writeString(serializedResultIntentForApp);
- out.writeString(appName);
out.writeInt(version);
}
@@ -178,18 +173,6 @@ public class DownloadRequest implements Parcelable {
}
}
- /** @hide */
- public synchronized void setAppName(String newAppName) {
- if (appName != null) {
- throw new IllegalStateException("Attempting to reset appName");
- }
- appName = newAppName;
- }
-
- public String getAppName() {
- return appName;
- }
-
public int getVersion() {
return version;
}
@@ -234,4 +217,29 @@ public class DownloadRequest implements Parcelable {
// Add updates for future versions here
return Base64.encodeToString(digest.digest(), Base64.URL_SAFE | Base64.NO_WRAP);
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null) {
+ return false;
+ }
+ if (!(o instanceof DownloadRequest)) {
+ return false;
+ }
+ DownloadRequest request = (DownloadRequest) o;
+ return downloadId == request.downloadId &&
+ subscriptionId == request.subscriptionId &&
+ version == request.version &&
+ Objects.equals(fileServiceInfo, request.fileServiceInfo) &&
+ Objects.equals(sourceUri, request.sourceUri) &&
+ Objects.equals(destinationUri, request.destinationUri) &&
+ Objects.equals(serializedResultIntentForApp, request.serializedResultIntentForApp);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(downloadId, fileServiceInfo, sourceUri, destinationUri,
+ subscriptionId, serializedResultIntentForApp, version);
+ }
}
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
index 1ce82d94b7e5..5bc53a82a3bb 100644
--- a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
@@ -29,16 +29,16 @@ import android.util.Log;
import java.io.File;
import java.io.FileFilter;
-import java.io.FilenameFilter;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
-import java.util.Set;
import java.util.UUID;
-import java.util.function.Predicate;
/**
* @hide
@@ -431,17 +431,16 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
}
toFile.getParentFile().mkdirs();
- // TODO: This will not work if the two files are on different filesystems. Add manual
- // copy later.
if (fromFile.renameTo(toFile)) {
return Uri.fromFile(toFile);
+ } else if (manualMove(fromFile, toFile)) {
+ return Uri.fromFile(toFile);
}
return null;
}
private static boolean verifyTempFilePath(Context context, FileServiceInfo serviceInfo,
Uri filePath) {
- // TODO: modify pursuant to final decision on temp file path scheme
if (!ContentResolver.SCHEME_FILE.equals(filePath.getScheme())) {
Log.w(LOG_TAG, "Uri " + filePath + " does not have a file scheme");
return false;
@@ -493,4 +492,40 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
}
return mMiddlewarePackageNameCache;
}
+
+ private static boolean manualMove(File src, File dst) {
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ if (!dst.exists()) {
+ dst.createNewFile();
+ }
+ in = new FileInputStream(src);
+ out = new FileOutputStream(dst);
+ byte[] buffer = new byte[2048];
+ int len;
+ do {
+ len = in.read(buffer);
+ out.write(buffer, 0, len);
+ } while (len > 0);
+ } catch (IOException e) {
+ Log.w(LOG_TAG, "Manual file move failed due to exception " + e);
+ if (dst.exists()) {
+ dst.delete();
+ }
+ return false;
+ } finally {
+ try {
+ if (in != null) {
+ in.close();
+ }
+ if (out != null) {
+ out.close();
+ }
+ } catch (IOException e) {
+ Log.w(LOG_TAG, "Error closing streams: " + e);
+ }
+ }
+ return true;
+ }
}
diff --git a/telephony/java/android/telephony/mbms/MbmsException.java b/telephony/java/android/telephony/mbms/MbmsException.java
index 8260b728a52f..e190623f5529 100644
--- a/telephony/java/android/telephony/mbms/MbmsException.java
+++ b/telephony/java/android/telephony/mbms/MbmsException.java
@@ -37,6 +37,8 @@ public class MbmsException extends Exception {
public static final int ERROR_UNABLE_TO_READ_SIM = 16;
public static final int ERROR_CARRIER_CHANGE_NOT_ALLOWED = 17;
public static final int ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT = 18;
+ public static final int ERROR_UNKNOWN_DOWNLOAD_REQUEST = 19;
+ public static final int ERROR_UNABLE_TO_INITIALIZE = 20;
private final int mErrorCode;
diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.java b/telephony/java/android/telephony/mbms/ServiceInfo.java
index b5675b2576dc..f9ad44c63118 100644
--- a/telephony/java/android/telephony/mbms/ServiceInfo.java
+++ b/telephony/java/android/telephony/mbms/ServiceInfo.java
@@ -26,6 +26,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -175,4 +176,26 @@ public class ServiceInfo implements Parcelable {
return sessionEndTime;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null) {
+ return false;
+ }
+ if (!(o instanceof ServiceInfo)) {
+ return false;
+ }
+ ServiceInfo that = (ServiceInfo) o;
+ return Objects.equals(names, that.names) &&
+ Objects.equals(className, that.className) &&
+ Objects.equals(locales, that.locales) &&
+ Objects.equals(serviceId, that.serviceId) &&
+ Objects.equals(sessionStartTime, that.sessionStartTime) &&
+ Objects.equals(sessionEndTime, that.sessionEndTime);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(names, className, locales, serviceId, sessionStartTime, sessionEndTime);
+ }
}
diff --git a/telephony/java/android/telephony/mbms/StreamingService.java b/telephony/java/android/telephony/mbms/StreamingService.java
index 608d3a921dc7..85731a14277f 100644
--- a/telephony/java/android/telephony/mbms/StreamingService.java
+++ b/telephony/java/android/telephony/mbms/StreamingService.java
@@ -42,7 +42,6 @@ public class StreamingService {
public final static int BROADCAST_METHOD = 1;
public final static int UNICAST_METHOD = 2;
- private final String mAppName;
private final int mSubscriptionId;
private final StreamingServiceInfo mServiceInfo;
private final IStreamingServiceCallback mCallback;
@@ -51,12 +50,10 @@ public class StreamingService {
/**
* @hide
*/
- public StreamingService(String appName,
- int subscriptionId,
+ public StreamingService(int subscriptionId,
IMbmsStreamingService service,
StreamingServiceInfo streamingServiceInfo,
IStreamingServiceCallback callback) {
- mAppName = appName;
mSubscriptionId = subscriptionId;
mService = service;
mServiceInfo = streamingServiceInfo;
@@ -77,7 +74,7 @@ public class StreamingService {
}
try {
- return mService.getPlaybackUri(mAppName, mSubscriptionId, mServiceInfo.getServiceId());
+ return mService.getPlaybackUri(mSubscriptionId, mServiceInfo.getServiceId());
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService = null;
@@ -103,7 +100,7 @@ public class StreamingService {
}
try {
- mService.stopStreaming(mAppName, mSubscriptionId, mServiceInfo.getServiceId());
+ mService.stopStreaming(mSubscriptionId, mServiceInfo.getServiceId());
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService = null;
@@ -117,7 +114,7 @@ public class StreamingService {
}
try {
- mService.disposeStream(mAppName, mSubscriptionId, mServiceInfo.getServiceId());
+ mService.disposeStream(mSubscriptionId, mServiceInfo.getServiceId());
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService = null;
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
index ff7d233bbf2c..7112e13d5650 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
@@ -29,31 +29,15 @@ import android.telephony.mbms.IDownloadCallback;
*/
interface IMbmsDownloadService
{
- /**
- * Initialize download service
- * Registers this listener, subId with this appName
- *
- * No return value. Async errors may be reported, but none expected (not doing anything yet).
- */
- void initialize(String appName, int subId, IMbmsDownloadManagerCallback listener);
+ void initialize(int subId, IMbmsDownloadManagerCallback listener);
- /**
- * - Registers serviceClasses of interest with the uid/appName/subId key.
- * - Starts asynch fetching data on download services of matching classes to be reported
- * later by callback.
- *
- * Note that subsequent calls with the same callback, appName, subId and uid will replace
- * the service class list.
- */
- int getFileServices(String appName, int subId, in List<String> serviceClasses);
+ int getFileServices(int subId, in List<String> serviceClasses);
+
+ int setTempFileRootDirectory(int subId, String rootDirectoryPath);
- int setTempFileRootDirectory(String appName, int subId, String rootDirectoryPath);
- /**
- * should move the params into a DownloadRequest parcelable
- */
int download(in DownloadRequest downloadRequest, IDownloadCallback listener);
- List<DownloadRequest> listPendingDownloads(String appName, int subscriptionId);
+ List<DownloadRequest> listPendingDownloads(int subscriptionId);
int cancelDownload(in DownloadRequest downloadRequest);
@@ -66,9 +50,5 @@ interface IMbmsDownloadService
*/
void resetDownloadKnowledge(in DownloadRequest downloadRequest);
- /**
- * End of life for this MbmsDownloadManager.
- * Any pending downloads remain in affect and may start up independently in the future.
- */
- void dispose(String appName, int subId);
+ void dispose(int subId);
}
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
index 8ff7fa7c54f3..1370b83857ec 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
@@ -27,28 +27,18 @@ import android.telephony.mbms.StreamingServiceInfo;
*/
interface IMbmsStreamingService
{
- int initialize(IMbmsStreamingManagerCallback listener, String appName, int subId);
+ int initialize(IMbmsStreamingManagerCallback listener, int subId);
- int getStreamingServices(String appName, int subId, in List<String> serviceClasses);
+ int getStreamingServices(int subId, in List<String> serviceClasses);
- int startStreaming(String appName, int subId, String serviceId,
+ int startStreaming(int subId, String serviceId,
IStreamingServiceCallback listener);
- /**
- * Per-stream api. Note each specifies what stream they apply to.
- */
+ Uri getPlaybackUri(int subId, String serviceId);
- Uri getPlaybackUri(String appName, int subId, String serviceId);
+ void stopStreaming(int subId, String serviceId);
- void stopStreaming(String appName, int subId, String serviceId);
+ void disposeStream(int subId, String serviceId);
- void disposeStream(String appName, int subId, String serviceId);
-
- /**
- * End of life for all MbmsStreamingManager's created by this uid/appName/subId.
- * Ends any streams run under this uid/appname/subId and calls the disposed methods
- * an callbacks registered for this uid/appName/subId and the disposed methods on any
- * listeners registered with startStreaming.
- */
- void dispose(String appName, int subId);
+ void dispose(int subId);
}
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
index 9577dd2e3d78..58bda6480999 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
@@ -21,6 +21,7 @@ import android.telephony.mbms.DownloadRequest;
import android.telephony.mbms.DownloadStatus;
import android.telephony.mbms.IDownloadCallback;
import android.telephony.mbms.IMbmsDownloadManagerCallback;
+import android.telephony.mbms.MbmsException;
import java.util.List;
@@ -31,23 +32,66 @@ import java.util.List;
* TODO: future systemapi
*/
public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
+ /**
+ * Initialize the download service for this app and subId, registering the listener.
+ *
+ * May throw an {@link IllegalArgumentException} or a {@link SecurityException}
+ *
+ * @param listener The callback to use to communicate with the app.
+ * @param subscriptionId The subscription ID to use.
+ */
@Override
- public void initialize(String appName, int subscriptionId,
+ public void initialize(int subscriptionId,
IMbmsDownloadManagerCallback listener) throws RemoteException {
}
+ /**
+ * Registers serviceClasses of interest with the appName/subId key.
+ * Starts async fetching data on streaming services of matching classes to be reported
+ * later via {@link IMbmsDownloadManagerCallback#fileServicesUpdated(List)}
+ *
+ * Note that subsequent calls with the same uid and subId will replace
+ * the service class list.
+ *
+ * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
+ *
+ * @param subscriptionId The subscription id to use.
+ * @param serviceClasses The service classes that the app wishes to get info on. The strings
+ * may contain arbitrary data as negotiated between the app and the
+ * carrier.
+ * @return One of {@link MbmsException#SUCCESS},
+ * {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY},
+ * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
+ */
@Override
- public int getFileServices(String appName, int subscriptionId, List<String> serviceClasses)
+ public int getFileServices(int subscriptionId, List<String> serviceClasses)
throws RemoteException {
return 0;
}
+ /**
+ * Sets the temp file root directory for this app/subscriptionId combination. The middleware
+ * should persist {@code rootDirectoryPath} and send it back when sending intents to the
+ * app's {@link android.telephony.mbms.MbmsDownloadReceiver}.
+ * @param subscriptionId The subscription id the download is operating under.
+ * @param rootDirectoryPath The path to the app's temp file root directory.
+ * @return {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY},
+ * {@link MbmsException#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT},
+ * or {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
+ */
@Override
- public int setTempFileRootDirectory(String appName, int subscriptionId,
+ public int setTempFileRootDirectory(int subscriptionId,
String rootDirectoryPath) throws RemoteException {
return 0;
}
+ /**
+ * Issues a request to download a set of files.
+ * @param downloadRequest An object describing the set of files to be downloaded.
+ * @param listener A listener through which the middleware can provide progress updates to
+ * the app while both are still running.
+ * @return TODO: enumerate possible return values
+ */
@Override
public int download(DownloadRequest downloadRequest, IDownloadCallback listener)
throws RemoteException {
@@ -55,11 +99,23 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
}
@Override
- public List<DownloadRequest> listPendingDownloads(String appName, int subscriptionId)
+ public List<DownloadRequest> listPendingDownloads(int subscriptionId)
throws RemoteException {
return null;
}
+ /**
+ * Issues a request to cancel the specified download request.
+ *
+ * If the middleware is unable to cancel the request for whatever reason, it should return
+ * synchronously with an error. If this method returns {@link MbmsException#SUCCESS}, the app
+ * will no longer be expecting any more file-completed intents from the middleware for this
+ * {@link DownloadRequest}.
+ * @param downloadRequest The request to cancel
+ * @return {@link MbmsException#SUCCESS},
+ * {@link MbmsException#ERROR_UNKNOWN_DOWNLOAD_REQUEST},
+ * {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY}
+ */
@Override
public int cancelDownload(DownloadRequest downloadRequest) throws RemoteException {
return 0;
@@ -76,7 +132,21 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
throws RemoteException {
}
+ /**
+ * Signals that the app wishes to dispose of the session identified by the
+ * {@code subscriptionId} argument and the caller's uid. No notification back to the
+ * app is required for this operation, and the corresponding callback provided via
+ * {@link #initialize(int, IMbmsDownloadManagerCallback)} should no longer be used
+ * after this method has been called by the app.
+ *
+ * Any download requests issued by the app should remain in effect until the app calls
+ * {@link #cancelDownload(DownloadRequest)} on another session.
+ *
+ * May throw an {@link IllegalStateException}
+ *
+ * @param subscriptionId The subscription id to use.
+ */
@Override
- public void dispose(String appName, int subscriptionId) throws RemoteException {
+ public void dispose(int subscriptionId) throws RemoteException {
}
}
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
index 2c1f085b67d3..b6cf628d4036 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
@@ -36,13 +36,12 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
* May throw an {@link IllegalArgumentException} or a {@link SecurityException}
*
* @param listener The callback to use to communicate with the app.
- * @param appName The app name as negotiated with the wireless carrier.
* @param subscriptionId The subscription ID to use.
* @return {@link MbmsException#SUCCESS} or {@link MbmsException#ERROR_ALREADY_INITIALIZED}
*/
@Override
- public int initialize(IMbmsStreamingManagerCallback listener, String appName,
- int subscriptionId) throws RemoteException {
+ public int initialize(IMbmsStreamingManagerCallback listener, int subscriptionId)
+ throws RemoteException {
return 0;
}
@@ -51,22 +50,21 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
* Starts async fetching data on streaming services of matching classes to be reported
* later via {@link IMbmsStreamingManagerCallback#streamingServicesUpdated(List)}
*
- * Note that subsequent calls with the same uid, appName and subId will replace
+ * Note that subsequent calls with the same uid and subId will replace
* the service class list.
*
* May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*
- * @param appName The app name as negotiated with the wireless carrier.
* @param subscriptionId The subscription id to use.
* @param serviceClasses The service classes that the app wishes to get info on. The strings
* may contain arbitrary data as negotiated between the app and the
* carrier.
* @return One of {@link MbmsException#SUCCESS},
- * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND},
+ * {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY},
* {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
*/
@Override
- public int getStreamingServices(String appName, int subscriptionId,
+ public int getStreamingServices(int subscriptionId,
List<String> serviceClasses) throws RemoteException {
return 0;
}
@@ -74,11 +72,10 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
/**
* Starts streaming on a particular service. This method may perform asynchronous work. When
* the middleware is ready to send bits to the frontend, it should inform the app via
- * {@link IStreamingServiceCallback#streamStateChanged(int)}.
+ * {@link IStreamingServiceCallback#streamStateUpdated(int)}.
*
* May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*
- * @param appName The app name as negotiated with the wireless carrier.
* @param subscriptionId The subscription id to use.
* @param serviceId The ID of the streaming service that the app has requested.
* @param listener The listener object on which the app wishes to receive updates.
@@ -86,8 +83,8 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
* or {@link MbmsException#ERROR_UNABLE_TO_START_SERVICE}.
*/
@Override
- public int startStreaming(String appName, int subscriptionId,
- String serviceId, IStreamingServiceCallback listener) throws RemoteException {
+ public int startStreaming(int subscriptionId, String serviceId,
+ IStreamingServiceCallback listener) throws RemoteException {
return 0;
}
@@ -97,13 +94,12 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
*
* May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*
- * @param appName The app name as negotiated with the wireless carrier.
* @param subscriptionId The subscription id to use.
* @param serviceId The ID of the streaming service that the app has requested.
* @return An opaque {@link Uri} to be passed to a video player that understands the format.
*/
@Override
- public @Nullable Uri getPlaybackUri(String appName, int subscriptionId, String serviceId)
+ public @Nullable Uri getPlaybackUri(int subscriptionId, String serviceId)
throws RemoteException {
return null;
}
@@ -111,16 +107,15 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
/**
* Stop streaming the stream identified by {@code serviceId}. Notification of the resulting
* stream state change should be reported to the app via
- * {@link IStreamingServiceCallback#streamStateChanged(int)}.
+ * {@link IStreamingServiceCallback#streamStateUpdated(int)}.
*
* May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*
- * @param appName The app name as negotiated with the wireless carrier.
* @param subscriptionId The subscription id to use.
* @param serviceId The ID of the streaming service that the app wishes to stop.
*/
@Override
- public void stopStreaming(String appName, int subscriptionId, String serviceId)
+ public void stopStreaming(int subscriptionId, String serviceId)
throws RemoteException {
}
@@ -128,33 +123,31 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
* Dispose of the stream identified by {@code serviceId} for the app identified by the
* {@code appName} and {@code subscriptionId} arguments along with the caller's uid.
* No notification back to the app is required for this operation, and the callback provided via
- * {@link #startStreaming(String, int, String, IStreamingServiceCallback)} should no longer be
+ * {@link #startStreaming(int, String, IStreamingServiceCallback)} should no longer be
* used after this method has called by the app.
*
* May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*
- * @param appName The app name as negotiated with the wireless carrier.
* @param subscriptionId The subscription id to use.
* @param serviceId The ID of the streaming service that the app wishes to dispose of.
*/
@Override
- public void disposeStream(String appName, int subscriptionId, String serviceId)
+ public void disposeStream(int subscriptionId, String serviceId)
throws RemoteException {
}
/**
- * Signals that the app wishes to dispose of the session identified by the {@code appName} and
- * {@code subscriptionId} arguments, as well as the caller's uid. No notification back to the
+ * Signals that the app wishes to dispose of the session identified by the
+ * {@code subscriptionId} argument and the caller's uid. No notification back to the
* app is required for this operation, and the corresponding callback provided via
- * {@link #initialize(IMbmsStreamingManagerCallback, String, int)} should no longer be used
+ * {@link #initialize(IMbmsStreamingManagerCallback, int)} should no longer be used
* after this method has been called by the app.
*
* May throw an {@link IllegalStateException}
*
- * @param appName The app name as negotiated with the wireless carrier.
* @param subscriptionId The subscription id to use.
*/
@Override
- public void dispose(String appName, int subscriptionId) throws RemoteException {
+ public void dispose(int subscriptionId) throws RemoteException {
}
}
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index 0752661b3a68..b41dadb2950e 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -16,6 +16,8 @@
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)
@@ -28,11 +30,109 @@ LOCAL_MODULE:= android.test.runner
include $(BUILD_JAVA_LIBRARY)
+# 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_JAVA_LIBRARIES := \
+ core-oj \
+ core-libart \
+ framework \
+ legacy-test \
+ android.test.mock \
+
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/src
+
+ANDROID_TEST_RUNNER_OUTPUT_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.runner.stubs_intermediates/api.txt
+ANDROID_TEST_RUNNER_OUTPUT_REMOVED_API_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.runner.stubs_intermediates/removed.txt
+
+ANDROID_TEST_RUNNER_API_FILE := $(LOCAL_PATH)/api/android-test-runner-current.txt
+ANDROID_TEST_RUNNER_REMOVED_API_FILE := $(LOCAL_PATH)/api/android-test-runner-removed.txt
+
+LOCAL_DROIDDOC_OPTIONS:= \
+ -stubpackages android.test:android.test.suitebuilder:junit.runner:junit.textui \
+ -stubsourceonly \
+ -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android.test.runner.stubs_intermediates/src \
+ -nodocs \
+ -api $(ANDROID_TEST_RUNNER_OUTPUT_API_FILE) \
+ -removedApi $(ANDROID_TEST_RUNNER_OUTPUT_REMOVED_API_FILE) \
+
+LOCAL_UNINSTALLABLE_MODULE := true
+LOCAL_MODULE := android-test-runner-api-stubs-gen
+
+include $(BUILD_DROIDDOC)
+
+# Remember the target that will trigger the code generation.
+android_test_runner_api_gen_stamp := $(full_target)
+
+# Add some additional dependencies
+$(ANDROID_TEST_RUNNER_OUTPUT_API_FILE): $(full_target)
+$(ANDROID_TEST_RUNNER_OUTPUT_REMOVED_API_FILE): $(full_target)
+
+# Build the android.test.runner.stubs library
+# ===========================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := android.test.runner.stubs
+
+LOCAL_JAVA_LIBRARIES := \
+ legacy.test.stubs \
+ android.test.mock.stubs \
+
+LOCAL_SOURCE_FILES_ALL_GENERATED := true
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Make sure to run droiddoc first to generate the stub source files.
+$(full_classes_compiled_jar) : $(android_test_runner_api_gen_stamp)
+$(full_classes_jack) : $(android_test_runner_api_gen_stamp)
+
+# Archive a copy of the classes.jar in SDK build.
+$(call dist-for-goals,sdk win_sdk,$(full_classes_jar):android.test.runner.stubs.jar)
+
+# Check that the android.test.runner.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-runner-api-current, \
+ $(ANDROID_TEST_RUNNER_API_FILE), \
+ $(ANDROID_TEST_RUNNER_OUTPUT_API_FILE), \
+ $(ANDROID_TEST_RUNNER_REMOVED_API_FILE), \
+ $(ANDROID_TEST_RUNNER_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_runner.txt, \
+ check-android-test-runner-api, \
+ $(call doc-timestamp-for,android-test-runner-api-stubs-gen) \
+ ))
+
+.PHONY: check-android-test-runner-api
+checkapi: check-android-test-runner-api
+
+.PHONY: update-android-test-runner-api
+update-api: update-android-test-runner-api
+
+update-android-test-runner-api: $(ANDROID_TEST_RUNNER_OUTPUT_API_FILE) | $(ACP)
+ @echo Copying current.txt
+ $(hide) $(ACP) $(ANDROID_TEST_RUNNER_OUTPUT_API_FILE) $(ANDROID_TEST_RUNNER_API_FILE)
+ @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 := $(call all-java-files-under, src/android/test/mock)
+LOCAL_SRC_FILES := $(android_test_mock_source_files)
LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
@@ -40,33 +140,45 @@ LOCAL_MODULE:= android.test.mock
include $(BUILD_JAVA_LIBRARY)
-# Generate the stub source files for android.test.mock.sdk
-# ========================================================
+# Generate the stub source files for android.test.mock.stubs
+# ==========================================================
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, src/android/test/mock)
+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.sdk_intermediates/src \
- -nodocs
+ -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-stubs-gen
+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)
-# Build the android.test.mock.sdk library
-# =======================================
+# 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.sdk
+LOCAL_MODULE := android.test.mock.stubs
LOCAL_SOURCE_FILES_ALL_GENERATED := true
@@ -77,7 +189,49 @@ $(full_classes_compiled_jar) : $(android_test_mock_gen_stamp)
$(full_classes_jack) : $(android_test_mock_gen_stamp)
# Archive a copy of the classes.jar in SDK build.
-$(call dist-for-goals,sdk win_sdk,$(full_classes_jar):android.test.mock.jar)
+$(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_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))
diff --git a/test-runner/api/android-test-mock-current.txt b/test-runner/api/android-test-mock-current.txt
new file mode 100644
index 000000000000..4063ed7dae5e
--- /dev/null
+++ b/test-runner/api/android-test-mock-current.txt
@@ -0,0 +1,413 @@
+package android.test.mock {
+
+ public deprecated class MockApplication extends android.app.Application {
+ ctor public MockApplication();
+ }
+
+ public class MockContentProvider extends android.content.ContentProvider {
+ ctor protected MockContentProvider();
+ ctor public MockContentProvider(android.content.Context);
+ ctor public MockContentProvider(android.content.Context, java.lang.String, java.lang.String, android.content.pm.PathPermission[]);
+ method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>);
+ method public int delete(android.net.Uri, java.lang.String, java.lang.String[]);
+ method public java.lang.String getType(android.net.Uri);
+ method public android.net.Uri insert(android.net.Uri, android.content.ContentValues);
+ method public boolean onCreate();
+ method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle);
+ method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+ method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+ }
+
+ public class MockContentResolver extends android.content.ContentResolver {
+ ctor public MockContentResolver();
+ ctor public MockContentResolver(android.content.Context);
+ method protected android.content.IContentProvider acquireProvider(android.content.Context, java.lang.String);
+ method protected android.content.IContentProvider acquireUnstableProvider(android.content.Context, java.lang.String);
+ method public void addProvider(java.lang.String, android.content.ContentProvider);
+ method public boolean releaseProvider(android.content.IContentProvider);
+ method public boolean releaseUnstableProvider(android.content.IContentProvider);
+ method public void unstableProviderDied(android.content.IContentProvider);
+ }
+
+ public class MockContext extends android.content.Context {
+ ctor public MockContext();
+ method public boolean bindService(android.content.Intent, android.content.ServiceConnection, int);
+ method public boolean canLoadUnsafeResources();
+ method public int checkCallingOrSelfPermission(java.lang.String);
+ method public int checkCallingOrSelfUriPermission(android.net.Uri, int);
+ method public int checkCallingPermission(java.lang.String);
+ method public int checkCallingUriPermission(android.net.Uri, int);
+ method public int checkPermission(java.lang.String, int, int);
+ method public int checkPermission(java.lang.String, int, int, android.os.IBinder);
+ method public int checkSelfPermission(java.lang.String);
+ method public int checkUriPermission(android.net.Uri, int, int, int);
+ method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
+ method public int checkUriPermission(android.net.Uri, int, int, int, android.os.IBinder);
+ method public void clearWallpaper();
+ method public android.content.Context createApplicationContext(android.content.pm.ApplicationInfo, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.content.Context createConfigurationContext(android.content.res.Configuration);
+ method public android.content.Context createContextForSplit(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.content.Context createCredentialProtectedStorageContext();
+ method public android.content.Context createDeviceProtectedStorageContext();
+ method public android.content.Context createDisplayContext(android.view.Display);
+ method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.content.Context createPackageContextAsUser(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public java.lang.String[] databaseList();
+ method public boolean deleteDatabase(java.lang.String);
+ method public boolean deleteFile(java.lang.String);
+ method public boolean deleteSharedPreferences(java.lang.String);
+ method public void enforceCallingOrSelfPermission(java.lang.String, java.lang.String);
+ method public void enforceCallingOrSelfUriPermission(android.net.Uri, int, java.lang.String);
+ method public void enforceCallingPermission(java.lang.String, java.lang.String);
+ method public void enforceCallingUriPermission(android.net.Uri, int, java.lang.String);
+ method public void enforcePermission(java.lang.String, int, int, java.lang.String);
+ method public void enforceUriPermission(android.net.Uri, int, int, int, java.lang.String);
+ method public void enforceUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int, java.lang.String);
+ method public java.lang.String[] fileList();
+ method public android.content.Context getApplicationContext();
+ method public android.content.pm.ApplicationInfo getApplicationInfo();
+ method public android.content.res.AssetManager getAssets();
+ method public java.lang.String getBasePackageName();
+ method public java.io.File getCacheDir();
+ method public java.lang.ClassLoader getClassLoader();
+ method public java.io.File getCodeCacheDir();
+ method public android.content.ContentResolver getContentResolver();
+ method public java.io.File getDataDir();
+ method public java.io.File getDatabasePath(java.lang.String);
+ method public java.io.File getDir(java.lang.String, int);
+ method public android.view.Display getDisplay();
+ method public android.view.DisplayAdjustments getDisplayAdjustments(int);
+ method public java.io.File getExternalCacheDir();
+ method public java.io.File[] getExternalCacheDirs();
+ method public java.io.File getExternalFilesDir(java.lang.String);
+ method public java.io.File[] getExternalFilesDirs(java.lang.String);
+ method public java.io.File[] getExternalMediaDirs();
+ method public java.io.File getFileStreamPath(java.lang.String);
+ method public java.io.File getFilesDir();
+ method public android.os.Looper getMainLooper();
+ method public java.io.File getNoBackupFilesDir();
+ method public java.io.File getObbDir();
+ method public java.io.File[] getObbDirs();
+ method public java.lang.String getOpPackageName();
+ method public java.lang.String getPackageCodePath();
+ method public android.content.pm.PackageManager getPackageManager();
+ method public java.lang.String getPackageName();
+ method public java.lang.String getPackageResourcePath();
+ method public java.io.File getPreloadsFileCache();
+ method public android.content.res.Resources getResources();
+ method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
+ method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
+ method public java.io.File getSharedPreferencesPath(java.lang.String);
+ method public java.lang.Object getSystemService(java.lang.String);
+ method public java.lang.String getSystemServiceName(java.lang.Class<?>);
+ method public android.content.res.Resources.Theme getTheme();
+ method public int getUserId();
+ method public android.graphics.drawable.Drawable getWallpaper();
+ method public int getWallpaperDesiredMinimumHeight();
+ method public int getWallpaperDesiredMinimumWidth();
+ method public void grantUriPermission(java.lang.String, android.net.Uri, int);
+ method public boolean isCredentialProtectedStorage();
+ method public boolean isDeviceProtectedStorage();
+ method public boolean moveDatabaseFrom(android.content.Context, java.lang.String);
+ method public boolean moveSharedPreferencesFrom(android.content.Context, java.lang.String);
+ method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
+ method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
+ method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
+ method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
+ method public android.graphics.drawable.Drawable peekWallpaper();
+ method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
+ method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int);
+ method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
+ method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, int);
+ method public android.content.Intent registerReceiverAsUser(android.content.BroadcastReceiver, android.os.UserHandle, android.content.IntentFilter, java.lang.String, android.os.Handler);
+ method public void reloadSharedPreferences();
+ method public void removeStickyBroadcast(android.content.Intent);
+ method public void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+ method public void revokeUriPermission(android.net.Uri, int);
+ method public void revokeUriPermission(java.lang.String, android.net.Uri, int);
+ method public void sendBroadcast(android.content.Intent);
+ method public void sendBroadcast(android.content.Intent, java.lang.String);
+ method public void sendBroadcast(android.content.Intent, java.lang.String, android.os.Bundle);
+ method public void sendBroadcast(android.content.Intent, java.lang.String, int);
+ method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+ method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String);
+ method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.os.Bundle);
+ method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, int);
+ method public void sendBroadcastMultiplePermissions(android.content.Intent, java.lang.String[]);
+ method public void sendOrderedBroadcast(android.content.Intent, java.lang.String);
+ method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+ method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+ method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, int, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+ method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+ method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, int, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+ method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, int, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+ method public void sendStickyBroadcast(android.content.Intent);
+ method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+ method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.os.Bundle);
+ method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+ method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+ method public void setTheme(int);
+ method public void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
+ method public void setWallpaper(java.io.InputStream) throws java.io.IOException;
+ method public void startActivities(android.content.Intent[]);
+ method public void startActivities(android.content.Intent[], android.os.Bundle);
+ method public void startActivity(android.content.Intent);
+ method public void startActivity(android.content.Intent, android.os.Bundle);
+ method public android.content.ComponentName startForegroundService(android.content.Intent);
+ method public android.content.ComponentName startForegroundServiceAsUser(android.content.Intent, android.os.UserHandle);
+ method public boolean startInstrumentation(android.content.ComponentName, java.lang.String, android.os.Bundle);
+ method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
+ method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+ method public android.content.ComponentName startService(android.content.Intent);
+ method public android.content.ComponentName startServiceAsUser(android.content.Intent, android.os.UserHandle);
+ method public boolean stopService(android.content.Intent);
+ method public boolean stopServiceAsUser(android.content.Intent, android.os.UserHandle);
+ method public void unbindService(android.content.ServiceConnection);
+ method public void unregisterReceiver(android.content.BroadcastReceiver);
+ method public void updateDisplay(int);
+ }
+
+ public deprecated class MockCursor implements android.database.Cursor {
+ ctor public MockCursor();
+ method public void close();
+ method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
+ method public deprecated void deactivate();
+ method public byte[] getBlob(int);
+ method public int getColumnCount();
+ method public int getColumnIndex(java.lang.String);
+ method public int getColumnIndexOrThrow(java.lang.String);
+ method public java.lang.String getColumnName(int);
+ method public java.lang.String[] getColumnNames();
+ method public int getCount();
+ method public double getDouble(int);
+ method public android.os.Bundle getExtras();
+ method public float getFloat(int);
+ method public int getInt(int);
+ method public long getLong(int);
+ method public android.net.Uri getNotificationUri();
+ method public int getPosition();
+ method public short getShort(int);
+ method public java.lang.String getString(int);
+ method public int getType(int);
+ method public boolean getWantsAllOnMoveCalls();
+ method public boolean isAfterLast();
+ method public boolean isBeforeFirst();
+ method public boolean isClosed();
+ method public boolean isFirst();
+ method public boolean isLast();
+ method public boolean isNull(int);
+ method public boolean move(int);
+ method public boolean moveToFirst();
+ method public boolean moveToLast();
+ method public boolean moveToNext();
+ method public boolean moveToPosition(int);
+ method public boolean moveToPrevious();
+ method public void registerContentObserver(android.database.ContentObserver);
+ method public void registerDataSetObserver(android.database.DataSetObserver);
+ method public deprecated boolean requery();
+ method public android.os.Bundle respond(android.os.Bundle);
+ method public void setExtras(android.os.Bundle);
+ method public void setNotificationUri(android.content.ContentResolver, android.net.Uri);
+ method public void unregisterContentObserver(android.database.ContentObserver);
+ method public void unregisterDataSetObserver(android.database.DataSetObserver);
+ }
+
+ public deprecated class MockDialogInterface implements android.content.DialogInterface {
+ ctor public MockDialogInterface();
+ method public void cancel();
+ method public void dismiss();
+ }
+
+ public deprecated class MockPackageManager extends android.content.pm.PackageManager {
+ ctor public MockPackageManager();
+ method public void addCrossProfileIntentFilter(android.content.IntentFilter, int, int, int);
+ method public void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
+ method public void addPackageToPreferred(java.lang.String);
+ method public boolean addPermission(android.content.pm.PermissionInfo);
+ method public boolean addPermissionAsync(android.content.pm.PermissionInfo);
+ method public void addPreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
+ method public boolean canRequestPackageInstalls();
+ method public java.lang.String[] canonicalToCurrentPackageNames(java.lang.String[]);
+ method public int checkPermission(java.lang.String, java.lang.String);
+ method public int checkSignatures(java.lang.String, java.lang.String);
+ method public int checkSignatures(int, int);
+ method public void clearApplicationUserData(java.lang.String, android.content.pm.IPackageDataObserver);
+ method public void clearCrossProfileIntentFilters(int);
+ method public void clearInstantAppCookie();
+ method public void clearPackagePreferredActivities(java.lang.String);
+ method public java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]);
+ method public void deleteApplicationCacheFiles(java.lang.String, android.content.pm.IPackageDataObserver);
+ method public void deleteApplicationCacheFilesAsUser(java.lang.String, int, android.content.pm.IPackageDataObserver);
+ method public void deletePackage(java.lang.String, android.content.pm.IPackageDeleteObserver, int);
+ method public void deletePackageAsUser(java.lang.String, android.content.pm.IPackageDeleteObserver, int, int);
+ method public void extendVerificationTimeout(int, int, long);
+ method public void flushPackageRestrictionsAsUser(int);
+ method public void freeStorage(java.lang.String, long, android.content.IntentSender);
+ method public void freeStorageAndNotify(java.lang.String, long, android.content.pm.IPackageDataObserver);
+ method public android.graphics.drawable.Drawable getActivityBanner(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.graphics.drawable.Drawable getActivityBanner(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.graphics.drawable.Drawable getActivityIcon(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.graphics.drawable.Drawable getActivityIcon(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.graphics.drawable.Drawable getActivityLogo(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.graphics.drawable.Drawable getActivityLogo(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public java.util.List<android.content.IntentFilter> getAllIntentFilters(java.lang.String);
+ method public java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int);
+ method public android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo);
+ method public android.graphics.drawable.Drawable getApplicationBanner(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public int getApplicationEnabledSetting(java.lang.String);
+ method public boolean getApplicationHiddenSettingAsUser(java.lang.String, android.os.UserHandle);
+ method public android.graphics.drawable.Drawable getApplicationIcon(android.content.pm.ApplicationInfo);
+ method public android.graphics.drawable.Drawable getApplicationIcon(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.content.pm.ApplicationInfo getApplicationInfoAsUser(java.lang.String, int, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public java.lang.CharSequence getApplicationLabel(android.content.pm.ApplicationInfo);
+ method public android.graphics.drawable.Drawable getApplicationLogo(android.content.pm.ApplicationInfo);
+ method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.content.pm.ChangedPackages getChangedPackages(int);
+ method public int getComponentEnabledSetting(android.content.ComponentName);
+ method public android.graphics.drawable.Drawable getDefaultActivityIcon();
+ method public java.lang.String getDefaultBrowserPackageNameAsUser(int);
+ method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
+ method public android.content.ComponentName getHomeActivities(java.util.List<android.content.pm.ResolveInfo>);
+ method public int getInstallReason(java.lang.String, android.os.UserHandle);
+ method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
+ method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplicationsAsUser(int, int);
+ method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
+ method public java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
+ method public java.lang.String getInstallerPackageName(java.lang.String);
+ method public java.lang.String getInstantAppAndroidId(java.lang.String, android.os.UserHandle);
+ method public byte[] getInstantAppCookie();
+ method public int getInstantAppCookieMaxBytes();
+ method public int getInstantAppCookieMaxSize();
+ method public android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String);
+ method public android.content.ComponentName getInstantAppInstallerComponent();
+ method public android.content.ComponentName getInstantAppResolverSettingsComponent();
+ method public java.util.List<android.content.pm.InstantAppInfo> getInstantApps();
+ method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
+ method public int getIntentVerificationStatusAsUser(java.lang.String, int);
+ method public android.content.pm.KeySet getKeySetByAlias(java.lang.String, java.lang.String);
+ method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
+ method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
+ method public int getMoveStatus(int);
+ method public java.lang.String getNameForUid(int);
+ method public java.util.List<android.os.storage.VolumeInfo> getPackageCandidateVolumes(android.content.pm.ApplicationInfo);
+ method public android.os.storage.VolumeInfo getPackageCurrentVolume(android.content.pm.ApplicationInfo);
+ method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.content.pm.PackageInfo getPackageInfoAsUser(java.lang.String, int, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.content.pm.PackageInstaller getPackageInstaller();
+ method public void getPackageSizeInfoAsUser(java.lang.String, int, android.content.pm.IPackageStatsObserver);
+ method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public int getPackageUidAsUser(java.lang.String, int, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public int getPackageUidAsUser(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public java.lang.String[] getPackagesForUid(int);
+ method public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
+ method public java.lang.String getPermissionControllerPackageName();
+ method public int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle);
+ method public android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.content.pm.PermissionInfo getPermissionInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public int getPreferredActivities(java.util.List<android.content.IntentFilter>, java.util.List<android.content.ComponentName>, java.lang.String);
+ method public java.util.List<android.content.pm.PackageInfo> getPreferredPackages(int);
+ method public java.util.List<android.os.storage.VolumeInfo> getPrimaryStorageCandidateVolumes();
+ method public android.os.storage.VolumeInfo getPrimaryStorageCurrentVolume();
+ method public android.content.pm.ProviderInfo getProviderInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.content.pm.ActivityInfo getReceiverInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.content.res.Resources getResourcesForActivity(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo);
+ method public android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public android.content.res.Resources getResourcesForApplicationAsUser(java.lang.String, int);
+ method public android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public java.lang.String getServicesSystemSharedLibraryPackageName();
+ method public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
+ method public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibrariesAsUser(int, int);
+ method public java.lang.String getSharedSystemSharedLibraryPackageName();
+ method public android.content.pm.KeySet getSigningKeySet(java.lang.String);
+ method public android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
+ method public java.lang.String[] getSystemSharedLibraryNames();
+ method public java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
+ method public int getUidForSharedUser(java.lang.String);
+ method public android.graphics.drawable.Drawable getUserBadgeForDensity(android.os.UserHandle, int);
+ method public android.graphics.drawable.Drawable getUserBadgeForDensityNoBackground(android.os.UserHandle, int);
+ method public android.graphics.drawable.Drawable getUserBadgedDrawableForDensity(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
+ method public android.graphics.drawable.Drawable getUserBadgedIcon(android.graphics.drawable.Drawable, android.os.UserHandle);
+ method public java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
+ method public android.content.pm.VerifierDeviceIdentity getVerifierDeviceIdentity();
+ method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
+ method public void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
+ method public boolean hasSystemFeature(java.lang.String);
+ method public boolean hasSystemFeature(java.lang.String, int);
+ method public int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public int installExistingPackage(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public int installExistingPackageAsUser(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public void installPackage(android.net.Uri, android.content.pm.IPackageInstallObserver, int, java.lang.String);
+ method public void installPackage(android.net.Uri, android.app.PackageInstallObserver, int, java.lang.String);
+ method public boolean isInstantApp();
+ method public boolean isInstantApp(java.lang.String);
+ method public boolean isPackageAvailable(java.lang.String);
+ method public boolean isPackageSuspendedForUser(java.lang.String, int);
+ method public boolean isPermissionReviewModeEnabled();
+ method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
+ method public boolean isSafeMode();
+ method public boolean isSignedBy(java.lang.String, android.content.pm.KeySet);
+ method public boolean isSignedByExactly(java.lang.String, android.content.pm.KeySet);
+ method public boolean isUpgrade();
+ method public android.graphics.drawable.Drawable loadItemIcon(android.content.pm.PackageItemInfo, android.content.pm.ApplicationInfo);
+ method public android.graphics.drawable.Drawable loadUnbadgedItemIcon(android.content.pm.PackageItemInfo, android.content.pm.ApplicationInfo);
+ method public int movePackage(java.lang.String, android.os.storage.VolumeInfo);
+ method public int movePrimaryStorage(android.os.storage.VolumeInfo);
+ method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
+ method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(android.content.Intent, int, int);
+ method public java.util.List<android.content.pm.ProviderInfo> queryContentProviders(java.lang.String, int, int);
+ method public java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(java.lang.String, int);
+ method public java.util.List<android.content.pm.ResolveInfo> queryIntentActivities(android.content.Intent, int);
+ method public java.util.List<android.content.pm.ResolveInfo> queryIntentActivitiesAsUser(android.content.Intent, int, int);
+ method public java.util.List<android.content.pm.ResolveInfo> queryIntentActivityOptions(android.content.ComponentName, android.content.Intent[], android.content.Intent, int);
+ method public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.Intent, int);
+ method public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProvidersAsUser(android.content.Intent, int, int);
+ method public java.util.List<android.content.pm.ResolveInfo> queryIntentServices(android.content.Intent, int);
+ method public java.util.List<android.content.pm.ResolveInfo> queryIntentServicesAsUser(android.content.Intent, int, int);
+ method public java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public void registerDexModule(java.lang.String, android.content.pm.PackageManager.DexModuleRegisterCallback);
+ method public void registerMoveCallback(android.content.pm.PackageManager.MoveCallback, android.os.Handler);
+ method public void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
+ method public void removePackageFromPreferred(java.lang.String);
+ method public void removePermission(java.lang.String);
+ method public void replacePreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
+ method public android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
+ method public android.content.pm.ResolveInfo resolveActivityAsUser(android.content.Intent, int, int);
+ method public android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int);
+ method public android.content.pm.ProviderInfo resolveContentProviderAsUser(java.lang.String, int, int);
+ method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
+ method public void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
+ method public void setApplicationCategoryHint(java.lang.String, int);
+ method public void setApplicationEnabledSetting(java.lang.String, int, int);
+ method public boolean setApplicationHiddenSettingAsUser(java.lang.String, boolean, android.os.UserHandle);
+ method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
+ method public boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int);
+ method public void setInstallerPackageName(java.lang.String, java.lang.String);
+ method public boolean setInstantAppCookie(byte[]);
+ method public java.lang.String[] setPackagesSuspendedAsUser(java.lang.String[], boolean, int);
+ method public void setUpdateAvailable(java.lang.String, boolean);
+ method public boolean shouldShowRequestPermissionRationale(java.lang.String);
+ method public void unregisterMoveCallback(android.content.pm.PackageManager.MoveCallback);
+ method public void updateInstantAppCookie(byte[]);
+ method public boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int);
+ method public void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
+ method public void verifyIntentFilter(int, int, java.util.List<java.lang.String>);
+ method public void verifyPendingInstall(int, int);
+ }
+
+ public deprecated class MockResources extends android.content.res.Resources {
+ ctor public MockResources();
+ method public int getColor(int) throws android.content.res.Resources.NotFoundException;
+ method public android.content.res.ColorStateList getColorStateList(int) throws android.content.res.Resources.NotFoundException;
+ method public android.graphics.drawable.Drawable getDrawable(int) throws android.content.res.Resources.NotFoundException;
+ method public void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
+ }
+
+}
+
diff --git a/test-runner/api/android-test-mock-removed.txt b/test-runner/api/android-test-mock-removed.txt
new file mode 100644
index 000000000000..9920f63d1632
--- /dev/null
+++ b/test-runner/api/android-test-mock-removed.txt
@@ -0,0 +1,9 @@
+package android.test.mock {
+
+ public deprecated class MockPackageManager extends android.content.pm.PackageManager {
+ method public deprecated java.lang.String getDefaultBrowserPackageName(int);
+ method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
+ }
+
+}
+
diff --git a/test-runner/api/android-test-runner-current.txt b/test-runner/api/android-test-runner-current.txt
new file mode 100644
index 000000000000..905cfe701ab6
--- /dev/null
+++ b/test-runner/api/android-test-runner-current.txt
@@ -0,0 +1,336 @@
+package android.test {
+
+ public abstract deprecated class ActivityInstrumentationTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
+ ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>);
+ ctor public ActivityInstrumentationTestCase(java.lang.String, java.lang.Class<T>, boolean);
+ method public T getActivity();
+ method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
+ }
+
+ public abstract deprecated class ActivityInstrumentationTestCase2<T extends android.app.Activity> extends android.test.ActivityTestCase {
+ ctor public deprecated ActivityInstrumentationTestCase2(java.lang.String, java.lang.Class<T>);
+ ctor public ActivityInstrumentationTestCase2(java.lang.Class<T>);
+ method public T getActivity();
+ method public void setActivityInitialTouchMode(boolean);
+ method public void setActivityIntent(android.content.Intent);
+ }
+
+ public abstract deprecated class ActivityTestCase extends android.test.InstrumentationTestCase {
+ ctor public ActivityTestCase();
+ method protected android.app.Activity getActivity();
+ method protected void scrubClass(java.lang.Class<?>) throws java.lang.IllegalAccessException;
+ method protected void setActivity(android.app.Activity);
+ }
+
+ public abstract deprecated class ActivityUnitTestCase<T extends android.app.Activity> extends android.test.ActivityTestCase {
+ ctor public ActivityUnitTestCase(java.lang.Class<T>);
+ method public T getActivity();
+ method public int getFinishedActivityRequest();
+ method public int getRequestedOrientation();
+ method public android.content.Intent getStartedActivityIntent();
+ method public int getStartedActivityRequest();
+ method public boolean isFinishCalled();
+ method public void setActivityContext(android.content.Context);
+ method public void setApplication(android.app.Application);
+ method protected T startActivity(android.content.Intent, android.os.Bundle, java.lang.Object);
+ }
+
+ public deprecated class AndroidTestRunner extends junit.runner.BaseTestRunner {
+ ctor public AndroidTestRunner();
+ method public void addTestListener(junit.framework.TestListener);
+ method public void clearTestListeners();
+ method protected junit.framework.TestResult createTestResult();
+ method public java.util.List<junit.framework.TestCase> getTestCases();
+ method public java.lang.String getTestClassName();
+ method public junit.framework.TestResult getTestResult();
+ method protected java.lang.Class loadSuiteClass(java.lang.String) throws java.lang.ClassNotFoundException;
+ method protected void runFailed(java.lang.String);
+ method public void runTest();
+ method public void runTest(junit.framework.TestResult);
+ method public void setContext(android.content.Context);
+ method public deprecated void setInstrumentaiton(android.app.Instrumentation);
+ method public void setInstrumentation(android.app.Instrumentation);
+ method public void setTest(junit.framework.Test);
+ method public void setTestClassName(java.lang.String, java.lang.String);
+ method public void testEnded(java.lang.String);
+ method public void testFailed(int, junit.framework.Test, java.lang.Throwable);
+ method public void testStarted(java.lang.String);
+ }
+
+ public abstract deprecated class ApplicationTestCase<T extends android.app.Application> extends android.test.AndroidTestCase {
+ ctor public ApplicationTestCase(java.lang.Class<T>);
+ method protected final void createApplication();
+ method public T getApplication();
+ method public android.content.Context getSystemContext();
+ method protected final void terminateApplication();
+ method public final void testApplicationTestCaseSetUpProperly() throws java.lang.Exception;
+ }
+
+ public deprecated class AssertionFailedError extends java.lang.Error {
+ ctor public AssertionFailedError();
+ ctor public AssertionFailedError(java.lang.String);
+ }
+
+ public deprecated class ComparisonFailure extends android.test.AssertionFailedError {
+ ctor public ComparisonFailure(java.lang.String, java.lang.String, java.lang.String);
+ }
+
+ public deprecated class InstrumentationTestRunner extends android.app.Instrumentation implements android.test.TestSuiteProvider {
+ ctor public InstrumentationTestRunner();
+ method public junit.framework.TestSuite getAllTests();
+ method protected android.test.AndroidTestRunner getAndroidTestRunner();
+ method public android.os.Bundle getArguments();
+ method public java.lang.ClassLoader getLoader();
+ method public junit.framework.TestSuite getTestSuite();
+ field public static final java.lang.String REPORT_KEY_NAME_CLASS = "class";
+ field public static final java.lang.String REPORT_KEY_NAME_TEST = "test";
+ field public static final java.lang.String REPORT_KEY_NUM_CURRENT = "current";
+ field public static final java.lang.String REPORT_KEY_NUM_TOTAL = "numtests";
+ field public static final java.lang.String REPORT_KEY_STACK = "stack";
+ field public static final java.lang.String REPORT_VALUE_ID = "InstrumentationTestRunner";
+ field public static final int REPORT_VALUE_RESULT_ERROR = -1; // 0xffffffff
+ field public static final int REPORT_VALUE_RESULT_FAILURE = -2; // 0xfffffffe
+ field public static final int REPORT_VALUE_RESULT_OK = 0; // 0x0
+ field public static final int REPORT_VALUE_RESULT_START = 1; // 0x1
+ }
+
+ public deprecated class IsolatedContext extends android.content.ContextWrapper {
+ ctor public IsolatedContext(android.content.ContentResolver, android.content.Context);
+ method public java.util.List<android.content.Intent> getAndClearBroadcastIntents();
+ }
+
+ public class LoaderTestCase extends android.test.AndroidTestCase {
+ ctor public LoaderTestCase();
+ method public <T> T getLoaderResultSynchronously(android.content.Loader<T>);
+ }
+
+ public final deprecated class MoreAsserts {
+ method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Object);
+ method public static void assertAssignableFrom(java.lang.Class<?>, java.lang.Class<?>);
+ method public static java.util.regex.MatchResult assertContainsRegex(java.lang.String, java.lang.String, java.lang.String);
+ method public static java.util.regex.MatchResult assertContainsRegex(java.lang.String, java.lang.String);
+ method public static void assertContentsInAnyOrder(java.lang.String, java.lang.Iterable<?>, java.lang.Object...);
+ method public static void assertContentsInAnyOrder(java.lang.Iterable<?>, java.lang.Object...);
+ method public static void assertContentsInOrder(java.lang.String, java.lang.Iterable<?>, java.lang.Object...);
+ method public static void assertContentsInOrder(java.lang.Iterable<?>, java.lang.Object...);
+ method public static void assertEmpty(java.lang.String, java.lang.Iterable<?>);
+ method public static void assertEmpty(java.lang.Iterable<?>);
+ method public static void assertEmpty(java.lang.String, java.util.Map<?, ?>);
+ method public static void assertEmpty(java.util.Map<?, ?>);
+ method public static void assertEquals(java.lang.String, byte[], byte[]);
+ method public static void assertEquals(byte[], byte[]);
+ method public static void assertEquals(java.lang.String, int[], int[]);
+ method public static void assertEquals(int[], int[]);
+ method public static void assertEquals(java.lang.String, double[], double[]);
+ method public static void assertEquals(double[], double[]);
+ method public static void assertEquals(java.lang.String, java.lang.Object[], java.lang.Object[]);
+ method public static void assertEquals(java.lang.Object[], java.lang.Object[]);
+ method public static void assertEquals(java.lang.String, java.util.Set<? extends java.lang.Object>, java.util.Set<? extends java.lang.Object>);
+ method public static void assertEquals(java.util.Set<? extends java.lang.Object>, java.util.Set<? extends java.lang.Object>);
+ method public static java.util.regex.MatchResult assertMatchesRegex(java.lang.String, java.lang.String, java.lang.String);
+ method public static java.util.regex.MatchResult assertMatchesRegex(java.lang.String, java.lang.String);
+ method public static void assertNotContainsRegex(java.lang.String, java.lang.String, java.lang.String);
+ method public static void assertNotContainsRegex(java.lang.String, java.lang.String);
+ method public static void assertNotEmpty(java.lang.String, java.lang.Iterable<?>);
+ method public static void assertNotEmpty(java.lang.Iterable<?>);
+ method public static void assertNotEmpty(java.lang.String, java.util.Map<?, ?>);
+ method public static void assertNotEmpty(java.util.Map<?, ?>);
+ method public static void assertNotEqual(java.lang.String, java.lang.Object, java.lang.Object);
+ method public static void assertNotEqual(java.lang.Object, java.lang.Object);
+ method public static void assertNotMatchesRegex(java.lang.String, java.lang.String, java.lang.String);
+ method public static void assertNotMatchesRegex(java.lang.String, java.lang.String);
+ method public static void checkEqualsAndHashCodeMethods(java.lang.String, java.lang.Object, java.lang.Object, boolean);
+ method public static void checkEqualsAndHashCodeMethods(java.lang.Object, java.lang.Object, boolean);
+ }
+
+ public abstract deprecated class ProviderTestCase<T extends android.content.ContentProvider> extends android.test.InstrumentationTestCase {
+ ctor public ProviderTestCase(java.lang.Class<T>, java.lang.String);
+ method public android.test.mock.MockContentResolver getMockContentResolver();
+ method public android.test.IsolatedContext getMockContext();
+ method public T getProvider();
+ method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+ }
+
+ public abstract class ProviderTestCase2<T extends android.content.ContentProvider> extends android.test.AndroidTestCase {
+ ctor public ProviderTestCase2(java.lang.Class<T>, java.lang.String);
+ method public android.test.mock.MockContentResolver getMockContentResolver();
+ method public android.test.IsolatedContext getMockContext();
+ method public T getProvider();
+ method public static <T extends android.content.ContentProvider> android.content.ContentResolver newResolverWithContentProviderFromSql(android.content.Context, java.lang.String, java.lang.Class<T>, java.lang.String, java.lang.String, int, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+ }
+
+ public deprecated class RenamingDelegatingContext extends android.content.ContextWrapper {
+ ctor public RenamingDelegatingContext(android.content.Context, java.lang.String);
+ ctor public RenamingDelegatingContext(android.content.Context, android.content.Context, java.lang.String);
+ method public java.lang.String getDatabasePrefix();
+ method public void makeExistingFilesAndDbsAccessible();
+ method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+ method public static <T extends android.content.ContentProvider> T providerWithRenamedContext(java.lang.Class<T>, android.content.Context, java.lang.String, boolean) throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+ }
+
+ public abstract deprecated class ServiceTestCase<T extends android.app.Service> extends android.test.AndroidTestCase {
+ ctor public ServiceTestCase(java.lang.Class<T>);
+ method protected android.os.IBinder bindService(android.content.Intent);
+ method public android.app.Application getApplication();
+ method public T getService();
+ method public android.content.Context getSystemContext();
+ method public void setApplication(android.app.Application);
+ method protected void setupService();
+ method protected void shutdownService();
+ method protected void startService(android.content.Intent);
+ method public void testServiceTestCaseSetUpProperly() throws java.lang.Exception;
+ }
+
+ public abstract deprecated class SingleLaunchActivityTestCase<T extends android.app.Activity> extends android.test.InstrumentationTestCase {
+ ctor public SingleLaunchActivityTestCase(java.lang.String, java.lang.Class<T>);
+ method public T getActivity();
+ method public void testActivityTestCaseSetUpProperly() throws java.lang.Exception;
+ }
+
+ public deprecated class SyncBaseInstrumentation extends android.test.InstrumentationTestCase {
+ ctor public SyncBaseInstrumentation();
+ method protected void cancelSyncsandDisableAutoSync();
+ method protected void syncProvider(android.net.Uri, java.lang.String, java.lang.String) throws java.lang.Exception;
+ }
+
+ public abstract deprecated interface TestSuiteProvider {
+ method public abstract junit.framework.TestSuite getTestSuite();
+ }
+
+ public deprecated class TouchUtils {
+ ctor public TouchUtils();
+ method public static void clickView(android.test.InstrumentationTestCase, android.view.View);
+ method public static deprecated void drag(android.test.ActivityInstrumentationTestCase, float, float, float, float, int);
+ method public static void drag(android.test.InstrumentationTestCase, float, float, float, float, int);
+ method public static deprecated void dragQuarterScreenDown(android.test.ActivityInstrumentationTestCase);
+ method public static void dragQuarterScreenDown(android.test.InstrumentationTestCase, android.app.Activity);
+ method public static deprecated void dragQuarterScreenUp(android.test.ActivityInstrumentationTestCase);
+ method public static void dragQuarterScreenUp(android.test.InstrumentationTestCase, android.app.Activity);
+ method public static deprecated int dragViewBy(android.test.ActivityInstrumentationTestCase, android.view.View, int, int, int);
+ method public static deprecated int dragViewBy(android.test.InstrumentationTestCase, android.view.View, int, int, int);
+ method public static deprecated int dragViewTo(android.test.ActivityInstrumentationTestCase, android.view.View, int, int, int);
+ method public static int dragViewTo(android.test.InstrumentationTestCase, android.view.View, int, int, int);
+ method public static deprecated void dragViewToBottom(android.test.ActivityInstrumentationTestCase, android.view.View);
+ method public static void dragViewToBottom(android.test.InstrumentationTestCase, android.app.Activity, android.view.View);
+ method public static deprecated void dragViewToBottom(android.test.ActivityInstrumentationTestCase, android.view.View, int);
+ method public static void dragViewToBottom(android.test.InstrumentationTestCase, android.app.Activity, android.view.View, int);
+ method public static deprecated void dragViewToTop(android.test.ActivityInstrumentationTestCase, android.view.View);
+ method public static deprecated void dragViewToTop(android.test.ActivityInstrumentationTestCase, android.view.View, int);
+ method public static void dragViewToTop(android.test.InstrumentationTestCase, android.view.View);
+ method public static void dragViewToTop(android.test.InstrumentationTestCase, android.view.View, int);
+ method public static deprecated int dragViewToX(android.test.ActivityInstrumentationTestCase, android.view.View, int, int);
+ method public static int dragViewToX(android.test.InstrumentationTestCase, android.view.View, int, int);
+ method public static deprecated int dragViewToY(android.test.ActivityInstrumentationTestCase, android.view.View, int, int);
+ method public static int dragViewToY(android.test.InstrumentationTestCase, android.view.View, int, int);
+ method public static deprecated void longClickView(android.test.ActivityInstrumentationTestCase, android.view.View);
+ method public static void longClickView(android.test.InstrumentationTestCase, android.view.View);
+ method public static deprecated void scrollToBottom(android.test.ActivityInstrumentationTestCase, android.view.ViewGroup);
+ method public static void scrollToBottom(android.test.InstrumentationTestCase, android.app.Activity, android.view.ViewGroup);
+ method public static deprecated void scrollToTop(android.test.ActivityInstrumentationTestCase, android.view.ViewGroup);
+ method public static void scrollToTop(android.test.InstrumentationTestCase, android.app.Activity, android.view.ViewGroup);
+ method public static void tapView(android.test.InstrumentationTestCase, android.view.View);
+ method public static void touchAndCancelView(android.test.InstrumentationTestCase, android.view.View);
+ }
+
+ public deprecated class ViewAsserts {
+ method public static void assertBaselineAligned(android.view.View, android.view.View);
+ method public static void assertBottomAligned(android.view.View, android.view.View);
+ method public static void assertBottomAligned(android.view.View, android.view.View, int);
+ method public static void assertGroupContains(android.view.ViewGroup, android.view.View);
+ method public static void assertGroupIntegrity(android.view.ViewGroup);
+ method public static void assertGroupNotContains(android.view.ViewGroup, android.view.View);
+ method public static void assertHasScreenCoordinates(android.view.View, android.view.View, int, int);
+ method public static void assertHorizontalCenterAligned(android.view.View, android.view.View);
+ method public static void assertLeftAligned(android.view.View, android.view.View);
+ method public static void assertLeftAligned(android.view.View, android.view.View, int);
+ method public static void assertOffScreenAbove(android.view.View, android.view.View);
+ method public static void assertOffScreenBelow(android.view.View, android.view.View);
+ method public static void assertOnScreen(android.view.View, android.view.View);
+ method public static void assertRightAligned(android.view.View, android.view.View);
+ method public static void assertRightAligned(android.view.View, android.view.View, int);
+ method public static void assertTopAligned(android.view.View, android.view.View);
+ method public static void assertTopAligned(android.view.View, android.view.View, int);
+ method public static void assertVerticalCenterAligned(android.view.View, android.view.View);
+ }
+
+}
+
+package android.test.suitebuilder {
+
+ public deprecated class TestMethod {
+ ctor public TestMethod(java.lang.reflect.Method, java.lang.Class<? extends junit.framework.TestCase>);
+ ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
+ ctor public TestMethod(junit.framework.TestCase);
+ method public junit.framework.TestCase createTest() throws java.lang.IllegalAccessException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
+ method public <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
+ method public java.lang.Class<? extends junit.framework.TestCase> getEnclosingClass();
+ method public java.lang.String getEnclosingClassname();
+ method public java.lang.String getName();
+ }
+
+ public deprecated class TestSuiteBuilder {
+ ctor public TestSuiteBuilder(java.lang.Class);
+ ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
+ method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
+ method public final android.test.suitebuilder.TestSuiteBuilder addRequirements(com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>...);
+ method public final junit.framework.TestSuite build();
+ method public android.test.suitebuilder.TestSuiteBuilder excludePackages(java.lang.String...);
+ method protected java.lang.String getSuiteName();
+ method public final android.test.suitebuilder.TestSuiteBuilder includeAllPackagesUnderHere();
+ method public android.test.suitebuilder.TestSuiteBuilder includePackages(java.lang.String...);
+ method public android.test.suitebuilder.TestSuiteBuilder named(java.lang.String);
+ }
+
+ public static deprecated class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
+ ctor public TestSuiteBuilder.FailedToCreateTests(java.lang.Exception);
+ method public void testSuiteConstructionFailed();
+ }
+
+}
+
+package junit.runner {
+
+ public abstract class BaseTestRunner implements junit.framework.TestListener {
+ ctor public BaseTestRunner();
+ method public synchronized void addError(junit.framework.Test, java.lang.Throwable);
+ method public synchronized void addFailure(junit.framework.Test, junit.framework.AssertionFailedError);
+ method protected void clearStatus();
+ method public java.lang.String elapsedTimeAsString(long);
+ method public synchronized void endTest(junit.framework.Test);
+ method public java.lang.String extractClassName(java.lang.String);
+ method public static java.lang.String getFilteredTrace(java.lang.Throwable);
+ method public static java.lang.String getFilteredTrace(java.lang.String);
+ method public deprecated junit.runner.TestSuiteLoader getLoader();
+ method public static java.lang.String getPreference(java.lang.String);
+ method public static int getPreference(java.lang.String, int);
+ method protected static java.util.Properties getPreferences();
+ method public junit.framework.Test getTest(java.lang.String);
+ method public static deprecated boolean inVAJava();
+ method protected java.lang.Class<?> loadSuiteClass(java.lang.String) throws java.lang.ClassNotFoundException;
+ method protected java.lang.String processArguments(java.lang.String[]);
+ method protected abstract void runFailed(java.lang.String);
+ method public static void savePreferences() throws java.io.IOException;
+ method public void setLoading(boolean);
+ method public void setPreference(java.lang.String, java.lang.String);
+ method protected static void setPreferences(java.util.Properties);
+ method protected static boolean showStackRaw();
+ method public synchronized void startTest(junit.framework.Test);
+ method public abstract void testEnded(java.lang.String);
+ method public abstract void testFailed(int, junit.framework.Test, java.lang.Throwable);
+ method public abstract void testStarted(java.lang.String);
+ method public static java.lang.String truncate(java.lang.String);
+ method protected boolean useReloadingTestSuiteLoader();
+ field public static final java.lang.String SUITE_METHODNAME = "suite";
+ }
+
+ public abstract interface TestSuiteLoader {
+ method public abstract java.lang.Class load(java.lang.String) throws java.lang.ClassNotFoundException;
+ method public abstract java.lang.Class reload(java.lang.Class) throws java.lang.ClassNotFoundException;
+ }
+
+ public class Version {
+ method public static java.lang.String id();
+ }
+
+}
+
diff --git a/test-runner/api/android-test-runner-removed.txt b/test-runner/api/android-test-runner-removed.txt
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test-runner/api/android-test-runner-removed.txt
diff --git a/test-runner/api/apicheck_msg_android_test_mock.txt b/test-runner/api/apicheck_msg_android_test_mock.txt
new file mode 100644
index 000000000000..e388935bf798
--- /dev/null
+++ b/test-runner/api/apicheck_msg_android_test_mock.txt
@@ -0,0 +1,17 @@
+
+******************************
+You have tried to change the API from what has been previously approved.
+
+To make these errors go away, you have two choices:
+ 1) You can add "@hide" javadoc comments to the methods, etc. listed in the
+ errors above.
+
+ 2) You can update android-test-mock-current.txt by executing the following command:
+ make update-android-test-mock-api
+
+ To submit the revised android-test-mock-current.txt to the main Android repository,
+ you will need approval.
+******************************
+
+
+
diff --git a/test-runner/api/apicheck_msg_android_test_runner.txt b/test-runner/api/apicheck_msg_android_test_runner.txt
new file mode 100644
index 000000000000..cf2d15ee1ee1
--- /dev/null
+++ b/test-runner/api/apicheck_msg_android_test_runner.txt
@@ -0,0 +1,17 @@
+
+******************************
+You have tried to change the API from what has been previously approved.
+
+To make these errors go away, you have two choices:
+ 1) You can add "@hide" javadoc comments to the methods, etc. listed in the
+ errors above.
+
+ 2) You can update android-test-runner-current.txt by executing the following command:
+ make update-android-test-runner-api
+
+ To submit the revised android-test-runner-current.txt to the main Android repository,
+ you will need approval.
+******************************
+
+
+
diff --git a/tests/ShowWhenLockedApp/Android.mk b/tests/ShowWhenLockedApp/Android.mk
new file mode 100644
index 000000000000..006416791dd9
--- /dev/null
+++ b/tests/ShowWhenLockedApp/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := ShowWhenLocked
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE) \ No newline at end of file
diff --git a/tests/ShowWhenLockedApp/AndroidManifest.xml b/tests/ShowWhenLockedApp/AndroidManifest.xml
new file mode 100644
index 000000000000..a872e061526f
--- /dev/null
+++ b/tests/ShowWhenLockedApp/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.showwhenlocked">
+ <application android:label="ShowWhenLocked">
+ <activity android:name=".ShowWhenLockedActivity"
+ android:showWhenLocked="true"
+ android:turnScreenOn="true"
+ android:launchMode="singleTask">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/ShowWhenLockedApp/src/com/android/showwhenlocked/ShowWhenLockedActivity.java b/tests/ShowWhenLockedApp/src/com/android/showwhenlocked/ShowWhenLockedActivity.java
new file mode 100644
index 000000000000..f71483182676
--- /dev/null
+++ b/tests/ShowWhenLockedApp/src/com/android/showwhenlocked/ShowWhenLockedActivity.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.showwhenlocked;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * Sample app to test the manifest attrs {@link android.R.attr#showWhenLocked}
+ * and {@link android.R.attr#turnScreenOn}.
+ *
+ * <p>Run with adb shell am start -n com.android.showwhenlocked/.ShowWhenLockedActivity to test
+ * when the phone has a keyguard enabled and/or the screen is off.
+ *
+ * Use the extra {@link #EXTRA_SHOW_WHEN_LOCKED} and {@link #EXTRA_TURN_SCREEN_ON} to test
+ * multiple scenarios.
+ *
+ * Ex: adb shell am start -n com.android.showwhenlocked/.ShowWhenLockedActivity --ez \
+ * showWhenLocked false \
+ * setTurnScreenOnAtStop false
+ *
+ * Note: Behavior may change if values are set to true after the Activity is already created
+ * and only brought to the front. For example, turnScreenOn only takes effect on the next launch
+ * if set using the extra value.
+ */
+public class ShowWhenLockedActivity extends Activity {
+ private static final String TAG = ShowWhenLockedActivity.class.getSimpleName();
+
+ /**
+ * The value set for this extra sets {@link #setShowWhenLocked(boolean)} as soon as the app
+ * is launched. This may cause delays in when the value set takes affect.
+ */
+ private static final String EXTRA_SHOW_WHEN_LOCKED = "showWhenLocked";
+
+ /**
+ * The value set for this extra sets {@link #setTurnScreenOn(boolean)} as soon as the app
+ * is launched. This may cause delays in when the value set takes affect.
+ */
+ private static final String EXTRA_TURN_SCREEN_ON = "turnScreenOn";
+
+ /**
+ * The value set for this extra will call {@link #setShowWhenLocked(boolean)} at onStop so
+ * it take effect on the next launch.
+ */
+ private static final String EXTRA_SHOW_WHEN_LOCKED_STOP = "setShowWhenLockedAtStop";
+
+ /**
+ * The value set for this extra will call {@link #setTurnScreenOn(boolean)} at onStop so
+ * it take effect on the next launch.
+ */
+ private static final String EXTRA_TURN_SCREEN_ON_STOP = "setTurnScreenOnAtStop";
+
+ /**
+ * The value set for this extra will call
+ * {@link KeyguardManager#requestDismissKeyguard(Activity, KeyguardManager.KeyguardDismissCallback)}
+ * as soon as the app is launched.
+ */
+ private static final String EXTRA_DISMISS_KEYGUARD = "dismissKeyguard";
+
+ private boolean showWhenLockedAtStop = true;
+ private boolean turnScreenOnAtStop = true;
+
+ private KeyguardManager mKeyguardManager;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Log.v(TAG, "onCreate");
+ mKeyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
+ handleExtras(getIntent().getExtras());
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ Log.v(TAG, "onStart");
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ handleExtras(intent.getExtras());
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ Log.v(TAG, "onResume");
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ Log.v(TAG, "onPause");
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ Log.v(TAG, "onStop");
+
+ setShowWhenLocked(showWhenLockedAtStop);
+ setTurnScreenOn(turnScreenOnAtStop);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ Log.v(TAG, "onDestroy");
+ }
+
+ private void handleExtras(Bundle extras) {
+ if (extras == null) {
+ return;
+ }
+
+ if (extras.containsKey(EXTRA_SHOW_WHEN_LOCKED)) {
+ boolean showWhenLocked = extras.getBoolean(EXTRA_SHOW_WHEN_LOCKED, true);
+ Log.v(TAG, "Setting showWhenLocked to " + showWhenLocked);
+ setShowWhenLocked(showWhenLocked);
+ }
+
+ if (extras.containsKey(EXTRA_TURN_SCREEN_ON)) {
+ boolean turnScreenOn = extras.getBoolean(EXTRA_TURN_SCREEN_ON, true);
+ Log.v(TAG, "Setting turnScreenOn to " + turnScreenOn);
+ setTurnScreenOn(turnScreenOn);
+ }
+
+ if (extras.containsKey(EXTRA_SHOW_WHEN_LOCKED_STOP)) {
+ showWhenLockedAtStop = extras.getBoolean(EXTRA_SHOW_WHEN_LOCKED_STOP, true);
+ Log.v(TAG, "Setting showWhenLockedAtStop to " + showWhenLockedAtStop);
+ }
+
+ if (extras.containsKey(EXTRA_TURN_SCREEN_ON_STOP)) {
+ turnScreenOnAtStop = extras.getBoolean(EXTRA_TURN_SCREEN_ON_STOP, true);
+ Log.v(TAG, "Setting turnScreenOnAtStop to " + turnScreenOnAtStop);
+ }
+
+ if (extras.containsKey(EXTRA_DISMISS_KEYGUARD)) {
+ if (extras.getBoolean(EXTRA_DISMISS_KEYGUARD, false)) {
+ Log.v(TAG, "Requesting dismiss keyguard");
+ mKeyguardManager.requestDismissKeyguard(this, null);
+ }
+ }
+ }
+}
+
diff --git a/tests/net/java/android/net/nsd/NsdManagerTest.java b/tests/net/java/android/net/nsd/NsdManagerTest.java
index adf699808666..f77608f95b3e 100644
--- a/tests/net/java/android/net/nsd/NsdManagerTest.java
+++ b/tests/net/java/android/net/nsd/NsdManagerTest.java
@@ -349,7 +349,6 @@ public class NsdManagerTest {
chan.connect(mContext, this, msg.replyTo);
chan.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
}
-
}
public static MockServiceHandler create(Context context) {
diff --git a/tests/net/java/android/net/util/SharedLogTest.java b/tests/net/java/android/net/util/SharedLogTest.java
index 3957cb075673..d46facfaba06 100644
--- a/tests/net/java/android/net/util/SharedLogTest.java
+++ b/tests/net/java/android/net/util/SharedLogTest.java
@@ -33,8 +33,8 @@ import java.util.Vector;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class SharedLogTest {
- private static final String TIMESTAMP_PATTERN = "\\d{2}:\\d{2}:\\d{2}\\.\\d{3}";
- private static final String TIMESTAMP = "HH:MM:SS.xxx";
+ private static final String TIMESTAMP_PATTERN = "\\d{2}:\\d{2}:\\d{2}";
+ private static final String TIMESTAMP = "HH:MM:SS";
@Test
public void testBasicOperation() {
@@ -85,7 +85,7 @@ public class SharedLogTest {
String got = lines[i];
String want = expected[i];
assertTrue(String.format("'%s' did not contain '%s'", got, want), got.endsWith(want));
- assertTrue(String.format("'%s' did not contain a HH:MM:SS.xxx timestamp", got),
+ assertTrue(String.format("'%s' did not contain a %s timestamp", got, TIMESTAMP),
got.replaceFirst(TIMESTAMP_PATTERN, TIMESTAMP).contains(TIMESTAMP));
}
}
diff --git a/tests/net/java/com/android/internal/util/TestUtils.java b/tests/net/java/com/android/internal/util/TestUtils.java
new file mode 100644
index 000000000000..c9fa340dc8b5
--- /dev/null
+++ b/tests/net/java/com/android/internal/util/TestUtils.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.internal.util;
+
+import static org.junit.Assert.fail;
+
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+
+public final class TestUtils {
+ private TestUtils() { }
+
+ /**
+ * Block until the given Handler thread becomes idle, or until timeoutMs has passed.
+ */
+ public static void waitForIdleHandler(HandlerThread handlerThread, long timeoutMs) {
+ // TODO: convert to getThreadHandler once it is available on aosp
+ waitForIdleLooper(handlerThread.getLooper(), timeoutMs);
+ }
+
+ /**
+ * Block until the given Looper becomes idle, or until timeoutMs has passed.
+ */
+ public static void waitForIdleLooper(Looper looper, long timeoutMs) {
+ waitForIdleHandler(new Handler(looper), timeoutMs);
+ }
+
+ /**
+ * Block until the given Handler becomes idle, or until timeoutMs has passed.
+ */
+ public static void waitForIdleHandler(Handler handler, long timeoutMs) {
+ final ConditionVariable cv = new ConditionVariable();
+ handler.post(() -> cv.open());
+ if (!cv.block(timeoutMs)) {
+ fail(handler.toString() + " did not become idle after " + timeoutMs + " ms");
+ }
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 198ddc6d0552..bed1c3272f92 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -19,10 +19,13 @@ package com.android.server;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+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 com.android.internal.util.TestUtils.waitForIdleHandler;
+
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
@@ -112,6 +115,7 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BooleanSupplier;
+import java.util.function.Predicate;
/**
* Tests for {@link ConnectivityService}.
@@ -212,20 +216,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
}
- /**
- * Block until the given handler becomes idle, or until timeoutMs has passed.
- */
- private static void waitForIdleHandler(HandlerThread handlerThread, int timeoutMs) {
- final ConditionVariable cv = new ConditionVariable();
- final Handler handler = new Handler(handlerThread.getLooper());
- handler.post(() -> cv.open());
- if (!cv.block(timeoutMs)) {
- fail("HandlerThread " + handlerThread.getName() +
- " did not become idle after " + timeoutMs + " ms");
- }
- }
-
- public void waitForIdle(int timeoutMs) {
+ public void waitForIdle(int timeoutMsAsInt) {
+ long timeoutMs = timeoutMsAsInt;
waitForIdleHandler(mService.mHandlerThread, timeoutMs);
waitForIdle(mCellNetworkAgent, timeoutMs);
waitForIdle(mWiFiNetworkAgent, timeoutMs);
@@ -233,7 +225,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
waitForIdleHandler(mService.mHandlerThread, timeoutMs);
}
- public void waitForIdle(MockNetworkAgent agent, int timeoutMs) {
+ public void waitForIdle(MockNetworkAgent agent, long timeoutMs) {
if (agent == null) {
return;
}
@@ -327,6 +319,9 @@ public class ConnectivityServiceTest extends AndroidTestCase {
case TRANSPORT_CELLULAR:
mScore = 50;
break;
+ case TRANSPORT_WIFI_AWARE:
+ mScore = 20;
+ break;
default:
throw new UnsupportedOperationException("unimplemented network type");
}
@@ -408,6 +403,15 @@ public class ConnectivityServiceTest extends AndroidTestCase {
* @param validated Indicate if network should pretend to be validated.
*/
public void connect(boolean validated) {
+ connect(validated, true);
+ }
+
+ /**
+ * Transition this NetworkAgent to CONNECTED state.
+ * @param validated Indicate if network should pretend to be validated.
+ * @param hasInternet Indicate if network should pretend to have NET_CAPABILITY_INTERNET.
+ */
+ public void connect(boolean validated, boolean hasInternet) {
assertEquals("MockNetworkAgents can only be connected once",
mNetworkInfo.getDetailedState(), DetailedState.IDLE);
assertFalse(mNetworkCapabilities.hasCapability(NET_CAPABILITY_INTERNET));
@@ -430,7 +434,9 @@ public class ConnectivityServiceTest extends AndroidTestCase {
};
mCm.registerNetworkCallback(request, callback);
}
- addCapability(NET_CAPABILITY_INTERNET);
+ if (hasInternet) {
+ addCapability(NET_CAPABILITY_INTERNET);
+ }
connectWithoutInternet();
@@ -784,7 +790,10 @@ public class ConnectivityServiceTest extends AndroidTestCase {
* Fails if TIMEOUT_MS goes by before {@code conditionVariable} opens.
*/
static private void waitFor(ConditionVariable conditionVariable) {
- assertTrue(conditionVariable.block(TIMEOUT_MS));
+ if (conditionVariable.block(TIMEOUT_MS)) {
+ return;
+ }
+ fail("ConditionVariable was blocked for more than " + TIMEOUT_MS + "ms");
}
@Override
@@ -842,7 +851,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
case TRANSPORT_CELLULAR:
return TYPE_MOBILE;
default:
- throw new IllegalStateException("Unknown transport " + transport);
+ return TYPE_NONE;
}
}
@@ -853,6 +862,9 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Test getActiveNetwork()
assertNotNull(mCm.getActiveNetwork());
assertEquals(mCm.getActiveNetwork(), mCm.getActiveNetworkForUid(Process.myUid()));
+ if (!NetworkCapabilities.isValidTransport(transport)) {
+ throw new IllegalStateException("Unknown transport " + transport);
+ }
switch (transport) {
case TRANSPORT_WIFI:
assertEquals(mCm.getActiveNetwork(), mWiFiNetworkAgent.getNetwork());
@@ -861,7 +873,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
assertEquals(mCm.getActiveNetwork(), mCellNetworkAgent.getNetwork());
break;
default:
- throw new IllegalStateException("Unknown transport" + transport);
+ break;
}
// Test getNetworkInfo(Network)
assertNotNull(mCm.getNetworkInfo(mCm.getActiveNetwork()));
@@ -879,7 +891,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
assertNull(mCm.getActiveNetwork());
assertNull(mCm.getActiveNetworkForUid(Process.myUid()));
// Test getAllNetworks()
- assertEquals(0, mCm.getAllNetworks().length);
+ assertEmpty(mCm.getAllNetworks());
}
/**
@@ -920,7 +932,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCellNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_CELLULAR);
- assertEquals(2, mCm.getAllNetworks().length);
+ assertLength(2, mCm.getAllNetworks());
assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) ||
mCm.getAllNetworks()[1].equals(mCm.getActiveNetwork()));
assertTrue(mCm.getAllNetworks()[0].equals(mWiFiNetworkAgent.getNetwork()) ||
@@ -930,7 +942,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
- assertEquals(2, mCm.getAllNetworks().length);
+ assertLength(2, mCm.getAllNetworks());
assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) ||
mCm.getAllNetworks()[1].equals(mCm.getActiveNetwork()));
assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) ||
@@ -938,9 +950,9 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Test cellular linger timeout.
waitFor(mCellNetworkAgent.getDisconnectedCV());
waitForIdle();
- assertEquals(1, mCm.getAllNetworks().length);
+ assertLength(1, mCm.getAllNetworks());
verifyActiveNetwork(TRANSPORT_WIFI);
- assertEquals(1, mCm.getAllNetworks().length);
+ assertLength(1, mCm.getAllNetworks());
assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());
// Test WiFi disconnect.
cv = waitForConnectivityBroadcasts(1);
@@ -1281,7 +1293,26 @@ public class ConnectivityServiceTest extends AndroidTestCase {
return expectCallback(state, agent, TIMEOUT_MS);
}
- void expectAvailableCallbacks(MockNetworkAgent agent, boolean expectSuspended, int timeoutMs) {
+ CallbackInfo expectCallbackLike(Predicate<CallbackInfo> fn) {
+ return expectCallbackLike(fn, TIMEOUT_MS);
+ }
+
+ CallbackInfo expectCallbackLike(Predicate<CallbackInfo> fn, int timeoutMs) {
+ int timeLeft = timeoutMs;
+ while (timeLeft > 0) {
+ long start = SystemClock.elapsedRealtime();
+ CallbackInfo info = nextCallback(timeLeft);
+ if (fn.test(info)) {
+ return info;
+ }
+ timeLeft -= (SystemClock.elapsedRealtime() - start);
+ }
+ fail("Did not receive expected callback after " + timeoutMs + "ms");
+ return null;
+ }
+
+ void expectAvailableCallbacks(
+ MockNetworkAgent agent, boolean expectSuspended, int timeoutMs) {
expectCallback(CallbackState.AVAILABLE, agent, timeoutMs);
if (expectSuspended) {
expectCallback(CallbackState.SUSPENDED, agent, timeoutMs);
@@ -1838,26 +1869,18 @@ public class ConnectivityServiceTest extends AndroidTestCase {
@SmallTest
public void testNoMutableNetworkRequests() throws Exception {
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("a"), 0);
- NetworkRequest.Builder builder = new NetworkRequest.Builder();
- builder.addCapability(NET_CAPABILITY_VALIDATED);
- try {
- mCm.requestNetwork(builder.build(), new NetworkCallback());
- fail();
- } catch (IllegalArgumentException expected) {}
- try {
- mCm.requestNetwork(builder.build(), pendingIntent);
- fail();
- } catch (IllegalArgumentException expected) {}
- builder = new NetworkRequest.Builder();
- builder.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
- try {
- mCm.requestNetwork(builder.build(), new NetworkCallback());
- fail();
- } catch (IllegalArgumentException expected) {}
- try {
- mCm.requestNetwork(builder.build(), pendingIntent);
- fail();
- } catch (IllegalArgumentException expected) {}
+ NetworkRequest request1 = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_VALIDATED)
+ .build();
+ NetworkRequest request2 = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL)
+ .build();
+
+ Class<IllegalArgumentException> expected = IllegalArgumentException.class;
+ assertException(() -> { mCm.requestNetwork(request1, new NetworkCallback()); }, expected);
+ assertException(() -> { mCm.requestNetwork(request1, pendingIntent); }, expected);
+ assertException(() -> { mCm.requestNetwork(request2, new NetworkCallback()); }, expected);
+ assertException(() -> { mCm.requestNetwork(request2, pendingIntent); }, expected);
}
@SmallTest
@@ -1869,7 +1892,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCellNetworkAgent.connectWithoutInternet();
waitFor(cv);
waitForIdle();
- assertEquals(0, mCm.getAllNetworks().length);
+ assertEmpty(mCm.getAllNetworks());
verifyNoNetwork();
// Test bringing up validated WiFi.
@@ -2543,7 +2566,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
assertTrue(testFactory.getMyStartRequested());
// Bring up cell data and check that the factory stops looking.
- assertEquals(1, mCm.getAllNetworks().length);
+ assertLength(1, mCm.getAllNetworks());
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
testFactory.expectAddRequests(2); // Because the cell request changes score twice.
mCellNetworkAgent.connect(true);
@@ -2554,7 +2577,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Check that cell data stays up.
waitForIdle();
verifyActiveNetwork(TRANSPORT_WIFI);
- assertEquals(2, mCm.getAllNetworks().length);
+ assertLength(2, mCm.getAllNetworks());
// Turn off mobile data always on and expect the request to disappear...
testFactory.expectRemoveRequests(1);
@@ -2563,7 +2586,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// ... and cell data to be torn down.
cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- assertEquals(1, mCm.getAllNetworks().length);
+ assertLength(1, mCm.getAllNetworks());
testFactory.unregister();
mCm.unregisterNetworkCallback(cellNetworkCallback);
@@ -2784,19 +2807,17 @@ public class ConnectivityServiceTest extends AndroidTestCase {
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
- final int requestTimeoutMs = 100;
+ final int requestTimeoutMs = 50;
mCm.requestNetwork(nr, networkCallback, requestTimeoutMs);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- final int assertTimeoutMs = 150;
+ final int assertTimeoutMs = 100;
networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, assertTimeoutMs);
- sleepFor(20);
mWiFiNetworkAgent.disconnect();
networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- // pass timeout and validate that UNAVAILABLE is not called
- sleepFor(100);
+ // Validate that UNAVAILABLE is not called
networkCallback.assertNoCallback();
}
@@ -2823,24 +2844,20 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
/**
- * Validate that when a network request is unregistered (cancelled) the time-out for that
- * request doesn't trigger the onUnavailable() callback.
+ * Validate that when a network request is unregistered (cancelled), no posterior event can
+ * trigger the callback.
*/
@SmallTest
- public void testTimedoutAfterUnregisteredNetworkRequest() {
+ public void testNoCallbackAfterUnregisteredNetworkRequest() {
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
final int timeoutMs = 10;
- mCm.requestNetwork(nr, networkCallback, timeoutMs);
- // remove request
+ mCm.requestNetwork(nr, networkCallback, timeoutMs);
mCm.unregisterNetworkCallback(networkCallback);
-
- // pass timeout and validate that no callbacks
- // Note: doesn't validate that nothing called from CS since even if called the CM already
- // unregisters the callback and won't pass it through!
- sleepFor(15);
+ // Regardless of the timeout, unregistering the callback in ConnectivityManager ensures
+ // that this callback will not be called.
networkCallback.assertNoCallback();
// create a network satisfying request - validate that request not triggered
@@ -3259,12 +3276,87 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
}
- /* test utilities */
- // TODO: eliminate all usages of sleepFor and replace by proper timeouts/waitForIdle.
- static private void sleepFor(int ms) {
+ @SmallTest
+ public void testNetworkInfoOfTypeNone() {
+ ConditionVariable broadcastCV = waitForConnectivityBroadcasts(1);
+
+ verifyNoNetwork();
+ MockNetworkAgent lowpanNetwork = new MockNetworkAgent(TRANSPORT_WIFI_AWARE);
+ assertNull(mCm.getActiveNetworkInfo());
+
+ Network[] allNetworks = mCm.getAllNetworks();
+ assertLength(1, allNetworks);
+ Network network = allNetworks[0];
+ NetworkCapabilities capabilities = mCm.getNetworkCapabilities(network);
+ assertTrue(capabilities.hasTransport(TRANSPORT_WIFI_AWARE));
+
+ final NetworkRequest request =
+ new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI_AWARE).build();
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(request, callback);
+
+ // Bring up lowpan.
+ lowpanNetwork.connect(false, false);
+ callback.expectAvailableCallbacks(lowpanNetwork);
+
+ assertNull(mCm.getActiveNetworkInfo());
+ assertNull(mCm.getActiveNetwork());
+ // TODO: getAllNetworkInfo is dirty and returns a non-empty array rght from the start
+ // of this test. Fix it and uncomment the assert below.
+ //assertEmpty(mCm.getAllNetworkInfo());
+
+ // Disconnect lowpan.
+ lowpanNetwork.disconnect();
+ callback.expectCallback(CallbackState.LOST, lowpanNetwork);
+ mCm.unregisterNetworkCallback(callback);
+
+ verifyNoNetwork();
+ if (broadcastCV.block(10)) {
+ fail("expected no broadcast, but got CONNECTIVITY_ACTION broadcast");
+ }
+ }
+
+ @SmallTest
+ public void testDeprecatedAndUnsupportedOperations() throws Exception {
+ final int TYPE_NONE = ConnectivityManager.TYPE_NONE;
+ assertNull(mCm.getNetworkInfo(TYPE_NONE));
+ assertNull(mCm.getNetworkForType(TYPE_NONE));
+ assertNull(mCm.getLinkProperties(TYPE_NONE));
+ assertFalse(mCm.isNetworkSupported(TYPE_NONE));
+
+ assertException(() -> { mCm.networkCapabilitiesForType(TYPE_NONE); },
+ IllegalArgumentException.class);
+
+ Class<UnsupportedOperationException> unsupported = UnsupportedOperationException.class;
+ assertException(() -> { mCm.startUsingNetworkFeature(TYPE_WIFI, ""); }, unsupported);
+ assertException(() -> { mCm.stopUsingNetworkFeature(TYPE_WIFI, ""); }, unsupported);
+ // TODO: let test context have configuration application target sdk version
+ // and test that pre-M requesting for TYPE_NONE sends back APN_REQUEST_FAILED
+ assertException(() -> { mCm.startUsingNetworkFeature(TYPE_NONE, ""); }, unsupported);
+ assertException(() -> { mCm.stopUsingNetworkFeature(TYPE_NONE, ""); }, unsupported);
+ assertException(() -> { mCm.requestRouteToHostAddress(TYPE_NONE, null); }, unsupported);
+ }
+
+ private static <T> void assertEmpty(T[] ts) {
+ int length = ts.length;
+ assertEquals("expected empty array, but length was " + length, 0, length);
+ }
+
+ private static <T> void assertLength(int expected, T[] got) {
+ int length = got.length;
+ assertEquals(String.format("expected array of length %s, but length was %s for %s",
+ expected, length, Arrays.toString(got)), expected, length);
+ }
+
+ private static <T> void assertException(Runnable block, Class<T> expected) {
try {
- Thread.sleep(ms);
- } catch (InterruptedException e) {
+ block.run();
+ fail("Expected exception of type " + expected);
+ } catch (Exception got) {
+ if (!got.getClass().equals(expected)) {
+ fail("Expected exception of type " + expected + " but got " + got);
+ }
+ return;
}
}
}
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index ab874ce2cc50..acf9e8f71718 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -16,6 +16,11 @@
package com.android.server.connectivity;
+import static android.hardware.usb.UsbManager.USB_CONFIGURED;
+import static android.hardware.usb.UsbManager.USB_CONNECTED;
+import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
+import static android.net.ConnectivityManager.TETHERING_WIFI;
+import static android.net.ConnectivityManager.TETHERING_USB;
import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
@@ -133,6 +138,7 @@ public class TetheringTest {
public Object getSystemService(String name) {
if (Context.CONNECTIVITY_SERVICE.equals(name)) return mConnectivityManager;
if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
+ if (Context.USB_SERVICE.equals(name)) return mUsbManager;
return super.getSystemService(name);
}
}
@@ -145,7 +151,7 @@ public class TetheringTest {
when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
.thenReturn(new String[0]);
when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
- .thenReturn(new String[]{ "test_wlan\\d" });
+ .thenReturn(new String[]{ "test_wlan\\d", "test_rndis\\d" });
when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
.thenReturn(new String[0]);
when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
@@ -245,6 +251,14 @@ public class TetheringTest {
mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
+ private void sendUsbBroadcast(boolean connected, boolean configured, boolean rndisFunction) {
+ final Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
+ intent.putExtra(USB_CONNECTED, connected);
+ intent.putExtra(USB_CONFIGURED, configured);
+ intent.putExtra(USB_FUNCTION_RNDIS, rndisFunction);
+ mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ }
+
private void verifyInterfaceServingModeStarted() throws Exception {
verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
verify(mNMService, times(1))
@@ -287,6 +301,32 @@ public class TetheringTest {
}
@Test
+ public void testUsbConfiguredBroadcastStartsTethering() throws Exception {
+ when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
+
+ // Emulate pressing the USB tethering button in Settings UI.
+ mTethering.startTethering(TETHERING_USB, null, false);
+ mLooper.dispatchAll();
+ verify(mUsbManager, times(1)).setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);
+
+ // Pretend we receive a USB connected broadcast. Here we also pretend
+ // that the RNDIS function is somehow enabled, so that we see if we
+ // might trip ourselves up.
+ sendUsbBroadcast(true, false, true);
+ mLooper.dispatchAll();
+ // This should produce no activity of any kind.
+ verifyNoMoreInteractions(mConnectivityManager);
+ verifyNoMoreInteractions(mNMService);
+
+ // Pretend we then receive USB configured broadcast.
+ sendUsbBroadcast(true, true, true);
+ mLooper.dispatchAll();
+ // Now we should see the start of tethering mechanics (in this case:
+ // tetherMatchingInterfaces() which starts by fetching all interfaces).
+ verify(mNMService, times(1)).listInterfaces();
+ }
+
+ @Test
public void failingLocalOnlyHotspotLegacyApBroadcastWithIfaceStatusChanged() throws Exception {
failingLocalOnlyHotspotLegacyApBroadcast(true);
}
@@ -366,7 +406,7 @@ public class TetheringTest {
when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
// Emulate pressing the WiFi tethering button.
- mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
+ mTethering.startTethering(TETHERING_WIFI, null, false);
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startSoftAp(null);
verifyNoMoreInteractions(mWifiManager);
@@ -394,7 +434,7 @@ public class TetheringTest {
when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
// Emulate pressing the WiFi tethering button.
- mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
+ mTethering.startTethering(TETHERING_WIFI, null, false);
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startSoftAp(null);
verifyNoMoreInteractions(mWifiManager);
@@ -440,7 +480,7 @@ public class TetheringTest {
/////
// Emulate pressing the WiFi tethering button.
- mTethering.stopTethering(ConnectivityManager.TETHERING_WIFI);
+ mTethering.stopTethering(TETHERING_WIFI);
mLooper.dispatchAll();
verify(mWifiManager, times(1)).stopSoftAp();
verifyNoMoreInteractions(mWifiManager);
@@ -476,7 +516,7 @@ public class TetheringTest {
doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
// Emulate pressing the WiFi tethering button.
- mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
+ mTethering.startTethering(TETHERING_WIFI, null, false);
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startSoftAp(null);
verifyNoMoreInteractions(mWifiManager);
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index fb5c5778d05b..69c93b14a486 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -44,6 +44,9 @@ import android.os.Message;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.IConnectivityManager;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
@@ -66,6 +69,7 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -77,6 +81,9 @@ import java.util.Set;
public class UpstreamNetworkMonitorTest {
private static final int EVENT_UNM_UPDATE = 1;
+ private static final boolean INCLUDES = true;
+ private static final boolean EXCLUDES = false;
+
@Mock private Context mContext;
@Mock private IConnectivityManager mCS;
@Mock private SharedLog mLog;
@@ -94,7 +101,8 @@ public class UpstreamNetworkMonitorTest {
mCM = spy(new TestConnectivityManager(mContext, mCS));
mSM = new TestStateMachine();
- mUNM = new UpstreamNetworkMonitor(mSM, EVENT_UNM_UPDATE, (ConnectivityManager) mCM, mLog);
+ mUNM = new UpstreamNetworkMonitor(
+ (ConnectivityManager) mCM, mSM, mLog, EVENT_UNM_UPDATE);
}
@After public void tearDown() throws Exception {
@@ -315,6 +323,101 @@ public class UpstreamNetworkMonitorTest {
assertTrue(netReq.networkCapabilities.hasCapability(NET_CAPABILITY_DUN));
}
+ @Test
+ public void testOffloadExemptPrefixes() throws Exception {
+ mUNM.start();
+
+ // [0] Test minimum set of exempt prefixes.
+ Set<IpPrefix> exempt = mUNM.getOffloadExemptPrefixes();
+ final String[] MINSET = {
+ "127.0.0.0/8", "169.254.0.0/16",
+ "::/3", "fe80::/64", "fc00::/7", "ff00::/8",
+ };
+ assertPrefixSet(exempt, INCLUDES, MINSET);
+ final Set<String> alreadySeen = new HashSet<>();
+ Collections.addAll(alreadySeen, MINSET);
+ assertEquals(alreadySeen.size(), exempt.size());
+
+ // [1] Pretend Wi-Fi connects.
+ final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
+ final LinkProperties wifiLp = new LinkProperties();
+ wifiLp.setInterfaceName("wlan0");
+ final String[] WIFI_ADDRS = {
+ "fe80::827a:bfff:fe6f:374d", "100.112.103.18",
+ "2001:db8:4:fd00:827a:bfff:fe6f:374d",
+ "2001:db8:4:fd00:6dea:325a:fdae:4ef4",
+ "fd6a:a640:60bf:e985::123", // ULA address for good measure.
+ };
+ for (String addrStr : WIFI_ADDRS) {
+ final String cidr = addrStr.contains(":") ? "/64" : "/20";
+ wifiLp.addLinkAddress(new LinkAddress(addrStr + cidr));
+ }
+ wifiAgent.fakeConnect();
+ wifiAgent.sendLinkProperties(wifiLp);
+
+ exempt = mUNM.getOffloadExemptPrefixes();
+ assertPrefixSet(exempt, INCLUDES, alreadySeen);
+ final String[] wifiLinkPrefixes = {
+ // Excludes link-local as that's already tested within MINSET.
+ "100.112.96.0/20", "2001:db8:4:fd00::/64", "fd6a:a640:60bf:e985::/64",
+ };
+ assertPrefixSet(exempt, INCLUDES, wifiLinkPrefixes);
+ Collections.addAll(alreadySeen, wifiLinkPrefixes);
+ assertEquals(alreadySeen.size(), exempt.size());
+
+ // [2] Pretend mobile connects.
+ final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
+ final LinkProperties cellLp = new LinkProperties();
+ cellLp.setInterfaceName("rmnet_data0");
+ final String[] CELL_ADDRS = {
+ "10.102.211.48", "2001:db8:0:1:b50e:70d9:10c9:433d",
+ };
+ for (String addrStr : CELL_ADDRS) {
+ final String cidr = addrStr.contains(":") ? "/64" : "/27";
+ cellLp.addLinkAddress(new LinkAddress(addrStr + cidr));
+ }
+ cellAgent.fakeConnect();
+ cellAgent.sendLinkProperties(cellLp);
+
+ exempt = mUNM.getOffloadExemptPrefixes();
+ assertPrefixSet(exempt, INCLUDES, alreadySeen);
+ final String[] cellLinkPrefixes = { "10.102.211.32/27", "2001:db8:0:1::/64" };
+ assertPrefixSet(exempt, INCLUDES, cellLinkPrefixes);
+ Collections.addAll(alreadySeen, cellLinkPrefixes);
+ assertEquals(alreadySeen.size(), exempt.size());
+
+ // [3] Pretend DUN connects.
+ final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
+ dunAgent.networkCapabilities.addCapability(NET_CAPABILITY_DUN);
+ final LinkProperties dunLp = new LinkProperties();
+ dunLp.setInterfaceName("rmnet_data1");
+ final String[] DUN_ADDRS = {
+ "192.0.2.48", "2001:db8:1:2:b50e:70d9:10c9:433d",
+ };
+ for (String addrStr : DUN_ADDRS) {
+ final String cidr = addrStr.contains(":") ? "/64" : "/27";
+ cellLp.addLinkAddress(new LinkAddress(addrStr + cidr));
+ }
+ dunAgent.fakeConnect();
+ dunAgent.sendLinkProperties(dunLp);
+
+ exempt = mUNM.getOffloadExemptPrefixes();
+ assertPrefixSet(exempt, INCLUDES, alreadySeen);
+ final String[] dunLinkPrefixes = { "192.0.2.32/27", "2001:db8:1:2::/64" };
+ assertPrefixSet(exempt, INCLUDES, dunLinkPrefixes);
+ Collections.addAll(alreadySeen, dunLinkPrefixes);
+ assertEquals(alreadySeen.size(), exempt.size());
+
+ // [4] Pretend Wi-Fi disconnected. It's addresses/prefixes should no
+ // longer be included (should be properly removed).
+ wifiAgent.fakeDisconnect();
+ exempt = mUNM.getOffloadExemptPrefixes();
+ assertPrefixSet(exempt, INCLUDES, MINSET);
+ assertPrefixSet(exempt, EXCLUDES, wifiLinkPrefixes);
+ assertPrefixSet(exempt, INCLUDES, cellLinkPrefixes);
+ assertPrefixSet(exempt, INCLUDES, dunLinkPrefixes);
+ }
+
private void assertSatisfiesLegacyType(int legacyType, NetworkState ns) {
if (legacyType == TYPE_NONE) {
assertTrue(ns == null);
@@ -476,6 +579,12 @@ public class UpstreamNetworkMonitorTest {
cb.onLost(networkId);
}
}
+
+ public void sendLinkProperties(LinkProperties lp) {
+ for (NetworkCallback cb : cm.listening.keySet()) {
+ cb.onLinkPropertiesChanged(networkId, lp);
+ }
+ }
}
public static class TestStateMachine extends StateMachine {
@@ -504,4 +613,19 @@ public class UpstreamNetworkMonitorTest {
static NetworkCapabilities copy(NetworkCapabilities nc) {
return new NetworkCapabilities(nc);
}
+
+ static void assertPrefixSet(Set<IpPrefix> prefixes, boolean expectation, String... expected) {
+ final Set<String> expectedSet = new HashSet<>();
+ Collections.addAll(expectedSet, expected);
+ assertPrefixSet(prefixes, expectation, expectedSet);
+ }
+
+ static void assertPrefixSet(Set<IpPrefix> prefixes, boolean expectation, Set<String> expected) {
+ for (String expectedPrefix : expected) {
+ final String errStr = expectation ? "did not find" : "found";
+ assertEquals(
+ String.format("Failed expectation: %s prefix: %s", errStr, expectedPrefix),
+ expectation, prefixes.contains(new IpPrefix(expectedPrefix)));
+ }
+ }
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
index 92dcdaca30fa..2be5dae97a10 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
@@ -27,6 +27,8 @@ import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+import static com.android.internal.util.TestUtils.waitForIdleHandler;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -56,7 +58,6 @@ import android.util.ArrayMap;
import com.android.internal.net.VpnInfo;
import com.android.server.net.NetworkStatsService;
-import com.android.server.net.NetworkStatsServiceTest.IdleableHandlerThread;
import com.android.server.net.NetworkStatsServiceTest.LatchedHandler;
import java.util.ArrayList;
@@ -102,7 +103,7 @@ public class NetworkStatsObserversTest {
private long mElapsedRealtime;
- private IdleableHandlerThread mObserverHandlerThread;
+ private HandlerThread mObserverHandlerThread;
private Handler mObserverNoopHandler;
private LatchedHandler mHandler;
@@ -118,7 +119,7 @@ public class NetworkStatsObserversTest {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mObserverHandlerThread = new IdleableHandlerThread("HandlerThread");
+ mObserverHandlerThread = new HandlerThread("HandlerThread");
mObserverHandlerThread.start();
final Looper observerLooper = mObserverHandlerThread.getLooper();
mStatsObservers = new NetworkStatsObservers() {
@@ -319,7 +320,7 @@ public class NetworkStatsObserversTest {
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
VPN_INFO, TEST_START);
waitForObserverToIdle();
- assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.lastMessageType);
}
@Test
@@ -356,7 +357,7 @@ public class NetworkStatsObserversTest {
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
VPN_INFO, TEST_START);
waitForObserverToIdle();
- assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.lastMessageType);
}
@Test
@@ -429,7 +430,7 @@ public class NetworkStatsObserversTest {
xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
VPN_INFO, TEST_START);
waitForObserverToIdle();
- assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.lastMessageType);
}
@Test
@@ -470,19 +471,7 @@ public class NetworkStatsObserversTest {
}
private void waitForObserverToIdle() {
- waitForIdleLooper(mObserverHandlerThread.getLooper(), WAIT_TIMEOUT_MS);
- waitForIdleLooper(mHandler.getLooper(), WAIT_TIMEOUT_MS);
- }
-
- // TODO: unify with ConnectivityService.waitForIdleHandler and
- // NetworkServiceStatsTest.IdleableHandlerThread
- private static void waitForIdleLooper(Looper looper, long timeoutMs) {
- final ConditionVariable cv = new ConditionVariable();
- final Handler handler = new Handler(looper);
- handler.post(() -> cv.open());
- if (!cv.block(timeoutMs)) {
- fail("Looper did not become idle after " + timeoutMs + " ms");
- }
+ waitForIdleHandler(mObserverHandlerThread, WAIT_TIMEOUT_MS);
+ waitForIdleHandler(mHandler, WAIT_TIMEOUT_MS);
}
-
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 029693f1903b..feb46d39b563 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -45,6 +45,7 @@ import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
+import static com.android.internal.util.TestUtils.waitForIdleHandler;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -154,7 +155,7 @@ public class NetworkStatsServiceTest {
private @Mock IConnectivityManager mConnManager;
private @Mock IBinder mBinder;
private @Mock AlarmManager mAlarmManager;
- private IdleableHandlerThread mHandlerThread;
+ private HandlerThread mHandlerThread;
private Handler mHandler;
private NetworkStatsService mService;
@@ -181,7 +182,7 @@ public class NetworkStatsServiceTest {
mServiceContext, mNetManager, mAlarmManager, wakeLock, mTime,
TelephonyManager.getDefault(), mSettings, new NetworkStatsObservers(),
mStatsDir, getBaseDir(mStatsDir));
- mHandlerThread = new IdleableHandlerThread("HandlerThread");
+ mHandlerThread = new HandlerThread("HandlerThread");
mHandlerThread.start();
Handler.Callback callback = new NetworkStatsService.HandlerCallback(mService);
mHandler = new Handler(mHandlerThread.getLooper(), callback);
@@ -886,7 +887,7 @@ public class NetworkStatsServiceTest {
// Send dummy message to make sure that any previous message has been handled
mHandler.sendMessage(mHandler.obtainMessage(-1));
- mHandlerThread.waitForIdle(WAIT_TIMEOUT);
+ waitForIdleHandler(mHandler, WAIT_TIMEOUT);
@@ -908,7 +909,7 @@ public class NetworkStatsServiceTest {
assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0);
// make sure callback has not being called
- assertEquals(INVALID_TYPE, latchedHandler.mLastMessageType);
+ assertEquals(INVALID_TYPE, latchedHandler.lastMessageType);
// and bump forward again, with counters going higher. this is
// important, since it will trigger the data usage callback
@@ -926,7 +927,7 @@ public class NetworkStatsServiceTest {
// Wait for the caller to ack receipt of CALLBACK_LIMIT_REACHED
assertTrue(cv.block(WAIT_TIMEOUT));
- assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, latchedHandler.mLastMessageType);
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, latchedHandler.lastMessageType);
cv.close();
// Allow binder to disconnect
@@ -937,7 +938,7 @@ public class NetworkStatsServiceTest {
// Wait for the caller to ack receipt of CALLBACK_RELEASED
assertTrue(cv.block(WAIT_TIMEOUT));
- assertEquals(NetworkStatsManager.CALLBACK_RELEASED, latchedHandler.mLastMessageType);
+ assertEquals(NetworkStatsManager.CALLBACK_RELEASED, latchedHandler.lastMessageType);
// Make sure that the caller binder gets disconnected
verify(mBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
@@ -1203,12 +1204,12 @@ public class NetworkStatsServiceTest {
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
// Send dummy message to make sure that any previous message has been handled
mHandler.sendMessage(mHandler.obtainMessage(-1));
- mHandlerThread.waitForIdle(WAIT_TIMEOUT);
+ waitForIdleHandler(mHandler, WAIT_TIMEOUT);
}
static class LatchedHandler extends Handler {
private final ConditionVariable mCv;
- int mLastMessageType = INVALID_TYPE;
+ int lastMessageType = INVALID_TYPE;
LatchedHandler(Looper looper, ConditionVariable cv) {
super(looper);
@@ -1217,49 +1218,9 @@ public class NetworkStatsServiceTest {
@Override
public void handleMessage(Message msg) {
- mLastMessageType = msg.what;
+ lastMessageType = msg.what;
mCv.open();
super.handleMessage(msg);
}
}
-
- /**
- * A subclass of HandlerThread that allows callers to wait for it to become idle. waitForIdle
- * will return immediately if the handler is already idle.
- */
- static class IdleableHandlerThread extends HandlerThread {
- private IdleHandler mIdleHandler;
-
- public IdleableHandlerThread(String name) {
- super(name);
- }
-
- public void waitForIdle(long timeoutMs) {
- final ConditionVariable cv = new ConditionVariable();
- final MessageQueue queue = getLooper().getQueue();
-
- synchronized (queue) {
- if (queue.isIdle()) {
- return;
- }
-
- assertNull("BUG: only one idle handler allowed", mIdleHandler);
- mIdleHandler = new IdleHandler() {
- public boolean queueIdle() {
- cv.open();
- mIdleHandler = null;
- return false; // Remove the handler.
- }
- };
- queue.addIdleHandler(mIdleHandler);
- }
-
- if (!cv.block(timeoutMs)) {
- fail("HandlerThread " + getName() + " did not become idle after " + timeoutMs
- + " ms");
- queue.removeIdleHandler(mIdleHandler);
- }
- }
- }
-
}
diff --git a/tools/aapt2/ConfigDescription.cpp b/tools/aapt2/ConfigDescription.cpp
index 7ff0c7227c9c..f16d806fe5c7 100644
--- a/tools/aapt2/ConfigDescription.cpp
+++ b/tools/aapt2/ConfigDescription.cpp
@@ -987,4 +987,8 @@ bool ConfigDescription::IsCompatibleWith(const ConfigDescription& o) const {
return !ConflictsWith(o) && !Dominates(o) && !o.Dominates(*this);
}
+::std::ostream& operator<<(::std::ostream& out, const ConfigDescription& o) {
+ return out << o.toString().string();
+}
+
} // namespace aapt
diff --git a/tools/aapt2/ConfigDescription.h b/tools/aapt2/ConfigDescription.h
index 65c96175091c..8c519a1a913c 100644
--- a/tools/aapt2/ConfigDescription.h
+++ b/tools/aapt2/ConfigDescription.h
@@ -24,30 +24,22 @@
namespace aapt {
-/*
- * Subclass of ResTable_config that adds convenient
- * initialization and comparison methods.
- */
+// Subclass of ResTable_config that adds convenient
+// initialization and comparison methods.
struct ConfigDescription : public android::ResTable_config {
- /**
- * Returns an immutable default config.
- */
+ // Returns an immutable default config.
static const ConfigDescription& DefaultConfig();
- /*
- * Parse a string of the form 'fr-sw600dp-land' and fill in the
- * given ResTable_config with resulting configuration parameters.
- *
- * The resulting configuration has the appropriate sdkVersion defined
- * for backwards compatibility.
- */
+ // Parse a string of the form 'fr-sw600dp-land' and fill in the
+ // given ResTable_config with resulting configuration parameters.
+ //
+ // The resulting configuration has the appropriate sdkVersion defined
+ // for backwards compatibility.
static bool Parse(const android::StringPiece& str, ConfigDescription* out = nullptr);
- /**
- * If the configuration uses an axis that was added after
- * the original Android release, make sure the SDK version
- * is set accordingly.
- */
+ // If the configuration uses an axis that was added after
+ // the original Android release, make sure the SDK version
+ // is set accordingly.
static void ApplyVersionForCompatibility(ConfigDescription* config);
ConfigDescription();
@@ -61,38 +53,30 @@ struct ConfigDescription : public android::ResTable_config {
ConfigDescription CopyWithoutSdkVersion() 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
- * by X, the same type is defined by Y with a value equal to or, in the case
- * of ranges, more specific than that of X.
- *
- * For example, the configuration 'en-w800dp' dominates 'en-rGB-w1024dp'. It
- * does not dominate 'fr', 'en-w720dp', or 'mcc001-en-w800dp'.
- */
+ // 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
+ // by X, the same type is defined by Y with a value equal to or, in the case
+ // of ranges, more specific than that of X.
+ //
+ // For example, the configuration 'en-w800dp' dominates 'en-rGB-w1024dp'. It
+ // does not dominate 'fr', 'en-w720dp', or 'mcc001-en-w800dp'.
bool Dominates(const ConfigDescription& o) const;
- /**
- * Returns true if this configuration defines a more important configuration
- * parameter than o. For example, "en" has higher precedence than "v23",
- * whereas "en" has the same precedence as "en-v23".
- */
+ // Returns true if this configuration defines a more important configuration
+ // parameter than o. For example, "en" has higher precedence than "v23",
+ // whereas "en" has the same precedence as "en-v23".
bool HasHigherPrecedenceThan(const ConfigDescription& o) const;
- /**
- * A configuration conflicts with another configuration if both
- * configurations define an incompatible configuration parameter. An
- * incompatible configuration parameter is a non-range, non-density parameter
- * that is defined in both configurations as a different, non-default value.
- */
+ // A configuration conflicts with another configuration if both
+ // configurations define an incompatible configuration parameter. An
+ // incompatible configuration parameter is a non-range, non-density parameter
+ // that is defined in both configurations as a different, non-default value.
bool ConflictsWith(const ConfigDescription& o) const;
- /**
- * A configuration is compatible with another configuration if both
- * configurations can match a common concrete device configuration and are
- * unrelated by domination. For example, land-v11 conflicts with port-v21
- * but is compatible with v21 (both land-v11 and v21 would match en-land-v23).
- */
+ // A configuration is compatible with another configuration if both
+ // configurations can match a common concrete device configuration and are
+ // unrelated by domination. For example, land-v11 conflicts with port-v21
+ // but is compatible with v21 (both land-v11 and v21 would match en-land-v23).
bool IsCompatibleWith(const ConfigDescription& o) const;
bool MatchWithDensity(const ConfigDescription& o) const;
@@ -105,6 +89,8 @@ struct ConfigDescription : public android::ResTable_config {
bool operator>(const ConfigDescription& o) const;
};
+::std::ostream& operator<<(::std::ostream& out, const ConfigDescription& o);
+
inline ConfigDescription::ConfigDescription() {
memset(this, 0, sizeof(*this));
size = sizeof(android::ResTable_config);
@@ -123,15 +109,13 @@ inline ConfigDescription::ConfigDescription(ConfigDescription&& o) {
*this = o;
}
-inline ConfigDescription& ConfigDescription::operator=(
- const android::ResTable_config& o) {
+inline ConfigDescription& ConfigDescription::operator=(const android::ResTable_config& o) {
*static_cast<android::ResTable_config*>(this) = o;
size = sizeof(android::ResTable_config);
return *this;
}
-inline ConfigDescription& ConfigDescription::operator=(
- const ConfigDescription& o) {
+inline ConfigDescription& ConfigDescription::operator=(const ConfigDescription& o) {
*static_cast<android::ResTable_config*>(this) = o;
return *this;
}
@@ -141,8 +125,7 @@ inline ConfigDescription& ConfigDescription::operator=(ConfigDescription&& o) {
return *this;
}
-inline bool ConfigDescription::MatchWithDensity(
- const ConfigDescription& o) const {
+inline bool ConfigDescription::MatchWithDensity(const ConfigDescription& o) const {
return match(o) && (density == 0 || density == o.density);
}
@@ -170,11 +153,6 @@ inline bool ConfigDescription::operator>(const ConfigDescription& o) const {
return compare(o) > 0;
}
-inline ::std::ostream& operator<<(::std::ostream& out,
- const ConfigDescription& o) {
- return out << o.toString().string();
-}
-
} // namespace aapt
#endif // AAPT_CONFIG_DESCRIPTION_H
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index e6bf3a6f9f56..353d734b69c6 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -60,6 +60,7 @@
#include "unflatten/BinaryResourceParser.h"
#include "util/Files.h"
#include "xml/XmlDom.h"
+#include "xml/XmlUtil.h"
using android::StringPiece;
using android::base::StringPrintf;
@@ -342,16 +343,18 @@ class ResourceFileFlattener {
ConfigDescription config;
// The entry this file came from.
- ResourceEntry* entry;
+ ResourceEntry* entry = nullptr;
// The file to copy as-is.
- io::IFile* file_to_copy;
+ io::IFile* file_to_copy = nullptr;
// The XML to process and flatten.
std::unique_ptr<xml::XmlResource> xml_to_flatten;
// The destination to write this file to.
std::string dst_path;
+
+ bool skip_versioning = false;
};
uint32_t GetCompressionFlags(const StringPiece& str);
@@ -431,19 +434,6 @@ uint32_t ResourceFileFlattener::GetCompressionFlags(const StringPiece& str) {
return ArchiveEntry::kCompress;
}
-static bool IsTransitionElement(const std::string& name) {
- return name == "fade" || name == "changeBounds" || name == "slide" || name == "explode" ||
- name == "changeImageTransform" || name == "changeTransform" ||
- name == "changeClipBounds" || name == "autoTransition" || name == "recolor" ||
- name == "changeScroll" || name == "transitionSet" || name == "transition" ||
- name == "transitionManager";
-}
-
-static bool IsVectorElement(const std::string& name) {
- return name == "vector" || name == "animated-vector" || name == "pathInterpolator" ||
- name == "objectAnimator";
-}
-
template <typename T>
std::vector<T> make_singleton_vec(T&& val) {
std::vector<T> vec;
@@ -476,21 +466,10 @@ std::vector<std::unique_ptr<xml::XmlResource>> ResourceFileFlattener::LinkAndVer
}
}
- if (options_.no_auto_version) {
+ if (options_.no_auto_version || file_op->skip_versioning) {
return make_singleton_vec(std::move(file_op->xml_to_flatten));
}
- if (options_.no_version_vectors || options_.no_version_transitions) {
- // Skip this if it is a vector or animated-vector.
- xml::Element* el = xml::FindRootElement(doc);
- if (el && el->namespace_uri.empty()) {
- if ((options_.no_version_vectors && IsVectorElement(el->name)) ||
- (options_.no_version_transitions && IsTransitionElement(el->name))) {
- return make_singleton_vec(std::move(file_op->xml_to_flatten));
- }
- }
- }
-
const ConfigDescription& config = file_op->config;
ResourceEntry* entry = file_op->entry;
@@ -504,15 +483,26 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
bool error = false;
std::map<std::pair<ConfigDescription, StringPiece>, FileOperation> config_sorted_files;
+ int tag_version_options = 0;
+ if (options_.no_version_vectors) {
+ tag_version_options |= xml::kNoVersionVector;
+ }
+
+ if (options_.no_version_transitions) {
+ tag_version_options |= xml::kNoVersionTransition;
+ }
+
for (auto& pkg : table->packages) {
for (auto& type : pkg->types) {
// Sort by config and name, so that we get better locality in the zip file.
config_sorted_files.clear();
- std::queue<FileOperation> file_operations;
// Populate the queue with all files in the ResourceTable.
for (auto& entry : type->entries) {
- for (auto& config_value : entry->values) {
+ const auto values_end = entry->values.end();
+ for (auto values_iter = entry->values.begin(); values_iter != values_end; ++values_iter) {
+ ResourceConfigValue* config_value = values_iter->get();
+
// WARNING! Do not insert or remove any resources while executing in this scope. It will
// corrupt the iteration order.
@@ -554,6 +544,44 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv
file_op.xml_to_flatten->file.config = config_value->config;
file_op.xml_to_flatten->file.source = file_ref->GetSource();
file_op.xml_to_flatten->file.name = ResourceName(pkg->name, type->type, entry->name);
+
+ // Check if this file needs to be versioned based on tag rules.
+ xml::Element* root_el = xml::FindRootElement(file_op.xml_to_flatten.get());
+ if (root_el == nullptr) {
+ context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
+ << "failed to find the root XML element");
+ return false;
+ }
+
+ if (root_el->namespace_uri.empty()) {
+ if (Maybe<xml::TagApiVersionResult> result =
+ xml::GetXmlTagApiVersion(root_el->name, tag_version_options)) {
+ file_op.skip_versioning = result.value().skip_version;
+ if (result.value().api_version && config_value->config.sdkVersion == 0u) {
+ const ApiVersion min_tag_version = result.value().api_version.value();
+ // Only version it if it doesn't specify its own version and the version is
+ // greater than the minSdk.
+ const util::Range<ApiVersion> valid_range{
+ context_->GetMinSdkVersion() + 1,
+ FindNextApiVersionForConfigInSortedVector(values_iter, values_end)};
+ if (valid_range.Contains(min_tag_version)) {
+ // Update the configurations. The iteration order will not be affected
+ // since sdkVersions in ConfigDescriptions are the last property compared
+ // in the sort function.
+ if (context_->IsVerbose()) {
+ context_->GetDiagnostics()->Note(DiagMessage(config_value->value->GetSource())
+ << "auto-versioning XML resource to API "
+ << min_tag_version);
+ }
+ const_cast<ConfigDescription&>(config_value->config).sdkVersion =
+ static_cast<uint16_t>(min_tag_version);
+ file_op.config.sdkVersion = static_cast<uint16_t>(min_tag_version);
+ file_op.xml_to_flatten->file.config.sdkVersion =
+ static_cast<uint16_t>(min_tag_version);
+ }
+ }
+ }
+ }
}
// NOTE(adamlesinski): Explicitly construct a StringPiece here, or
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/adaptive-icon.xml b/tools/aapt2/integration-tests/AppOne/res/drawable/adaptive-icon.xml
new file mode 100644
index 000000000000..e3cda7e1e979
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/adaptive-icon.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<adaptive-icon xmlns:android="http://schema.android.com/apk/res/android">
+ <background android:drawable="@android:color/white" />
+ <foreground android:drawable="@drawable/image" />
+</adaptive-icon>
diff --git a/tools/aapt2/link/AutoVersioner.cpp b/tools/aapt2/link/AutoVersioner.cpp
index f80c6e9b34d3..4ac70d91bcc9 100644
--- a/tools/aapt2/link/AutoVersioner.cpp
+++ b/tools/aapt2/link/AutoVersioner.cpp
@@ -34,6 +34,19 @@ bool ShouldGenerateVersionedResource(const ResourceEntry* entry, const ConfigDes
return sdk_version_to_generate < FindNextApiVersionForConfig(entry, config);
}
+ApiVersion FindNextApiVersionForConfigInSortedVector(
+ std::vector<std::unique_ptr<ResourceConfigValue>>::const_iterator start,
+ std::vector<std::unique_ptr<ResourceConfigValue>>::const_iterator end) {
+ const ConfigDescription start_config = (*start)->config.CopyWithoutSdkVersion();
+ ++start;
+ if (start != end) {
+ if ((*start)->config.CopyWithoutSdkVersion() == start_config) {
+ return static_cast<ApiVersion>((*start)->config.sdkVersion);
+ }
+ }
+ return std::numeric_limits<ApiVersion>::max();
+}
+
ApiVersion FindNextApiVersionForConfig(const ResourceEntry* entry,
const ConfigDescription& config) {
const auto end_iter = entry->values.end();
@@ -46,25 +59,7 @@ ApiVersion FindNextApiVersionForConfig(const ResourceEntry* entry,
// The source config came from this list, so it should be here.
CHECK(iter != entry->values.end());
- ++iter;
-
- // The next configuration either only varies in sdkVersion, or it is completely different
- // and therefore incompatible. If it is incompatible, we must generate the versioned resource.
-
- // NOTE: The ordering of configurations takes sdkVersion as higher precedence than other
- // qualifiers, so we need to iterate through the entire list to be sure there
- // are no higher sdk level versions of this resource.
- ConfigDescription temp_config(config);
- for (; iter != end_iter; ++iter) {
- temp_config.sdkVersion = (*iter)->config.sdkVersion;
- if (temp_config == (*iter)->config) {
- // The two configs are the same, return the sdkVersion.
- return (*iter)->config.sdkVersion;
- }
- }
-
- // Didn't find another config with a different sdk version, so return the highest possible value.
- return std::numeric_limits<ApiVersion>::max();
+ return FindNextApiVersionForConfigInSortedVector(iter, end_iter);
}
bool AutoVersioner::Consume(IAaptContext* context, ResourceTable* table) {
diff --git a/tools/aapt2/link/AutoVersioner_test.cpp b/tools/aapt2/link/AutoVersioner_test.cpp
index 49639f8ad549..88a831b9e801 100644
--- a/tools/aapt2/link/AutoVersioner_test.cpp
+++ b/tools/aapt2/link/AutoVersioner_test.cpp
@@ -42,8 +42,8 @@ TEST(AutoVersionerTest, GenerateVersionedResourceWhenHigherVersionExists) {
ResourceEntry entry("foo");
entry.values.push_back(util::make_unique<ResourceConfigValue>(ConfigDescription::DefaultConfig(), ""));
- entry.values.push_back(util::make_unique<ResourceConfigValue>(sw600dp_v13_config, ""));
entry.values.push_back(util::make_unique<ResourceConfigValue>(v21_config, ""));
+ entry.values.push_back(util::make_unique<ResourceConfigValue>(sw600dp_v13_config, ""));
EXPECT_TRUE(ShouldGenerateVersionedResource(&entry, ConfigDescription::DefaultConfig(), 17));
EXPECT_FALSE(ShouldGenerateVersionedResource(&entry, ConfigDescription::DefaultConfig(), 22));
diff --git a/tools/aapt2/link/Linkers.h b/tools/aapt2/link/Linkers.h
index 5527f9092c87..493b6b1181b9 100644
--- a/tools/aapt2/link/Linkers.h
+++ b/tools/aapt2/link/Linkers.h
@@ -23,6 +23,7 @@
#include "android-base/macros.h"
#include "Resource.h"
+#include "ResourceTable.h"
#include "SdkConstants.h"
#include "process/IResourceTableConsumer.h"
#include "xml/XmlDom.h"
@@ -41,17 +42,19 @@ struct CallSite {
ResourceNameRef resource;
};
-/**
- * Determines whether a versioned resource should be created. If a versioned
- * resource already exists, it takes precedence.
- */
+// Determines whether a versioned resource should be created. If a versioned resource already
+// exists, it takes precedence.
bool ShouldGenerateVersionedResource(const ResourceEntry* entry, const ConfigDescription& config,
const ApiVersion sdk_version_to_generate);
-// Finds the next largest ApiVersion of the config which is identical to the given config except
-// for sdkVersion.
+// Finds the next largest ApiVersion of `config` for values defined for `entry`.
ApiVersion FindNextApiVersionForConfig(const ResourceEntry* entry, const ConfigDescription& config);
+// Finds the next largest ApiVersion of the config pointed to by the iterator `start`.
+ApiVersion FindNextApiVersionForConfigInSortedVector(
+ std::vector<std::unique_ptr<ResourceConfigValue>>::const_iterator start,
+ std::vector<std::unique_ptr<ResourceConfigValue>>::const_iterator end);
+
class AutoVersioner : public IResourceTableConsumer {
public:
AutoVersioner() = default;
diff --git a/tools/aapt2/readme.md b/tools/aapt2/readme.md
index ebcd4698d8d5..8c476fac3b89 100644
--- a/tools/aapt2/readme.md
+++ b/tools/aapt2/readme.md
@@ -9,6 +9,7 @@
(bug 62839863)
- Fixed issue where Java classes referenced from fragments and menus were not added to
the set of Proguard keep rules. (bug 62216174)
+- Automatically version XML `<adaptive-icon>` resources to v26. (bug 62316340)
## Version 2.17
### `aapt2 ...`
diff --git a/tools/aapt2/util/TypeTraits.h b/tools/aapt2/util/TypeTraits.h
index b6539edce6d9..6fcb4bdb4145 100644
--- a/tools/aapt2/util/TypeTraits.h
+++ b/tools/aapt2/util/TypeTraits.h
@@ -38,6 +38,7 @@ namespace aapt {
DEFINE_HAS_BINARY_OP_TRAIT(has_eq_op, ==);
DEFINE_HAS_BINARY_OP_TRAIT(has_lt_op, <);
+DEFINE_HAS_BINARY_OP_TRAIT(has_lte_op, <=);
/**
* Type trait that checks if two types can be equated (==) and compared (<).
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index 386f74b0301a..8bca9dd739bf 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -48,6 +48,11 @@ template <typename T>
struct Range {
T start;
T end;
+
+ typename std::enable_if<has_lte_op<const T, const T>::value, bool>::type Contains(
+ const T& t) const {
+ return start <= t && t < end;
+ }
};
std::vector<std::string> Split(const android::StringPiece& str, char sep);
diff --git a/tools/aapt2/xml/XmlUtil.cpp b/tools/aapt2/xml/XmlUtil.cpp
index fb8cee8b5634..fa1b0f049678 100644
--- a/tools/aapt2/xml/XmlUtil.cpp
+++ b/tools/aapt2/xml/XmlUtil.cpp
@@ -80,5 +80,65 @@ void TransformReferenceFromNamespace(IPackageDeclStack* decl_stack,
}
}
+namespace {
+
+struct TagCompat {
+ ApiVersion api_version;
+
+ enum class XmlType {
+ kVector,
+ kTransition,
+ kAdaptiveIcon,
+ };
+
+ XmlType type;
+};
+
+std::unordered_map<StringPiece, TagCompat> sTagVersions = {
+ {"fade", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}},
+ {"changeBounds", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}},
+ {"slide", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}},
+ {"explode", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}},
+ {"changeImageTransform", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}},
+ {"changeTransform", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}},
+ {"changeClipBounds", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}},
+ {"autoTransition", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}},
+ {"recolor", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}},
+ {"changeScroll", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}},
+ {"transitionSet", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}},
+ {"transition", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}},
+ {"transitionManager", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}},
+
+ {"vector", {SDK_LOLLIPOP, TagCompat::XmlType::kVector}},
+ {"animated-vector", {SDK_LOLLIPOP, TagCompat::XmlType::kVector}},
+ {"pathInterpolator", {SDK_LOLLIPOP, TagCompat::XmlType::kVector}},
+ {"objectAnimator", {SDK_LOLLIPOP, TagCompat::XmlType::kVector}},
+
+ {"adaptive-icon", {SDK_O, TagCompat::XmlType::kAdaptiveIcon}},
+};
+
+} // namespace
+
+Maybe<TagApiVersionResult> GetXmlTagApiVersion(const StringPiece& tag_name, int options) {
+ auto iter = sTagVersions.find(tag_name);
+ if (iter == sTagVersions.end()) {
+ return {};
+ }
+
+ const TagCompat& tag_compat = iter->second;
+ if (options & kNoVersionVector) {
+ if (tag_compat.type == TagCompat::XmlType::kVector) {
+ return TagApiVersionResult{{}, true /*skip_version*/};
+ }
+ }
+
+ if (options & kNoVersionTransition) {
+ if (tag_compat.type == TagCompat::XmlType::kTransition) {
+ return TagApiVersionResult{{}, true /*skip_version*/};
+ }
+ }
+ return TagApiVersionResult{tag_compat.api_version, false /*skip_version*/};
+}
+
} // namespace xml
} // namespace aapt
diff --git a/tools/aapt2/xml/XmlUtil.h b/tools/aapt2/xml/XmlUtil.h
index 1650ac2124ac..552f42adc464 100644
--- a/tools/aapt2/xml/XmlUtil.h
+++ b/tools/aapt2/xml/XmlUtil.h
@@ -20,18 +20,16 @@
#include <string>
#include "ResourceValues.h"
+#include "SdkConstants.h"
#include "util/Maybe.h"
namespace aapt {
namespace xml {
constexpr const char* kSchemaAuto = "http://schemas.android.com/apk/res-auto";
-constexpr const char* kSchemaPublicPrefix =
- "http://schemas.android.com/apk/res/";
-constexpr const char* kSchemaPrivatePrefix =
- "http://schemas.android.com/apk/prv/res/";
-constexpr const char* kSchemaAndroid =
- "http://schemas.android.com/apk/res/android";
+constexpr const char* kSchemaPublicPrefix = "http://schemas.android.com/apk/res/";
+constexpr const char* kSchemaPrivatePrefix = "http://schemas.android.com/apk/prv/res/";
+constexpr const char* kSchemaAndroid = "http://schemas.android.com/apk/res/android";
constexpr const char* kSchemaTools = "http://schemas.android.com/tools";
constexpr const char* kSchemaAapt = "http://schemas.android.com/aapt";
@@ -102,6 +100,24 @@ struct IPackageDeclStack {
void TransformReferenceFromNamespace(IPackageDeclStack* decl_stack,
const android::StringPiece& local_package, Reference* in_ref);
+struct TagApiVersionResult {
+ // If set, the API version to apply.
+ Maybe<ApiVersion> api_version;
+
+ // Whether to skip any auto-versioning.
+ bool skip_version;
+};
+
+enum TagVersionOptions : int {
+ // Skip versioning XML resources that deal with vector drawables.
+ kNoVersionVector,
+
+ // Skip versioning XML resources that deal with transitions.
+ kNoVersionTransition,
+};
+
+Maybe<TagApiVersionResult> GetXmlTagApiVersion(const android::StringPiece& tag_name, int options);
+
} // namespace xml
} // namespace aapt