summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--api/current.txt207
-rw-r--r--api/removed.txt8
-rw-r--r--api/system-current.txt318
-rw-r--r--api/system-removed.txt8
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java7
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java26
-rw-r--r--core/java/android/app/Activity.java123
-rw-r--r--core/java/android/app/ActivityManager.java3
-rw-r--r--core/java/android/app/ActivityView.java7
-rw-r--r--core/java/android/app/ApplicationPackageManager.java15
-rw-r--r--core/java/android/app/AssistStructure.java305
-rw-r--r--core/java/android/app/ContextImpl.java9
-rw-r--r--core/java/android/app/Fragment.java101
-rw-r--r--core/java/android/app/SystemServiceRegistry.java8
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java194
-rw-r--r--core/java/android/app/admin/DevicePolicyManagerInternal.java9
-rw-r--r--core/java/android/app/usage/NetworkStatsManager.java233
-rw-r--r--core/java/android/app/usage/NetworkUsageStats.java479
-rw-r--r--core/java/android/bluetooth/le/ScanSettings.java9
-rw-r--r--core/java/android/content/Context.java34
-rw-r--r--core/java/android/content/ContextWrapper.java5
-rw-r--r--core/java/android/content/Intent.java60
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java12
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl44
-rw-r--r--core/java/android/content/pm/PackageInfo.java5
-rw-r--r--core/java/android/content/pm/PackageManager.java139
-rw-r--r--core/java/android/content/pm/PackageParser.java70
-rw-r--r--core/java/android/content/res/ColorStateList.java27
-rw-r--r--core/java/android/content/res/Configuration.java3
-rw-r--r--core/java/android/content/res/Resources.java51
-rw-r--r--core/java/android/database/DatabaseErrorHandler.java5
-rwxr-xr-xcore/java/android/database/DefaultDatabaseErrorHandler.java4
-rw-r--r--core/java/android/hardware/SystemSensorManager.java27
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java3
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java3
-rw-r--r--core/java/android/net/ConnectivityManager.java2
-rw-r--r--core/java/android/net/INetworkStatsService.aidl8
-rw-r--r--core/java/android/net/INetworkStatsSession.aidl6
-rw-r--r--core/java/android/net/NetworkCapabilities.java4
-rw-r--r--core/java/android/net/NetworkStats.java41
-rw-r--r--core/java/android/os/BatteryStats.java1010
-rw-r--r--core/java/android/os/IPowerManager.aidl2
-rw-r--r--core/java/android/os/PowerManager.java51
-rw-r--r--core/java/android/os/PowerManagerInternal.java4
-rw-r--r--core/java/android/os/storage/IMountService.java25
-rw-r--r--core/java/android/preference/Preference.java6
-rw-r--r--core/java/android/provider/ContactsContract.java14
-rw-r--r--core/java/android/provider/Settings.java10
-rw-r--r--core/java/android/security/IKeystoreService.aidl8
-rw-r--r--core/java/android/security/NetworkSecurityPolicy.java79
-rw-r--r--core/java/android/security/keymaster/KeymasterBlob.aidl20
-rw-r--r--core/java/android/security/keymaster/KeymasterBlob.java55
-rw-r--r--core/java/android/security/keymaster/KeymasterBlobArgument.java7
-rw-r--r--core/java/android/security/keymaster/KeymasterBooleanArgument.java6
-rw-r--r--core/java/android/security/keymaster/KeymasterDateArgument.java6
-rw-r--r--core/java/android/security/keymaster/KeymasterIntArgument.java9
-rw-r--r--core/java/android/security/keymaster/KeymasterLongArgument.java6
-rw-r--r--core/java/android/service/fingerprint/Fingerprint.aidl19
-rw-r--r--core/java/android/service/fingerprint/Fingerprint.java93
-rw-r--r--core/java/android/service/fingerprint/FingerprintManager.java566
-rw-r--r--core/java/android/service/fingerprint/FingerprintManagerReceiver.java76
-rw-r--r--core/java/android/service/fingerprint/FingerprintUtils.java2
-rw-r--r--core/java/android/service/fingerprint/IFingerprintService.aidl37
-rw-r--r--core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl10
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java42
-rw-r--r--core/java/android/text/Html.java16
-rw-r--r--core/java/android/text/Layout.java5
-rw-r--r--core/java/android/text/StaticLayout.java55
-rw-r--r--core/java/android/text/style/URLSpan.java8
-rw-r--r--core/java/android/util/IntArray.java26
-rw-r--r--core/java/android/view/LayoutInflater.java183
-rw-r--r--core/java/android/view/PhoneFallbackEventHandler.java100
-rw-r--r--core/java/android/view/PhoneWindow.java22
-rw-r--r--core/java/android/view/TextureView.java6
-rw-r--r--core/java/android/view/View.java359
-rw-r--r--core/java/android/view/ViewRootImpl.java29
-rw-r--r--core/java/android/view/Window.java4
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java12
-rw-r--r--core/java/android/webkit/WebChromeClient.java8
-rw-r--r--core/java/android/widget/AppSecurityPermissions.java8
-rw-r--r--core/java/android/widget/CalendarView.java199
-rw-r--r--core/java/android/widget/CalendarViewLegacyDelegate.java9
-rw-r--r--core/java/android/widget/CalendarViewMaterialDelegate.java160
-rw-r--r--core/java/android/widget/DatePicker.java47
-rwxr-xr-xcore/java/android/widget/DatePickerCalendarDelegate.java504
-rw-r--r--core/java/android/widget/DayPickerAdapter.java283
-rw-r--r--core/java/android/widget/DayPickerView.java560
-rw-r--r--core/java/android/widget/Editor.java107
-rw-r--r--core/java/android/widget/FrameLayout.java326
-rw-r--r--core/java/android/widget/Gallery.java20
-rw-r--r--core/java/android/widget/ListPopupWindow.java35
-rw-r--r--core/java/android/widget/PopupWindow.java123
-rw-r--r--core/java/android/widget/RadialTimePickerView.java25
-rw-r--r--core/java/android/widget/SimpleMonthAdapter.java220
-rw-r--r--core/java/android/widget/SimpleMonthView.java695
-rw-r--r--core/java/android/widget/TextViewWithCircularIndicator.java87
-rw-r--r--core/java/android/widget/YearPickerView.java245
-rw-r--r--core/java/com/android/internal/content/NativeLibraryHelper.java31
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodUtils.java72
-rw-r--r--core/java/com/android/internal/logging/EventLogTags.logtags7
-rw-r--r--core/java/com/android/internal/logging/MetricsConstants.java153
-rw-r--r--core/java/com/android/internal/logging/MetricsLogger.java47
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java1155
-rw-r--r--core/java/com/android/internal/os/KernelWakelockReader.java192
-rw-r--r--core/java/com/android/internal/os/KernelWakelockStats.java37
-rw-r--r--core/java/com/android/internal/util/Protocol.java1
-rw-r--r--core/java/com/android/internal/util/ScreenShapeHelper.java48
-rw-r--r--core/java/com/android/internal/widget/AccessibleDateAnimator.java56
-rw-r--r--core/java/com/android/internal/widget/FloatingToolbar.java596
-rw-r--r--core/java/com/android/internal/widget/ViewPager.java34
-rw-r--r--core/jni/AndroidRuntime.cpp24
-rw-r--r--core/jni/android/graphics/MinikinUtils.cpp35
-rw-r--r--core/jni/android/graphics/MinikinUtils.h20
-rw-r--r--core/jni/android/graphics/Paint.cpp10
-rw-r--r--core/jni/android/graphics/TypefaceImpl.h2
-rw-r--r--core/jni/android_hardware_SensorManager.cpp23
-rw-r--r--core/jni/android_server_FingerprintManager.cpp43
-rw-r--r--core/jni/android_text_StaticLayout.cpp619
-rw-r--r--core/jni/com_android_internal_content_NativeLibraryHelper.cpp46
-rw-r--r--core/res/AndroidManifest.xml5
-rw-r--r--core/res/res/anim/ic_checkbox_checked_box_inner_merged_animation.xml52
-rw-r--r--core/res/res/anim/ic_checkbox_checked_check_path_merged_animation.xml42
-rw-r--r--core/res/res/anim/ic_checkbox_checked_icon_null_animation.xml50
-rw-r--r--core/res/res/anim/ic_checkbox_unchecked_box_inner_merged_animation.xml42
-rw-r--r--core/res/res/anim/ic_checkbox_unchecked_box_outer_merged_animation.xml52
-rw-r--r--core/res/res/anim/ic_checkbox_unchecked_icon_null_animation.xml50
-rw-r--r--core/res/res/color/date_picker_header_text_material.xml2
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_off_mtrl_000.pngbin900 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_off_mtrl_001.pngbin835 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_off_mtrl_002.pngbin699 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_off_mtrl_003.pngbin669 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_off_mtrl_004.pngbin613 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_off_mtrl_005.pngbin610 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_off_mtrl_006.pngbin597 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_off_mtrl_007.pngbin763 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_off_mtrl_008.pngbin758 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_off_mtrl_009.pngbin693 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_off_mtrl_010.pngbin664 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_off_mtrl_011.pngbin614 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_off_mtrl_012.pngbin579 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_off_mtrl_013.pngbin581 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_off_mtrl_014.pngbin602 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_off_mtrl_015.pngbin602 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_on_mtrl_000.pngbin602 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_on_mtrl_001.pngbin673 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_on_mtrl_002.pngbin696 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_on_mtrl_003.pngbin588 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_on_mtrl_004.pngbin544 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_on_mtrl_005.pngbin548 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_on_mtrl_006.pngbin648 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_on_mtrl_007.pngbin647 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_on_mtrl_008.pngbin763 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_on_mtrl_009.pngbin827 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_on_mtrl_010.pngbin810 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_on_mtrl_011.pngbin906 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_on_mtrl_012.pngbin872 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_on_mtrl_013.pngbin882 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_on_mtrl_014.pngbin903 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_check_to_on_mtrl_015.pngbin900 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_off_mtrl_000.pngbin724 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_off_mtrl_001.pngbin695 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_off_mtrl_002.pngbin611 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_off_mtrl_003.pngbin572 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_off_mtrl_004.pngbin571 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_off_mtrl_005.pngbin530 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_off_mtrl_006.pngbin568 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_off_mtrl_007.pngbin598 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_off_mtrl_008.pngbin619 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_off_mtrl_009.pngbin572 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_off_mtrl_010.pngbin604 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_off_mtrl_011.pngbin539 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_off_mtrl_012.pngbin573 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_off_mtrl_013.pngbin566 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_off_mtrl_014.pngbin606 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_off_mtrl_015.pngbin595 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_on_mtrl_000.pngbin595 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_on_mtrl_001.pngbin568 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_on_mtrl_002.pngbin581 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_on_mtrl_003.pngbin495 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_on_mtrl_004.pngbin536 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_on_mtrl_005.pngbin518 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_on_mtrl_006.pngbin567 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_on_mtrl_007.pngbin578 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_on_mtrl_008.pngbin615 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_on_mtrl_009.pngbin693 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_on_mtrl_010.pngbin677 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_on_mtrl_011.pngbin674 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_on_mtrl_012.pngbin685 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_on_mtrl_013.pngbin708 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_on_mtrl_014.pngbin708 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_check_to_on_mtrl_015.pngbin724 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_000.pngbin910 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_001.pngbin928 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_002.pngbin826 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_003.pngbin762 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_004.pngbin755 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_005.pngbin682 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_006.pngbin687 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_007.pngbin854 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_008.pngbin777 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_009.pngbin751 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_010.pngbin767 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_011.pngbin757 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_012.pngbin734 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_013.pngbin709 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_014.pngbin708 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_015.pngbin719 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_000.pngbin719 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_001.pngbin783 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_002.pngbin824 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_003.pngbin661 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_004.pngbin622 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_005.pngbin613 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_006.pngbin739 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_007.pngbin744 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_008.pngbin889 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_009.pngbin906 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_010.pngbin942 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_011.pngbin894 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_012.pngbin949 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_013.pngbin944 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_014.pngbin942 -> 0 bytes
-rw-r--r--core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_015.pngbin910 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_000.pngbin1210 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_001.pngbin1232 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_002.pngbin1064 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_003.pngbin960 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_004.pngbin935 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_005.pngbin874 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_006.pngbin876 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_007.pngbin1123 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_008.pngbin1033 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_009.pngbin921 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_010.pngbin826 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_011.pngbin888 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_012.pngbin866 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_013.pngbin854 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_014.pngbin851 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_015.pngbin822 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_000.pngbin822 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_001.pngbin943 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_002.pngbin1051 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_003.pngbin861 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_004.pngbin749 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_005.pngbin688 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_006.pngbin948 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_007.pngbin934 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_008.pngbin1204 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_009.pngbin1283 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_010.pngbin1363 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_011.pngbin1309 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_012.pngbin1240 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_013.pngbin1240 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_014.pngbin1220 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_015.pngbin1210 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_000.pngbin881 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_001.pngbin895 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_002.pngbin804 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_003.pngbin743 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_004.pngbin690 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_005.pngbin626 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_006.pngbin662 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_007.pngbin765 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_008.pngbin711 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_009.pngbin726 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_010.pngbin671 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_011.pngbin604 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_012.pngbin621 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_013.pngbin647 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_014.pngbin623 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_015.pngbin588 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_000.pngbin588 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_001.pngbin703 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_002.pngbin806 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_003.pngbin629 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_004.pngbin547 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_005.pngbin545 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_006.pngbin698 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_007.pngbin721 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_008.pngbin817 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_009.pngbin879 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_010.pngbin955 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_011.pngbin977 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_012.pngbin906 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_013.pngbin913 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_014.pngbin914 -> 0 bytes
-rw-r--r--core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_015.pngbin881 -> 0 bytes
-rw-r--r--core/res/res/drawable/btn_check_material_anim.xml164
-rw-r--r--core/res/res/drawable/ic_checkbox_checked.xml52
-rw-r--r--core/res/res/drawable/ic_checkbox_checked_animation.xml30
-rw-r--r--core/res/res/drawable/ic_checkbox_unchecked.xml52
-rw-r--r--core/res/res/drawable/ic_checkbox_unchecked_animation.xml30
-rw-r--r--core/res/res/drawable/pointer_arrow_icon.xml4
-rw-r--r--core/res/res/interpolator/ic_checkbox_checked_animation_interpolator_0.xml (renamed from core/res/res/drawable/time_picker_header_material.xml)10
-rw-r--r--core/res/res/interpolator/ic_checkbox_checked_animation_interpolator_1.xml (renamed from core/res/res/layout/date_picker_view_animator.xml)13
-rw-r--r--core/res/res/interpolator/ic_checkbox_unchecked_animation_interpolator_0.xml20
-rw-r--r--core/res/res/interpolator/ic_checkbox_unchecked_animation_interpolator_1.xml20
-rw-r--r--core/res/res/layout-land/date_picker_holo.xml32
-rw-r--r--core/res/res/layout-land/date_picker_material.xml49
-rw-r--r--core/res/res/layout-watch/progress_dialog_material.xml47
-rw-r--r--core/res/res/layout/alert_dialog_button_bar_material.xml8
-rw-r--r--core/res/res/layout/date_picker_header_material.xml54
-rw-r--r--core/res/res/layout/date_picker_material.xml (renamed from core/res/res/layout/date_picker_holo.xml)14
-rw-r--r--core/res/res/layout/date_picker_selected_date.xml73
-rw-r--r--core/res/res/layout/date_picker_view_animator_material.xml38
-rw-r--r--core/res/res/layout/floating_popup_container.xml25
-rw-r--r--core/res/res/layout/floating_popup_menu_button.xml31
-rw-r--r--core/res/res/layout/floating_popup_open_overflow_button.xml25
-rw-r--r--core/res/res/layout/year_label_text_view.xml15
-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.xml2
-rw-r--r--core/res/res/values-bg/strings.xml2
-rw-r--r--core/res/res/values-bn-rBD/strings.xml2
-rw-r--r--core/res/res/values-ca/strings.xml2
-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.xml4
-rw-r--r--core/res/res/values-el/strings.xml2
-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.xml2
-rw-r--r--core/res/res/values-es/strings.xml2
-rw-r--r--core/res/res/values-et-rEE/strings.xml2
-rw-r--r--core/res/res/values-eu-rES/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.xml2
-rw-r--r--core/res/res/values-fr/strings.xml2
-rw-r--r--core/res/res/values-gl-rES/strings.xml2
-rw-r--r--core/res/res/values-hi/strings.xml10
-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-rAM/strings.xml2
-rw-r--r--core/res/res/values-in/strings.xml2
-rw-r--r--core/res/res/values-is-rIS/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.xml2
-rw-r--r--core/res/res/values-ka-rGE/strings.xml2
-rw-r--r--core/res/res/values-kk-rKZ/strings.xml2
-rw-r--r--core/res/res/values-km-rKH/strings.xml2
-rw-r--r--core/res/res/values-kn-rIN/strings.xml2
-rw-r--r--core/res/res/values-ko/strings.xml2
-rw-r--r--core/res/res/values-ky-rKG/strings.xml2
-rw-r--r--core/res/res/values-land/dimens_material.xml10
-rw-r--r--core/res/res/values-lo-rLA/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-mcc310-mnc260/strings.xml2
-rw-r--r--core/res/res/values-mk-rMK/strings.xml2
-rw-r--r--core/res/res/values-ml-rIN/strings.xml2
-rw-r--r--core/res/res/values-mn-rMN/strings.xml2
-rw-r--r--core/res/res/values-mr-rIN/strings.xml2
-rw-r--r--core/res/res/values-ms-rMY/strings.xml2
-rw-r--r--core/res/res/values-my-rMM/strings.xml2
-rw-r--r--core/res/res/values-nb/strings.xml2
-rw-r--r--core/res/res/values-ne-rNP/strings.xml2
-rw-r--r--core/res/res/values-nl/strings.xml2
-rw-r--r--core/res/res/values-pl/strings.xml2
-rw-r--r--core/res/res/values-pt-rPT/strings.xml2
-rw-r--r--core/res/res/values-pt/strings.xml2
-rw-r--r--core/res/res/values-ro/strings.xml2
-rw-r--r--core/res/res/values-ru/strings.xml2
-rw-r--r--core/res/res/values-si-rLK/strings.xml2
-rw-r--r--core/res/res/values-sk/strings.xml2
-rw-r--r--core/res/res/values-sl/strings.xml2
-rw-r--r--core/res/res/values-sr/strings.xml2
-rw-r--r--core/res/res/values-sv/strings.xml2
-rw-r--r--core/res/res/values-sw/strings.xml2
-rw-r--r--core/res/res/values-ta-rIN/strings.xml2
-rw-r--r--core/res/res/values-te-rIN/strings.xml2
-rw-r--r--core/res/res/values-th/strings.xml2
-rw-r--r--core/res/res/values-tl/strings.xml2
-rw-r--r--core/res/res/values-tr/strings.xml2
-rw-r--r--core/res/res/values-uk/strings.xml2
-rw-r--r--core/res/res/values-ur-rPK/strings.xml2
-rw-r--r--core/res/res/values-uz-rUZ/strings.xml2
-rw-r--r--core/res/res/values-vi/strings.xml2
-rw-r--r--core/res/res/values-zh-rCN/strings.xml5
-rw-r--r--core/res/res/values-zh-rHK/strings.xml2
-rw-r--r--core/res/res/values-zh-rTW/strings.xml2
-rw-r--r--core/res/res/values-zu/strings.xml2
-rw-r--r--core/res/res/values/attrs.xml231
-rw-r--r--core/res/res/values/attrs_manifest.xml33
-rw-r--r--core/res/res/values/colors_material.xml48
-rwxr-xr-xcore/res/res/values/config.xml12
-rw-r--r--core/res/res/values/dimens.xml7
-rw-r--r--core/res/res/values/dimens_material.xml24
-rw-r--r--core/res/res/values/ids.xml1
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--core/res/res/values/strings.xml50
-rw-r--r--core/res/res/values/styles_material.xml82
-rwxr-xr-xcore/res/res/values/symbols.xml68
-rw-r--r--core/res/res/values/themes_material.xml6
-rw-r--r--core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java82
-rw-r--r--core/tests/coretests/apks/install_jni_lib/Android.mk8
-rw-r--r--core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp6
-rw-r--r--core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk11
-rw-r--r--core/tests/coretests/apks/install_jni_lib_open_from_apk/AndroidManifest.xml28
-rw-r--r--core/tests/coretests/apks/install_jni_lib_open_from_apk/res/values/strings.xml19
-rw-r--r--core/tests/coretests/apks/install_jni_lib_open_from_apk/src/com/android/frameworks/coretests/JNITests.java26
-rw-r--r--core/tests/coretests/apks/install_jni_lib_open_from_apk/src/com/android/frameworks/coretests/OpenFromApkActivity.java38
-rw-r--r--core/tests/coretests/src/android/net/NetworkStatsTest.java31
-rw-r--r--data/etc/platform.xml4
-rw-r--r--data/fonts/Android.mk3
-rw-r--r--docs/html/google/auth/http-auth.jd2
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java141
-rw-r--r--graphics/java/android/graphics/drawable/BitmapDrawable.java12
-rw-r--r--graphics/java/android/graphics/drawable/VectorDrawable.java21
-rw-r--r--keystore/java/android/security/KeyStore.java6
-rw-r--r--keystore/tests/src/android/security/KeyStoreTest.java22
-rw-r--r--libs/hwui/DisplayListRenderer.cpp2
-rw-r--r--libs/hwui/DisplayListRenderer.h3
-rw-r--r--libs/hwui/ShadowTessellator.cpp1
-rw-r--r--libs/hwui/TessellationCache.cpp1
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp1
-rw-r--r--libs/hwui/thread/Signal.h6
-rw-r--r--libs/hwui/thread/TaskManager.cpp7
-rw-r--r--media/java/android/media/AudioManager.java28
-rw-r--r--media/java/android/media/AudioRecord.java166
-rw-r--r--media/java/android/media/MediaDescription.java32
-rw-r--r--media/java/android/media/MediaDrm.java26
-rw-r--r--media/java/android/media/MediaRecorder.java7
-rw-r--r--media/java/android/media/MediaRouter.java6
-rw-r--r--media/java/android/media/SoundPool.java591
-rw-r--r--media/java/android/media/session/ISessionCallback.aidl5
-rw-r--r--media/java/android/media/session/ISessionController.aidl5
-rw-r--r--media/java/android/media/session/MediaController.java27
-rw-r--r--media/java/android/media/session/MediaSession.java23
-rw-r--r--media/java/android/media/session/PlaybackState.java17
-rw-r--r--media/java/android/media/tv/TvContract.java44
-rw-r--r--media/java/android/media/tv/TvInputService.java15
-rw-r--r--media/jni/android_media_ImageWriter.cpp2
-rw-r--r--media/jni/android_media_MediaDrm.cpp41
-rw-r--r--media/jni/soundpool/Android.mk2
-rw-r--r--media/jni/soundpool/android_media_SoundPool.cpp (renamed from media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp)90
-rw-r--r--packages/DocumentsUI/AndroidManifest.xml13
-rw-r--r--packages/DocumentsUI/res/values/styles.xml18
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java152
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java6
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java26
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java12
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java143
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/PickFragment.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java8
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsCache.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java14
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java6
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java952
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java110
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java19
-rw-r--r--packages/PrintSpooler/res/values-hi/strings.xml2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java3
-rw-r--r--packages/Shell/AndroidManifest.xml12
-rw-r--r--packages/Shell/res/values-af/strings.xml2
-rw-r--r--packages/Shell/res/values-am/strings.xml2
-rw-r--r--packages/Shell/res/values-ar/strings.xml2
-rw-r--r--packages/Shell/res/values-bg/strings.xml2
-rw-r--r--packages/Shell/res/values-bn-rBD/strings.xml2
-rw-r--r--packages/Shell/res/values-ca/strings.xml2
-rw-r--r--packages/Shell/res/values-cs/strings.xml2
-rw-r--r--packages/Shell/res/values-da/strings.xml2
-rw-r--r--packages/Shell/res/values-de/strings.xml2
-rw-r--r--packages/Shell/res/values-el/strings.xml2
-rw-r--r--packages/Shell/res/values-en-rAU/strings.xml2
-rw-r--r--packages/Shell/res/values-en-rGB/strings.xml2
-rw-r--r--packages/Shell/res/values-en-rIN/strings.xml2
-rw-r--r--packages/Shell/res/values-es-rUS/strings.xml2
-rw-r--r--packages/Shell/res/values-es/strings.xml2
-rw-r--r--packages/Shell/res/values-et-rEE/strings.xml2
-rw-r--r--packages/Shell/res/values-eu-rES/strings.xml2
-rw-r--r--packages/Shell/res/values-fa/strings.xml2
-rw-r--r--packages/Shell/res/values-fi/strings.xml2
-rw-r--r--packages/Shell/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/Shell/res/values-fr/strings.xml2
-rw-r--r--packages/Shell/res/values-gl-rES/strings.xml2
-rw-r--r--packages/Shell/res/values-hi/strings.xml2
-rw-r--r--packages/Shell/res/values-hr/strings.xml2
-rw-r--r--packages/Shell/res/values-hu/strings.xml2
-rw-r--r--packages/Shell/res/values-hy-rAM/strings.xml2
-rw-r--r--packages/Shell/res/values-in/strings.xml2
-rw-r--r--packages/Shell/res/values-is-rIS/strings.xml2
-rw-r--r--packages/Shell/res/values-it/strings.xml2
-rw-r--r--packages/Shell/res/values-iw/strings.xml2
-rw-r--r--packages/Shell/res/values-ja/strings.xml2
-rw-r--r--packages/Shell/res/values-ka-rGE/strings.xml2
-rw-r--r--packages/Shell/res/values-kk-rKZ/strings.xml2
-rw-r--r--packages/Shell/res/values-km-rKH/strings.xml2
-rw-r--r--packages/Shell/res/values-kn-rIN/strings.xml2
-rw-r--r--packages/Shell/res/values-ko/strings.xml2
-rw-r--r--packages/Shell/res/values-ky-rKG/strings.xml2
-rw-r--r--packages/Shell/res/values-lo-rLA/strings.xml2
-rw-r--r--packages/Shell/res/values-lt/strings.xml2
-rw-r--r--packages/Shell/res/values-lv/strings.xml2
-rw-r--r--packages/Shell/res/values-mk-rMK/strings.xml2
-rw-r--r--packages/Shell/res/values-ml-rIN/strings.xml2
-rw-r--r--packages/Shell/res/values-mn-rMN/strings.xml2
-rw-r--r--packages/Shell/res/values-mr-rIN/strings.xml2
-rw-r--r--packages/Shell/res/values-ms-rMY/strings.xml2
-rw-r--r--packages/Shell/res/values-my-rMM/strings.xml2
-rw-r--r--packages/Shell/res/values-nb/strings.xml2
-rw-r--r--packages/Shell/res/values-ne-rNP/strings.xml2
-rw-r--r--packages/Shell/res/values-nl/strings.xml2
-rw-r--r--packages/Shell/res/values-pl/strings.xml2
-rw-r--r--packages/Shell/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/Shell/res/values-pt/strings.xml2
-rw-r--r--packages/Shell/res/values-ro/strings.xml2
-rw-r--r--packages/Shell/res/values-ru/strings.xml2
-rw-r--r--packages/Shell/res/values-si-rLK/strings.xml2
-rw-r--r--packages/Shell/res/values-sk/strings.xml2
-rw-r--r--packages/Shell/res/values-sl/strings.xml2
-rw-r--r--packages/Shell/res/values-sr/strings.xml2
-rw-r--r--packages/Shell/res/values-sv/strings.xml2
-rw-r--r--packages/Shell/res/values-sw/strings.xml2
-rw-r--r--packages/Shell/res/values-ta-rIN/strings.xml2
-rw-r--r--packages/Shell/res/values-te-rIN/strings.xml2
-rw-r--r--packages/Shell/res/values-th/strings.xml2
-rw-r--r--packages/Shell/res/values-tl/strings.xml2
-rw-r--r--packages/Shell/res/values-tr/strings.xml2
-rw-r--r--packages/Shell/res/values-uk/strings.xml2
-rw-r--r--packages/Shell/res/values-ur-rPK/strings.xml2
-rw-r--r--packages/Shell/res/values-uz-rUZ/strings.xml2
-rw-r--r--packages/Shell/res/values-vi/strings.xml2
-rw-r--r--packages/Shell/res/values-zh-rCN/strings.xml2
-rw-r--r--packages/Shell/res/values-zh-rHK/strings.xml2
-rw-r--r--packages/Shell/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/Shell/res/values-zu/strings.xml2
-rw-r--r--packages/Shell/res/values/strings.xml3
-rw-r--r--packages/Shell/src/com/android/shell/BugreportStorageProvider.java164
-rw-r--r--packages/SystemUI/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/res/drawable/vector_drawable_place_bottom.xml24
-rw-r--r--packages/SystemUI/res/drawable/vector_drawable_place_bottom_left.xml24
-rw-r--r--packages/SystemUI/res/drawable/vector_drawable_place_bottom_right.xml24
-rw-r--r--packages/SystemUI/res/drawable/vector_drawable_place_fullscreen.xml33
-rw-r--r--packages/SystemUI/res/drawable/vector_drawable_place_left.xml24
-rw-r--r--packages/SystemUI/res/drawable/vector_drawable_place_right.xml24
-rw-r--r--packages/SystemUI/res/drawable/vector_drawable_place_top.xml24
-rw-r--r--packages/SystemUI/res/drawable/vector_drawable_place_top_left.xml24
-rw-r--r--packages/SystemUI/res/drawable/vector_drawable_place_top_right.xml24
-rw-r--r--packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml51
-rw-r--r--packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml51
-rw-r--r--packages/SystemUI/res/layout-sw600dp/recents_task_resize_dialog.xml93
-rw-r--r--packages/SystemUI/res/layout/recents_multistack_stack_size_dialog.xml70
-rw-r--r--packages/SystemUI/res/values-af/strings.xml6
-rw-r--r--packages/SystemUI/res/values-am/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml6
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml6
-rw-r--r--packages/SystemUI/res/values-bn-rBD/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml6
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml6
-rw-r--r--packages/SystemUI/res/values-da/strings.xml6
-rw-r--r--packages/SystemUI/res/values-de/strings.xml6
-rw-r--r--packages/SystemUI/res/values-el/strings.xml5
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml6
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml6
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml6
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml6
-rw-r--r--packages/SystemUI/res/values-es/strings.xml5
-rw-r--r--packages/SystemUI/res/values-et-rEE/strings.xml6
-rw-r--r--packages/SystemUI/res/values-eu-rES/strings.xml6
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml6
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml6
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml6
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-gl-rES/strings.xml6
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml6
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml6
-rw-r--r--packages/SystemUI/res/values-hy-rAM/strings.xml6
-rw-r--r--packages/SystemUI/res/values-in/strings.xml6
-rw-r--r--packages/SystemUI/res/values-is-rIS/strings.xml6
-rw-r--r--packages/SystemUI/res/values-it/strings.xml5
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ka-rGE/strings.xml6
-rw-r--r--packages/SystemUI/res/values-kk-rKZ/strings.xml6
-rw-r--r--packages/SystemUI/res/values-km-rKH/strings.xml6
-rw-r--r--packages/SystemUI/res/values-kn-rIN/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ky-rKG/strings.xml7
-rw-r--r--packages/SystemUI/res/values-lo-rLA/strings.xml6
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml6
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml6
-rw-r--r--packages/SystemUI/res/values-mk-rMK/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ml-rIN/strings.xml6
-rw-r--r--packages/SystemUI/res/values-mn-rMN/strings.xml6
-rw-r--r--packages/SystemUI/res/values-mr-rIN/strings.xml5
-rw-r--r--packages/SystemUI/res/values-ms-rMY/strings.xml6
-rw-r--r--packages/SystemUI/res/values-my-rMM/strings.xml6
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ne-rNP/strings.xml5
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml6
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml6
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml6
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml6
-rw-r--r--packages/SystemUI/res/values-si-rLK/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ta-rIN/strings.xml6
-rw-r--r--packages/SystemUI/res/values-te-rIN/strings.xml6
-rw-r--r--packages/SystemUI/res/values-th/strings.xml6
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml6
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ur-rPK/strings.xml6
-rw-r--r--packages/SystemUI/res/values-uz-rUZ/strings.xml6
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml6
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml6
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml6
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml6
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml6
-rw-r--r--packages/SystemUI/res/values/strings.xml4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Recents.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java222
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java263
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java3
-rw-r--r--rs/java/android/renderscript/Allocation.java38
-rw-r--r--rs/java/android/renderscript/Element.java3
-rw-r--r--rs/java/android/renderscript/FileA3D.java3
-rw-r--r--rs/java/android/renderscript/Mesh.java6
-rw-r--r--rs/java/android/renderscript/RenderScript.java43
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java38
-rw-r--r--services/core/java/com/android/server/EventLogTags.logtags1
-rw-r--r--services/core/java/com/android/server/InputMethodManagerService.java98
-rw-r--r--services/core/java/com/android/server/MidiService.java39
-rw-r--r--services/core/java/com/android/server/MountService.java26
-rw-r--r--services/core/java/com/android/server/PersistentDataBlockService.java8
-rw-r--r--services/core/java/com/android/server/SystemConfig.java18
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java26
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java85
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java11
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java60
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java189
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java2
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java65
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java8
-rw-r--r--services/core/java/com/android/server/fingerprint/FingerprintService.java210
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java14
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java4
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java59
-rw-r--r--services/core/java/com/android/server/job/controllers/StateController.java6
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java14
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java24
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java14
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsCollection.java56
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java84
-rw-r--r--services/core/java/com/android/server/pm/BasePermission.java40
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java634
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java17
-rw-r--r--services/core/java/com/android/server/pm/PermissionsState.java532
-rw-r--r--services/core/java/com/android/server/pm/SettingBase.java (renamed from services/core/java/com/android/server/pm/GrantedPermissions.java)40
-rw-r--r--services/core/java/com/android/server/pm/Settings.java717
-rw-r--r--services/core/java/com/android/server/pm/SharedUserSetting.java2
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java1
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java4
-rw-r--r--services/core/java/com/android/server/power/DeviceIdleController.java (renamed from services/core/java/com/android/server/DeviceIdleController.java)83
-rw-r--r--services/core/java/com/android/server/power/Notifier.java38
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java48
-rw-r--r--services/core/java/com/android/server/trust/TrustAgentWrapper.java7
-rw-r--r--services/core/java/com/android/server/wm/DimLayer.java39
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java16
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java115
-rw-r--r--services/core/jni/com_android_server_UsbMidiDevice.cpp11
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java111
-rw-r--r--services/java/com/android/server/SystemServer.java78
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java36
-rw-r--r--services/usb/java/com/android/server/usb/UsbAlsaManager.java4
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java24
-rw-r--r--services/usb/java/com/android/server/usb/UsbMidiDevice.java17
-rw-r--r--telecomm/java/android/telecom/Call.java4
-rw-r--r--telecomm/java/android/telecom/Connection.java4
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java38
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl12
-rw-r--r--test-runner/src/android/test/mock/MockContext.java5
-rw-r--r--test-runner/src/android/test/mock/MockPackageManager.java4
-rw-r--r--tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java23
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java11
-rw-r--r--tools/layoutlib/.idea/libraries/guava.xml4
-rw-r--r--tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml10
-rw-r--r--tools/layoutlib/.idea/runConfigurations/Bridge_quick.xml29
-rw-r--r--tools/layoutlib/.idea/runConfigurations/Create.xml4
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java4
-rw-r--r--tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java63
-rw-r--r--tools/layoutlib/bridge/src/android/view/BridgeInflater.java6
-rw-r--r--tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java129
-rw-r--r--tools/layoutlib/bridge/src/android/view/RectShadowPainter.java156
-rw-r--r--tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java90
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java6
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java10
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java17
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java37
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java10
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java16
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java5
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle14
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/androidTest/debug/com/android/layoutlib/test/myapplication/test/BuildConfig.classbin0 -> 792 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/BuildConfig.classbin775 -> 777 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.classbin0 -> 1174 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.classbin0 -> 1300 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.pngbin3272 -> 8075 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradle/wrapper/gradle-wrapper.properties4
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/androidTest/java/com/android/layoulib/test/myapplication/ApplicationTest.java13
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomCalendar.java31
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomDate.java31
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/layout.xml24
-rw-r--r--tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java2
-rw-r--r--tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java19
-rw-r--r--wifi/java/android/net/wifi/IRttManager.aidl3
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl4
-rw-r--r--wifi/java/android/net/wifi/RttManager.aidl18
-rw-r--r--wifi/java/android/net/wifi/RttManager.java545
-rw-r--r--wifi/java/android/net/wifi/ScanResult.java43
-rw-r--r--wifi/java/android/net/wifi/WifiActivityEnergyInfo.java35
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java23
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java21
-rw-r--r--wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java2
738 files changed, 16805 insertions, 7967 deletions
diff --git a/Android.mk b/Android.mk
index 1df2af3aece9..2462d7339add 100644
--- a/Android.mk
+++ b/Android.mk
@@ -45,6 +45,7 @@ LOCAL_SRC_FILES += \
core/java/android/content/EventLogTags.logtags \
core/java/android/speech/tts/EventLogTags.logtags \
core/java/android/webkit/EventLogTags.logtags \
+ core/java/com/android/internal/logging/EventLogTags.logtags \
## READ ME: ########################################################
##
diff --git a/api/current.txt b/api/current.txt
index c004b15f4c35..4c761cecc8bf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -92,6 +92,7 @@ package android {
field public static final java.lang.String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS";
field public static final java.lang.String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
field public static final java.lang.String NFC = "android.permission.NFC";
+ field public static final java.lang.String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
field public static final deprecated java.lang.String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
field public static final java.lang.String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
field public static final java.lang.String READ_CALENDAR = "android.permission.READ_CALENDAR";
@@ -464,8 +465,8 @@ package android {
field public static final int datePickerMode = 16843955; // 0x10104b3
field public static final int datePickerStyle = 16843612; // 0x101035c
field public static final int dateTextAppearance = 16843593; // 0x1010349
- field public static final int dayOfWeekBackground = 16843924; // 0x1010494
- field public static final int dayOfWeekTextAppearance = 16843925; // 0x1010495
+ field public static final deprecated int dayOfWeekBackground = 16843924; // 0x1010494
+ field public static final deprecated int dayOfWeekTextAppearance = 16843925; // 0x1010495
field public static final int debuggable = 16842767; // 0x101000f
field public static final int defaultValue = 16843245; // 0x10101ed
field public static final int delay = 16843212; // 0x10101cc
@@ -555,6 +556,7 @@ package android {
field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
field public static final int exported = 16842768; // 0x1010010
field public static final int extraTension = 16843371; // 0x101026b
+ field public static final int extractNativeLibs = 16844008; // 0x10104e8
field public static final int factor = 16843219; // 0x10101d3
field public static final int fadeDuration = 16843384; // 0x1010278
field public static final int fadeEnabled = 16843390; // 0x101027e
@@ -587,7 +589,7 @@ package android {
field public static final int flipInterval = 16843129; // 0x1010179
field public static final int focusable = 16842970; // 0x10100da
field public static final int focusableInTouchMode = 16842971; // 0x10100db
- field public static final int focusedMonthDateColor = 16843587; // 0x1010343
+ field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
field public static final int footerDividersEnabled = 16843311; // 0x101022f
@@ -651,9 +653,9 @@ package android {
field public static final int hasCode = 16842764; // 0x101000c
field public static final int headerAmPmTextAppearance = 16843936; // 0x10104a0
field public static final int headerBackground = 16843055; // 0x101012f
- field public static final int headerDayOfMonthTextAppearance = 16843927; // 0x1010497
+ field public static final deprecated int headerDayOfMonthTextAppearance = 16843927; // 0x1010497
field public static final int headerDividersEnabled = 16843310; // 0x101022e
- field public static final int headerMonthTextAppearance = 16843926; // 0x1010496
+ field public static final deprecated int headerMonthTextAppearance = 16843926; // 0x1010496
field public static final int headerTimeTextAppearance = 16843935; // 0x101049f
field public static final int headerYearTextAppearance = 16843928; // 0x1010498
field public static final int height = 16843093; // 0x1010155
@@ -1094,8 +1096,8 @@ package android {
field public static final int selectable = 16843238; // 0x10101e6
field public static final int selectableItemBackground = 16843534; // 0x101030e
field public static final int selectableItemBackgroundBorderless = 16843868; // 0x101045c
- field public static final int selectedDateVerticalBar = 16843591; // 0x1010347
- field public static final int selectedWeekBackgroundColor = 16843586; // 0x1010342
+ field public static final deprecated int selectedDateVerticalBar = 16843591; // 0x1010347
+ field public static final deprecated int selectedWeekBackgroundColor = 16843586; // 0x1010342
field public static final int sessionService = 16843837; // 0x101043d
field public static final int settingsActivity = 16843301; // 0x1010225
field public static final int setupActivity = 16843766; // 0x10103f6
@@ -1114,8 +1116,8 @@ package android {
field public static final int showOnLockScreen = 16843721; // 0x10103c9
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showText = 16843949; // 0x10104ad
- field public static final int showWeekNumber = 16843582; // 0x101033e
- field public static final int shownWeekCount = 16843585; // 0x1010341
+ field public static final deprecated int showWeekNumber = 16843582; // 0x101033e
+ 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
field public static final int singleUser = 16843711; // 0x10103bf
@@ -1352,13 +1354,14 @@ package android {
field public static final int typeface = 16842902; // 0x1010096
field public static final int uiOptions = 16843672; // 0x1010398
field public static final int uncertainGestureColor = 16843382; // 0x1010276
- field public static final int unfocusedMonthDateColor = 16843588; // 0x1010344
+ field public static final deprecated int unfocusedMonthDateColor = 16843588; // 0x1010344
field public static final int unselectedAlpha = 16843278; // 0x101020e
field public static final int updatePeriodMillis = 16843344; // 0x1010250
field public static final int useDefaultMargins = 16843641; // 0x1010379
field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
field public static final int useLevel = 16843167; // 0x101019f
field public static final int userVisible = 16843409; // 0x1010291
+ field public static final int usesCleartextTraffic = 16844009; // 0x10104e9
field public static final int value = 16842788; // 0x1010024
field public static final int valueFrom = 16843486; // 0x10102de
field public static final int valueTo = 16843487; // 0x10102df
@@ -1394,8 +1397,8 @@ package android {
field public static final int webTextViewStyle = 16843449; // 0x10102b9
field public static final int webViewStyle = 16842885; // 0x1010085
field public static final int weekDayTextAppearance = 16843592; // 0x1010348
- field public static final int weekNumberColor = 16843589; // 0x1010345
- field public static final int weekSeparatorLineColor = 16843590; // 0x1010346
+ field public static final deprecated int weekNumberColor = 16843589; // 0x1010345
+ field public static final deprecated int weekSeparatorLineColor = 16843590; // 0x1010346
field public static final int weightSum = 16843048; // 0x1010128
field public static final int widgetCategory = 16843716; // 0x10103c4
field public static final int widgetLayout = 16843243; // 0x10101eb
@@ -1454,7 +1457,7 @@ package android {
field public static final int xlargeScreens = 16843455; // 0x10102bf
field public static final int y = 16842925; // 0x10100ad
field public static final int yearListItemTextAppearance = 16843929; // 0x1010499
- field public static final int yearListSelectorColor = 16843930; // 0x101049a
+ field public static final deprecated int yearListSelectorColor = 16843930; // 0x101049a
field public static final int yesNoPreferenceStyle = 16842896; // 0x1010090
field public static final int zAdjustment = 16843201; // 0x10101c1
}
@@ -3431,6 +3434,7 @@ package android.app {
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
method public void onProvideAssistContent(android.app.AssistContent);
method public void onProvideAssistData(android.os.Bundle);
+ method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
method protected void onRestart();
method protected void onRestoreInstanceState(android.os.Bundle);
method public void onRestoreInstanceState(android.os.Bundle, android.os.PersistableBundle);
@@ -3461,6 +3465,7 @@ package android.app {
method public boolean releaseInstance();
method public final deprecated void removeDialog(int);
method public void reportFullyDrawn();
+ method public final void requestPermissions(java.lang.String[], int);
method public boolean requestVisibleBehind(boolean);
method public final boolean requestWindowFeature(int);
method public final void runOnUiThread(java.lang.Runnable);
@@ -3977,22 +3982,25 @@ package android.app {
method public int describeContents();
method public android.content.ComponentName getActivityComponent();
method public static android.app.AssistStructure getAssistStructure(android.os.Bundle);
- method public void getWindowAt(int, android.app.AssistStructure.ViewNode);
- method public int getWindowCount();
+ method public android.app.AssistStructure.WindowNode getWindowNodeAt(int);
+ method public int getWindowNodeCount();
method public void writeToParcel(android.os.Parcel, int);
field public static final java.lang.String ASSIST_KEY = "android:assist_structure";
field public static final android.os.Parcelable.Creator<android.app.AssistStructure> CREATOR;
}
public static class AssistStructure.ViewNode {
- ctor public AssistStructure.ViewNode();
- method public void getChildAt(int, android.app.AssistStructure.ViewNode);
+ method public android.app.AssistStructure.ViewNode getChildAt(int);
method public int getChildCount();
method public java.lang.String getClassName();
- method public java.lang.String getContentDescription();
+ method public java.lang.CharSequence getContentDescription();
method public android.os.Bundle getExtras();
method public int getHeight();
method public java.lang.String getHint();
+ method public int getId();
+ method public java.lang.String getIdEntry();
+ method public java.lang.String getIdPackage();
+ method public java.lang.String getIdType();
method public int getLeft();
method public int getScrollX();
method public int getScrollY();
@@ -4023,6 +4031,15 @@ package android.app {
field public static final int TEXT_STYLE_UNDERLINE = 4; // 0x4
}
+ public static class AssistStructure.WindowNode {
+ method public int getHeight();
+ method public int getLeft();
+ method public android.app.AssistStructure.ViewNode getRootViewNode();
+ method public java.lang.CharSequence getTitle();
+ method public int getTop();
+ method public int getWidth();
+ }
+
public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
@@ -4303,6 +4320,7 @@ package android.app {
method public void onOptionsMenuClosed(android.view.Menu);
method public void onPause();
method public void onPrepareOptionsMenu(android.view.Menu);
+ method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
method public void onResume();
method public void onSaveInstanceState(android.os.Bundle);
method public void onStart();
@@ -4311,6 +4329,7 @@ package android.app {
method public void onViewCreated(android.view.View, android.os.Bundle);
method public void onViewStateRestored(android.os.Bundle);
method public void registerForContextMenu(android.view.View);
+ method public final void requestPermissions(java.lang.String[], int);
method public void setAllowEnterTransitionOverlap(boolean);
method public void setAllowReturnTransitionOverlap(boolean);
method public void setArguments(android.os.Bundle);
@@ -5663,12 +5682,18 @@ package android.app.admin {
field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
+ field public static final java.lang.String EXTRA_PROVISIONING_BT_DEVICE_ID = "android.app.extra.PROVISIONING_BT_DEVICE_ID";
+ field public static final java.lang.String EXTRA_PROVISIONING_BT_MAC_ADDRESS = "android.app.extra.PROVISIONING_BT_MAC_ADDRESS";
+ field public static final java.lang.String EXTRA_PROVISIONING_BT_USE_PROXY = "android.app.extra.PROVISIONING_BT_USE_PROXY";
+ field public static final java.lang.String EXTRA_PROVISIONING_BT_UUID = "android.app.extra.PROVISIONING_BT_UUID";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
+ field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE = "android.app.extra.PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
field public static final deprecated java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME";
+ field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION";
@@ -5697,6 +5722,7 @@ package android.app.admin {
field public static final int KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS = 8; // 0x8
field public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1; // 0x1
field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning";
+ field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC_V2 = "application/com.android.managedprovisioning.v2";
field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000
field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000
field public static final int PASSWORD_QUALITY_BIOMETRIC_WEAK = 32768; // 0x8000
@@ -5882,6 +5908,37 @@ package android.app.usage {
field public static final android.os.Parcelable.Creator<android.app.usage.ConfigurationStats> CREATOR;
}
+ public class NetworkStatsManager {
+ method public android.app.usage.NetworkUsageStats queryDetails(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method public android.app.usage.NetworkUsageStats queryDetailsForUid(int, java.lang.String, long, long, int) throws android.os.RemoteException, java.lang.SecurityException;
+ method public android.app.usage.NetworkUsageStats querySummary(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method public android.app.usage.NetworkUsageStats.Bucket querySummaryForDevice(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method public android.app.usage.NetworkUsageStats.Bucket querySummaryForUser(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ }
+
+ public final class NetworkUsageStats implements java.lang.AutoCloseable {
+ method public void close();
+ method public boolean getNextBucket(android.app.usage.NetworkUsageStats.Bucket);
+ method public boolean hasNextBucket();
+ }
+
+ public static class NetworkUsageStats.Bucket {
+ ctor public NetworkUsageStats.Bucket();
+ method public long getEndTimeStamp();
+ method public long getRxBytes();
+ method public long getRxPackets();
+ method public long getStartTimeStamp();
+ method public int getState();
+ method public long getTxBytes();
+ method public long getTxPackets();
+ method public int getUid();
+ field public static final int STATE_ALL = -1; // 0xffffffff
+ field public static final int STATE_DEFAULT = 1; // 0x1
+ field public static final int STATE_FOREGROUND = 2; // 0x2
+ field public static final int UID_REMOVED = -4; // 0xfffffffc
+ field public static final int UID_TETHERING = -5; // 0xfffffffb
+ }
+
public final class UsageEvents implements android.os.Parcelable {
method public int describeContents();
method public boolean getNextEvent(android.app.usage.UsageEvents.Event);
@@ -6931,6 +6988,7 @@ package android.bluetooth.le {
field public static final int SCAN_MODE_BALANCED = 1; // 0x1
field public static final int SCAN_MODE_LOW_LATENCY = 2; // 0x2
field public static final int SCAN_MODE_LOW_POWER = 0; // 0x0
+ field public static final int SCAN_MODE_OPPORTUNISTIC = -1; // 0xffffffff
}
public static final class ScanSettings.Builder {
@@ -7395,6 +7453,7 @@ package android.content {
method public abstract int checkCallingPermission(java.lang.String);
method public abstract int checkCallingUriPermission(android.net.Uri, int);
method public abstract int checkPermission(java.lang.String, int, int);
+ method public abstract int checkSelfPermission(java.lang.String);
method public abstract int checkUriPermission(android.net.Uri, int, int, int);
method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
method public abstract deprecated void clearWallpaper() throws java.io.IOException;
@@ -7538,6 +7597,7 @@ package android.content {
field public static final int MODE_PRIVATE = 0; // 0x0
field public static final deprecated int MODE_WORLD_READABLE = 1; // 0x1
field public static final deprecated int MODE_WORLD_WRITEABLE = 2; // 0x2
+ field public static final java.lang.String NETWORK_STATS_SERVICE = "netstats";
field public static final java.lang.String NFC_SERVICE = "nfc";
field public static final java.lang.String NOTIFICATION_SERVICE = "notification";
field public static final java.lang.String NSD_SERVICE = "servicediscovery";
@@ -7572,6 +7632,7 @@ package android.content {
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 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 deprecated void clearWallpaper() throws java.io.IOException;
@@ -8645,6 +8706,7 @@ package android.content.pm {
field public static final int FLAG_ALLOW_TASK_REPARENTING = 32; // 0x20
field public static final int FLAG_DEBUGGABLE = 2; // 0x2
field public static final int FLAG_EXTERNAL_STORAGE = 262144; // 0x40000
+ field public static final int FLAG_EXTRACT_NATIVE_LIBS = 268435456; // 0x10000000
field public static final int FLAG_FACTORY_TEST = 16; // 0x10
field public static final int FLAG_FULL_BACKUP_ONLY = 67108864; // 0x4000000
field public static final int FLAG_HAS_CODE = 4; // 0x4
@@ -8667,6 +8729,7 @@ package android.content.pm {
field public static final int FLAG_SYSTEM = 1; // 0x1
field public static final int FLAG_TEST_ONLY = 256; // 0x100
field public static final int FLAG_UPDATED_SYSTEM_APP = 128; // 0x80
+ field public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 134217728; // 0x8000000
field public static final int FLAG_VM_SAFE_MODE = 16384; // 0x4000
field public java.lang.String backupAgentName;
field public java.lang.String className;
@@ -8824,7 +8887,6 @@ package android.content.pm {
field public static final int INSTALL_LOCATION_INTERNAL_ONLY = 1; // 0x1
field public static final int INSTALL_LOCATION_PREFER_EXTERNAL = 2; // 0x2
field public static final int REQUESTED_PERMISSION_GRANTED = 2; // 0x2
- field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
field public android.content.pm.ActivityInfo[] activities;
field public android.content.pm.ApplicationInfo applicationInfo;
field public int baseRevisionCode;
@@ -11871,9 +11933,12 @@ package android.graphics.drawable {
public class AnimatedVectorDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable {
ctor public AnimatedVectorDrawable();
+ method public void addListener(android.animation.Animator.AnimatorListener);
method public void draw(android.graphics.Canvas);
+ method public java.util.List<android.animation.Animator.AnimatorListener> getListeners();
method public int getOpacity();
method public boolean isRunning();
+ method public void removeListener(android.animation.Animator.AnimatorListener);
method public void setAlpha(int);
method public void setColorFilter(android.graphics.ColorFilter);
method public void start();
@@ -14547,6 +14612,14 @@ package android.media {
field public static final int SUCCESS = 0; // 0x0
}
+ public static class AudioRecord.Builder {
+ ctor public AudioRecord.Builder();
+ method public android.media.AudioRecord build() throws java.lang.UnsupportedOperationException;
+ method public android.media.AudioRecord.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioRecord.Builder setCapturePreset(int) throws java.lang.IllegalArgumentException;
+ }
+
public static abstract interface AudioRecord.OnRecordPositionUpdateListener {
method public abstract void onMarkerReached(android.media.AudioRecord);
method public abstract void onPeriodicNotification(android.media.AudioRecord);
@@ -15168,6 +15241,7 @@ package android.media {
method public android.graphics.Bitmap getIconBitmap();
method public android.net.Uri getIconUri();
method public java.lang.String getMediaId();
+ method public android.net.Uri getMediaUri();
method public java.lang.CharSequence getSubtitle();
method public java.lang.CharSequence getTitle();
method public void writeToParcel(android.os.Parcel, int);
@@ -15182,6 +15256,7 @@ package android.media {
method public android.media.MediaDescription.Builder setIconBitmap(android.graphics.Bitmap);
method public android.media.MediaDescription.Builder setIconUri(android.net.Uri);
method public android.media.MediaDescription.Builder setMediaId(java.lang.String);
+ method public android.media.MediaDescription.Builder setMediaUri(android.net.Uri);
method public android.media.MediaDescription.Builder setSubtitle(java.lang.CharSequence);
method public android.media.MediaDescription.Builder setTitle(java.lang.CharSequence);
}
@@ -15223,6 +15298,9 @@ package android.media {
field public static final java.lang.String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
field public static final java.lang.String PROPERTY_VENDOR = "vendor";
field public static final java.lang.String PROPERTY_VERSION = "version";
+ field public static final int REQUEST_TYPE_INITIAL = 0; // 0x0
+ field public static final int REQUEST_TYPE_RELEASE = 2; // 0x2
+ field public static final int REQUEST_TYPE_RENEWAL = 1; // 0x1
}
public final class MediaDrm.CryptoSession {
@@ -15235,6 +15313,7 @@ package android.media {
public static final class MediaDrm.KeyRequest {
method public byte[] getData();
method public java.lang.String getDefaultUrl();
+ method public int getRequestType();
}
public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException {
@@ -16995,6 +17074,7 @@ package android.media.session {
method public void play();
method public void playFromMediaId(java.lang.String, android.os.Bundle);
method public void playFromSearch(java.lang.String, android.os.Bundle);
+ method public void playFromUri(android.net.Uri, android.os.Bundle);
method public void rewind();
method public void seekTo(long);
method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
@@ -17042,6 +17122,7 @@ package android.media.session {
method public void onPlay();
method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
+ method public void onPlayFromUri(android.net.Uri, android.os.Bundle);
method public void onRewind();
method public void onSeekTo(long);
method public void onSetRating(android.media.Rating);
@@ -17096,6 +17177,7 @@ package android.media.session {
field public static final long ACTION_PLAY = 4L; // 0x4L
field public static final long ACTION_PLAY_FROM_MEDIA_ID = 1024L; // 0x400L
field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
+ field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
field public static final long ACTION_REWIND = 8L; // 0x8L
field public static final long ACTION_SEEK_TO = 256L; // 0x100L
@@ -17266,6 +17348,10 @@ package android.media.tv {
field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
field public static final java.lang.String COLUMN_SEASON_NUMBER = "season_number";
@@ -18547,7 +18633,10 @@ package android.net.wifi {
field public int frequency;
field public boolean is80211McRTTResponder;
field public int level;
+ field public java.lang.String operatorFriendlyName;
+ field public boolean passpointNetwork;
field public long timestamp;
+ field public java.lang.String venueName;
}
public final class SupplicantState extends java.lang.Enum implements android.os.Parcelable {
@@ -18574,6 +18663,7 @@ package android.net.wifi {
public class WifiConfiguration implements android.os.Parcelable {
ctor public WifiConfiguration();
method public int describeContents();
+ method public boolean isPasspoint();
method public void writeToParcel(android.os.Parcel, int);
field public java.lang.String BSSID;
field public java.lang.String FQDN;
@@ -22851,6 +22941,7 @@ package android.os {
}
public final class PowerManager {
+ method public boolean isDeviceIdleMode();
method public boolean isInteractive();
method public boolean isPowerSaveMode();
method public deprecated boolean isScreenOn();
@@ -22858,6 +22949,7 @@ package android.os {
method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
method public void reboot(java.lang.String);
field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
+ field public static final java.lang.String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
field public static final java.lang.String ACTION_POWER_SAVE_MODE_CHANGED = "android.os.action.POWER_SAVE_MODE_CHANGED";
field public static final deprecated int FULL_WAKE_LOCK = 26; // 0x1a
field public static final int ON_AFTER_RELEASE = 536870912; // 0x20000000
@@ -26664,6 +26756,16 @@ package android.renderscript {
method public void copy1DRangeFromUnchecked(int, int, short[]);
method public void copy1DRangeFromUnchecked(int, int, byte[]);
method public void copy1DRangeFromUnchecked(int, int, float[]);
+ method public void copy1DRangeTo(int, int, java.lang.Object);
+ method public void copy1DRangeTo(int, int, int[]);
+ method public void copy1DRangeTo(int, int, short[]);
+ method public void copy1DRangeTo(int, int, byte[]);
+ method public void copy1DRangeTo(int, int, float[]);
+ method public void copy1DRangeToUnchecked(int, int, java.lang.Object);
+ method public void copy1DRangeToUnchecked(int, int, int[]);
+ method public void copy1DRangeToUnchecked(int, int, short[]);
+ method public void copy1DRangeToUnchecked(int, int, byte[]);
+ method public void copy1DRangeToUnchecked(int, int, float[]);
method public void copy2DRangeFrom(int, int, int, int, java.lang.Object);
method public void copy2DRangeFrom(int, int, int, int, byte[]);
method public void copy2DRangeFrom(int, int, int, int, short[]);
@@ -26671,6 +26773,14 @@ package android.renderscript {
method public void copy2DRangeFrom(int, int, int, int, float[]);
method public void copy2DRangeFrom(int, int, int, int, android.renderscript.Allocation, int, int);
method public void copy2DRangeFrom(int, int, android.graphics.Bitmap);
+ method public void copy2DRangeTo(int, int, int, int, java.lang.Object);
+ method public void copy2DRangeTo(int, int, int, int, byte[]);
+ method public void copy2DRangeTo(int, int, int, int, short[]);
+ method public void copy2DRangeTo(int, int, int, int, int[]);
+ method public void copy2DRangeTo(int, int, int, int, float[]);
+ method public void copy3DRangeFrom(int, int, int, int, int, int, java.lang.Object);
+ method public void copy3DRangeFrom(int, int, int, int, int, int, android.renderscript.Allocation, int, int, int);
+ method public void copy3DRangeTo(int, int, int, int, int, int, java.lang.Object);
method public void copyFrom(android.renderscript.BaseObj[]);
method public void copyFrom(java.lang.Object);
method public void copyFrom(int[]);
@@ -26690,6 +26800,7 @@ package android.renderscript {
method public void copyTo(short[]);
method public void copyTo(int[]);
method public void copyTo(float[]);
+ method public void copyToFieldPacker(int, int, int, int, android.renderscript.FieldPacker);
method public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int);
method public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap);
method public static android.renderscript.Allocation createCubemapFromCubeFaces(android.renderscript.RenderScript, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int);
@@ -26715,6 +26826,7 @@ package android.renderscript {
method public deprecated synchronized void resize(int);
method public void setFromFieldPacker(int, android.renderscript.FieldPacker);
method public void setFromFieldPacker(int, int, android.renderscript.FieldPacker);
+ method public void setFromFieldPacker(int, int, int, int, android.renderscript.FieldPacker);
method public void setOnBufferAvailableListener(android.renderscript.Allocation.OnBufferAvailableListener);
method public void setSurface(android.view.Surface);
method public void syncAll(int);
@@ -27660,6 +27772,11 @@ package android.security {
method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean);
}
+ public class NetworkSecurityPolicy {
+ method public static android.security.NetworkSecurityPolicy getInstance();
+ method public boolean isCleartextTrafficPermitted();
+ }
+
}
package android.service.carrier {
@@ -29678,6 +29795,7 @@ package android.telephony {
method public boolean setOperatorBrandOverride(java.lang.String);
method public boolean setPreferredNetworkTypeToGlobal();
method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
+ field public static final java.lang.String ACTION_EMERGENCY_ASSISTANCE = "android.telephony.action.EMERGENCY_ASSISTANCE";
field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
field public static final int CALL_STATE_IDLE = 0; // 0x0
@@ -30174,6 +30292,7 @@ package android.test.mock {
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 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 void clearWallpaper();
@@ -34408,6 +34527,10 @@ package android.view {
method public boolean getFitsSystemWindows();
method public java.util.ArrayList<android.view.View> getFocusables(int);
method public void getFocusedRect(android.graphics.Rect);
+ method public android.graphics.drawable.Drawable getForeground();
+ method public int getForegroundGravity();
+ method public android.content.res.ColorStateList getForegroundTintList();
+ method public android.graphics.PorterDuff.Mode getForegroundTintMode();
method public boolean getGlobalVisibleRect(android.graphics.Rect, android.graphics.Point);
method public final boolean getGlobalVisibleRect(android.graphics.Rect);
method public android.os.Handler getHandler();
@@ -34579,6 +34702,7 @@ package android.view {
method protected void onDisplayHint(int);
method public boolean onDragEvent(android.view.DragEvent);
method protected void onDraw(android.graphics.Canvas);
+ method public void onDrawForeground(android.graphics.Canvas);
method protected final void onDrawScrollBars(android.graphics.Canvas);
method public boolean onFilterTouchEventForSecurity(android.view.MotionEvent);
method protected void onFinishInflate();
@@ -34684,6 +34808,10 @@ package android.view {
method public void setFitsSystemWindows(boolean);
method public void setFocusable(boolean);
method public void setFocusableInTouchMode(boolean);
+ method public void setForeground(android.graphics.drawable.Drawable);
+ method public void setForegroundGravity(int);
+ method public void setForegroundTintList(android.content.res.ColorStateList);
+ method public void setForegroundTintMode(android.graphics.PorterDuff.Mode);
method public void setHapticFeedbackEnabled(boolean);
method public void setHasTransientState(boolean);
method public void setHorizontalFadingEdgeEnabled(boolean);
@@ -36105,6 +36233,7 @@ package android.view.accessibility {
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SELECT;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_SELECTION;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_TEXT;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SHOW_ON_SCREEN;
}
public static final class AccessibilityNodeInfo.CollectionInfo {
@@ -38152,34 +38281,34 @@ package android.widget {
method public long getDate();
method public int getDateTextAppearance();
method public int getFirstDayOfWeek();
- method public int getFocusedMonthDateColor();
+ method public deprecated int getFocusedMonthDateColor();
method public long getMaxDate();
method public long getMinDate();
- method public android.graphics.drawable.Drawable getSelectedDateVerticalBar();
- method public int getSelectedWeekBackgroundColor();
+ method public deprecated android.graphics.drawable.Drawable getSelectedDateVerticalBar();
+ method public deprecated int getSelectedWeekBackgroundColor();
method public boolean getShowWeekNumber();
- method public int getShownWeekCount();
- method public int getUnfocusedMonthDateColor();
+ method public deprecated int getShownWeekCount();
+ method public deprecated int getUnfocusedMonthDateColor();
method public int getWeekDayTextAppearance();
- method public int getWeekNumberColor();
- method public int getWeekSeparatorLineColor();
+ method public deprecated int getWeekNumberColor();
+ method public deprecated int getWeekSeparatorLineColor();
method public void setDate(long);
method public void setDate(long, boolean, boolean);
method public void setDateTextAppearance(int);
method public void setFirstDayOfWeek(int);
- method public void setFocusedMonthDateColor(int);
+ method public deprecated void setFocusedMonthDateColor(int);
method public void setMaxDate(long);
method public void setMinDate(long);
method public void setOnDateChangeListener(android.widget.CalendarView.OnDateChangeListener);
- method public void setSelectedDateVerticalBar(int);
- method public void setSelectedDateVerticalBar(android.graphics.drawable.Drawable);
- method public void setSelectedWeekBackgroundColor(int);
+ method public deprecated void setSelectedDateVerticalBar(int);
+ method public deprecated void setSelectedDateVerticalBar(android.graphics.drawable.Drawable);
+ method public deprecated void setSelectedWeekBackgroundColor(int);
method public void setShowWeekNumber(boolean);
- method public void setShownWeekCount(int);
- method public void setUnfocusedMonthDateColor(int);
+ method public deprecated void setShownWeekCount(int);
+ method public deprecated void setUnfocusedMonthDateColor(int);
method public void setWeekDayTextAppearance(int);
- method public void setWeekNumberColor(int);
- method public void setWeekSeparatorLineColor(int);
+ method public deprecated void setWeekNumberColor(int);
+ method public deprecated void setWeekSeparatorLineColor(int);
}
public static abstract interface CalendarView.OnDateChangeListener {
@@ -38512,16 +38641,8 @@ package android.widget {
ctor public FrameLayout(android.content.Context, android.util.AttributeSet, int);
ctor public FrameLayout(android.content.Context, android.util.AttributeSet, int, int);
method public deprecated boolean getConsiderGoneChildrenWhenMeasuring();
- method public android.graphics.drawable.Drawable getForeground();
- method public int getForegroundGravity();
- method public android.content.res.ColorStateList getForegroundTintList();
- method public android.graphics.PorterDuff.Mode getForegroundTintMode();
method public boolean getMeasureAllChildren();
method protected void onLayout(boolean, int, int, int, int);
- method public void setForeground(android.graphics.drawable.Drawable);
- method public void setForegroundGravity(int);
- method public void setForegroundTintList(android.content.res.ColorStateList);
- method public void setForegroundTintMode(android.graphics.PorterDuff.Mode);
method public void setMeasureAllChildren(boolean);
}
@@ -39112,7 +39233,7 @@ package android.widget {
method public void setTouchInterceptor(android.view.View.OnTouchListener);
method public void setTouchable(boolean);
method public void setWidth(int);
- method public void setWindowLayoutMode(int, int);
+ method public deprecated void setWindowLayoutMode(int, int);
method public void showAsDropDown(android.view.View);
method public void showAsDropDown(android.view.View, int, int);
method public void showAsDropDown(android.view.View, int, int, int);
diff --git a/api/removed.txt b/api/removed.txt
index 1b209a9cb154..c2b9d3ef8c72 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -1,3 +1,11 @@
+package android.content.pm {
+
+ public class PackageInfo implements android.os.Parcelable {
+ field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
+ }
+
+}
+
package android.media {
public class AudioFormat {
diff --git a/api/system-current.txt b/api/system-current.txt
index aa20ff1a87f7..a123dd5ef1cf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -536,8 +536,8 @@ package android {
field public static final int datePickerMode = 16843955; // 0x10104b3
field public static final int datePickerStyle = 16843612; // 0x101035c
field public static final int dateTextAppearance = 16843593; // 0x1010349
- field public static final int dayOfWeekBackground = 16843924; // 0x1010494
- field public static final int dayOfWeekTextAppearance = 16843925; // 0x1010495
+ field public static final deprecated int dayOfWeekBackground = 16843924; // 0x1010494
+ field public static final deprecated int dayOfWeekTextAppearance = 16843925; // 0x1010495
field public static final int debuggable = 16842767; // 0x101000f
field public static final int defaultValue = 16843245; // 0x10101ed
field public static final int delay = 16843212; // 0x10101cc
@@ -627,6 +627,7 @@ package android {
field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
field public static final int exported = 16842768; // 0x1010010
field public static final int extraTension = 16843371; // 0x101026b
+ field public static final int extractNativeLibs = 16844008; // 0x10104e8
field public static final int factor = 16843219; // 0x10101d3
field public static final int fadeDuration = 16843384; // 0x1010278
field public static final int fadeEnabled = 16843390; // 0x101027e
@@ -659,7 +660,7 @@ package android {
field public static final int flipInterval = 16843129; // 0x1010179
field public static final int focusable = 16842970; // 0x10100da
field public static final int focusableInTouchMode = 16842971; // 0x10100db
- field public static final int focusedMonthDateColor = 16843587; // 0x1010343
+ field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
field public static final int footerDividersEnabled = 16843311; // 0x101022f
@@ -723,9 +724,9 @@ package android {
field public static final int hasCode = 16842764; // 0x101000c
field public static final int headerAmPmTextAppearance = 16843936; // 0x10104a0
field public static final int headerBackground = 16843055; // 0x101012f
- field public static final int headerDayOfMonthTextAppearance = 16843927; // 0x1010497
+ field public static final deprecated int headerDayOfMonthTextAppearance = 16843927; // 0x1010497
field public static final int headerDividersEnabled = 16843310; // 0x101022e
- field public static final int headerMonthTextAppearance = 16843926; // 0x1010496
+ field public static final deprecated int headerMonthTextAppearance = 16843926; // 0x1010496
field public static final int headerTimeTextAppearance = 16843935; // 0x101049f
field public static final int headerYearTextAppearance = 16843928; // 0x1010498
field public static final int height = 16843093; // 0x1010155
@@ -1170,8 +1171,8 @@ package android {
field public static final int selectable = 16843238; // 0x10101e6
field public static final int selectableItemBackground = 16843534; // 0x101030e
field public static final int selectableItemBackgroundBorderless = 16843868; // 0x101045c
- field public static final int selectedDateVerticalBar = 16843591; // 0x1010347
- field public static final int selectedWeekBackgroundColor = 16843586; // 0x1010342
+ field public static final deprecated int selectedDateVerticalBar = 16843591; // 0x1010347
+ field public static final deprecated int selectedWeekBackgroundColor = 16843586; // 0x1010342
field public static final int sessionService = 16843837; // 0x101043d
field public static final int settingsActivity = 16843301; // 0x1010225
field public static final int setupActivity = 16843766; // 0x10103f6
@@ -1190,8 +1191,8 @@ package android {
field public static final int showOnLockScreen = 16843721; // 0x10103c9
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showText = 16843949; // 0x10104ad
- field public static final int showWeekNumber = 16843582; // 0x101033e
- field public static final int shownWeekCount = 16843585; // 0x1010341
+ field public static final deprecated int showWeekNumber = 16843582; // 0x101033e
+ 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
field public static final int singleUser = 16843711; // 0x10103bf
@@ -1428,13 +1429,14 @@ package android {
field public static final int typeface = 16842902; // 0x1010096
field public static final int uiOptions = 16843672; // 0x1010398
field public static final int uncertainGestureColor = 16843382; // 0x1010276
- field public static final int unfocusedMonthDateColor = 16843588; // 0x1010344
+ field public static final deprecated int unfocusedMonthDateColor = 16843588; // 0x1010344
field public static final int unselectedAlpha = 16843278; // 0x101020e
field public static final int updatePeriodMillis = 16843344; // 0x1010250
field public static final int useDefaultMargins = 16843641; // 0x1010379
field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
field public static final int useLevel = 16843167; // 0x101019f
field public static final int userVisible = 16843409; // 0x1010291
+ field public static final int usesCleartextTraffic = 16844009; // 0x10104e9
field public static final int value = 16842788; // 0x1010024
field public static final int valueFrom = 16843486; // 0x10102de
field public static final int valueTo = 16843487; // 0x10102df
@@ -1470,8 +1472,8 @@ package android {
field public static final int webTextViewStyle = 16843449; // 0x10102b9
field public static final int webViewStyle = 16842885; // 0x1010085
field public static final int weekDayTextAppearance = 16843592; // 0x1010348
- field public static final int weekNumberColor = 16843589; // 0x1010345
- field public static final int weekSeparatorLineColor = 16843590; // 0x1010346
+ field public static final deprecated int weekNumberColor = 16843589; // 0x1010345
+ field public static final deprecated int weekSeparatorLineColor = 16843590; // 0x1010346
field public static final int weightSum = 16843048; // 0x1010128
field public static final int widgetCategory = 16843716; // 0x10103c4
field public static final int widgetLayout = 16843243; // 0x10101eb
@@ -1530,7 +1532,7 @@ package android {
field public static final int xlargeScreens = 16843455; // 0x10102bf
field public static final int y = 16842925; // 0x10100ad
field public static final int yearListItemTextAppearance = 16843929; // 0x1010499
- field public static final int yearListSelectorColor = 16843930; // 0x101049a
+ field public static final deprecated int yearListSelectorColor = 16843930; // 0x101049a
field public static final int yesNoPreferenceStyle = 16842896; // 0x1010090
field public static final int zAdjustment = 16843201; // 0x10101c1
}
@@ -3514,6 +3516,7 @@ package android.app {
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
method public void onProvideAssistContent(android.app.AssistContent);
method public void onProvideAssistData(android.os.Bundle);
+ method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
method protected void onRestart();
method protected void onRestoreInstanceState(android.os.Bundle);
method public void onRestoreInstanceState(android.os.Bundle, android.os.PersistableBundle);
@@ -3544,6 +3547,7 @@ package android.app {
method public boolean releaseInstance();
method public final deprecated void removeDialog(int);
method public void reportFullyDrawn();
+ method public final void requestPermissions(java.lang.String[], int);
method public boolean requestVisibleBehind(boolean);
method public final boolean requestWindowFeature(int);
method public final void runOnUiThread(java.lang.Runnable);
@@ -4067,22 +4071,25 @@ package android.app {
method public int describeContents();
method public android.content.ComponentName getActivityComponent();
method public static android.app.AssistStructure getAssistStructure(android.os.Bundle);
- method public void getWindowAt(int, android.app.AssistStructure.ViewNode);
- method public int getWindowCount();
+ method public android.app.AssistStructure.WindowNode getWindowNodeAt(int);
+ method public int getWindowNodeCount();
method public void writeToParcel(android.os.Parcel, int);
field public static final java.lang.String ASSIST_KEY = "android:assist_structure";
field public static final android.os.Parcelable.Creator<android.app.AssistStructure> CREATOR;
}
public static class AssistStructure.ViewNode {
- ctor public AssistStructure.ViewNode();
- method public void getChildAt(int, android.app.AssistStructure.ViewNode);
+ method public android.app.AssistStructure.ViewNode getChildAt(int);
method public int getChildCount();
method public java.lang.String getClassName();
- method public java.lang.String getContentDescription();
+ method public java.lang.CharSequence getContentDescription();
method public android.os.Bundle getExtras();
method public int getHeight();
method public java.lang.String getHint();
+ method public int getId();
+ method public java.lang.String getIdEntry();
+ method public java.lang.String getIdPackage();
+ method public java.lang.String getIdType();
method public int getLeft();
method public int getScrollX();
method public int getScrollY();
@@ -4113,6 +4120,15 @@ package android.app {
field public static final int TEXT_STYLE_UNDERLINE = 4; // 0x4
}
+ public static class AssistStructure.WindowNode {
+ method public int getHeight();
+ method public int getLeft();
+ method public android.app.AssistStructure.ViewNode getRootViewNode();
+ method public java.lang.CharSequence getTitle();
+ method public int getTop();
+ method public int getWidth();
+ }
+
public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
@@ -4393,6 +4409,7 @@ package android.app {
method public void onOptionsMenuClosed(android.view.Menu);
method public void onPause();
method public void onPrepareOptionsMenu(android.view.Menu);
+ method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
method public void onResume();
method public void onSaveInstanceState(android.os.Bundle);
method public void onStart();
@@ -4401,6 +4418,7 @@ package android.app {
method public void onViewCreated(android.view.View, android.os.Bundle);
method public void onViewStateRestored(android.os.Bundle);
method public void registerForContextMenu(android.view.View);
+ method public final void requestPermissions(java.lang.String[], int);
method public void setAllowEnterTransitionOverlap(boolean);
method public void setAllowReturnTransitionOverlap(boolean);
method public void setArguments(android.os.Bundle);
@@ -5767,12 +5785,18 @@ package android.app.admin {
field public static final java.lang.String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
+ field public static final java.lang.String EXTRA_PROVISIONING_BT_DEVICE_ID = "android.app.extra.PROVISIONING_BT_DEVICE_ID";
+ field public static final java.lang.String EXTRA_PROVISIONING_BT_MAC_ADDRESS = "android.app.extra.PROVISIONING_BT_MAC_ADDRESS";
+ field public static final java.lang.String EXTRA_PROVISIONING_BT_USE_PROXY = "android.app.extra.PROVISIONING_BT_USE_PROXY";
+ field public static final java.lang.String EXTRA_PROVISIONING_BT_UUID = "android.app.extra.PROVISIONING_BT_UUID";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
+ field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE = "android.app.extra.PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
field public static final deprecated java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME";
+ field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION";
@@ -5801,6 +5825,7 @@ package android.app.admin {
field public static final int KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS = 8; // 0x8
field public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1; // 0x1
field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning";
+ field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC_V2 = "application/com.android.managedprovisioning.v2";
field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000
field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000
field public static final int PASSWORD_QUALITY_BIOMETRIC_WEAK = 32768; // 0x8000
@@ -6062,6 +6087,37 @@ package android.app.usage {
field public static final android.os.Parcelable.Creator<android.app.usage.ConfigurationStats> CREATOR;
}
+ public class NetworkStatsManager {
+ method public android.app.usage.NetworkUsageStats queryDetails(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method public android.app.usage.NetworkUsageStats queryDetailsForUid(int, java.lang.String, long, long, int) throws android.os.RemoteException, java.lang.SecurityException;
+ method public android.app.usage.NetworkUsageStats querySummary(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method public android.app.usage.NetworkUsageStats.Bucket querySummaryForDevice(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method public android.app.usage.NetworkUsageStats.Bucket querySummaryForUser(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ }
+
+ public final class NetworkUsageStats implements java.lang.AutoCloseable {
+ method public void close();
+ method public boolean getNextBucket(android.app.usage.NetworkUsageStats.Bucket);
+ method public boolean hasNextBucket();
+ }
+
+ public static class NetworkUsageStats.Bucket {
+ ctor public NetworkUsageStats.Bucket();
+ method public long getEndTimeStamp();
+ method public long getRxBytes();
+ method public long getRxPackets();
+ method public long getStartTimeStamp();
+ method public int getState();
+ method public long getTxBytes();
+ method public long getTxPackets();
+ method public int getUid();
+ field public static final int STATE_ALL = -1; // 0xffffffff
+ field public static final int STATE_DEFAULT = 1; // 0x1
+ field public static final int STATE_FOREGROUND = 2; // 0x2
+ field public static final int UID_REMOVED = -4; // 0xfffffffc
+ field public static final int UID_TETHERING = -5; // 0xfffffffb
+ }
+
public final class UsageEvents implements android.os.Parcelable {
method public int describeContents();
method public boolean getNextEvent(android.app.usage.UsageEvents.Event);
@@ -7126,6 +7182,7 @@ package android.bluetooth.le {
field public static final int SCAN_MODE_BALANCED = 1; // 0x1
field public static final int SCAN_MODE_LOW_LATENCY = 2; // 0x2
field public static final int SCAN_MODE_LOW_POWER = 0; // 0x0
+ field public static final int SCAN_MODE_OPPORTUNISTIC = -1; // 0xffffffff
field public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; // 0x1
field public static final int SCAN_RESULT_TYPE_FULL = 0; // 0x0
}
@@ -7601,6 +7658,7 @@ package android.content {
method public abstract int checkCallingPermission(java.lang.String);
method public abstract int checkCallingUriPermission(android.net.Uri, int);
method public abstract int checkPermission(java.lang.String, int, int);
+ method public abstract int checkSelfPermission(java.lang.String);
method public abstract int checkUriPermission(android.net.Uri, int, int, int);
method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
method public abstract deprecated void clearWallpaper() throws java.io.IOException;
@@ -7747,6 +7805,7 @@ package android.content {
field public static final deprecated int MODE_WORLD_READABLE = 1; // 0x1
field public static final deprecated int MODE_WORLD_WRITEABLE = 2; // 0x2
field public static final java.lang.String NETWORK_SCORE_SERVICE = "network_score";
+ field public static final java.lang.String NETWORK_STATS_SERVICE = "netstats";
field public static final java.lang.String NFC_SERVICE = "nfc";
field public static final java.lang.String NOTIFICATION_SERVICE = "notification";
field public static final java.lang.String NSD_SERVICE = "servicediscovery";
@@ -7784,6 +7843,7 @@ package android.content {
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 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 deprecated void clearWallpaper() throws java.io.IOException;
@@ -8118,8 +8178,10 @@ package android.content {
field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN";
field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
+ field public static final java.lang.String ACTION_MANAGE_APP_PERMISSIONS = "android.intent.action.MANAGE_APP_PERMISSIONS";
field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
+ field public static final java.lang.String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS";
field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
field public static final java.lang.String ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON";
field public static final java.lang.String ACTION_MEDIA_CHECKING = "android.intent.action.MEDIA_CHECKING";
@@ -8256,6 +8318,8 @@ package android.content {
field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
field public static final java.lang.String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
@@ -8860,6 +8924,7 @@ package android.content.pm {
field public static final int FLAG_ALLOW_TASK_REPARENTING = 32; // 0x20
field public static final int FLAG_DEBUGGABLE = 2; // 0x2
field public static final int FLAG_EXTERNAL_STORAGE = 262144; // 0x40000
+ field public static final int FLAG_EXTRACT_NATIVE_LIBS = 268435456; // 0x10000000
field public static final int FLAG_FACTORY_TEST = 16; // 0x10
field public static final int FLAG_FULL_BACKUP_ONLY = 67108864; // 0x4000000
field public static final int FLAG_HAS_CODE = 4; // 0x4
@@ -8882,6 +8947,7 @@ package android.content.pm {
field public static final int FLAG_SYSTEM = 1; // 0x1
field public static final int FLAG_TEST_ONLY = 256; // 0x100
field public static final int FLAG_UPDATED_SYSTEM_APP = 128; // 0x80
+ field public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 134217728; // 0x8000000
field public static final int FLAG_VM_SAFE_MODE = 16384; // 0x4000
field public java.lang.String backupAgentName;
field public java.lang.String className;
@@ -9064,7 +9130,6 @@ package android.content.pm {
field public static final int INSTALL_LOCATION_INTERNAL_ONLY = 1; // 0x1
field public static final int INSTALL_LOCATION_PREFER_EXTERNAL = 2; // 0x2
field public static final int REQUESTED_PERMISSION_GRANTED = 2; // 0x2
- field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
field public android.content.pm.ActivityInfo[] activities;
field public android.content.pm.ApplicationInfo applicationInfo;
field public int baseRevisionCode;
@@ -9264,6 +9329,7 @@ package android.content.pm {
method public abstract android.graphics.drawable.Drawable getUserBadgedIcon(android.graphics.drawable.Drawable, android.os.UserHandle);
method public abstract java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle);
method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
+ method public abstract void grantPermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public abstract boolean hasSystemFeature(java.lang.String);
method public abstract boolean isSafeMode();
method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -9279,16 +9345,20 @@ package android.content.pm {
method public abstract android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
method public abstract android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int);
method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
+ method public abstract void revokePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public abstract void setApplicationEnabledSetting(java.lang.String, int, int);
method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
method public abstract void verifyPendingInstall(int, int);
+ field public static final java.lang.String ACTION_REQUEST_PERMISSIONS = "android.content.pm.action.REQUEST_PERMISSIONS";
field public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; // 0x0
field public static final int COMPONENT_ENABLED_STATE_DISABLED = 2; // 0x2
field public static final int COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED = 4; // 0x4
field public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3; // 0x3
field public static final int COMPONENT_ENABLED_STATE_ENABLED = 1; // 0x1
field public static final int DONT_KILL_APP = 1; // 0x1
+ field public static final java.lang.String EXTRA_REQUEST_PERMISSIONS_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";
+ field public static final java.lang.String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
field public static final java.lang.String EXTRA_VERIFICATION_ID = "android.content.pm.extra.VERIFICATION_ID";
field public static final java.lang.String EXTRA_VERIFICATION_RESULT = "android.content.pm.extra.VERIFICATION_RESULT";
field public static final java.lang.String FEATURE_APP_WIDGETS = "android.software.app_widgets";
@@ -12146,9 +12216,12 @@ package android.graphics.drawable {
public class AnimatedVectorDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable {
ctor public AnimatedVectorDrawable();
+ method public void addListener(android.animation.Animator.AnimatorListener);
method public void draw(android.graphics.Canvas);
+ method public java.util.List<android.animation.Animator.AnimatorListener> getListeners();
method public int getOpacity();
method public boolean isRunning();
+ method public void removeListener(android.animation.Animator.AnimatorListener);
method public void setAlpha(int);
method public void setColorFilter(android.graphics.ColorFilter);
method public void start();
@@ -15737,6 +15810,16 @@ package android.media {
field public static final int SUCCESS = 0; // 0x0
}
+ public static class AudioRecord.Builder {
+ ctor public AudioRecord.Builder();
+ method public android.media.AudioRecord build() throws java.lang.UnsupportedOperationException;
+ method public android.media.AudioRecord.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioRecord.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioRecord.Builder setCapturePreset(int) throws java.lang.IllegalArgumentException;
+ method public android.media.AudioRecord.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
+ }
+
public static abstract interface AudioRecord.OnRecordPositionUpdateListener {
method public abstract void onMarkerReached(android.media.AudioRecord);
method public abstract void onPeriodicNotification(android.media.AudioRecord);
@@ -16358,6 +16441,7 @@ package android.media {
method public android.graphics.Bitmap getIconBitmap();
method public android.net.Uri getIconUri();
method public java.lang.String getMediaId();
+ method public android.net.Uri getMediaUri();
method public java.lang.CharSequence getSubtitle();
method public java.lang.CharSequence getTitle();
method public void writeToParcel(android.os.Parcel, int);
@@ -16372,6 +16456,7 @@ package android.media {
method public android.media.MediaDescription.Builder setIconBitmap(android.graphics.Bitmap);
method public android.media.MediaDescription.Builder setIconUri(android.net.Uri);
method public android.media.MediaDescription.Builder setMediaId(java.lang.String);
+ method public android.media.MediaDescription.Builder setMediaUri(android.net.Uri);
method public android.media.MediaDescription.Builder setSubtitle(java.lang.CharSequence);
method public android.media.MediaDescription.Builder setTitle(java.lang.CharSequence);
}
@@ -16414,6 +16499,9 @@ package android.media {
field public static final java.lang.String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
field public static final java.lang.String PROPERTY_VENDOR = "vendor";
field public static final java.lang.String PROPERTY_VERSION = "version";
+ field public static final int REQUEST_TYPE_INITIAL = 0; // 0x0
+ field public static final int REQUEST_TYPE_RELEASE = 2; // 0x2
+ field public static final int REQUEST_TYPE_RENEWAL = 1; // 0x1
}
public final class MediaDrm.CryptoSession {
@@ -16426,6 +16514,7 @@ package android.media {
public static final class MediaDrm.KeyRequest {
method public byte[] getData();
method public java.lang.String getDefaultUrl();
+ method public int getRequestType();
}
public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException {
@@ -18252,6 +18341,7 @@ package android.media.session {
method public void play();
method public void playFromMediaId(java.lang.String, android.os.Bundle);
method public void playFromSearch(java.lang.String, android.os.Bundle);
+ method public void playFromUri(android.net.Uri, android.os.Bundle);
method public void rewind();
method public void seekTo(long);
method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
@@ -18299,6 +18389,7 @@ package android.media.session {
method public void onPlay();
method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
+ method public void onPlayFromUri(android.net.Uri, android.os.Bundle);
method public void onRewind();
method public void onSeekTo(long);
method public void onSetRating(android.media.Rating);
@@ -18353,6 +18444,7 @@ package android.media.session {
field public static final long ACTION_PLAY = 4L; // 0x4L
field public static final long ACTION_PLAY_FROM_MEDIA_ID = 1024L; // 0x400L
field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
+ field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
field public static final long ACTION_REWIND = 8L; // 0x8L
field public static final long ACTION_SEEK_TO = 256L; // 0x100L
@@ -18537,6 +18629,10 @@ package android.media.tv {
field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
field public static final java.lang.String COLUMN_SEASON_NUMBER = "season_number";
@@ -20034,7 +20130,8 @@ package android.net.wifi {
}
public class RttManager {
- method public android.net.wifi.RttManager.Capabilities getCapabilities();
+ method public deprecated android.net.wifi.RttManager.Capabilities getCapabilities();
+ method public android.net.wifi.RttManager.RttCapabilities getRttCapabilities();
method public void startRanging(android.net.wifi.RttManager.RttParams[], android.net.wifi.RttManager.RttListener);
method public void stopRanging(android.net.wifi.RttManager.RttListener);
field public static final int BASE = 160256; // 0x27200
@@ -20044,10 +20141,19 @@ package android.net.wifi {
field public static final int CMD_OP_STOP_RANGING = 160257; // 0x27201
field public static final int CMD_OP_SUCCEEDED = 160259; // 0x27203
field public static final java.lang.String DESCRIPTION_KEY = "android.net.wifi.RttManager.Description";
+ field public static final int PREAMBLE_HT = 2; // 0x2
+ field public static final int PREAMBLE_LEGACY = 1; // 0x1
+ field public static final int PREAMBLE_VHT = 4; // 0x4
field public static final int REASON_INVALID_LISTENER = -3; // 0xfffffffd
field public static final int REASON_INVALID_REQUEST = -4; // 0xfffffffc
field public static final int REASON_NOT_AVAILABLE = -2; // 0xfffffffe
field public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
+ field public static final int RTT_BW_10_SUPPORT = 2; // 0x2
+ field public static final int RTT_BW_160_SUPPORT = 32; // 0x20
+ field public static final int RTT_BW_20_SUPPORT = 4; // 0x4
+ field public static final int RTT_BW_40_SUPPORT = 8; // 0x8
+ field public static final int RTT_BW_5_SUPPORT = 1; // 0x1
+ field public static final int RTT_BW_80_SUPPORT = 16; // 0x10
field public static final int RTT_CHANNEL_WIDTH_10 = 6; // 0x6
field public static final int RTT_CHANNEL_WIDTH_160 = 3; // 0x3
field public static final int RTT_CHANNEL_WIDTH_20 = 0; // 0x0
@@ -20055,26 +20161,31 @@ package android.net.wifi {
field public static final int RTT_CHANNEL_WIDTH_5 = 5; // 0x5
field public static final int RTT_CHANNEL_WIDTH_80 = 2; // 0x2
field public static final int RTT_CHANNEL_WIDTH_80P80 = 4; // 0x4
- field public static final int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1; // 0xffffffff
+ field public static final deprecated int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1; // 0xffffffff
field public static final int RTT_PEER_TYPE_AP = 1; // 0x1
field public static final int RTT_PEER_TYPE_STA = 2; // 0x2
field public static final int RTT_PEER_TYPE_UNSPECIFIED = 0; // 0x0
field public static final int RTT_STATUS_ABORTED = 8; // 0x8
field public static final int RTT_STATUS_FAILURE = 1; // 0x1
field public static final int RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6; // 0x6
+ field public static final int RTT_STATUS_FAIL_BUSY_TRY_LATER = 12; // 0xc
+ field public static final int RTT_STATUS_FAIL_INVALID_TS = 9; // 0x9
field public static final int RTT_STATUS_FAIL_NOT_SCHEDULED_YET = 4; // 0x4
field public static final int RTT_STATUS_FAIL_NO_CAPABILITY = 7; // 0x7
field public static final int RTT_STATUS_FAIL_NO_RSP = 2; // 0x2
+ field public static final int RTT_STATUS_FAIL_PROTOCOL = 10; // 0xa
field public static final int RTT_STATUS_FAIL_REJECTED = 3; // 0x3
+ field public static final int RTT_STATUS_FAIL_SCHEDULE = 11; // 0xb
field public static final int RTT_STATUS_FAIL_TM_TIMEOUT = 5; // 0x5
field public static final int RTT_STATUS_SUCCESS = 0; // 0x0
- field public static final int RTT_TYPE_11_MC = 4; // 0x4
- field public static final int RTT_TYPE_11_V = 2; // 0x2
+ field public static final deprecated int RTT_TYPE_11_MC = 4; // 0x4
+ field public static final deprecated int RTT_TYPE_11_V = 2; // 0x2
field public static final int RTT_TYPE_ONE_SIDED = 1; // 0x1
- field public static final int RTT_TYPE_UNSPECIFIED = 0; // 0x0
+ field public static final int RTT_TYPE_TWO_SIDED = 4; // 0x4
+ field public static final deprecated int RTT_TYPE_UNSPECIFIED = 0; // 0x0
}
- public class RttManager.Capabilities {
+ public deprecated class RttManager.Capabilities {
ctor public RttManager.Capabilities();
field public int supportedPeerType;
field public int supportedType;
@@ -20093,6 +20204,20 @@ package android.net.wifi {
field public android.net.wifi.RttManager.RttResult[] mResults;
}
+ public static class RttManager.RttCapabilities implements android.os.Parcelable {
+ ctor public RttManager.RttCapabilities();
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public int bwSupported;
+ field public boolean lciSupported;
+ field public boolean lcrSupported;
+ field public boolean oneSidedRttSupported;
+ field public int preambleSupported;
+ field public deprecated boolean supportedPeerType;
+ field public deprecated boolean supportedType;
+ field public boolean twoSided11McRttSupported;
+ }
+
public static abstract interface RttManager.RttListener {
method public abstract void onAborted();
method public abstract void onFailure(int, java.lang.String);
@@ -20101,30 +20226,64 @@ package android.net.wifi {
public static class RttManager.RttParams {
ctor public RttManager.RttParams();
+ field public boolean LCIRequest;
+ field public boolean LCRRequest;
+ field public int bandwidth;
field public java.lang.String bssid;
+ field public int burstTimeout;
+ field public int centerFreq0;
+ field public int centerFreq1;
field public int channelWidth;
field public int deviceType;
field public int frequency;
- field public int num_retries;
- field public int num_samples;
+ field public int interval;
+ field public int numRetriesPerFTMR;
+ field public int numRetriesPerMeasurementFrame;
+ field public int numSamplesPerBurst;
+ field public deprecated int num_retries;
+ field public deprecated int num_samples;
+ field public int numberBurst;
+ field public int preamble;
field public int requestType;
}
public static class RttManager.RttResult {
ctor public RttManager.RttResult();
field public java.lang.String bssid;
- field public int distance_cm;
- field public int distance_sd_cm;
- field public int distance_spread_cm;
- field public int requestType;
+ field public int burstDuration;
+ field public int burstNumber;
+ field public int distance;
+ field public int distanceSpread;
+ field public int distanceStandardDeviation;
+ field public deprecated int distance_cm;
+ field public deprecated int distance_sd_cm;
+ field public deprecated int distance_spread_cm;
+ field public int frameNumberPerBurstPeer;
+ field public int measurementFrameNumber;
+ field public int measurementType;
+ field public deprecated int requestType;
+ field public int retryAfterDuration;
field public int rssi;
- field public int rssi_spread;
- field public long rtt_ns;
- field public long rtt_sd_ns;
- field public long rtt_spread_ns;
+ field public int rssiSpread;
+ field public deprecated int rssi_spread;
+ field public long rtt;
+ field public long rttSpread;
+ field public long rttStandardDeviation;
+ field public deprecated long rtt_ns;
+ field public deprecated long rtt_sd_ns;
+ field public deprecated long rtt_spread_ns;
+ field public int rxRate;
field public int status;
+ field public int successMeasurementFrameNumber;
field public long ts;
- field public int tx_rate;
+ field public int txRate;
+ field public deprecated int tx_rate;
+ }
+
+ public class RttManager.wifiInformationElement {
+ ctor public RttManager.wifiInformationElement();
+ field public java.lang.String data;
+ field public int id;
}
public class ScanResult implements android.os.Parcelable {
@@ -20144,7 +20303,10 @@ package android.net.wifi {
field public int frequency;
field public boolean is80211McRTTResponder;
field public int level;
+ field public java.lang.String operatorFriendlyName;
+ field public boolean passpointNetwork;
field public long timestamp;
+ field public java.lang.String venueName;
}
public final class SupplicantState extends java.lang.Enum implements android.os.Parcelable {
@@ -20171,6 +20333,7 @@ package android.net.wifi {
public class WifiConfiguration implements android.os.Parcelable {
ctor public WifiConfiguration();
method public int describeContents();
+ method public boolean isPasspoint();
method public void writeToParcel(android.os.Parcel, int);
field public java.lang.String BSSID;
field public java.lang.String FQDN;
@@ -24638,15 +24801,19 @@ package android.os {
}
public final class PowerManager {
+ method public boolean isDeviceIdleMode();
method public boolean isInteractive();
method public boolean isPowerSaveMode();
+ method public boolean isScreenBrightnessBoosted();
method public deprecated boolean isScreenOn();
method public boolean isWakeLockLevelSupported(int);
method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
method public void reboot(java.lang.String);
method public void userActivity(long, int, int);
field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
+ field public static final java.lang.String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
field public static final java.lang.String ACTION_POWER_SAVE_MODE_CHANGED = "android.os.action.POWER_SAVE_MODE_CHANGED";
+ field public static final java.lang.String ACTION_SCREEN_BRIGHTNESS_BOOST_CHANGED = "android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED";
field public static final deprecated int FULL_WAKE_LOCK = 26; // 0x1a
field public static final int ON_AFTER_RELEASE = 536870912; // 0x20000000
field public static final int PARTIAL_WAKE_LOCK = 1; // 0x1
@@ -28462,6 +28629,16 @@ package android.renderscript {
method public void copy1DRangeFromUnchecked(int, int, short[]);
method public void copy1DRangeFromUnchecked(int, int, byte[]);
method public void copy1DRangeFromUnchecked(int, int, float[]);
+ method public void copy1DRangeTo(int, int, java.lang.Object);
+ method public void copy1DRangeTo(int, int, int[]);
+ method public void copy1DRangeTo(int, int, short[]);
+ method public void copy1DRangeTo(int, int, byte[]);
+ method public void copy1DRangeTo(int, int, float[]);
+ method public void copy1DRangeToUnchecked(int, int, java.lang.Object);
+ method public void copy1DRangeToUnchecked(int, int, int[]);
+ method public void copy1DRangeToUnchecked(int, int, short[]);
+ method public void copy1DRangeToUnchecked(int, int, byte[]);
+ method public void copy1DRangeToUnchecked(int, int, float[]);
method public void copy2DRangeFrom(int, int, int, int, java.lang.Object);
method public void copy2DRangeFrom(int, int, int, int, byte[]);
method public void copy2DRangeFrom(int, int, int, int, short[]);
@@ -28469,6 +28646,14 @@ package android.renderscript {
method public void copy2DRangeFrom(int, int, int, int, float[]);
method public void copy2DRangeFrom(int, int, int, int, android.renderscript.Allocation, int, int);
method public void copy2DRangeFrom(int, int, android.graphics.Bitmap);
+ method public void copy2DRangeTo(int, int, int, int, java.lang.Object);
+ method public void copy2DRangeTo(int, int, int, int, byte[]);
+ method public void copy2DRangeTo(int, int, int, int, short[]);
+ method public void copy2DRangeTo(int, int, int, int, int[]);
+ method public void copy2DRangeTo(int, int, int, int, float[]);
+ method public void copy3DRangeFrom(int, int, int, int, int, int, java.lang.Object);
+ method public void copy3DRangeFrom(int, int, int, int, int, int, android.renderscript.Allocation, int, int, int);
+ method public void copy3DRangeTo(int, int, int, int, int, int, java.lang.Object);
method public void copyFrom(android.renderscript.BaseObj[]);
method public void copyFrom(java.lang.Object);
method public void copyFrom(int[]);
@@ -28488,6 +28673,7 @@ package android.renderscript {
method public void copyTo(short[]);
method public void copyTo(int[]);
method public void copyTo(float[]);
+ method public void copyToFieldPacker(int, int, int, int, android.renderscript.FieldPacker);
method public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int);
method public static android.renderscript.Allocation createCubemapFromBitmap(android.renderscript.RenderScript, android.graphics.Bitmap);
method public static android.renderscript.Allocation createCubemapFromCubeFaces(android.renderscript.RenderScript, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Bitmap, android.renderscript.Allocation.MipmapControl, int);
@@ -28513,6 +28699,7 @@ package android.renderscript {
method public deprecated synchronized void resize(int);
method public void setFromFieldPacker(int, android.renderscript.FieldPacker);
method public void setFromFieldPacker(int, int, android.renderscript.FieldPacker);
+ method public void setFromFieldPacker(int, int, int, int, android.renderscript.FieldPacker);
method public void setOnBufferAvailableListener(android.renderscript.Allocation.OnBufferAvailableListener);
method public void setSurface(android.view.Surface);
method public void syncAll(int);
@@ -29458,6 +29645,11 @@ package android.security {
method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean);
}
+ public class NetworkSecurityPolicy {
+ method public static android.security.NetworkSecurityPolicy getInstance();
+ method public boolean isCleartextTrafficPermitted();
+ }
+
}
package android.service.carrier {
@@ -32037,6 +32229,7 @@ package android.telephony {
method public int[] supplyPukReportResult(java.lang.String, java.lang.String);
method public void toggleRadioOnOff();
method public void updateServiceLocation();
+ field public static final java.lang.String ACTION_EMERGENCY_ASSISTANCE = "android.telephony.action.EMERGENCY_ASSISTANCE";
field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
field public static final int CALL_STATE_IDLE = 0; // 0x0
@@ -32533,6 +32726,7 @@ package android.test.mock {
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 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 void clearWallpaper();
@@ -32732,6 +32926,7 @@ package android.test.mock {
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.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
+ method public void grantPermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public boolean hasSystemFeature(java.lang.String);
method public boolean isSafeMode();
method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -32747,6 +32942,7 @@ package android.test.mock {
method public android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
method public android.content.pm.ProviderInfo resolveContentProvider(java.lang.String, int);
method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
+ method public void revokePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public void setApplicationEnabledSetting(java.lang.String, int, int);
method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public void setInstallerPackageName(java.lang.String, java.lang.String);
@@ -36767,6 +36963,10 @@ package android.view {
method public boolean getFitsSystemWindows();
method public java.util.ArrayList<android.view.View> getFocusables(int);
method public void getFocusedRect(android.graphics.Rect);
+ method public android.graphics.drawable.Drawable getForeground();
+ method public int getForegroundGravity();
+ method public android.content.res.ColorStateList getForegroundTintList();
+ method public android.graphics.PorterDuff.Mode getForegroundTintMode();
method public boolean getGlobalVisibleRect(android.graphics.Rect, android.graphics.Point);
method public final boolean getGlobalVisibleRect(android.graphics.Rect);
method public android.os.Handler getHandler();
@@ -36938,6 +37138,7 @@ package android.view {
method protected void onDisplayHint(int);
method public boolean onDragEvent(android.view.DragEvent);
method protected void onDraw(android.graphics.Canvas);
+ method public void onDrawForeground(android.graphics.Canvas);
method protected final void onDrawScrollBars(android.graphics.Canvas);
method public boolean onFilterTouchEventForSecurity(android.view.MotionEvent);
method protected void onFinishInflate();
@@ -37043,6 +37244,10 @@ package android.view {
method public void setFitsSystemWindows(boolean);
method public void setFocusable(boolean);
method public void setFocusableInTouchMode(boolean);
+ method public void setForeground(android.graphics.drawable.Drawable);
+ method public void setForegroundGravity(int);
+ method public void setForegroundTintList(android.content.res.ColorStateList);
+ method public void setForegroundTintMode(android.graphics.PorterDuff.Mode);
method public void setHapticFeedbackEnabled(boolean);
method public void setHasTransientState(boolean);
method public void setHorizontalFadingEdgeEnabled(boolean);
@@ -38467,6 +38672,7 @@ package android.view.accessibility {
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SELECT;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_SELECTION;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_TEXT;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SHOW_ON_SCREEN;
}
public static final class AccessibilityNodeInfo.CollectionInfo {
@@ -40812,34 +41018,34 @@ package android.widget {
method public long getDate();
method public int getDateTextAppearance();
method public int getFirstDayOfWeek();
- method public int getFocusedMonthDateColor();
+ method public deprecated int getFocusedMonthDateColor();
method public long getMaxDate();
method public long getMinDate();
- method public android.graphics.drawable.Drawable getSelectedDateVerticalBar();
- method public int getSelectedWeekBackgroundColor();
+ method public deprecated android.graphics.drawable.Drawable getSelectedDateVerticalBar();
+ method public deprecated int getSelectedWeekBackgroundColor();
method public boolean getShowWeekNumber();
- method public int getShownWeekCount();
- method public int getUnfocusedMonthDateColor();
+ method public deprecated int getShownWeekCount();
+ method public deprecated int getUnfocusedMonthDateColor();
method public int getWeekDayTextAppearance();
- method public int getWeekNumberColor();
- method public int getWeekSeparatorLineColor();
+ method public deprecated int getWeekNumberColor();
+ method public deprecated int getWeekSeparatorLineColor();
method public void setDate(long);
method public void setDate(long, boolean, boolean);
method public void setDateTextAppearance(int);
method public void setFirstDayOfWeek(int);
- method public void setFocusedMonthDateColor(int);
+ method public deprecated void setFocusedMonthDateColor(int);
method public void setMaxDate(long);
method public void setMinDate(long);
method public void setOnDateChangeListener(android.widget.CalendarView.OnDateChangeListener);
- method public void setSelectedDateVerticalBar(int);
- method public void setSelectedDateVerticalBar(android.graphics.drawable.Drawable);
- method public void setSelectedWeekBackgroundColor(int);
+ method public deprecated void setSelectedDateVerticalBar(int);
+ method public deprecated void setSelectedDateVerticalBar(android.graphics.drawable.Drawable);
+ method public deprecated void setSelectedWeekBackgroundColor(int);
method public void setShowWeekNumber(boolean);
- method public void setShownWeekCount(int);
- method public void setUnfocusedMonthDateColor(int);
+ method public deprecated void setShownWeekCount(int);
+ method public deprecated void setUnfocusedMonthDateColor(int);
method public void setWeekDayTextAppearance(int);
- method public void setWeekNumberColor(int);
- method public void setWeekSeparatorLineColor(int);
+ method public deprecated void setWeekNumberColor(int);
+ method public deprecated void setWeekSeparatorLineColor(int);
}
public static abstract interface CalendarView.OnDateChangeListener {
@@ -41172,16 +41378,8 @@ package android.widget {
ctor public FrameLayout(android.content.Context, android.util.AttributeSet, int);
ctor public FrameLayout(android.content.Context, android.util.AttributeSet, int, int);
method public deprecated boolean getConsiderGoneChildrenWhenMeasuring();
- method public android.graphics.drawable.Drawable getForeground();
- method public int getForegroundGravity();
- method public android.content.res.ColorStateList getForegroundTintList();
- method public android.graphics.PorterDuff.Mode getForegroundTintMode();
method public boolean getMeasureAllChildren();
method protected void onLayout(boolean, int, int, int, int);
- method public void setForeground(android.graphics.drawable.Drawable);
- method public void setForegroundGravity(int);
- method public void setForegroundTintList(android.content.res.ColorStateList);
- method public void setForegroundTintMode(android.graphics.PorterDuff.Mode);
method public void setMeasureAllChildren(boolean);
}
@@ -41772,7 +41970,7 @@ package android.widget {
method public void setTouchInterceptor(android.view.View.OnTouchListener);
method public void setTouchable(boolean);
method public void setWidth(int);
- method public void setWindowLayoutMode(int, int);
+ method public deprecated void setWindowLayoutMode(int, int);
method public void showAsDropDown(android.view.View);
method public void showAsDropDown(android.view.View, int, int);
method public void showAsDropDown(android.view.View, int, int, int);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 1b209a9cb154..c2b9d3ef8c72 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -1,3 +1,11 @@
+package android.content.pm {
+
+ public class PackageInfo implements android.os.Parcelable {
+ field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
+ }
+
+}
+
package android.media {
public class AudioFormat {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 29ba1d7a146f..0a53371bae62 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -112,7 +112,7 @@ public class Am extends BaseCommand {
" am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" +
" [--user <USER_ID> | current]\n" +
" [--no-window-animation] [--abi <ABI>] <COMPONENT>\n" +
- " am profile start [--user <USER_ID> current] <PROCESS> <FILE>\n" +
+ " am profile start [--user <USER_ID> current] [--sampling INTERVAL] <PROCESS> <FILE>\n" +
" am profile stop [--user <USER_ID> current] [<PROCESS>]\n" +
" am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" +
" am set-debug-app [-w] [--persistent] <PACKAGE>\n" +
@@ -1031,6 +1031,7 @@ public class Am extends BaseCommand {
boolean wall = false;
int userId = UserHandle.USER_CURRENT;
int profileType = 0;
+ mSamplingInterval = 0;
String process = null;
@@ -1044,6 +1045,8 @@ public class Am extends BaseCommand {
userId = parseUserArg(nextArgRequired());
} else if (opt.equals("--wall")) {
wall = true;
+ } else if (opt.equals("--sampling")) {
+ mSamplingInterval = Integer.parseInt(nextArgRequired());
} else {
System.err.println("Error: Unknown option: " + opt);
return;
@@ -1093,7 +1096,7 @@ public class Am extends BaseCommand {
System.err.println("Consider using a file under /data/local/tmp/");
return;
}
- profilerInfo = new ProfilerInfo(profileFile, fd, 0, false);
+ profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false);
}
try {
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index c48a61817ed2..89dd0792cbe3 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -892,6 +892,8 @@ public final class Pm {
installFlags |= PackageManager.INSTALL_INTERNAL;
} else if (opt.equals("-d")) {
installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
+ } else if (opt.equals("-g")) {
+ installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS;
} else if (opt.equals("--originating-uri")) {
originatingUriString = nextOptionData();
if (originatingUriString == null) {
@@ -1517,6 +1519,15 @@ public final class Pm {
}
private int runGrantRevokePermission(boolean grant) {
+ int userId = UserHandle.USER_CURRENT;
+
+ String opt = null;
+ while ((opt = nextOption()) != null) {
+ if (opt.equals("--user")) {
+ userId = Integer.parseInt(nextArg());
+ }
+ }
+
String pkg = nextArg();
if (pkg == null) {
System.err.println("Error: no package specified");
@@ -1529,11 +1540,12 @@ public final class Pm {
showUsage();
return 1;
}
+
try {
if (grant) {
- mPm.grantPermission(pkg, perm);
+ mPm.grantPermission(pkg, perm, userId);
} else {
- mPm.revokePermission(pkg, perm);
+ mPm.revokePermission(pkg, perm, userId);
}
return 0;
} catch (RemoteException e) {
@@ -1815,8 +1827,8 @@ public final class Pm {
System.err.println(" pm disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm hide [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm unhide [--user USER_ID] PACKAGE_OR_COMPONENT");
- System.err.println(" pm grant PACKAGE PERMISSION");
- System.err.println(" pm revoke PACKAGE PERMISSION");
+ System.err.println(" pm grant [--user USER_ID] PACKAGE PERMISSION");
+ System.err.println(" pm revoke [--user USER_ID] PACKAGE PERMISSION");
System.err.println(" pm set-install-location [0/auto] [1/internal] [2/external]");
System.err.println(" pm get-install-location");
System.err.println(" pm set-permission-enforced PERMISSION [true|false]");
@@ -1868,6 +1880,7 @@ public final class Pm {
System.err.println(" -f: install application on internal flash");
System.err.println(" -d: allow version code downgrade");
System.err.println(" -p: partial application install");
+ System.err.println(" -g: grant all runtime permissions");
System.err.println(" -S: size in bytes of entire session");
System.err.println("");
System.err.println("pm install-write: write a package into existing session; path may");
@@ -1889,8 +1902,9 @@ public final class Pm {
System.err.println(" as \"package/class\").");
System.err.println("");
System.err.println("pm grant, revoke: these commands either grant or revoke permissions");
- System.err.println(" to applications. Only optional permissions the application has");
- System.err.println(" declared can be granted or revoked.");
+ System.err.println(" to apps. The permissions must be declared as used in the app's");
+ System.err.println(" manifest, be runtime permissions (protection level dangerous),");
+ System.err.println(" and the app targeting SDK greater than Lollipop MR1.");
System.err.println("");
System.err.println("pm get-install-location: returns the current install location.");
System.err.println(" 0 [auto]: Let system decide the best location");
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 7fcbe35839ad..b5817df5bd38 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3726,6 +3726,95 @@ public class Activity extends ContextThemeWrapper
}
/**
+ * Requests permissions to be granted to this application. These permissions
+ * must be requested in your manifest, they should not be granted to your app,
+ * and they should have protection level {@link android.content.pm.PermissionInfo
+ * #PROTECTION_DANGEROUS dangerous}, regardless whether they are declared by
+ * the platform or a third-party app.
+ * <p>
+ * Normal permissions {@link android.content.pm.PermissionInfo#PROTECTION_NORMAL}
+ * are granted at install time if requested in the manifest. Signature permissions
+ * {@link android.content.pm.PermissionInfo#PROTECTION_SIGNATURE} are granted at
+ * install time if requested in the manifest and the signature of your app matches
+ * the signature of the app declaring the permissions.
+ * </p>
+ * <p>
+ * If your app does not have the requested permissions the user will be presented
+ * with UI for accepting them. After the user has accepted or rejected the
+ * requested permissions you will receive a callback on {@link
+ * #onRequestPermissionsResult(int, String[], int[])} reporting whether the
+ * permissions were granted or not.
+ * </p>
+ * <p>
+ * Note that requesting a permission does not guarantee it will be granted and
+ * your app should be able to run without having this permission.
+ * </p>
+ * <p>
+ * This method may start an activity allowing the user to choose which permissions
+ * to grant and which to reject. Hence, you should be prepared that your activity
+ * may be paused and resumed. Further, granting some permissions may require
+ * a restart of you application. In such a case, the system will recreate the
+ * activity stack before delivering the result to {@link
+ * #onRequestPermissionsResult(int, String[], int[])}.
+ * </p>
+ * <p>
+ * When checking whether you have a permission you should use {@link
+ * #checkSelfPermission(String)}.
+ * </p>
+ * <p>
+ * A sample permissions request looks like this:
+ * </p>
+ * <code><pre><p>
+ * private void showContacts() {
+ * if (checkSelfPermission(Manifest.permission.READ_CONTACTS)
+ * != PackageManager.PERMISSION_GRANTED) {
+ * requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
+ * PERMISSIONS_REQUEST_READ_CONTACTS);
+ * } else {
+ * doShowContacts();
+ * }
+ * }
+ *
+ * {@literal @}Override
+ * public void onRequestPermissionsResult(int requestCode, String[] permissions,
+ * int[] grantResults) {
+ * if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS
+ * && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ * showContacts();
+ * }
+ * }
+ * </code></pre></p>
+ *
+ * @param permissions The requested permissions.
+ * @param requestCode Application specific request code to match with a result
+ * reported to {@link #onRequestPermissionsResult(int, String[], int[])}.
+ *
+ * @see #onRequestPermissionsResult(int, String[], int[])
+ * @see #checkSelfPermission(String)
+ */
+ public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
+ Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
+ startActivityForResult(intent, requestCode);
+ }
+
+ /**
+ * Callback for the result from requesting permissions. This method
+ * is invoked for every call on {@link #requestPermissions(String[], int)}.
+ *
+ * @param requestCode The request code passed in {@link #requestPermissions(String[], int)}.
+ * @param permissions The requested permissions. Never null.
+ * @param grantResults The grant results for the corresponding permissions
+ * which is either {@link android.content.pm.PackageManager#PERMISSION_GRANTED}
+ * or {@link android.content.pm.PackageManager#PERMISSION_DENIED}. Never null.
+ *
+ * @see #requestPermissions(String[], int)
+ */
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
+ /* callback - no nothing */
+ }
+
+ /**
* Same as calling {@link #startActivityForResult(Intent, int, Bundle)}
* with no options.
*
@@ -6269,11 +6358,19 @@ public class Activity extends ContextThemeWrapper
+ ", resCode=" + resultCode + ", data=" + data);
mFragments.noteStateNotSaved();
if (who == null) {
- onActivityResult(requestCode, resultCode, data);
+ if (isRequestPermissionResult(data)) {
+ dispatchRequestPermissionsResult(requestCode, data);
+ } else {
+ onActivityResult(requestCode, resultCode, data);
+ }
} else {
Fragment frag = mFragments.findFragmentByWho(who);
if (frag != null) {
- frag.onActivityResult(requestCode, resultCode, data);
+ if (isRequestPermissionResult(data)) {
+ dispatchRequestPermissionsResultToFragment(requestCode, data, frag);
+ } else {
+ frag.onActivityResult(requestCode, resultCode, data);
+ }
}
}
}
@@ -6343,4 +6440,26 @@ public class Activity extends ContextThemeWrapper
*/
public void onTranslucentConversionComplete(boolean drawComplete);
}
+
+ private void dispatchRequestPermissionsResult(int requestCode, Intent data) {
+ String[] permissions = data.getStringArrayExtra(
+ PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES);
+ final int[] grantResults = data.getIntArrayExtra(
+ PackageManager.EXTRA_REQUEST_PERMISSIONS_RESULTS);
+ onRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
+
+ private void dispatchRequestPermissionsResultToFragment(int requestCode, Intent data,
+ Fragment fragement) {
+ String[] permissions = data.getStringArrayExtra(
+ PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES);
+ final int[] grantResults = data.getIntArrayExtra(
+ PackageManager.EXTRA_REQUEST_PERMISSIONS_RESULTS);
+ fragement.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
+
+ private static boolean isRequestPermissionResult(Intent intent) {
+ return intent != null
+ && PackageManager.ACTION_REQUEST_PERMISSIONS.equals(intent.getAction());
+ }
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 29b024ac751e..d143f8b5d65b 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2493,7 +2493,8 @@ public class ActivityManager {
public static int checkComponentPermission(String permission, int uid,
int owningUid, boolean exported) {
// Root, system server get to do everything.
- if (uid == 0 || uid == Process.SYSTEM_UID) {
+ final int appId = UserHandle.getAppId(uid);
+ if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
return PackageManager.PERMISSION_GRANTED;
}
// Isolated processes don't get any permissions.
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 2cb27b05ff8b..eafcdb24c3d1 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -350,10 +350,15 @@ public class ActivityView extends ViewGroup {
if (activityView != null) {
final ActivityViewCallback callback = activityView.mActivityViewCallback;
if (callback != null) {
+ final WeakReference<ActivityViewCallback> callbackRef =
+ new WeakReference<>(callback);
activityView.post(new Runnable() {
@Override
public void run() {
- callback.onAllActivitiesComplete(activityView);
+ ActivityViewCallback callback = callbackRef.get();
+ if (callback != null) {
+ callback.onAllActivitiesComplete(activityView);
+ }
}
});
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 9f81670013c5..6d74905cf9e2 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -81,7 +81,6 @@ import java.util.List;
/*package*/
final class ApplicationPackageManager extends PackageManager {
private static final String TAG = "ApplicationPackageManager";
- private final static boolean DEBUG = false;
private final static boolean DEBUG_ICONS = false;
// Default flags to use with PackageManager when no flags are given.
@@ -186,8 +185,8 @@ final class ApplicationPackageManager extends PackageManager {
public int[] getPackageGids(String packageName)
throws NameNotFoundException {
try {
- int[] gids = mPM.getPackageGids(packageName);
- if (gids == null || gids.length > 0) {
+ int[] gids = mPM.getPackageGids(packageName, mContext.getUserId());
+ if (gids != null) {
return gids;
}
} catch (RemoteException e) {
@@ -398,7 +397,7 @@ final class ApplicationPackageManager extends PackageManager {
@Override
public int checkPermission(String permName, String pkgName) {
try {
- return mPM.checkPermission(permName, pkgName);
+ return mPM.checkPermission(permName, pkgName, mContext.getUserId());
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
@@ -432,18 +431,18 @@ final class ApplicationPackageManager extends PackageManager {
}
@Override
- public void grantPermission(String packageName, String permissionName) {
+ public void grantPermission(String packageName, String permissionName, UserHandle user) {
try {
- mPM.grantPermission(packageName, permissionName);
+ mPM.grantPermission(packageName, permissionName, user.getIdentifier());
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
}
@Override
- public void revokePermission(String packageName, String permissionName) {
+ public void revokePermission(String packageName, String permissionName, UserHandle user) {
try {
- mPM.revokePermission(packageName, permissionName);
+ mPM.revokePermission(packageName, permissionName, user.getIdentifier());
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
diff --git a/core/java/android/app/AssistStructure.java b/core/java/android/app/AssistStructure.java
index 25153fc5e24f..c435ccb27d7f 100644
--- a/core/java/android/app/AssistStructure.java
+++ b/core/java/android/app/AssistStructure.java
@@ -17,6 +17,7 @@
package android.app;
import android.content.ComponentName;
+import android.content.res.Resources;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
@@ -53,7 +54,7 @@ final public class AssistStructure implements Parcelable {
final ComponentName mActivityComponent;
- final ArrayList<ViewNodeImpl> mRootViews = new ArrayList<>();
+ final ArrayList<WindowNode> mWindowNodes = new ArrayList<>();
ViewAssistStructureImpl mTmpViewAssistStructureImpl = new ViewAssistStructureImpl();
Bundle mTmpExtras = new Bundle();
@@ -178,7 +179,91 @@ final public class AssistStructure implements Parcelable {
}
}
- final static class ViewNodeImpl {
+ /**
+ * Describes a window in the assist data.
+ */
+ static public class WindowNode {
+ final int mX;
+ final int mY;
+ final int mWidth;
+ final int mHeight;
+ final CharSequence mTitle;
+ final ViewNode mRoot;
+
+ WindowNode(AssistStructure assist, ViewRootImpl root) {
+ View view = root.getView();
+ Rect rect = new Rect();
+ view.getBoundsOnScreen(rect);
+ mX = rect.left - view.getLeft();
+ mY = rect.top - view.getTop();
+ mWidth = rect.width();
+ mHeight = rect.height();
+ mTitle = root.getTitle();
+ mRoot = new ViewNode(assist, view);
+ }
+
+ WindowNode(Parcel in, PooledStringReader preader) {
+ mX = in.readInt();
+ mY = in.readInt();
+ mWidth = in.readInt();
+ mHeight = in.readInt();
+ mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ mRoot = new ViewNode(in, preader);
+ }
+
+ void writeToParcel(Parcel out, PooledStringWriter pwriter) {
+ out.writeInt(mX);
+ out.writeInt(mY);
+ out.writeInt(mWidth);
+ out.writeInt(mHeight);
+ TextUtils.writeToParcel(mTitle, out, 0);
+ mRoot.writeToParcel(out, pwriter);
+ }
+
+ public int getLeft() {
+ return mX;
+ }
+
+ public int getTop() {
+ return mY;
+ }
+
+ public int getWidth() {
+ return mWidth;
+ }
+
+ public int getHeight() {
+ return mHeight;
+ }
+
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ public ViewNode getRootViewNode() {
+ return mRoot;
+ }
+ }
+
+ /**
+ * Describes a single view in the assist data.
+ */
+ static public class ViewNode {
+ /**
+ * Magic value for text color that has not been defined, which is very unlikely
+ * to be confused with a real text color.
+ */
+ public static final int TEXT_COLOR_UNDEFINED = 1;
+
+ public static final int TEXT_STYLE_BOLD = 1<<0;
+ public static final int TEXT_STYLE_ITALIC = 1<<1;
+ public static final int TEXT_STYLE_UNDERLINE = 1<<2;
+ public static final int TEXT_STYLE_STRIKE_THRU = 1<<3;
+
+ final int mId;
+ final String mIdPackage;
+ final String mIdType;
+ final String mIdEntry;
final int mX;
final int mY;
final int mScrollX;
@@ -201,17 +286,34 @@ final public class AssistStructure implements Parcelable {
final int mFlags;
final String mClassName;
- final String mContentDescription;
+ final CharSequence mContentDescription;
final ViewNodeTextImpl mText;
final Bundle mExtras;
- final ViewNodeImpl[] mChildren;
-
- ViewNodeImpl(AssistStructure assistStructure, View view, int left, int top,
- CharSequence contentDescription) {
- mX = left;
- mY = top;
+ final ViewNode[] mChildren;
+
+ ViewNode(AssistStructure assistStructure, View view) {
+ mId = view.getId();
+ if (mId > 0 && (mId&0xff000000) != 0 && (mId&0x00ff0000) != 0
+ && (mId&0x0000ffff) != 0) {
+ String pkg, type, entry;
+ try {
+ Resources res = view.getResources();
+ entry = res.getResourceEntryName(mId);
+ type = res.getResourceTypeName(mId);
+ pkg = res.getResourcePackageName(mId);
+ } catch (Resources.NotFoundException e) {
+ entry = type = pkg = null;
+ }
+ mIdPackage = pkg;
+ mIdType = type;
+ mIdEntry = entry;
+ } else {
+ mIdPackage = mIdType = mIdEntry = null;
+ }
+ mX = view.getLeft();
+ mY = view.getTop();
mScrollX = view.getScrollX();
mScrollY = view.getScrollY();
mWidth = view.getWidth();
@@ -249,7 +351,7 @@ final public class AssistStructure implements Parcelable {
}
mFlags = flags;
mClassName = view.getAccessibilityClassName().toString();
- mContentDescription = contentDescription != null ? contentDescription.toString() : null;
+ mContentDescription = view.getContentDescription();
final ViewAssistStructureImpl viewData = assistStructure.mTmpViewAssistStructureImpl;
final Bundle extras = assistStructure.mTmpExtras;
view.onProvideAssistStructure(viewData, extras);
@@ -269,9 +371,9 @@ final public class AssistStructure implements Parcelable {
ViewGroup vg = (ViewGroup)view;
final int NCHILDREN = vg.getChildCount();
if (NCHILDREN > 0) {
- mChildren = new ViewNodeImpl[NCHILDREN];
+ mChildren = new ViewNode[NCHILDREN];
for (int i=0; i<NCHILDREN; i++) {
- mChildren[i] = new ViewNodeImpl(assistStructure, vg.getChildAt(i));
+ mChildren[i] = new ViewNode(assistStructure, vg.getChildAt(i));
}
} else {
mChildren = null;
@@ -281,11 +383,19 @@ final public class AssistStructure implements Parcelable {
}
}
- ViewNodeImpl(AssistStructure assistStructure, View view) {
- this(assistStructure, view, view.getLeft(), view.getTop(), view.getContentDescription());
- }
-
- ViewNodeImpl(Parcel in, PooledStringReader preader) {
+ ViewNode(Parcel in, PooledStringReader preader) {
+ mId = in.readInt();
+ if (mId != 0) {
+ mIdEntry = preader.readString();
+ if (mIdEntry != null) {
+ mIdType = preader.readString();
+ mIdPackage = preader.readString();
+ } else {
+ mIdPackage = mIdType = null;
+ }
+ } else {
+ mIdPackage = mIdType = mIdEntry = null;
+ }
mX = in.readInt();
mY = in.readInt();
mScrollX = in.readInt();
@@ -294,7 +404,7 @@ final public class AssistStructure implements Parcelable {
mHeight = in.readInt();
mFlags = in.readInt();
mClassName = preader.readString();
- mContentDescription = in.readString();
+ mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
if (in.readInt() != 0) {
mText = new ViewNodeTextImpl(in);
} else {
@@ -303,9 +413,9 @@ final public class AssistStructure implements Parcelable {
mExtras = in.readBundle();
final int NCHILDREN = in.readInt();
if (NCHILDREN > 0) {
- mChildren = new ViewNodeImpl[NCHILDREN];
+ mChildren = new ViewNode[NCHILDREN];
for (int i=0; i<NCHILDREN; i++) {
- mChildren[i] = new ViewNodeImpl(in, preader);
+ mChildren[i] = new ViewNode(in, preader);
}
} else {
mChildren = null;
@@ -313,6 +423,14 @@ final public class AssistStructure implements Parcelable {
}
void writeToParcel(Parcel out, PooledStringWriter pwriter) {
+ out.writeInt(mId);
+ if (mId != 0) {
+ pwriter.writeString(mIdEntry);
+ if (mIdEntry != null) {
+ pwriter.writeString(mIdType);
+ pwriter.writeString(mIdPackage);
+ }
+ }
out.writeInt(mX);
out.writeInt(mY);
out.writeInt(mScrollX);
@@ -321,7 +439,7 @@ final public class AssistStructure implements Parcelable {
out.writeInt(mHeight);
out.writeInt(mFlags);
pwriter.writeString(mClassName);
- out.writeString(mContentDescription);
+ TextUtils.writeToParcel(mContentDescription, out, 0);
if (mText != null) {
out.writeInt(1);
mText.writeToParcel(out);
@@ -339,146 +457,141 @@ final public class AssistStructure implements Parcelable {
out.writeInt(0);
}
}
- }
- /**
- * Provides access to information about a single view in the assist data.
- */
- static public class ViewNode {
- /**
- * Magic value for text color that has not been defined, which is very unlikely
- * to be confused with a real text color.
- */
- public static final int TEXT_COLOR_UNDEFINED = 1;
+ public int getId() {
+ return mId;
+ }
- public static final int TEXT_STYLE_BOLD = 1<<0;
- public static final int TEXT_STYLE_ITALIC = 1<<1;
- public static final int TEXT_STYLE_UNDERLINE = 1<<2;
- public static final int TEXT_STYLE_STRIKE_THRU = 1<<3;
+ public String getIdPackage() {
+ return mIdPackage;
+ }
- ViewNodeImpl mImpl;
+ public String getIdType() {
+ return mIdType;
+ }
- public ViewNode() {
+ public String getIdEntry() {
+ return mIdEntry;
}
public int getLeft() {
- return mImpl.mX;
+ return mX;
}
public int getTop() {
- return mImpl.mY;
+ return mY;
}
public int getScrollX() {
- return mImpl.mScrollX;
+ return mScrollX;
}
public int getScrollY() {
- return mImpl.mScrollY;
+ return mScrollY;
}
public int getWidth() {
- return mImpl.mWidth;
+ return mWidth;
}
public int getHeight() {
- return mImpl.mHeight;
+ return mHeight;
}
public int getVisibility() {
- return mImpl.mFlags&ViewNodeImpl.FLAGS_VISIBILITY_MASK;
+ return mFlags&ViewNode.FLAGS_VISIBILITY_MASK;
}
public boolean isEnabled() {
- return (mImpl.mFlags&ViewNodeImpl.FLAGS_DISABLED) == 0;
+ return (mFlags&ViewNode.FLAGS_DISABLED) == 0;
}
public boolean isClickable() {
- return (mImpl.mFlags&ViewNodeImpl.FLAGS_CLICKABLE) != 0;
+ return (mFlags&ViewNode.FLAGS_CLICKABLE) != 0;
}
public boolean isFocusable() {
- return (mImpl.mFlags&ViewNodeImpl.FLAGS_FOCUSABLE) != 0;
+ return (mFlags&ViewNode.FLAGS_FOCUSABLE) != 0;
}
public boolean isFocused() {
- return (mImpl.mFlags&ViewNodeImpl.FLAGS_FOCUSED) != 0;
+ return (mFlags&ViewNode.FLAGS_FOCUSED) != 0;
}
public boolean isAccessibilityFocused() {
- return (mImpl.mFlags&ViewNodeImpl.FLAGS_ACCESSIBILITY_FOCUSED) != 0;
+ return (mFlags&ViewNode.FLAGS_ACCESSIBILITY_FOCUSED) != 0;
}
public boolean isCheckable() {
- return (mImpl.mFlags&ViewNodeImpl.FLAGS_CHECKABLE) != 0;
+ return (mFlags&ViewNode.FLAGS_CHECKABLE) != 0;
}
public boolean isChecked() {
- return (mImpl.mFlags&ViewNodeImpl.FLAGS_CHECKED) != 0;
+ return (mFlags&ViewNode.FLAGS_CHECKED) != 0;
}
public boolean isSelected() {
- return (mImpl.mFlags&ViewNodeImpl.FLAGS_SELECTED) != 0;
+ return (mFlags&ViewNode.FLAGS_SELECTED) != 0;
}
public boolean isActivated() {
- return (mImpl.mFlags&ViewNodeImpl.FLAGS_ACTIVATED) != 0;
+ return (mFlags&ViewNode.FLAGS_ACTIVATED) != 0;
}
public boolean isLongClickable() {
- return (mImpl.mFlags&ViewNodeImpl.FLAGS_LONG_CLICKABLE) != 0;
+ return (mFlags&ViewNode.FLAGS_LONG_CLICKABLE) != 0;
}
public String getClassName() {
- return mImpl.mClassName;
+ return mClassName;
}
- public String getContentDescription() {
- return mImpl.mContentDescription;
+ public CharSequence getContentDescription() {
+ return mContentDescription;
}
public CharSequence getText() {
- return mImpl.mText != null ? mImpl.mText.mText : null;
+ return mText != null ? mText.mText : null;
}
public int getTextSelectionStart() {
- return mImpl.mText != null ? mImpl.mText.mTextSelectionStart : -1;
+ return mText != null ? mText.mTextSelectionStart : -1;
}
public int getTextSelectionEnd() {
- return mImpl.mText != null ? mImpl.mText.mTextSelectionEnd : -1;
+ return mText != null ? mText.mTextSelectionEnd : -1;
}
public int getTextColor() {
- return mImpl.mText != null ? mImpl.mText.mTextColor : TEXT_COLOR_UNDEFINED;
+ return mText != null ? mText.mTextColor : TEXT_COLOR_UNDEFINED;
}
public int getTextBackgroundColor() {
- return mImpl.mText != null ? mImpl.mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
+ return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
}
public float getTextSize() {
- return mImpl.mText != null ? mImpl.mText.mTextSize : 0;
+ return mText != null ? mText.mTextSize : 0;
}
public int getTextStyle() {
- return mImpl.mText != null ? mImpl.mText.mTextStyle : 0;
+ return mText != null ? mText.mTextStyle : 0;
}
public String getHint() {
- return mImpl.mText != null ? mImpl.mText.mHint : null;
+ return mText != null ? mText.mHint : null;
}
public Bundle getExtras() {
- return mImpl.mExtras;
+ return mExtras;
}
public int getChildCount() {
- return mImpl.mChildren != null ? mImpl.mChildren.length : 0;
+ return mChildren != null ? mChildren.length : 0;
}
- public void getChildAt(int index, ViewNode outNode) {
- outNode.mImpl = mImpl.mChildren[index];
+ public ViewNode getChildAt(int index) {
+ return mChildren[index];
}
}
@@ -488,12 +601,7 @@ final public class AssistStructure implements Parcelable {
activity.getActivityToken());
for (int i=0; i<views.size(); i++) {
ViewRootImpl root = views.get(i);
- View view = root.getView();
- Rect rect = new Rect();
- view.getBoundsOnScreen(rect);
- CharSequence title = root.getTitle();
- mRootViews.add(new ViewNodeImpl(this, view, rect.left, rect.top,
- title != null ? title : view.getContentDescription()));
+ mWindowNodes.add(new WindowNode(this, root));
}
}
@@ -502,7 +610,7 @@ final public class AssistStructure implements Parcelable {
mActivityComponent = ComponentName.readFromParcel(in);
final int N = in.readInt();
for (int i=0; i<N; i++) {
- mRootViews.add(new ViewNodeImpl(in, preader));
+ mWindowNodes.add(new WindowNode(in, preader));
}
//dump();
}
@@ -510,24 +618,37 @@ final public class AssistStructure implements Parcelable {
/** @hide */
public void dump() {
Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString());
- ViewNode node = new ViewNode();
- final int N = getWindowCount();
+ final int N = getWindowNodeCount();
for (int i=0; i<N; i++) {
- Log.i(TAG, "Window #" + i + ":");
- getWindowAt(i, node);
- dump(" ", node);
+ WindowNode node = getWindowNodeAt(i);
+ Log.i(TAG, "Window #" + i + " [" + node.getLeft() + "," + node.getTop()
+ + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getTitle());
+ dump(" ", node.getRootViewNode());
}
}
void dump(String prefix, ViewNode node) {
Log.i(TAG, prefix + "View [" + node.getLeft() + "," + node.getTop()
+ " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getClassName());
+ int id = node.getId();
+ if (id != 0) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(prefix); sb.append(" ID: #"); sb.append(Integer.toHexString(id));
+ String entry = node.getIdEntry();
+ if (entry != null) {
+ String type = node.getIdType();
+ String pkg = node.getIdPackage();
+ sb.append(" "); sb.append(pkg); sb.append(":"); sb.append(type);
+ sb.append("/"); sb.append(entry);
+ }
+ Log.i(TAG, sb.toString());
+ }
int scrollX = node.getScrollX();
int scrollY = node.getScrollY();
if (scrollX != 0 || scrollY != 0) {
Log.i(TAG, prefix + " Scroll: " + scrollX + "," + scrollY);
}
- String contentDescription = node.getContentDescription();
+ CharSequence contentDescription = node.getContentDescription();
if (contentDescription != null) {
Log.i(TAG, prefix + " Content description: " + contentDescription);
}
@@ -552,9 +673,8 @@ final public class AssistStructure implements Parcelable {
if (NCHILDREN > 0) {
Log.i(TAG, prefix + " Children:");
String cprefix = prefix + " ";
- ViewNode cnode = new ViewNode();
for (int i=0; i<NCHILDREN; i++) {
- node.getChildAt(i, cnode);
+ ViewNode cnode = node.getChildAt(i);
dump(cprefix, cnode);
}
}
@@ -575,17 +695,16 @@ final public class AssistStructure implements Parcelable {
/**
* Return the number of window contents that have been collected in this assist data.
*/
- public int getWindowCount() {
- return mRootViews.size();
+ public int getWindowNodeCount() {
+ return mWindowNodes.size();
}
/**
- * Return the root view for one of the windows in the assist data.
- * @param index Which window to retrieve, may be 0 to {@link #getWindowCount()}-1.
- * @param outNode Node in which to place the window's root view.
+ * Return one of the windows in the assist data.
+ * @param index Which window to retrieve, may be 0 to {@link #getWindowNodeCount()}-1.
*/
- public void getWindowAt(int index, ViewNode outNode) {
- outNode.mImpl = mRootViews.get(index);
+ public WindowNode getWindowNodeAt(int index) {
+ return mWindowNodes.get(index);
}
public int describeContents() {
@@ -596,10 +715,10 @@ final public class AssistStructure implements Parcelable {
int start = out.dataPosition();
PooledStringWriter pwriter = new PooledStringWriter(out);
ComponentName.writeToParcel(mActivityComponent, out);
- final int N = mRootViews.size();
+ final int N = mWindowNodes.size();
out.writeInt(N);
for (int i=0; i<N; i++) {
- mRootViews.get(i).writeToParcel(out, pwriter);
+ mWindowNodes.get(i).writeToParcel(out, pwriter);
}
pwriter.finish();
Log.i(TAG, "Flattened assist data: " + (out.dataPosition() - start) + " bytes");
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index eb27830895e0..4ccd69fa5088 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1323,6 +1323,15 @@ class ContextImpl extends Context {
Binder.getCallingUid());
}
+ @Override
+ public int checkSelfPermission(String permission) {
+ if (permission == null) {
+ throw new IllegalArgumentException("permission is null");
+ }
+
+ return checkPermission(permission, Process.myPid(), Process.myUid());
+ }
+
private void enforce(
String permission, int resultOfCheck,
boolean selfToo, int uid, String message) {
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index bdcc3127eec5..4fdae7f8b95a 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -17,6 +17,7 @@
package android.app;
import android.animation.Animator;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.content.ComponentCallbacks2;
@@ -1092,13 +1093,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
if (mActivity == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
- if (options != null) {
- mActivity.startActivityFromFragment(this, intent, requestCode, options);
- } else {
- // Note we want to go through this call for compatibility with
- // applications that may have overridden the method.
- mActivity.startActivityFromFragment(this, intent, requestCode, options);
- }
+ mActivity.startActivityFromFragment(this, intent, requestCode, options);
}
/**
@@ -1119,6 +1114,98 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
}
/**
+ * Requests permissions to be granted to this application. These permissions
+ * must be requested in your manifest, they should not be granted to your app,
+ * and they should have protection level {@link android.content.pm.PermissionInfo
+ * #PROTECTION_DANGEROUS dangerous}, regardless whether they are declared by
+ * the platform or a third-party app.
+ * <p>
+ * Normal permissions {@link android.content.pm.PermissionInfo#PROTECTION_NORMAL}
+ * are granted at install time if requested in the manifest. Signature permissions
+ * {@link android.content.pm.PermissionInfo#PROTECTION_SIGNATURE} are granted at
+ * install time if requested in the manifest and the signature of your app matches
+ * the signature of the app declaring the permissions.
+ * </p>
+ * <p>
+ * If your app does not have the requested permissions the user will be presented
+ * with UI for accepting them. After the user has accepted or rejected the
+ * requested permissions you will receive a callback on {@link
+ * #onRequestPermissionsResult(int, String[], int[])} reporting whether the
+ * permissions were granted or not.
+ * </p>
+ * <p>
+ * Note that requesting a permission does not guarantee it will be granted and
+ * your app should be able to run without having this permission.
+ * </p>
+ * <p>
+ * This method may start an activity allowing the user to choose which permissions
+ * to grant and which to reject. Hence, you should be prepared that your activity
+ * may be paused and resumed. Further, granting some permissions may require
+ * a restart of you application. In such a case, the system will recreate the
+ * activity stack before delivering the result to {@link
+ * #onRequestPermissionsResult(int, String[], int[])}.
+ * </p>
+ * <p>
+ * When checking whether you have a permission you should use {@link
+ * android.content.Context#checkSelfPermission(String)}.
+ * </p>
+ * <p>
+ * A sample permissions request looks like this:
+ * </p>
+ * <code><pre><p>
+ * private void showContacts() {
+ * if (getActivity().checkSelfPermission(Manifest.permission.READ_CONTACTS)
+ * != PackageManager.PERMISSION_GRANTED) {
+ * requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
+ * PERMISSIONS_REQUEST_READ_CONTACTS);
+ * } else {
+ * doShowContacts();
+ * }
+ * }
+ *
+ * {@literal @}Override
+ * public void onRequestPermissionsResult(int requestCode, String[] permissions,
+ * int[] grantResults) {
+ * if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS
+ * && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ * doShowContacts();
+ * }
+ * }
+ * </code></pre></p>
+ *
+ * @param permissions The requested permissions.
+ * @param requestCode Application specific request code to match with a result
+ * reported to {@link #onRequestPermissionsResult(int, String[], int[])}.
+ *
+ * @see #onRequestPermissionsResult(int, String[], int[])
+ * @see android.content.Context#checkSelfPermission(String)
+ */
+ public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
+ if (mActivity == null) {
+ throw new IllegalStateException("Fragment " + this + " not attached to Activity");
+ }
+ Intent intent = mActivity.getPackageManager().buildRequestPermissionsIntent(permissions);
+ mActivity.startActivityFromFragment(this, intent, requestCode, null);
+ }
+
+ /**
+ * Callback for the result from requesting permissions. This method
+ * is invoked for every call on {@link #requestPermissions(String[], int)}.
+ *
+ * @param requestCode The request code passed in {@link #requestPermissions(String[], int)}.
+ * @param permissions The requested permissions. Never null.
+ * @param grantResults The grant results for the corresponding permissions
+ * which is either {@link android.content.pm.PackageManager#PERMISSION_GRANTED}
+ * or {@link android.content.pm.PackageManager#PERMISSION_DENIED}. Never null.
+ *
+ * @see #requestPermissions(String[], int)
+ */
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
+ /* callback - do nothing */
+ }
+
+ /**
* @hide Hack so that DialogFragment can make its Dialog before creating
* its views, and the view construction can use the dialog's context for
* inflation. Maybe this should become a public API. Note sure.
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index fd7bae70d012..59fe490192de 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -27,6 +27,7 @@ import android.app.job.IJobScheduler;
import android.app.job.JobScheduler;
import android.app.trust.TrustManager;
import android.app.usage.IUsageStatsManager;
+import android.app.usage.NetworkStatsManager;
import android.app.usage.UsageStatsManager;
import android.appwidget.AppWidgetManager;
import android.bluetooth.BluetoothManager;
@@ -639,6 +640,13 @@ final class SystemServiceRegistry {
return new UsageStatsManager(ctx.getOuterContext(), service);
}});
+ registerService(Context.NETWORK_STATS_SERVICE, NetworkStatsManager.class,
+ new CachedServiceFetcher<NetworkStatsManager>() {
+ @Override
+ public NetworkStatsManager createService(ContextImpl ctx) {
+ return new NetworkStatsManager(ctx.getOuterContext());
+ }});
+
registerService(Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
new StaticServiceFetcher<JobScheduler>() {
@Override
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 682a46809692..cf6619fa23ce 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -20,7 +20,6 @@ import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.app.Activity;
-import android.app.admin.IDevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -176,7 +175,8 @@ public class DevicePolicyManager {
*
* <p>This component is set as device owner and active admin when device owner provisioning is
* started by an NFC message containing an NFC record with MIME type
- * {@link #MIME_TYPE_PROVISIONING_NFC}.
+ * {@link #MIME_TYPE_PROVISIONING_NFC_V2}. For the NFC record, the component name should be
+ * flattened to a string, via {@link ComponentName#flattenToShortString()}.
*
* @see DeviceAdminReceiver
*/
@@ -341,6 +341,18 @@ public class DevicePolicyManager {
= "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
/**
+ * An int extra holding a minimum required version code for the device admin package. If the
+ * device admin is already installed on the device, it will only be re-downloaded from
+ * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION} if the version of the
+ * installed package is less than this version code.
+ *
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
+ * provisioning via an NFC bump.
+ */
+ public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE
+ = "android.app.extra.PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE";
+
+ /**
* A String extra holding a http cookie header which should be used in the http request to the
* url specified in {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
*
@@ -351,10 +363,10 @@ public class DevicePolicyManager {
= "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
/**
- * A String extra holding the SHA-1 checksum of the file at download location specified in
- * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}. If this doesn't match
- * the file at the download location an error will be shown to the user and the user will be
- * asked to factory reset the device.
+ * A String extra holding the URL-safe base64 encoded SHA-1 checksum of the file at download
+ * location specified in {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}. If
+ * this doesn't match the file at the download location an error will be shown to the user and
+ * the user will be asked to factory reset the device.
*
* <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
* provisioning via an NFC bump.
@@ -380,21 +392,23 @@ public class DevicePolicyManager {
* A boolean extra indicating whether device encryption is required as part of Device Owner
* provisioning.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION =
"android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
/**
- * On devices managed by a device owner app, a String representation of a Component name extra
- * indicating the component of the application that is temporarily granted device owner
- * privileges during device initialization and profile owner privileges during secondary user
- * initialization.
+ * On devices managed by a device owner app, a {@link ComponentName} extra indicating the
+ * component of the application that is temporarily granted device owner privileges during
+ * device initialization and profile owner privileges during secondary user initialization.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
- * provisioning via an NFC bump.
- * @see ComponentName#unflattenFromString()
+ * <p>
+ * It can also be used in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts
+ * device owner provisioning via an NFC bump. For the NFC record, it should be flattened to a
+ * string first.
+ *
+ * @see ComponentName#flattenToShortString()
*/
public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME
= "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME";
@@ -404,53 +418,105 @@ public class DevicePolicyManager {
* initializer package. When not provided it is assumed that the device initializer package is
* already installed.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION
= "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION";
/**
+ * An int extra holding a minimum required version code for the device initializer package.
+ * If the initializer is already installed on the device, it will only be re-downloaded from
+ * {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION} if the version of
+ * the installed package is less than this version code.
+ *
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
+ * provisioning via an NFC bump.
+ */
+ public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE
+ = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE";
+
+ /**
* A String extra holding a http cookie header which should be used in the http request to the
* url specified in {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER
= "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
/**
- * A String extra holding the SHA-1 checksum of the file at download location specified in
+ * A String extra holding the URL-safe base64 encoded SHA-1 checksum of the file at download
+ * location specified in
* {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}. If this doesn't
* match the file at the download location an error will be shown to the user and the user will
* be asked to factory reset the device.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM
= "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
/**
- * This MIME type is used for starting the Device Owner provisioning.
+ * A String extra holding the MAC address of the Bluetooth device to connect to with status
+ * updates during provisioning.
*
- * <p>During device owner provisioning a device admin app is set as the owner of the device.
- * A device owner has full control over the device. The device owner can not be modified by the
- * user and the only way of resetting the device is if the device owner app calls a factory
- * reset.
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
+ * provisioning via an NFC bump.
+ */
+ public static final String EXTRA_PROVISIONING_BT_MAC_ADDRESS
+ = "android.app.extra.PROVISIONING_BT_MAC_ADDRESS";
+
+ /**
+ * A String extra holding the Bluetooth service UUID on the device to connect to with status
+ * updates during provisioning.
*
- * <p> A typical use case would be a device that is owned by a company, but used by either an
- * employee or client.
+ * <p>This value must be specified when {@code #EXTRA_PROVISIONING_BT_MAC_ADDRESS} is present.
+ *
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
+ * provisioning via an NFC bump.
+ */
+ public static final String EXTRA_PROVISIONING_BT_UUID
+ = "android.app.extra.PROVISIONING_BT_UUID";
+
+ /**
+ * A String extra holding a unique identifier used to identify the device connecting over
+ * Bluetooth. This identifier will be part of every status message sent to the remote device.
*
- * <p> The NFC message should be send to an unprovisioned device.
+ * <p>This value must be specified when {@code #EXTRA_PROVISIONING_BT_MAC_ADDRESS} is present.
+ *
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
+ * provisioning via an NFC bump.
+ */
+ public static final String EXTRA_PROVISIONING_BT_DEVICE_ID
+ = "android.app.extra.PROVISIONING_BT_DEVICE_ID";
+
+ /**
+ * A Boolean extra that that will cause a provisioned device to temporarily proxy network
+ * traffic over Bluetooth. When a Wi-Fi network is available, the network proxy will stop.
+ *
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
+ * provisioning via an NFC bump.
+ */
+ public static final String EXTRA_PROVISIONING_BT_USE_PROXY
+ = "android.app.extra.PROVISIONING_BT_USE_PROXY";
+ /**
+ * This MIME type is used for starting the Device Owner provisioning that does not require
+ * provisioning features introduced in Android API level
+ * {@link android.os.Build.VERSION_CODES#MNC} or later levels.
+ *
+ * <p>For more information about the provisioning process see
+ * {@link #MIME_TYPE_PROVISIONING_NFC_V2}.
*
* <p>The NFC record must contain a serialized {@link java.util.Properties} object which
* contains the following properties:
* <ul>
- * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM}</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_LOCAL_TIME} (convert to String), optional</li>
* <li>{@link #EXTRA_PROVISIONING_TIME_ZONE}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_LOCALE}, optional</li>
@@ -461,17 +527,56 @@ public class DevicePolicyManager {
* <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_HOST}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_PORT} (convert to String), optional</li>
* <li>{@link #EXTRA_PROVISIONING_WIFI_PROXY_BYPASS}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_WIFI_PAC_URL}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li></ul>
+ * <li>{@link #EXTRA_PROVISIONING_WIFI_PAC_URL}, optional</li></ul>
*
* <p>
- * In version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, it should also contain
- * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}.
- * As of {@link android.os.Build.VERSION_CODES#MNC}, it should contain
- * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} instead, (although
- * specifying only {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is still supported).
- * This componentName must have been converted to a String via
- * {@link android.content.ComponentName#flattenToString()}
+ * As of {@link android.os.Build.VERSION_CODES#MNC}, the properties should contain
+ * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} instead of
+ * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}, (although specifying only
+ * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is still supported).
+ *
+ * @see #MIME_TYPE_PROVISIONING_NFC_V2
+ *
+ */
+ public static final String MIME_TYPE_PROVISIONING_NFC
+ = "application/com.android.managedprovisioning";
+
+
+ /**
+ * This MIME type is used for starting the Device Owner provisioning that requires
+ * new provisioning features introduced in API version
+ * {@link android.os.Build.VERSION_CODES#MNC} in addition to those supported in earlier
+ * versions.
+ *
+ * <p>During device owner provisioning a device admin app is set as the owner of the device.
+ * A device owner has full control over the device. The device owner can not be modified by the
+ * user and the only way of resetting the device is if the device owner app calls a factory
+ * reset.
+ *
+ * <p> A typical use case would be a device that is owned by a company, but used by either an
+ * employee or client.
+ *
+ * <p> The NFC message should be sent to an unprovisioned device.
+ *
+ * <p>The NFC record must contain a serialized {@link java.util.Properties} object which
+ * contains the following properties in addition to properties listed at
+ * {@link #MIME_TYPE_PROVISIONING_NFC}:
+ * <ul>
+ * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}.
+ * Replaces {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}. The value of the property
+ * should be converted to a String via
+ * {@link android.content.ComponentName#flattenToString()}</li>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_BT_MAC_ADDRESS}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_BT_UUID}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_BT_DEVICE_ID}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_BT_USE_PROXY}, optional</li></ul>
*
* <p> When device owner provisioning has completed, an intent of the type
* {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcasted to the
@@ -483,8 +588,8 @@ public class DevicePolicyManager {
* <p>Input: Nothing.</p>
* <p>Output: Nothing</p>
*/
- public static final String MIME_TYPE_PROVISIONING_NFC
- = "application/com.android.managedprovisioning";
+ public static final String MIME_TYPE_PROVISIONING_NFC_V2
+ = "application/com.android.managedprovisioning.v2";
/**
* Activity action: ask the user to add a new device administrator to the system.
@@ -509,11 +614,10 @@ public class DevicePolicyManager {
/**
* @hide
* Activity action: ask the user to add a new device administrator as the profile owner
- * for this user. Only system privileged apps that have MANAGE_USERS and MANAGE_DEVICE_ADMINS
- * permission can call this API.
+ * for this user. Only system apps can launch this intent.
*
- * <p>The ComponentName of the profile owner admin is pass in {@link #EXTRA_DEVICE_ADMIN} extra
- * field. This will invoke a UI to bring the user through adding the profile owner admin
+ * <p>The ComponentName of the profile owner admin is passed in the {@link #EXTRA_DEVICE_ADMIN}
+ * extra field. This will invoke a UI to bring the user through adding the profile owner admin
* to remotely control restrictions on the user.
*
* <p>The intent must be invoked via {@link Activity#startActivityForResult()} to receive the
@@ -525,8 +629,8 @@ public class DevicePolicyManager {
* field to provide the user with additional explanation (in addition
* to your component's description) about what is being added.
*
- * <p>If there is already a profile owner active or the caller doesn't have the required
- * permissions, the operation will return a failure result.
+ * <p>If there is already a profile owner active or the caller is not a system app, the
+ * operation will return a failure result.
*/
@SystemApi
public static final String ACTION_SET_PROFILE_OWNER
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index a1f1d920ba7c..0a0d77d2a465 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -60,4 +60,13 @@ public abstract class DevicePolicyManagerInternal {
*/
public abstract void addOnCrossProfileWidgetProvidersChangeListener(
OnCrossProfileWidgetProvidersChangeListener listener);
+
+ /**
+ * Checks if an app with given uid is an active device admin of its user and has the policy
+ * specified.
+ * @param uid App uid.
+ * @param reqPolicy Required policy, for policies see {@link DevicePolicyManager}.
+ * @return true if the uid is an active admin with the given policy.
+ */
+ public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy);
}
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
new file mode 100644
index 000000000000..af7c053a417d
--- /dev/null
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -0,0 +1,233 @@
+/**
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package android.app.usage;
+
+import android.app.usage.NetworkUsageStats.Bucket;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkIdentity;
+import android.net.NetworkTemplate;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+/**
+ * Provides access to network usage history and statistics. Usage data is collected in
+ * discrete bins of time called 'Buckets'. See {@link NetworkUsageStats.Bucket} for details.
+ * <p />
+ * Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and
+ * Long.MAX_VALUE can be used to simulate open ended intervals). All queries (except
+ * {@link #querySummaryForDevice}) collect only network usage of apps belonging to the same user
+ * as the client. In addition tethering usage, usage by removed users and apps, and usage by system
+ * is also included in the results.
+ * <h3>
+ * Summary queries
+ * </h3>
+ * These queries aggregate network usage across the whole interval. Therefore there will be only one
+ * bucket for a particular key and state combination. In case of the user-wide and device-wide
+ * summaries a single bucket containing the totalised network usage is returned.
+ * <h3>
+ * History queries
+ * </h3>
+ * These queries do not aggregate over time but do aggregate over state. Therefore there can be
+ * multiple buckets for a particular key but all Bucket's state is going to be
+ * {@link NetworkUsageStats.Bucket#STATE_ALL}.
+ * <p />
+ * <b>NOTE:</b> This API requires the permission
+ * {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, which is a system-level permission and
+ * will not be granted to third-party apps. However, declaring the permission implies intention to
+ * use the API and the user of the device can grant permission through the Settings application.
+ * Profile owner apps are automatically granted permission to query data on the profile they manage
+ * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps likewise get
+ * access to usage data of the primary user.
+ */
+public class NetworkStatsManager {
+ private final static String TAG = "NetworkStatsManager";
+
+ private final Context mContext;
+
+ /**
+ * {@hide}
+ */
+ public NetworkStatsManager(Context context) {
+ mContext = context;
+ }
+ /**
+ * Query network usage statistics summaries. Result is summarised data usage for the whole
+ * device. Result is a single Bucket aggregated over time, state and uid.
+ *
+ * @param networkType As defined in {@link ConnectivityManager}, e.g.
+ * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
+ * etc.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * @param startTime Start of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @return Bucket object or null if permissions are insufficient or error happened during
+ * statistics collection.
+ */
+ public Bucket querySummaryForDevice(int networkType, String subscriberId,
+ long startTime, long endTime) throws SecurityException, RemoteException {
+ NetworkTemplate template = createTemplate(networkType, subscriberId);
+ if (template == null) {
+ return null;
+ }
+
+ Bucket bucket = null;
+ NetworkUsageStats stats = new NetworkUsageStats(mContext, template, startTime, endTime);
+ bucket = stats.getDeviceSummaryForNetwork(startTime, endTime);
+
+ stats.close();
+ return bucket;
+ }
+
+ /**
+ * Query network usage statistics summaries. Result is summarised data usage for all uids
+ * belonging to calling user. Result is a single Bucket aggregated over time, state and uid.
+ *
+ * @param networkType As defined in {@link ConnectivityManager}, e.g.
+ * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
+ * etc.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * @param startTime Start of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @return Bucket object or null if permissions are insufficient or error happened during
+ * statistics collection.
+ */
+ public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
+ long endTime) throws SecurityException, RemoteException {
+ NetworkTemplate template = createTemplate(networkType, subscriberId);
+ if (template == null) {
+ return null;
+ }
+
+ NetworkUsageStats stats;
+ stats = new NetworkUsageStats(mContext, template, startTime, endTime);
+ stats.startSummaryEnumeration(startTime, endTime);
+
+ stats.close();
+ return stats.getSummaryAggregate();
+ }
+
+ /**
+ * Query network usage statistics summaries. Result filtered to include only uids belonging to
+ * calling user. Result is aggregated over time, hence all buckets will have the same start and
+ * end timestamps. Not aggregated over state or uid.
+ *
+ * @param networkType As defined in {@link ConnectivityManager}, e.g.
+ * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
+ * etc.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * @param startTime Start of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @return Statistics object or null if permissions are insufficient or error happened during
+ * statistics collection.
+ */
+ public NetworkUsageStats querySummary(int networkType, String subscriberId, long startTime,
+ long endTime) throws SecurityException, RemoteException {
+ NetworkTemplate template = createTemplate(networkType, subscriberId);
+ if (template == null) {
+ return null;
+ }
+
+ NetworkUsageStats result;
+ result = new NetworkUsageStats(mContext, template, startTime, endTime);
+ result.startSummaryEnumeration(startTime, endTime);
+
+ return result;
+ }
+
+ /**
+ * Query network usage statistics details. Only usable for uids belonging to calling user.
+ * Result is aggregated over state but not aggregated over time.
+ *
+ * @param networkType As defined in {@link ConnectivityManager}, e.g.
+ * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
+ * etc.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * @param startTime Start of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param uid UID of app
+ * @return Statistics object or null if permissions are insufficient or error happened during
+ * statistics collection.
+ */
+ public NetworkUsageStats queryDetailsForUid(int networkType, String subscriberId,
+ long startTime, long endTime, int uid) throws SecurityException, RemoteException {
+ NetworkTemplate template = createTemplate(networkType, subscriberId);
+ if (template == null) {
+ return null;
+ }
+
+ NetworkUsageStats result;
+ result = new NetworkUsageStats(mContext, template, startTime, endTime);
+ result.startHistoryEnumeration(uid);
+
+ return result;
+ }
+
+ /**
+ * Query network usage statistics details. Result filtered to include only uids belonging to
+ * calling user. Result is aggregated over state but not aggregated over time or uid.
+ *
+ * @param networkType As defined in {@link ConnectivityManager}, e.g.
+ * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
+ * etc.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * @param startTime Start of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @return Statistics object or null if permissions are insufficient or error happened during
+ * statistics collection.
+ */
+ public NetworkUsageStats queryDetails(int networkType, String subscriberId, long startTime,
+ long endTime) throws SecurityException, RemoteException {
+ NetworkTemplate template = createTemplate(networkType, subscriberId);
+ if (template == null) {
+ return null;
+ }
+ NetworkUsageStats result;
+ result = new NetworkUsageStats(mContext, template, startTime, endTime);
+ result.startUserUidEnumeration();
+ return result;
+ }
+
+ private static NetworkTemplate createTemplate(int networkType, String subscriberId) {
+ NetworkTemplate template = null;
+ switch (networkType) {
+ case ConnectivityManager.TYPE_MOBILE: {
+ template = NetworkTemplate.buildTemplateMobileAll(subscriberId);
+ } break;
+ case ConnectivityManager.TYPE_WIFI: {
+ template = NetworkTemplate.buildTemplateWifiWildcard();
+ } break;
+ default: {
+ Log.w(TAG, "Cannot create template for network type " + networkType
+ + ", subscriberId '" + NetworkIdentity.scrubSubscriberId(subscriberId) +
+ "'.");
+ }
+ }
+ return template;
+ }
+}
diff --git a/core/java/android/app/usage/NetworkUsageStats.java b/core/java/android/app/usage/NetworkUsageStats.java
new file mode 100644
index 000000000000..990d23194037
--- /dev/null
+++ b/core/java/android/app/usage/NetworkUsageStats.java
@@ -0,0 +1,479 @@
+/**
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package android.app.usage;
+
+import android.content.Context;
+import android.net.INetworkStatsService;
+import android.net.INetworkStatsSession;
+import android.net.NetworkStats;
+import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
+import android.net.TrafficStats;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import dalvik.system.CloseGuard;
+
+/**
+ * Class providing enumeration over buckets of network usage statistics. NetworkUsageStats objects
+ * are returned as results to various queries in {@link NetworkStatsManager}.
+ */
+public final class NetworkUsageStats implements AutoCloseable {
+ private final static String TAG = "NetworkUsageStats";
+
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ /**
+ * Start timestamp of stats collected
+ */
+ private final long mStartTimeStamp;
+
+ /**
+ * End timestamp of stats collected
+ */
+ private final long mEndTimeStamp;
+
+
+ /**
+ * Non-null array indicates the query enumerates over uids.
+ */
+ private int[] mUids;
+
+ /**
+ * Index of the current uid in mUids when doing uid enumeration or a single uid value,
+ * depending on query type.
+ */
+ private int mUidOrUidIndex;
+
+ /**
+ * The session while the query requires it, null if all the stats have been collected or close()
+ * has been called.
+ */
+ private INetworkStatsSession mSession;
+ private NetworkTemplate mTemplate;
+
+ /**
+ * Results of a summary query.
+ */
+ private NetworkStats mSummary = null;
+
+ /**
+ * Results of detail queries.
+ */
+ private NetworkStatsHistory mHistory = null;
+
+ /**
+ * Where we are in enumerating over the current result.
+ */
+ private int mEnumerationIndex = 0;
+
+ /**
+ * Recycling entry objects to prevent heap fragmentation.
+ */
+ private NetworkStats.Entry mRecycledSummaryEntry = null;
+ private NetworkStatsHistory.Entry mRecycledHistoryEntry = null;
+
+ /** @hide */
+ NetworkUsageStats(Context context, NetworkTemplate template, long startTimestamp,
+ long endTimestamp) throws RemoteException, SecurityException {
+ final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+ // Open network stats session
+ mSession = statsService.openSessionForUsageStats(context.getOpPackageName());
+ mCloseGuard.open("close");
+ mTemplate = template;
+ mStartTimeStamp = startTimestamp;
+ mEndTimeStamp = endTimestamp;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ // -------------------------BEGINNING OF PUBLIC API-----------------------------------
+
+ /**
+ * Buckets are the smallest elements of a query result. As some dimensions of a result may be
+ * aggregated (e.g. time or state) some values may be equal across all buckets.
+ */
+ public static class Bucket {
+ /**
+ * Combined usage across all other states.
+ */
+ public static final int STATE_ALL = -1;
+
+ /**
+ * Usage not accounted in any other states.
+ */
+ public static final int STATE_DEFAULT = 0x1;
+
+ /**
+ * Foreground usage.
+ */
+ public static final int STATE_FOREGROUND = 0x2;
+
+ /**
+ * Special UID value for removed apps.
+ */
+ public static final int UID_REMOVED = -4;
+
+ /**
+ * Special UID value for data usage by tethering.
+ */
+ public static final int UID_TETHERING = -5;
+
+ private int mUid;
+ private int mState;
+ private long mBeginTimeStamp;
+ private long mEndTimeStamp;
+ private long mRxBytes;
+ private long mRxPackets;
+ private long mTxBytes;
+ private long mTxPackets;
+
+ private static int convertState(int networkStatsSet) {
+ switch (networkStatsSet) {
+ case NetworkStats.SET_ALL : return STATE_ALL;
+ case NetworkStats.SET_DEFAULT : return STATE_DEFAULT;
+ case NetworkStats.SET_FOREGROUND : return STATE_FOREGROUND;
+ }
+ return 0;
+ }
+
+ private static int convertUid(int uid) {
+ switch (uid) {
+ case TrafficStats.UID_REMOVED: return UID_REMOVED;
+ case TrafficStats.UID_TETHERING: return UID_TETHERING;
+ }
+ return uid;
+ }
+
+ public Bucket() {
+ }
+
+ /**
+ * Key of the bucket. Usually an app uid or one of the following special values:<p />
+ * <ul>
+ * <li>{@link #UID_REMOVED}</li>
+ * <li>{@link #UID_TETHERING}</li>
+ * <li>{@link android.os.Process#SYSTEM_UID}</li>
+ * </ul>
+ * @return Bucket key.
+ */
+ public int getUid() {
+ return mUid;
+ }
+
+ /**
+ * Usage state. One of the following values:<p/>
+ * <ul>
+ * <li>{@link #STATE_ALL}</li>
+ * <li>{@link #STATE_DEFAULT}</li>
+ * <li>{@link #STATE_FOREGROUND}</li>
+ * </ul>
+ * @return Usage state.
+ */
+ public int getState() {
+ return mState;
+ }
+
+ /**
+ * Start timestamp of the bucket's time interval. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @return Start of interval.
+ */
+ public long getStartTimeStamp() {
+ return mBeginTimeStamp;
+ }
+
+ /**
+ * End timestamp of the bucket's time interval. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @return End of interval.
+ */
+ public long getEndTimeStamp() {
+ return mEndTimeStamp;
+ }
+
+ /**
+ * Number of bytes received during the bucket's time interval. Statistics are measured at
+ * the network layer, so they include both TCP and UDP usage.
+ * @return Number of bytes.
+ */
+ public long getRxBytes() {
+ return mRxBytes;
+ }
+
+ /**
+ * Number of bytes transmitted during the bucket's time interval. Statistics are measured at
+ * the network layer, so they include both TCP and UDP usage.
+ * @return Number of bytes.
+ */
+ public long getTxBytes() {
+ return mTxBytes;
+ }
+
+ /**
+ * Number of packets received during the bucket's time interval. Statistics are measured at
+ * the network layer, so they include both TCP and UDP usage.
+ * @return Number of packets.
+ */
+ public long getRxPackets() {
+ return mRxPackets;
+ }
+
+ /**
+ * Number of packets transmitted during the bucket's time interval. Statistics are measured
+ * at the network layer, so they include both TCP and UDP usage.
+ * @return Number of packets.
+ */
+ public long getTxPackets() {
+ return mTxPackets;
+ }
+ }
+
+ /**
+ * Fills the recycled bucket with data of the next bin in the enumeration.
+ * @param bucketOut Bucket to be filled with data.
+ * @return true if successfully filled the bucket, false otherwise.
+ */
+ public boolean getNextBucket(Bucket bucketOut) {
+ if (mSummary != null) {
+ return getNextSummaryBucket(bucketOut);
+ } else {
+ return getNextHistoryBucket(bucketOut);
+ }
+ }
+
+ /**
+ * Check if it is possible to ask for a next bucket in the enumeration.
+ * @return true if there is at least one more bucket.
+ */
+ public boolean hasNextBucket() {
+ if (mSummary != null) {
+ return mEnumerationIndex < mSummary.size();
+ } else if (mHistory != null) {
+ return mEnumerationIndex < mHistory.size()
+ || hasNextUid();
+ }
+ return false;
+ }
+
+ /**
+ * Closes the enumeration. Call this method before this object gets out of scope.
+ */
+ @Override
+ public void close() {
+ if (mSession != null) {
+ try {
+ mSession.close();
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ // Otherwise, meh
+ }
+ }
+ mSession = null;
+ if (mCloseGuard != null) {
+ mCloseGuard.close();
+ }
+ }
+
+ // -------------------------END OF PUBLIC API-----------------------------------
+
+ /**
+ * Collects device summary results into a Bucket.
+ * @param startTime
+ * @param endTime
+ * @throws RemoteException
+ */
+ Bucket getDeviceSummaryForNetwork(long startTime, long endTime) throws RemoteException {
+ mSummary = mSession.getDeviceSummaryForNetwork(mTemplate, startTime, endTime);
+
+ // Setting enumeration index beyond end to avoid accidental enumeration over data that does
+ // not belong to the calling user.
+ mEnumerationIndex = mSummary.size();
+
+ return getSummaryAggregate();
+ }
+
+ /**
+ * Collects summary results and sets summary enumeration mode.
+ * @param startTime
+ * @param endTime
+ * @throws RemoteException
+ */
+ void startSummaryEnumeration(long startTime, long endTime) throws RemoteException {
+ mSummary = mSession.getSummaryForAllUid(mTemplate, startTime, endTime, false);
+
+ mEnumerationIndex = 0;
+ }
+
+ /**
+ * Collects history results for uid and resets history enumeration index.
+ */
+ void startHistoryEnumeration(int uid) {
+ mHistory = null;
+ try {
+ mHistory = mSession.getHistoryForUid(mTemplate, uid, NetworkStats.SET_ALL,
+ NetworkStats.TAG_NONE, NetworkStatsHistory.FIELD_ALL);
+ setSingleUid(uid);
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ // Leaving mHistory null
+ }
+ mEnumerationIndex = 0;
+ }
+
+ /**
+ * Starts uid enumeration for current user.
+ * @throws RemoteException
+ */
+ void startUserUidEnumeration() throws RemoteException {
+ setUidEnumeration(mSession.getRelevantUids());
+ stepHistory();
+ }
+
+ /**
+ * Steps to next uid in enumeration and collects history for that.
+ */
+ private void stepHistory(){
+ if (hasNextUid()) {
+ stepUid();
+ mHistory = null;
+ try {
+ mHistory = mSession.getHistoryForUid(mTemplate, getUid(), NetworkStats.SET_ALL,
+ NetworkStats.TAG_NONE, NetworkStatsHistory.FIELD_ALL);
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ // Leaving mHistory null
+ }
+ mEnumerationIndex = 0;
+ }
+ }
+
+ private void fillBucketFromSummaryEntry(Bucket bucketOut) {
+ bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid);
+ bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set);
+ bucketOut.mBeginTimeStamp = mStartTimeStamp;
+ bucketOut.mEndTimeStamp = mEndTimeStamp;
+ bucketOut.mRxBytes = mRecycledSummaryEntry.rxBytes;
+ bucketOut.mRxPackets = mRecycledSummaryEntry.rxPackets;
+ bucketOut.mTxBytes = mRecycledSummaryEntry.txBytes;
+ bucketOut.mTxPackets = mRecycledSummaryEntry.txPackets;
+ }
+
+ /**
+ * Getting the next item in summary enumeration.
+ * @param bucketOut Next item will be set here.
+ * @return true if a next item could be set.
+ */
+ private boolean getNextSummaryBucket(Bucket bucketOut) {
+ if (bucketOut != null && mEnumerationIndex < mSummary.size()) {
+ mRecycledSummaryEntry = mSummary.getValues(mEnumerationIndex++, mRecycledSummaryEntry);
+ fillBucketFromSummaryEntry(bucketOut);
+ return true;
+ }
+ return false;
+ }
+
+ Bucket getSummaryAggregate() {
+ if (mSummary == null) {
+ return null;
+ }
+ Bucket bucket = new Bucket();
+ if (mRecycledSummaryEntry == null) {
+ mRecycledSummaryEntry = new NetworkStats.Entry();
+ }
+ mSummary.getTotal(mRecycledSummaryEntry);
+ fillBucketFromSummaryEntry(bucket);
+ return bucket;
+ }
+ /**
+ * Getting the next item in a history enumeration.
+ * @param bucketOut Next item will be set here.
+ * @return true if a next item could be set.
+ */
+ private boolean getNextHistoryBucket(Bucket bucketOut) {
+ if (bucketOut != null && mHistory != null) {
+ if (mEnumerationIndex < mHistory.size()) {
+ mRecycledHistoryEntry = mHistory.getValues(mEnumerationIndex++,
+ mRecycledHistoryEntry);
+ bucketOut.mUid = Bucket.convertUid(getUid());
+ bucketOut.mState = Bucket.STATE_ALL;
+ bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart;
+ bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart +
+ mRecycledHistoryEntry.bucketDuration;
+ bucketOut.mRxBytes = mRecycledHistoryEntry.rxBytes;
+ bucketOut.mRxPackets = mRecycledHistoryEntry.rxPackets;
+ bucketOut.mTxBytes = mRecycledHistoryEntry.txBytes;
+ bucketOut.mTxPackets = mRecycledHistoryEntry.txPackets;
+ return true;
+ } else if (hasNextUid()) {
+ stepHistory();
+ return getNextHistoryBucket(bucketOut);
+ }
+ }
+ return false;
+ }
+
+ // ------------------ UID LOGIC------------------------
+
+ private boolean isUidEnumeration() {
+ return mUids != null;
+ }
+
+ private boolean hasNextUid() {
+ return isUidEnumeration() && (mUidOrUidIndex + 1) < mUids.length;
+ }
+
+ private int getUid() {
+ // Check if uid enumeration.
+ if (isUidEnumeration()) {
+ if (mUidOrUidIndex < 0 || mUidOrUidIndex >= mUids.length) {
+ throw new IndexOutOfBoundsException(
+ "Index=" + mUidOrUidIndex + " mUids.length=" + mUids.length);
+ }
+ return mUids[mUidOrUidIndex];
+ }
+ // Single uid mode.
+ return mUidOrUidIndex;
+ }
+
+ private void setSingleUid(int uid) {
+ mUidOrUidIndex = uid;
+ }
+
+ private void setUidEnumeration(int[] uids) {
+ mUids = uids;
+ mUidOrUidIndex = -1;
+ }
+
+ private void stepUid() {
+ if (mUids != null) {
+ ++mUidOrUidIndex;
+ }
+ }
+}
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index 7eae4398e59d..0106686f8f82 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -25,6 +25,13 @@ import android.os.Parcelable;
* parameters for the scan.
*/
public final class ScanSettings implements Parcelable {
+
+ /**
+ * A special Bluetooth LE scan mode. Applications using this scan mode will passively listen for
+ * other scan results without starting BLE scans themselves.
+ */
+ public static final int SCAN_MODE_OPPORTUNISTIC = -1;
+
/**
* Perform Bluetooth LE scan in low power mode. This is the default scan mode as it consumes the
* least power.
@@ -177,7 +184,7 @@ public final class ScanSettings implements Parcelable {
* @throws IllegalArgumentException If the {@code scanMode} is invalid.
*/
public Builder setScanMode(int scanMode) {
- if (scanMode < SCAN_MODE_LOW_POWER || scanMode > SCAN_MODE_LOW_LATENCY) {
+ if (scanMode < SCAN_MODE_OPPORTUNISTIC || scanMode > SCAN_MODE_LOW_LATENCY) {
throw new IllegalArgumentException("invalid scan mode " + scanMode);
}
mScanMode = scanMode;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 80b5e0b98e7c..e9d4e598bc22 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2149,7 +2149,7 @@ public abstract class Context {
CONNECTIVITY_SERVICE,
//@hide: UPDATE_LOCK_SERVICE,
//@hide: NETWORKMANAGEMENT_SERVICE,
- //@hide: NETWORK_STATS_SERVICE,
+ NETWORK_STATS_SERVICE,
//@hide: NETWORK_POLICY_SERVICE,
WIFI_SERVICE,
WIFI_PASSPOINT_SERVICE,
@@ -2259,6 +2259,9 @@ public abstract class Context {
* <dd> A {@link android.os.BatteryManager} for managing battery state
* <dt> {@link #JOB_SCHEDULER_SERVICE} ("taskmanager")
* <dd> A {@link android.app.job.JobScheduler} for managing scheduled tasks
+ * <dt> {@link #NETWORK_STATS_SERVICE} ("netstats")
+ * <dd> A {@link android.app.usage.NetworkStatsManager NetworkStatsManager} for querying network
+ * usage statistics.
* </dl>
*
* <p>Note: System services obtained via this API may be closely associated with
@@ -2316,6 +2319,8 @@ public abstract class Context {
* @see android.os.BatteryManager
* @see #JOB_SCHEDULER_SERVICE
* @see android.app.job.JobScheduler
+ * @see #NETWORK_STATS_SERVICE
+ * @see android.app.usage.NetworkStatsManager
*/
public abstract Object getSystemService(@ServiceName @NonNull String name);
@@ -2334,7 +2339,8 @@ public abstract class Context {
* {@link android.telephony.TelephonyManager}, {@link android.telephony.SubscriptionManager},
* {@link android.view.inputmethod.InputMethodManager},
* {@link android.app.UiModeManager}, {@link android.app.DownloadManager},
- * {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler}.
+ * {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler},
+ * {@link android.app.usage.NetworkStatsManager}.
* </p><p>
* Note: System services obtained via this API may be closely associated with
* the Context in which they are obtained from. In general, do not share the
@@ -2563,7 +2569,13 @@ public abstract class Context {
*/
public static final String NETWORKMANAGEMENT_SERVICE = "network_management";
- /** {@hide} */
+ /**
+ * Use with {@link #getSystemService} to retrieve a {@link
+ * android.app.usage.NetworkStatsManager} for querying network usage stats.
+ *
+ * @see #getSystemService
+ * @see android.app.usage.NetworkStatsManager
+ */
public static final String NETWORK_STATS_SERVICE = "netstats";
/** {@hide} */
public static final String NETWORK_POLICY_SERVICE = "netpolicy";
@@ -2819,7 +2831,7 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a
- * {@link android.bluetooth.BluetoothAdapter} for using Bluetooth.
+ * {@link android.bluetooth.BluetoothManager} for using Bluetooth.
*
* @see #getSystemService
*/
@@ -3109,6 +3121,20 @@ public abstract class Context {
public abstract int checkCallingOrSelfPermission(@NonNull String permission);
/**
+ * Determine whether <em>you</em> have been granted a particular permission.
+ *
+ * @param permission The name of the permission being checked.
+ *
+ * @return {@link PackageManager#PERMISSION_GRANTED} if you have the
+ * permission, or {@link PackageManager#PERMISSION_DENIED} if not.
+ *
+ * @see PackageManager#checkPermission(String, String)
+ * @see #checkCallingPermission(String)
+ */
+ @PackageManager.PermissionResult
+ public abstract int checkSelfPermission(@NonNull String permission);
+
+ /**
* If the given permission is not allowed for a particular process
* and user ID running in the system, throw a {@link SecurityException}.
*
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 6e8b7c13455c..8c5a87cb26b4 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -602,6 +602,11 @@ public class ContextWrapper extends Context {
}
@Override
+ public int checkSelfPermission(String permission) {
+ return mBase.checkSelfPermission(permission);
+ }
+
+ @Override
public void enforcePermission(
String permission, int pid, int uid, String message) {
mBase.enforcePermission(permission, pid, uid, message);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9be96a1cda8f..030b77028cfa 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1502,6 +1502,66 @@ public class Intent implements Parcelable, Cloneable {
*/
public static final String METADATA_SETUP_VERSION = "android.SETUP_VERSION";
+ /**
+ * Activity action: Launch UI to manage the permissions of an app.
+ * <p>
+ * Input: {@link #EXTRA_PACKAGE_NAME} specifies the package whose permissions
+ * will be managed by the launched UI.
+ * </p>
+ * <p>
+ * Output: Nothing.
+ * </p>
+ *
+ * @see #EXTRA_PACKAGE_NAME
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_APP_PERMISSIONS =
+ "android.intent.action.MANAGE_APP_PERMISSIONS";
+
+ /**
+ * Intent extra: An app package name.
+ * <p>
+ * Type: String
+ * </p>S
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
+
+ /**
+ * Activity action: Launch UI to manage which apps have a given permission.
+ * <p>
+ * Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission access
+ * to which will be managed by the launched UI.
+ * </p>
+ * <p>
+ * Output: Nothing.
+ * </p>
+ *
+ * @see #EXTRA_PERMISSION_NAME
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_PERMISSION_APPS =
+ "android.intent.action.MANAGE_PERMISSION_APPS";
+
+ /**
+ * Intent extra: The name of a permission.
+ * <p>
+ * Type: String
+ * </p>
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent broadcast actions (see action variable).
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 29befc8ef241..2496e455d0fb 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -340,12 +340,15 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* cleartext network traffic, in which case platform components (e.g., HTTP stacks,
* {@code WebView}, {@code MediaPlayer}) will refuse app's requests to use cleartext traffic.
* Third-party libraries are encouraged to honor this flag as well.
- *
- * @hide
*/
public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 1<<27;
/**
+ * When set installer extracts native libs from .apk files.
+ */
+ public static final int FLAG_EXTRACT_NATIVE_LIBS = 1<<28;
+
+ /**
* Value for {@link #flags}: true if code from this application will need to be
* loaded into other applications' processes. On devices that support multiple
* instruction sets, this implies the code might be loaded into a process that's
@@ -374,7 +377,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* {@link #FLAG_LARGE_HEAP}, {@link #FLAG_STOPPED},
* {@link #FLAG_SUPPORTS_RTL}, {@link #FLAG_INSTALLED},
* {@link #FLAG_IS_DATA_ONLY}, {@link #FLAG_IS_GAME},
- * {@link #FLAG_FULL_BACKUP_ONLY}, {@link #FLAG_MULTIARCH}.
+ * {@link #FLAG_FULL_BACKUP_ONLY}, {@link #FLAG_USES_CLEARTEXT_TRAFFIC},
+ * {@link #FLAG_MULTIARCH}.
*/
public int flags = 0;
@@ -650,7 +654,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
}
pw.println(prefix + "dataDir=" + dataDir);
if (sharedLibraryFiles != null) {
- pw.println(prefix + "sharedLibraryFiles=" + sharedLibraryFiles);
+ pw.println(prefix + "sharedLibraryFiles=" + Arrays.toString(sharedLibraryFiles));
}
pw.println(prefix + "enabled=" + enabled + " targetSdkVersion=" + targetSdkVersion
+ " versionCode=" + versionCode);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 3e5d3623fe8d..c6d97f16bb75 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -46,32 +46,34 @@ import android.content.pm.UserInfo;
import android.content.pm.VerificationParams;
import android.content.pm.VerifierDeviceIdentity;
import android.net.Uri;
+import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.content.IntentSender;
+import com.android.internal.os.IResultReceiver;
/**
* See {@link PackageManager} for documentation on most of the APIs
* here.
- *
+ *
* {@hide}
*/
interface IPackageManager {
boolean isPackageAvailable(String packageName, int userId);
PackageInfo getPackageInfo(String packageName, int flags, int userId);
int getPackageUid(String packageName, int userId);
- int[] getPackageGids(String packageName);
-
+ int[] getPackageGids(String packageName, int userId);
+
String[] currentToCanonicalPackageNames(in String[] names);
String[] canonicalToCurrentPackageNames(in String[] names);
PermissionInfo getPermissionInfo(String name, int flags);
-
+
List<PermissionInfo> queryPermissionsByGroup(String group, int flags);
-
+
PermissionGroupInfo getPermissionGroupInfo(String name, int flags);
-
+
List<PermissionGroupInfo> getAllPermissionGroups(int flags);
-
+
ApplicationInfo getApplicationInfo(String packageName, int flags ,int userId);
ActivityInfo getActivityInfo(in ComponentName className, int flags, int userId);
@@ -85,28 +87,28 @@ interface IPackageManager {
ProviderInfo getProviderInfo(in ComponentName className, int flags, int userId);
- int checkPermission(String permName, String pkgName);
-
+ int checkPermission(String permName, String pkgName, int userId);
+
int checkUidPermission(String permName, int uid);
-
+
boolean addPermission(in PermissionInfo info);
-
+
void removePermission(String name);
- void grantPermission(String packageName, String permissionName);
+ boolean grantPermission(String packageName, String permissionName, int userId);
- void revokePermission(String packageName, String permissionName);
+ boolean revokePermission(String packageName, String permissionName, int userId);
boolean isProtectedBroadcast(String actionName);
-
+
int checkSignatures(String pkg1, String pkg2);
-
+
int checkUidSignatures(int uid1, int uid2);
-
+
String[] getPackagesForUid(int uid);
-
+
String getNameForUid(int uid);
-
+
int getUidForSharedUser(String sharedUserName);
int getFlagsForUid(int uid);
@@ -121,7 +123,7 @@ interface IPackageManager {
boolean canForwardTo(in Intent intent, String resolvedType, int sourceUserId, int targetUserId);
- List<ResolveInfo> queryIntentActivities(in Intent intent,
+ List<ResolveInfo> queryIntentActivities(in Intent intent,
String resolvedType, int flags, int userId);
List<ResolveInfo> queryIntentActivityOptions(
@@ -168,7 +170,7 @@ interface IPackageManager {
/**
* Retrieve all applications that are marked as persistent.
- *
+ *
* @return A List&lt;applicationInfo> containing one entry for each persistent
* application.
*/
@@ -178,7 +180,7 @@ interface IPackageManager {
/**
* Retrieve sync information for all content providers.
- *
+ *
* @param outNames Filled in with a list of the root names of the content
* providers that can sync.
* @param outInfo Filled in with a list of the ProviderInfo for each
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 92232693e7d2..9e6c6b501f62 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -167,8 +167,7 @@ public class PackageInfo implements Parcelable {
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_PERMISSIONS} was set. Each value matches
* the corresponding entry in {@link #requestedPermissions}, and will have
- * the flags {@link #REQUESTED_PERMISSION_REQUIRED} and
- * {@link #REQUESTED_PERMISSION_GRANTED} set as appropriate.
+ * the flag {@link #REQUESTED_PERMISSION_GRANTED} set as appropriate.
*/
public int[] requestedPermissionsFlags;
@@ -176,6 +175,8 @@ public class PackageInfo implements Parcelable {
* Flag for {@link #requestedPermissionsFlags}: the requested permission
* is required for the application to run; the user can not optionally
* disable it. Currently all permissions are required.
+ *
+ * @removed We do not support required permissions.
*/
public static final int REQUESTED_PERMISSION_REQUIRED = 1<<0;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 3da57cb52418..59a16dab5d72 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -44,6 +44,7 @@ import android.os.Environment;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.AndroidException;
+import com.android.internal.util.ArrayUtils;
import java.io.File;
import java.lang.annotation.Retention;
@@ -377,6 +378,16 @@ public abstract class PackageManager {
public static final int INSTALL_ALLOW_DOWNGRADE = 0x00000080;
/**
+ * Flag parameter for {@link #installPackage} to indicate that all runtime
+ * permissions should be granted to the package. If {@link #INSTALL_ALL_USERS}
+ * is set the runtime permissions will be granted to all users, otherwise
+ * only to the owner.
+ *
+ * @hide
+ */
+ public static final int INSTALL_GRANT_RUNTIME_PERMISSIONS = 0x00000100;
+
+ /**
* Flag parameter for
* {@link #setComponentEnabledSetting(android.content.ComponentName, int, int)} to indicate
* that you don't want to kill the app containing the component. Be careful when you set this
@@ -1663,21 +1674,46 @@ public abstract class PackageManager {
= "android.content.pm.extra.VERIFICATION_VERSION_CODE";
/**
- * The action used to request that the user approve a permission request
- * from the application.
+ * The action used to request that the user approve a grant permissions
+ * request from the application.
*
* @hide
*/
- public static final String ACTION_REQUEST_PERMISSION
- = "android.content.pm.action.REQUEST_PERMISSION";
+ @SystemApi
+ public static final String ACTION_REQUEST_PERMISSIONS =
+ "android.content.pm.action.REQUEST_PERMISSIONS";
/**
- * Extra field name for the list of permissions, which the user must approve.
+ * The component name handling runtime permission grants.
*
* @hide
*/
- public static final String EXTRA_REQUEST_PERMISSION_PERMISSION_LIST
- = "android.content.pm.extra.PERMISSION_LIST";
+ public static final String GRANT_PERMISSIONS_PACKAGE_NAME =
+ "com.android.packageinstaller";
+
+ /**
+ * The names of the requested permissions.
+ * <p>
+ * <strong>Type:</strong> String[]
+ * </p>
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_REQUEST_PERMISSIONS_NAMES =
+ "android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";
+
+ /**
+ * The results from the permissions request.
+ * <p>
+ * <strong>Type:</strong> int[] of #PermissionResult
+ * </p>
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS
+ = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
/**
* String extra for {@link PackageInstallObserver} in the 'extras' Bundle in case of
@@ -2184,51 +2220,70 @@ public abstract class PackageManager {
public abstract void removePermission(String name);
/**
- * Returns an {@link Intent} suitable for passing to {@code startActivityForResult}
- * which prompts the user to grant {@code permissions} to this application.
- * @hide
+ * Grant a runtime permission to an application which the application does not
+ * already have. The permission must have been requested by the application.
+ * If the application is not allowed to hold the permission, a {@link
+ * java.lang.SecurityException} is thrown.
+ * <p>
+ * <strong>Note: </strong>Using this API requires holding
+ * android.permission.GRANT_REVOKE_PERMISSIONS and if the user id is
+ * not the current user android.permission.INTERACT_ACROSS_USERS_FULL.
+ * </p>
+ *
+ * @param packageName The package to which to grant the permission.
+ * @param permissionName The permission name to grant.
+ * @param user The user for which to grant the permission.
*
- * @throws NullPointerException if {@code permissions} is {@code null}.
- * @throws IllegalArgumentException if {@code permissions} contains {@code null}.
+ * @see #revokePermission(String, String, android.os.UserHandle)
+ *
+ * @hide
*/
- public Intent buildPermissionRequestIntent(String... permissions) {
- if (permissions == null) {
- throw new NullPointerException("permissions cannot be null");
- }
- for (String permission : permissions) {
- if (permission == null) {
- throw new IllegalArgumentException("permissions cannot contain null");
- }
- }
-
- Intent i = new Intent(ACTION_REQUEST_PERMISSION);
- i.putExtra(EXTRA_REQUEST_PERMISSION_PERMISSION_LIST, permissions);
- i.setPackage("com.android.packageinstaller");
- return i;
- }
+ @SystemApi
+ public abstract void grantPermission(@NonNull String packageName,
+ @NonNull String permissionName, @NonNull UserHandle user);
/**
- * Grant a permission to an application which the application does not
- * already have. The permission must have been requested by the application,
- * but as an optional permission. If the application is not allowed to
- * hold the permission, a SecurityException is thrown.
- * @hide
+ * Revoke a runtime permission that was previously granted by {@link
+ * #grantPermission(String, String, android.os.UserHandle)}. The permission
+ * must have been requested by and granted to the application. If the
+ * application is not allowed to hold the permission, a {@link
+ * java.lang.SecurityException} is thrown.
+ * <p>
+ * <strong>Note: </strong>Using this API requires holding
+ * android.permission.GRANT_REVOKE_PERMISSIONS and if the user id is
+ * not the current user android.permission.INTERACT_ACROSS_USERS_FULL.
+ * </p>
+ *
+ * @param packageName The package from which to revoke the permission.
+ * @param permissionName The permission name to revoke.
+ * @param user The user for which to revoke the permission.
*
- * @param packageName The name of the package that the permission will be
- * granted to.
- * @param permissionName The name of the permission.
+ * @see #grantPermission(String, String, android.os.UserHandle)
+ *
+ * @hide
*/
- public abstract void grantPermission(String packageName, String permissionName);
+ @SystemApi
+ public abstract void revokePermission(@NonNull String packageName,
+ @NonNull String permissionName, @NonNull UserHandle user);
/**
- * Revoke a permission that was previously granted by {@link #grantPermission}.
- * @hide
+ * Returns an {@link android.content.Intent} suitable for passing to
+ * {@link android.app.Activity#startActivityForResult(android.content.Intent, int)}
+ * which prompts the user to grant permissions to this application.
+ *
+ * @throws NullPointerException if {@code permissions} is {@code null} or empty.
*
- * @param packageName The name of the package that the permission will be
- * granted to.
- * @param permissionName The name of the permission.
+ * @hide
*/
- public abstract void revokePermission(String packageName, String permissionName);
+ public Intent buildRequestPermissionsIntent(@NonNull String[] permissions) {
+ if (ArrayUtils.isEmpty(permissions)) {
+ throw new NullPointerException("permission cannot be null or empty");
+ }
+ Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
+ intent.putExtra(EXTRA_REQUEST_PERMISSIONS_NAMES, permissions);
+ intent.setPackage(GRANT_PERMISSIONS_PACKAGE_NAME);
+ return intent;
+ }
/**
* Compare the signatures of two packages to determine if the same
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c443ff3a1140..212cf6d85d1e 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -269,6 +269,7 @@ public class PackageParser {
public final boolean coreApp;
public final boolean multiArch;
+ public final boolean extractNativeLibs;
public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
String[] splitCodePaths, int[] splitRevisionCodes) {
@@ -284,6 +285,7 @@ public class PackageParser {
this.splitRevisionCodes = splitRevisionCodes;
this.coreApp = baseApk.coreApp;
this.multiArch = baseApk.multiArch;
+ this.extractNativeLibs = baseApk.extractNativeLibs;
}
public List<String> getAllCodePaths() {
@@ -310,10 +312,12 @@ public class PackageParser {
public final Signature[] signatures;
public final boolean coreApp;
public final boolean multiArch;
+ public final boolean extractNativeLibs;
public ApkLite(String codePath, String packageName, String splitName, int versionCode,
int revisionCode, int installLocation, List<VerifierInfo> verifiers,
- Signature[] signatures, boolean coreApp, boolean multiArch) {
+ Signature[] signatures, boolean coreApp, boolean multiArch,
+ boolean extractNativeLibs) {
this.codePath = codePath;
this.packageName = packageName;
this.splitName = splitName;
@@ -324,6 +328,7 @@ public class PackageParser {
this.signatures = signatures;
this.coreApp = coreApp;
this.multiArch = multiArch;
+ this.extractNativeLibs = extractNativeLibs;
}
}
@@ -371,16 +376,6 @@ public class PackageParser {
return path.endsWith(".apk");
}
- /*
- public static PackageInfo generatePackageInfo(PackageParser.Package p,
- int gids[], int flags, long firstInstallTime, long lastUpdateTime,
- HashSet<String> grantedPermissions) {
- PackageUserState state = new PackageUserState();
- return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
- grantedPermissions, state, UserHandle.getCallingUserId());
- }
- */
-
/**
* Generate and return the {@link PackageInfo} for a parsed package.
*
@@ -389,7 +384,7 @@ public class PackageParser {
*/
public static PackageInfo generatePackageInfo(PackageParser.Package p,
int gids[], int flags, long firstInstallTime, long lastUpdateTime,
- ArraySet<String> grantedPermissions, PackageUserState state) {
+ Set<String> grantedPermissions, PackageUserState state) {
return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
grantedPermissions, state, UserHandle.getCallingUserId());
@@ -410,7 +405,7 @@ public class PackageParser {
public static PackageInfo generatePackageInfo(PackageParser.Package p,
int gids[], int flags, long firstInstallTime, long lastUpdateTime,
- ArraySet<String> grantedPermissions, PackageUserState state, int userId) {
+ Set<String> grantedPermissions, PackageUserState state, int userId) {
if (!checkUseInstalledOrHidden(flags, state)) {
return null;
@@ -569,9 +564,8 @@ public class PackageParser {
for (int i=0; i<N; i++) {
final String perm = p.requestedPermissions.get(i);
pi.requestedPermissions[i] = perm;
- if (p.requestedPermissionsRequired.get(i)) {
- pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED;
- }
+ // The notion of required permissions is deprecated but for compatibility.
+ pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED;
if (grantedPermissions != null && grantedPermissions.contains(perm)) {
pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED;
}
@@ -1270,6 +1264,7 @@ public class PackageParser {
int revisionCode = 0;
boolean coreApp = false;
boolean multiArch = false;
+ boolean extractNativeLibs = true;
for (int i = 0; i < attrs.getAttributeCount(); i++) {
final String attr = attrs.getAttributeName(i);
@@ -1308,14 +1303,17 @@ public class PackageParser {
final String attr = attrs.getAttributeName(i);
if ("multiArch".equals(attr)) {
multiArch = attrs.getAttributeBooleanValue(i, false);
- break;
+ }
+ if ("extractNativeLibs".equals(attr)) {
+ extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
}
}
}
}
return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
- revisionCode, installLocation, verifiers, signatures, coreApp, multiArch);
+ revisionCode, installLocation, verifiers, signatures, coreApp, multiArch,
+ extractNativeLibs);
}
/**
@@ -1812,7 +1810,6 @@ public class PackageParser {
}
implicitPerms.append(npi.name);
pkg.requestedPermissions.add(npi.name);
- pkg.requestedPermissionsRequired.add(Boolean.TRUE);
}
}
if (implicitPerms != null) {
@@ -1831,7 +1828,6 @@ public class PackageParser {
final String perm = spi.newPerms[in];
if (!pkg.requestedPermissions.contains(perm)) {
pkg.requestedPermissions.add(perm);
- pkg.requestedPermissionsRequired.add(Boolean.TRUE);
}
}
}
@@ -1865,17 +1861,6 @@ public class PackageParser {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
}
- /*
- * b/8528162: Ignore the <uses-permission android:required> attribute if
- * targetSdkVersion < JELLY_BEAN_MR2. There are lots of apps in the wild
- * which are improperly using this attribute, even though it never worked.
- */
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) {
- for (int i = 0; i < pkg.requestedPermissionsRequired.size(); i++) {
- pkg.requestedPermissionsRequired.set(i, Boolean.TRUE);
- }
- }
-
return pkg;
}
@@ -1911,11 +1896,6 @@ public class PackageParser {
// that may change.
String name = sa.getNonResourceString(
com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
-/*
- boolean required = sa.getBoolean(
- com.android.internal.R.styleable.AndroidManifestUsesPermission_required, true);
-*/
- boolean required = true; // Optional <uses-permission> not supported
int maxSdkVersion = 0;
TypedValue val = sa.peekValue(
@@ -1933,13 +1913,9 @@ public class PackageParser {
int index = pkg.requestedPermissions.indexOf(name);
if (index == -1) {
pkg.requestedPermissions.add(name.intern());
- pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE);
} else {
- if (pkg.requestedPermissionsRequired.get(index) != required) {
- outError[0] = "conflicting <uses-permission> entries";
- mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return false;
- }
+ Slog.w(TAG, "Ignoring duplicate uses-permission: " + name + " in package: "
+ + pkg.packageName + " at: " + parser.getPositionDescription());
}
}
}
@@ -2569,6 +2545,12 @@ public class PackageParser {
ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
}
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs,
+ true)) {
+ ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
+ }
+
String str;
str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestApplication_permission, 0);
@@ -3116,8 +3098,7 @@ public class PackageParser {
}
a.info.resizeable = sa.getBoolean(
- R.styleable.AndroidManifestActivity_resizeableActivity,
- owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.MNC);
+ R.styleable.AndroidManifestActivity_resizeableActivity, false);
if (a.info.resizeable) {
// Fixed screen orientation isn't supported with resizeable activities.
a.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -4218,7 +4199,6 @@ public class PackageParser {
public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
public final ArrayList<String> requestedPermissions = new ArrayList<String>();
- public final ArrayList<Boolean> requestedPermissionsRequired = new ArrayList<Boolean>();
public ArrayList<String> protectedBroadcasts;
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 841b09d0ddb6..7d8dff3c546b 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -464,6 +464,33 @@ public class ColorStateList implements Parcelable {
return mColors;
}
+ /**
+ * Returns whether the specified state is referenced in any of the state
+ * specs contained within this ColorStateList.
+ * <p>
+ * Any reference, either positive or negative {ex. ~R.attr.state_enabled},
+ * will cause this method to return {@code true}. Wildcards are not counted
+ * as references.
+ *
+ * @param state the state to search for
+ * @return {@code true} if the state if referenced, {@code false} otherwise
+ * @hide Use only as directed. For internal use only.
+ */
+ public boolean hasState(int state) {
+ final int[][] stateSpecs = mStateSpecs;
+ final int specCount = stateSpecs.length;
+ for (int specIndex = 0; specIndex < specCount; specIndex++) {
+ final int[] states = stateSpecs[specIndex];
+ final int stateCount = states.length;
+ for (int stateIndex = 0; stateIndex < stateCount; stateIndex++) {
+ if (states[stateIndex] == state || states[stateIndex] == ~state) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
@Override
public String toString() {
return "ColorStateList{" +
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 14af58481f05..b5eeb3037e86 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1314,7 +1314,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* {@link View#LAYOUT_DIRECTION_LTR}. If not null will set it to the layout direction
* corresponding to the Locale.
*
- * @see {@link View#LAYOUT_DIRECTION_LTR} and {@link View#LAYOUT_DIRECTION_RTL}
+ * @see View#LAYOUT_DIRECTION_LTR
+ * @see View#LAYOUT_DIRECTION_RTL
*/
public void setLayoutDirection(Locale locale) {
// There is a "1" difference between the configuration values for
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 95ad57e5b496..44018ffe0f38 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -111,12 +111,12 @@ public class Resources {
// single-threaded, and after that these are immutable.
private static final LongSparseArray<ConstantState>[] sPreloadedDrawables;
private static final LongSparseArray<ConstantState> sPreloadedColorDrawables
- = new LongSparseArray<ConstantState>();
+ = new LongSparseArray<>();
private static final LongSparseArray<ColorStateListFactory> sPreloadedColorStateLists
- = new LongSparseArray<ColorStateListFactory>();
+ = new LongSparseArray<>();
// Pool of TypedArrays targeted to this Resources object.
- final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<TypedArray>(5);
+ final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
// Used by BridgeResources in layoutlib
static Resources mSystem = null;
@@ -128,21 +128,19 @@ public class Resources {
private final Object mAccessLock = new Object();
private final Configuration mTmpConfig = new Configuration();
private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> mDrawableCache =
- new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>();
+ new ArrayMap<>();
private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> mColorDrawableCache =
- new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>();
+ new ArrayMap<>();
private final ConfigurationBoundResourceCache<ColorStateList> mColorStateListCache =
- new ConfigurationBoundResourceCache<ColorStateList>(this);
+ new ConfigurationBoundResourceCache<>(this);
private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
- new ConfigurationBoundResourceCache<Animator>(this);
+ new ConfigurationBoundResourceCache<>(this);
private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
- new ConfigurationBoundResourceCache<StateListAnimator>(this);
+ new ConfigurationBoundResourceCache<>(this);
private TypedValue mTmpValue = new TypedValue();
private boolean mPreloading;
- private TypedArray mCachedStyledAttributes = null;
-
private int mLastCachedXmlBlockIndex = -1;
private final int[] mCachedXmlBlockIds = { 0, 0, 0, 0 };
private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[4];
@@ -157,8 +155,8 @@ public class Resources {
static {
sPreloadedDrawables = new LongSparseArray[2];
- sPreloadedDrawables[0] = new LongSparseArray<ConstantState>();
- sPreloadedDrawables[1] = new LongSparseArray<ConstantState>();
+ sPreloadedDrawables[0] = new LongSparseArray<>();
+ sPreloadedDrawables[1] = new LongSparseArray<>();
}
/**
@@ -1876,7 +1874,7 @@ public class Resources {
// the framework.
mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
- int configChanges = calcConfigChanges(config);
+ final int configChanges = calcConfigChanges(config);
if (mConfiguration.locale == null) {
mConfiguration.locale = Locale.getDefault();
mConfiguration.setLayoutDirection(mConfiguration.locale);
@@ -1891,7 +1889,8 @@ public class Resources {
if (mConfiguration.locale != null) {
locale = adjustLanguageTag(mConfiguration.locale.toLanguageTag());
}
- int width, height;
+
+ final int width, height;
if (mMetrics.widthPixels >= mMetrics.heightPixels) {
width = mMetrics.widthPixels;
height = mMetrics.heightPixels;
@@ -1901,12 +1900,15 @@ public class Resources {
//noinspection SuspiciousNameCombination
height = mMetrics.widthPixels;
}
- int keyboardHidden = mConfiguration.keyboardHidden;
- if (keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
- && mConfiguration.hardKeyboardHidden
- == Configuration.HARDKEYBOARDHIDDEN_YES) {
+
+ final int keyboardHidden;
+ if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
+ && mConfiguration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
+ } else {
+ keyboardHidden = mConfiguration.keyboardHidden;
}
+
mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
locale, mConfiguration.orientation,
mConfiguration.touchscreen,
@@ -2508,10 +2510,10 @@ public class Resources {
// Clean out the caches before we add more. This shouldn't
// happen very often.
pruneCaches(caches);
- themedCache = new LongSparseArray<WeakReference<ConstantState>>(1);
+ themedCache = new LongSparseArray<>(1);
caches.put(themeKey, themedCache);
}
- themedCache.put(key, new WeakReference<ConstantState>(cs));
+ themedCache.put(key, new WeakReference<>(cs));
}
}
}
@@ -2830,15 +2832,6 @@ public class Resources {
+ Integer.toHexString(id));
}
- /*package*/ void recycleCachedStyledAttributes(TypedArray attrs) {
- synchronized (mAccessLock) {
- final TypedArray cached = mCachedStyledAttributes;
- if (cached == null || cached.mData.length < attrs.mData.length) {
- mCachedStyledAttributes = attrs;
- }
- }
- }
-
/**
* Obtains styled attributes from the theme, if available, or unstyled
* resources if the theme is null.
diff --git a/core/java/android/database/DatabaseErrorHandler.java b/core/java/android/database/DatabaseErrorHandler.java
index f0c5452becdb..55ad92104da5 100644
--- a/core/java/android/database/DatabaseErrorHandler.java
+++ b/core/java/android/database/DatabaseErrorHandler.java
@@ -19,13 +19,12 @@ package android.database;
import android.database.sqlite.SQLiteDatabase;
/**
- * An interface to let the apps define the actions to take when the following errors are detected
- * database corruption
+ * An interface to let apps define an action to take when database corruption is detected.
*/
public interface DatabaseErrorHandler {
/**
- * defines the method to be invoked when database corruption is detected.
+ * The method invoked when database corruption is detected.
* @param dbObj the {@link SQLiteDatabase} object representing the database on which corruption
* is detected.
*/
diff --git a/core/java/android/database/DefaultDatabaseErrorHandler.java b/core/java/android/database/DefaultDatabaseErrorHandler.java
index b234e348000e..7fa2b409c59d 100755
--- a/core/java/android/database/DefaultDatabaseErrorHandler.java
+++ b/core/java/android/database/DefaultDatabaseErrorHandler.java
@@ -24,7 +24,7 @@ import android.util.Log;
import android.util.Pair;
/**
- * Default class used to define the actions to take when the database corruption is reported
+ * Default class used to define the action to take when database corruption is reported
* by sqlite.
* <p>
* An application can specify an implementation of {@link DatabaseErrorHandler} on the
@@ -38,7 +38,7 @@ import android.util.Pair;
* The specified {@link DatabaseErrorHandler} is used to handle database corruption errors, if they
* occur.
* <p>
- * If null is specified for DatabaeErrorHandler param in the above calls, then this class is used
+ * If null is specified for the DatabaseErrorHandler param in the above calls, this class is used
* as the default {@link DatabaseErrorHandler}.
*/
public final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler {
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index a6c3ea43339e..88fa339a53cb 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -54,11 +54,13 @@ public class SystemSensorManager extends SensorManager {
// Looper associated with the context in which this instance was created.
private final Looper mMainLooper;
private final int mTargetSdkLevel;
+ private final String mPackageName;
/** {@hide} */
public SystemSensorManager(Context context, Looper mainLooper) {
mMainLooper = mainLooper;
mTargetSdkLevel = context.getApplicationInfo().targetSdkVersion;
+ mPackageName = context.getPackageName();
synchronized(sSensorModuleLock) {
if (!sSensorModuleInitialized) {
sSensorModuleInitialized = true;
@@ -117,14 +119,14 @@ public class SystemSensorManager extends SensorManager {
if (queue == null) {
Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
queue = new SensorEventQueue(listener, looper, this);
- if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags)) {
+ if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) {
queue.dispose();
return false;
}
mSensorListeners.put(listener, queue);
return true;
} else {
- return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags);
+ return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs);
}
}
}
@@ -165,14 +167,14 @@ public class SystemSensorManager extends SensorManager {
TriggerEventQueue queue = mTriggerListeners.get(listener);
if (queue == null) {
queue = new TriggerEventQueue(listener, mMainLooper, this);
- if (!queue.addSensor(sensor, 0, 0, 0)) {
+ if (!queue.addSensor(sensor, 0, 0)) {
queue.dispose();
return false;
}
mTriggerListeners.put(listener, queue);
return true;
} else {
- return queue.addSensor(sensor, 0, 0, 0);
+ return queue.addSensor(sensor, 0, 0);
}
}
}
@@ -223,9 +225,9 @@ public class SystemSensorManager extends SensorManager {
*/
private static abstract class BaseEventQueue {
private native long nativeInitBaseEventQueue(BaseEventQueue eventQ, MessageQueue msgQ,
- float[] scratch);
+ float[] scratch, String packageName);
private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
- int maxBatchReportLatencyUs, int reservedFlags);
+ int maxBatchReportLatencyUs);
private static native int nativeDisableSensor(long eventQ, int handle);
private static native void nativeDestroySensorEventQueue(long eventQ);
private static native int nativeFlushSensor(long eventQ);
@@ -238,7 +240,8 @@ public class SystemSensorManager extends SensorManager {
protected final SystemSensorManager mManager;
BaseEventQueue(Looper looper, SystemSensorManager manager) {
- nSensorEventQueue = nativeInitBaseEventQueue(this, looper.getQueue(), mScratch);
+ nSensorEventQueue = nativeInitBaseEventQueue(this, looper.getQueue(), mScratch,
+ manager.mPackageName);
mCloseGuard.open("dispose");
mManager = manager;
}
@@ -248,7 +251,7 @@ public class SystemSensorManager extends SensorManager {
}
public boolean addSensor(
- Sensor sensor, int delayUs, int maxBatchReportLatencyUs, int reservedFlags) {
+ Sensor sensor, int delayUs, int maxBatchReportLatencyUs) {
// Check if already present.
int handle = sensor.getHandle();
if (mActiveSensors.get(handle)) return false;
@@ -256,10 +259,10 @@ public class SystemSensorManager extends SensorManager {
// Get ready to receive events before calling enable.
mActiveSensors.put(handle, true);
addSensorEvent(sensor);
- if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags) != 0) {
+ if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs) != 0) {
// Try continuous mode if batching fails.
if (maxBatchReportLatencyUs == 0 ||
- maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0, 0) != 0) {
+ maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0) != 0) {
removeSensor(sensor, false);
return false;
}
@@ -328,11 +331,11 @@ public class SystemSensorManager extends SensorManager {
}
private int enableSensor(
- Sensor sensor, int rateUs, int maxBatchReportLatencyUs, int reservedFlags) {
+ Sensor sensor, int rateUs, int maxBatchReportLatencyUs) {
if (nSensorEventQueue == 0) throw new NullPointerException();
if (sensor == null) throw new NullPointerException();
return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs,
- maxBatchReportLatencyUs, reservedFlags);
+ maxBatchReportLatencyUs);
}
private int disableSensor(Sensor sensor) {
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 7569ea5c9059..b8fb8e7aaaa6 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1541,7 +1541,8 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* to the camera, that the JPEG picture needs to be rotated by, to be viewed
* upright.</p>
* <p>Camera devices may either encode this value into the JPEG EXIF header, or
- * rotate the image data to match this orientation.</p>
+ * rotate the image data to match this orientation. When the image data is rotated,
+ * the thumbnail data will also be rotated.</p>
* <p>Note that this orientation is relative to the orientation of the camera sensor, given
* by {@link CameraCharacteristics#SENSOR_ORIENTATION android.sensor.orientation}.</p>
* <p>To translate from the device orientation given by the Android sensor APIs, the following
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index b84dc2e0f8b8..e346dc2fa88b 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2230,7 +2230,8 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* to the camera, that the JPEG picture needs to be rotated by, to be viewed
* upright.</p>
* <p>Camera devices may either encode this value into the JPEG EXIF header, or
- * rotate the image data to match this orientation.</p>
+ * rotate the image data to match this orientation. When the image data is rotated,
+ * the thumbnail data will also be rotated.</p>
* <p>Note that this orientation is relative to the orientation of the camera sensor, given
* by {@link CameraCharacteristics#SENSOR_ORIENTATION android.sensor.orientation}.</p>
* <p>To translate from the device orientation given by the Android sensor APIs, the following
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 34a07276ca42..a0e2bf8a7682 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2337,7 +2337,7 @@ public class ConnectivityManager {
* successfully finding a network for the applications request. Retrieve it with
* {@link android.content.Intent#getParcelableExtra(String)}.
* <p>
- * Note that if you intend to invoke (@link #setProcessDefaultNetwork(Network)) or
+ * Note that if you intend to invoke {@link #setProcessDefaultNetwork} or
* {@link Network#openConnection(java.net.URL)} then you must get a
* ConnectivityManager instance before doing so.
*/
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 2c3881c4f7a1..6436e4267655 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -27,6 +27,14 @@ interface INetworkStatsService {
/** Start a statistics query session. */
INetworkStatsSession openSession();
+ /** Start a statistics query session. If calling package is profile or device owner then it is
+ * granted automatic access if apiLevel is NetworkStatsManager.API_LEVEL_DPC_ALLOWED. If
+ * apiLevel is at least NetworkStatsManager.API_LEVEL_REQUIRES_PACKAGE_USAGE_STATS then
+ * PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted
+ * READ_NETWORK_USAGE_STATS is checked for.
+ */
+ INetworkStatsSession openSessionForUsageStats(String callingPackage);
+
/** Return network layer usage total for traffic that matches template. */
long getNetworkTotalBytes(in NetworkTemplate template, long start, long end);
diff --git a/core/java/android/net/INetworkStatsSession.aidl b/core/java/android/net/INetworkStatsSession.aidl
index 1596fa2b0101..7bcb04328b12 100644
--- a/core/java/android/net/INetworkStatsSession.aidl
+++ b/core/java/android/net/INetworkStatsSession.aidl
@@ -23,6 +23,9 @@ import android.net.NetworkTemplate;
/** {@hide} */
interface INetworkStatsSession {
+ /** Return device aggregated network layer usage summary for traffic that matches template. */
+ NetworkStats getDeviceSummaryForNetwork(in NetworkTemplate template, long start, long end);
+
/** Return network layer usage summary for traffic that matches template. */
NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
/** Return historical network layer stats for traffic that matches template. */
@@ -33,6 +36,9 @@ interface INetworkStatsSession {
/** Return historical network layer stats for specific UID traffic that matches template. */
NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields);
+ /** Return array of uids that have stats and are accessible to the calling user */
+ int[] getRelevantUids();
+
void close();
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index a7f9c5bcc0ab..8c8bfab9c76d 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -148,9 +148,9 @@ public final class NetworkCapabilities implements Parcelable {
*/
public static final int NET_CAPABILITY_TRUSTED = 14;
- /*
+ /**
* Indicates that this network is not a VPN. This capability is set by default and should be
- * explicitly cleared when creating VPN networks.
+ * explicitly cleared for VPN networks.
*/
public static final int NET_CAPABILITY_NOT_VPN = 15;
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 0766253e63f5..77d7e0cd76b1 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -50,12 +50,19 @@ public class NetworkStats implements Parcelable {
public static final int UID_ALL = -1;
/** {@link #tag} value matching any tag. */
public static final int TAG_ALL = -1;
- /** {@link #set} value when all sets combined. */
+ /** {@link #set} value when all sets combined, not including debug sets. */
public static final int SET_ALL = -1;
/** {@link #set} value where background data is accounted. */
public static final int SET_DEFAULT = 0;
/** {@link #set} value where foreground data is accounted. */
public static final int SET_FOREGROUND = 1;
+ /** All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values. */
+ public static final int SET_DEBUG_START = 1000;
+ /** Debug {@link #set} value when the VPN stats are moved in. */
+ public static final int SET_DBG_VPN_IN = 1001;
+ /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */
+ public static final int SET_DBG_VPN_OUT = 1002;
+
/** {@link #tag} value for total data across all tags. */
public static final int TAG_NONE = 0;
@@ -729,6 +736,10 @@ public class NetworkStats implements Parcelable {
return "DEFAULT";
case SET_FOREGROUND:
return "FOREGROUND";
+ case SET_DBG_VPN_IN:
+ return "DBG_VPN_IN";
+ case SET_DBG_VPN_OUT:
+ return "DBG_VPN_OUT";
default:
return "UNKNOWN";
}
@@ -745,12 +756,27 @@ public class NetworkStats implements Parcelable {
return "def";
case SET_FOREGROUND:
return "fg";
+ case SET_DBG_VPN_IN:
+ return "vpnin";
+ case SET_DBG_VPN_OUT:
+ return "vpnout";
default:
return "unk";
}
}
/**
+ * @return true if the querySet matches the dataSet.
+ */
+ public static boolean setMatches(int querySet, int dataSet) {
+ if (querySet == dataSet) {
+ return true;
+ }
+ // SET_ALL matches all non-debugging sets.
+ return querySet == SET_ALL && dataSet < SET_DEBUG_START;
+ }
+
+ /**
* Return text description of {@link #tag} value.
*/
public static String tagToString(int tag) {
@@ -843,6 +869,9 @@ public class NetworkStats implements Parcelable {
if (recycle.uid == UID_ALL) {
throw new IllegalStateException(
"Cannot adjust VPN accounting on an iface aggregated NetworkStats.");
+ } if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) {
+ throw new IllegalStateException(
+ "Cannot adjust VPN accounting on a NetworkStats containing SET_DBG_VPN_*");
}
if (recycle.uid == tunUid && recycle.tag == TAG_NONE
@@ -906,6 +935,9 @@ public class NetworkStats implements Parcelable {
combineValues(tmpEntry);
if (tag[i] == TAG_NONE) {
moved.add(tmpEntry);
+ // Add debug info
+ tmpEntry.set = SET_DBG_VPN_IN;
+ combineValues(tmpEntry);
}
}
}
@@ -913,6 +945,13 @@ public class NetworkStats implements Parcelable {
}
private void deductTrafficFromVpnApp(int tunUid, String underlyingIface, Entry moved) {
+ // Add debug info
+ moved.uid = tunUid;
+ moved.set = SET_DBG_VPN_OUT;
+ moved.tag = TAG_NONE;
+ moved.iface = underlyingIface;
+ combineValues(moved);
+
// Caveat: if the vpn software uses tag, the total tagged traffic may be greater than
// the TAG_NONE traffic.
int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE);
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index cab03da7e4c0..8b3ecae1d97d 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -29,6 +29,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.telephony.SignalStrength;
import android.text.format.DateFormat;
+import android.util.ArrayMap;
import android.util.Printer;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -283,21 +284,21 @@ public abstract class BatteryStats implements Parcelable {
*
* @return a Map from Strings to Uid.Wakelock objects.
*/
- public abstract Map<String, ? extends Wakelock> getWakelockStats();
+ public abstract ArrayMap<String, ? extends Wakelock> getWakelockStats();
/**
* Returns a mapping containing sync statistics.
*
* @return a Map from Strings to Timer objects.
*/
- public abstract Map<String, ? extends Timer> getSyncStats();
+ public abstract ArrayMap<String, ? extends Timer> getSyncStats();
/**
* Returns a mapping containing scheduled job statistics.
*
* @return a Map from Strings to Timer objects.
*/
- public abstract Map<String, ? extends Timer> getJobStats();
+ public abstract ArrayMap<String, ? extends Timer> getJobStats();
/**
* The statistics associated with a particular wake lock.
@@ -323,14 +324,14 @@ public abstract class BatteryStats implements Parcelable {
*
* @return a Map from Strings to Uid.Proc objects.
*/
- public abstract Map<String, ? extends Proc> getProcessStats();
+ public abstract ArrayMap<String, ? extends Proc> getProcessStats();
/**
* Returns a mapping containing package statistics.
*
* @return a Map from Strings to Uid.Pkg objects.
*/
- public abstract Map<String, ? extends Pkg> getPackageStats();
+ public abstract ArrayMap<String, ? extends Pkg> getPackageStats();
/**
* {@hide}
@@ -501,17 +502,16 @@ public abstract class BatteryStats implements Parcelable {
public static abstract class Pkg {
/**
- * Returns the number of times this package has done something that could wake up the
- * device from sleep.
- *
- * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
+ * Returns information about all wakeup alarms that have been triggered for this
+ * package. The mapping keys are tag names for the alarms, the counter contains
+ * the number of times the alarm was triggered while on battery.
*/
- public abstract int getWakeups(int which);
+ public abstract ArrayMap<String, ? extends Counter> getWakeupAlarmStats();
/**
* Returns a mapping containing service statistics.
*/
- public abstract Map<String, ? extends Serv> getServiceStats();
+ public abstract ArrayMap<String, ? extends Serv> getServiceStats();
/**
* The statistics associated with a particular service.
@@ -613,6 +613,9 @@ public abstract class BatteryStats implements Parcelable {
if ((initMode&STEP_LEVEL_MODE_POWER_SAVE) != 0) {
out.append('p');
}
+ if ((initMode&STEP_LEVEL_MODE_DEVICE_IDLE) != 0) {
+ out.append('i');
+ }
switch ((modMode&STEP_LEVEL_MODE_SCREEN_STATE) + 1) {
case Display.STATE_OFF: out.append('F'); break;
case Display.STATE_ON: out.append('O'); break;
@@ -622,6 +625,9 @@ public abstract class BatteryStats implements Parcelable {
if ((modMode&STEP_LEVEL_MODE_POWER_SAVE) != 0) {
out.append('P');
}
+ if ((modMode&STEP_LEVEL_MODE_DEVICE_IDLE) != 0) {
+ out.append('I');
+ }
out.append('-');
appendHex(level, 4, out);
out.append('-');
@@ -648,6 +654,9 @@ public abstract class BatteryStats implements Parcelable {
case 'p': out |= (((long)STEP_LEVEL_MODE_POWER_SAVE)
<< STEP_LEVEL_INITIAL_MODE_SHIFT);
break;
+ case 'i': out |= (((long)STEP_LEVEL_MODE_DEVICE_IDLE)
+ << STEP_LEVEL_INITIAL_MODE_SHIFT);
+ break;
case 'F': out |= (((long)Display.STATE_OFF-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
break;
case 'O': out |= (((long)Display.STATE_ON-1)<<STEP_LEVEL_MODIFIED_MODE_SHIFT);
@@ -660,6 +669,9 @@ public abstract class BatteryStats implements Parcelable {
case 'P': out |= (((long)STEP_LEVEL_MODE_POWER_SAVE)
<< STEP_LEVEL_MODIFIED_MODE_SHIFT);
break;
+ case 'I': out |= (((long)STEP_LEVEL_MODE_DEVICE_IDLE)
+ << STEP_LEVEL_MODIFIED_MODE_SHIFT);
+ break;
}
}
i++;
@@ -820,11 +832,18 @@ public abstract class BatteryStats implements Parcelable {
}
}
+ public static final class PackageChange {
+ public String mPackageName;
+ public boolean mUpdate;
+ public int mVersionCode;
+ }
+
public static final class DailyItem {
public long mStartTime;
public long mEndTime;
public LevelStepTracker mDischargeSteps;
public LevelStepTracker mChargeSteps;
+ public ArrayList<PackageChange> mPackageChanges;
}
public abstract DailyItem getDailyItemLocked(int daysAgo);
@@ -1333,7 +1352,7 @@ public abstract class BatteryStats implements Parcelable {
int idx = code&HistoryItem.EVENT_TYPE_MASK;
HashMap<String, SparseIntArray> active = mActiveEvents[idx];
if (active == null) {
- active = new HashMap<String, SparseIntArray>();
+ active = new HashMap<>();
mActiveEvents[idx] = active;
}
SparseIntArray uids = active.get(name);
@@ -1524,6 +1543,23 @@ public abstract class BatteryStats implements Parcelable {
public abstract int getDeviceIdleModeEnabledCount(int which);
/**
+ * Returns the time in microseconds that device has been in idling while on
+ * battery. This is broader than {@link #getDeviceIdleModeEnabledTime} -- it
+ * counts all of the time that we consider the device to be idle, whether or not
+ * it is currently in the actual device idle mode.
+ *
+ * {@hide}
+ */
+ public abstract long getDeviceIdlingTime(long elapsedRealtimeUs, int which);
+
+ /**
+ * Returns the number of times that the devie has started idling.
+ *
+ * {@hide}
+ */
+ public abstract int getDeviceIdlingCount(int which);
+
+ /**
* Returns the number of times that connectivity state changed.
*
* {@hide}
@@ -2069,45 +2105,44 @@ public abstract class BatteryStats implements Parcelable {
// Step duration mode: power save is on.
public static final int STEP_LEVEL_MODE_POWER_SAVE = 0x04;
+ // Step duration mode: device is currently in idle mode.
+ public static final int STEP_LEVEL_MODE_DEVICE_IDLE = 0x08;
+
public static final int[] STEP_LEVEL_MODES_OF_INTEREST = new int[] {
STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+ STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE|STEP_LEVEL_MODE_DEVICE_IDLE,
+ STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_DEVICE_IDLE,
STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
- STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
- STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE,
+ STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_POWER_SAVE|STEP_LEVEL_MODE_DEVICE_IDLE,
+ STEP_LEVEL_MODE_SCREEN_STATE|STEP_LEVEL_MODE_DEVICE_IDLE,
};
public static final int[] STEP_LEVEL_MODE_VALUES = new int[] {
(Display.STATE_OFF-1),
(Display.STATE_OFF-1)|STEP_LEVEL_MODE_POWER_SAVE,
+ (Display.STATE_OFF-1)|STEP_LEVEL_MODE_DEVICE_IDLE,
(Display.STATE_ON-1),
(Display.STATE_ON-1)|STEP_LEVEL_MODE_POWER_SAVE,
(Display.STATE_DOZE-1),
(Display.STATE_DOZE-1)|STEP_LEVEL_MODE_POWER_SAVE,
(Display.STATE_DOZE_SUSPEND-1),
(Display.STATE_DOZE_SUSPEND-1)|STEP_LEVEL_MODE_POWER_SAVE,
+ (Display.STATE_DOZE_SUSPEND-1)|STEP_LEVEL_MODE_DEVICE_IDLE,
};
public static final String[] STEP_LEVEL_MODE_LABELS = new String[] {
"screen off",
"screen off power save",
+ "screen off device idle",
"screen on",
"screen on power save",
"screen doze",
"screen doze power save",
"screen doze-suspend",
"screen doze-suspend power save",
- };
- public static final String[] STEP_LEVEL_MODE_TAGS = new String[] {
- "off",
- "off-save",
- "on",
- "on-save",
- "doze",
- "doze-save",
- "susp",
- "susp-save",
+ "screen doze-suspend device idle",
};
/**
@@ -2140,6 +2175,8 @@ public abstract class BatteryStats implements Parcelable {
*/
public abstract LevelStepTracker getDailyChargeLevelStepTracker();
+ public abstract ArrayList<PackageChange> getDailyPackageChanges();
+
public abstract Map<String, ? extends Timer> getWakeupReasonStats();
public abstract Map<String, ? extends Timer> getKernelWakelockStats();
@@ -2338,18 +2375,19 @@ public abstract class BatteryStats implements Parcelable {
final long interactiveTime = getInteractiveTime(rawRealtime, which);
final long powerSaveModeEnabledTime = getPowerSaveModeEnabledTime(rawRealtime, which);
final long deviceIdleModeEnabledTime = getDeviceIdleModeEnabledTime(rawRealtime, which);
+ final long deviceIdlingTime = getDeviceIdlingTime(rawRealtime, which);
final int connChanges = getNumConnectivityChange(which);
final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
final long wifiOnTime = getWifiOnTime(rawRealtime, which);
final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
final long bluetoothOnTime = getBluetoothOnTime(rawRealtime, which);
- StringBuilder sb = new StringBuilder(128);
+ final StringBuilder sb = new StringBuilder(128);
- SparseArray<? extends Uid> uidStats = getUidStats();
+ final SparseArray<? extends Uid> uidStats = getUidStats();
final int NU = uidStats.size();
- String category = STAT_NAMES[which];
+ final String category = STAT_NAMES[which];
// Dump "battery" stat
dumpLine(pw, 0 /* uid */, category, BATTERY_DATA,
@@ -2364,37 +2402,35 @@ public abstract class BatteryStats implements Parcelable {
long partialWakeLockTimeTotal = 0;
for (int iu = 0; iu < NU; iu++) {
- Uid u = uidStats.valueAt(iu);
-
- Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
- if (wakelocks.size() > 0) {
- for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
- : wakelocks.entrySet()) {
- Uid.Wakelock wl = ent.getValue();
-
- Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
- if (fullWakeTimer != null) {
- fullWakeLockTimeTotal += fullWakeTimer.getTotalTimeLocked(rawRealtime,
- which);
- }
+ final Uid u = uidStats.valueAt(iu);
- Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
- if (partialWakeTimer != null) {
- partialWakeLockTimeTotal += partialWakeTimer.getTotalTimeLocked(
- rawRealtime, which);
- }
+ final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
+ = u.getWakelockStats();
+ for (int iw=wakelocks.size()-1; iw>=0; iw--) {
+ final Uid.Wakelock wl = wakelocks.valueAt(iw);
+
+ final Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
+ if (fullWakeTimer != null) {
+ fullWakeLockTimeTotal += fullWakeTimer.getTotalTimeLocked(rawRealtime,
+ which);
+ }
+
+ final Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
+ if (partialWakeTimer != null) {
+ partialWakeLockTimeTotal += partialWakeTimer.getTotalTimeLocked(
+ rawRealtime, which);
}
}
}
- long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
- long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
- long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
- long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
- long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
- long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
- long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
- long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+ final long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
+ final long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
+ final long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
+ final long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
+ final long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
+ final long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
+ final long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
+ final long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
// Dump network stats
dumpLine(pw, 0 /* uid */, category, GLOBAL_NETWORK_DATA,
@@ -2410,7 +2446,8 @@ public abstract class BatteryStats implements Parcelable {
0 /*legacy input event count*/, getMobileRadioActiveTime(rawRealtime, which) / 1000,
getMobileRadioActiveAdjustedTime(which) / 1000, interactiveTime / 1000,
powerSaveModeEnabledTime / 1000, connChanges, deviceIdleModeEnabledTime / 1000,
- getDeviceIdleModeEnabledCount(which));
+ getDeviceIdleModeEnabledCount(which), deviceIdlingTime / 1000,
+ getDeviceIdlingCount(which));
// Dump screen brightness stats
Object[] args = new Object[NUM_SCREEN_BRIGHTNESS_BINS];
@@ -2505,7 +2542,7 @@ public abstract class BatteryStats implements Parcelable {
}
if (reqUid < 0) {
- Map<String, ? extends Timer> kernelWakelocks = getKernelWakelockStats();
+ final Map<String, ? extends Timer> kernelWakelocks = getKernelWakelockStats();
if (kernelWakelocks.size() > 0) {
for (Map.Entry<String, ? extends Timer> ent : kernelWakelocks.entrySet()) {
sb.setLength(0);
@@ -2514,7 +2551,7 @@ public abstract class BatteryStats implements Parcelable {
sb.toString());
}
}
- Map<String, ? extends Timer> wakeupReasons = getWakeupReasonStats();
+ final Map<String, ? extends Timer> wakeupReasons = getWakeupReasonStats();
if (wakeupReasons.size() > 0) {
for (Map.Entry<String, ? extends Timer> ent : wakeupReasons.entrySet()) {
// Not doing the regular wake lock formatting to remain compatible
@@ -2527,10 +2564,10 @@ public abstract class BatteryStats implements Parcelable {
}
}
- BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
+ final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
helper.create(this);
helper.refreshStats(which, UserHandle.USER_ALL);
- List<BatterySipper> sippers = helper.getUsageList();
+ final List<BatterySipper> sippers = helper.getUsageList();
if (sippers != null && sippers.size() > 0) {
dumpLine(pw, 0 /* uid */, category, POWER_USE_SUMMARY_DATA,
BatteryStatsHelper.makemAh(helper.getPowerProfile().getBatteryCapacity()),
@@ -2538,7 +2575,7 @@ public abstract class BatteryStats implements Parcelable {
BatteryStatsHelper.makemAh(helper.getMinDrainedPower()),
BatteryStatsHelper.makemAh(helper.getMaxDrainedPower()));
for (int i=0; i<sippers.size(); i++) {
- BatterySipper bs = sippers.get(i);
+ final BatterySipper bs = sippers.get(i);
int uid = 0;
String label;
switch (bs.drainType) {
@@ -2590,22 +2627,22 @@ public abstract class BatteryStats implements Parcelable {
if (reqUid >= 0 && uid != reqUid) {
continue;
}
- Uid u = uidStats.valueAt(iu);
+ final Uid u = uidStats.valueAt(iu);
// Dump Network stats per uid, if any
- long mobileBytesRx = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
- long mobileBytesTx = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
- long wifiBytesRx = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
- long wifiBytesTx = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
- long mobilePacketsRx = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
- long mobilePacketsTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
- long mobileActiveTime = u.getMobileRadioActiveTime(which);
- int mobileActiveCount = u.getMobileRadioActiveCount(which);
- long wifiPacketsRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
- long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
- long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
- long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
- int wifiScanCount = u.getWifiScanCount(which);
- long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
+ final long mobileBytesRx = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
+ final long mobileBytesTx = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
+ final long wifiBytesRx = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
+ final long wifiBytesTx = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
+ final long mobilePacketsRx = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
+ final long mobilePacketsTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
+ final long mobileActiveTime = u.getMobileRadioActiveTime(which);
+ final int mobileActiveCount = u.getMobileRadioActiveCount(which);
+ final long wifiPacketsRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
+ final long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+ final long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
+ final long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
+ final int wifiScanCount = u.getWifiScanCount(which);
+ final long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
if (mobileBytesRx > 0 || mobileBytesTx > 0 || wifiBytesRx > 0 || wifiBytesTx > 0
|| mobilePacketsRx > 0 || mobilePacketsTx > 0 || wifiPacketsRx > 0
@@ -2636,93 +2673,90 @@ public abstract class BatteryStats implements Parcelable {
}
}
- Map<String, ? extends Uid.Wakelock> wakelocks = u.getWakelockStats();
- if (wakelocks.size() > 0) {
- for (Map.Entry<String, ? extends Uid.Wakelock> ent : wakelocks.entrySet()) {
- Uid.Wakelock wl = ent.getValue();
- String linePrefix = "";
- sb.setLength(0);
- linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL),
- rawRealtime, "f", which, linePrefix);
- linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL),
- rawRealtime, "p", which, linePrefix);
- linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW),
- rawRealtime, "w", which, linePrefix);
-
- // Only log if we had at lease one wakelock...
- if (sb.length() > 0) {
- String name = ent.getKey();
- if (name.indexOf(',') >= 0) {
- name = name.replace(',', '_');
- }
- dumpLine(pw, uid, category, WAKELOCK_DATA, name, sb.toString());
+ final ArrayMap<String, ? extends Uid.Wakelock> wakelocks = u.getWakelockStats();
+ for (int iw=wakelocks.size()-1; iw>=0; iw--) {
+ final Uid.Wakelock wl = wakelocks.valueAt(iw);
+ String linePrefix = "";
+ sb.setLength(0);
+ linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL),
+ rawRealtime, "f", which, linePrefix);
+ linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL),
+ rawRealtime, "p", which, linePrefix);
+ linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW),
+ rawRealtime, "w", which, linePrefix);
+
+ // Only log if we had at lease one wakelock...
+ if (sb.length() > 0) {
+ String name = wakelocks.keyAt(iw);
+ if (name.indexOf(',') >= 0) {
+ name = name.replace(',', '_');
}
+ dumpLine(pw, uid, category, WAKELOCK_DATA, name, sb.toString());
}
}
- Map<String, ? extends Timer> syncs = u.getSyncStats();
- if (syncs.size() > 0) {
- for (Map.Entry<String, ? extends Timer> ent : syncs.entrySet()) {
- Timer timer = ent.getValue();
- // Convert from microseconds to milliseconds with rounding
- long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
- int count = timer.getCountLocked(which);
- if (totalTime != 0) {
- dumpLine(pw, uid, category, SYNC_DATA, ent.getKey(), totalTime, count);
- }
+ final ArrayMap<String, ? extends Timer> syncs = u.getSyncStats();
+ for (int isy=syncs.size()-1; isy>=0; isy--) {
+ final Timer timer = syncs.valueAt(isy);
+ // Convert from microseconds to milliseconds with rounding
+ final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
+ final int count = timer.getCountLocked(which);
+ if (totalTime != 0) {
+ dumpLine(pw, uid, category, SYNC_DATA, syncs.keyAt(isy), totalTime, count);
}
}
- Map<String, ? extends Timer> jobs = u.getJobStats();
- if (jobs.size() > 0) {
- for (Map.Entry<String, ? extends Timer> ent : jobs.entrySet()) {
- Timer timer = ent.getValue();
- // Convert from microseconds to milliseconds with rounding
- long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
- int count = timer.getCountLocked(which);
- if (totalTime != 0) {
- dumpLine(pw, uid, category, JOB_DATA, ent.getKey(), totalTime, count);
- }
+ final ArrayMap<String, ? extends Timer> jobs = u.getJobStats();
+ for (int ij=jobs.size()-1; ij>=0; ij--) {
+ final Timer timer = jobs.valueAt(ij);
+ // Convert from microseconds to milliseconds with rounding
+ final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
+ final int count = timer.getCountLocked(which);
+ if (totalTime != 0) {
+ dumpLine(pw, uid, category, JOB_DATA, jobs.keyAt(ij), totalTime, count);
}
}
- SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
- int NSE = sensors.size();
+ final SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
+ final int NSE = sensors.size();
for (int ise=0; ise<NSE; ise++) {
- Uid.Sensor se = sensors.valueAt(ise);
- int sensorNumber = sensors.keyAt(ise);
- Timer timer = se.getSensorTime();
+ final Uid.Sensor se = sensors.valueAt(ise);
+ final int sensorNumber = sensors.keyAt(ise);
+ final Timer timer = se.getSensorTime();
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
- int count = timer.getCountLocked(which);
+ final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500)
+ / 1000;
+ final int count = timer.getCountLocked(which);
if (totalTime != 0) {
dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count);
}
}
}
- Timer vibTimer = u.getVibratorOnTimer();
+ final Timer vibTimer = u.getVibratorOnTimer();
if (vibTimer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTime = (vibTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
- int count = vibTimer.getCountLocked(which);
+ final long totalTime = (vibTimer.getTotalTimeLocked(rawRealtime, which) + 500)
+ / 1000;
+ final int count = vibTimer.getCountLocked(which);
if (totalTime != 0) {
dumpLine(pw, uid, category, VIBRATOR_DATA, totalTime, count);
}
}
- Timer fgTimer = u.getForegroundActivityTimer();
+ final Timer fgTimer = u.getForegroundActivityTimer();
if (fgTimer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
- int count = fgTimer.getCountLocked(which);
+ final long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500)
+ / 1000;
+ final int count = fgTimer.getCountLocked(which);
if (totalTime != 0) {
dumpLine(pw, uid, category, FOREGROUND_DATA, totalTime, count);
}
}
- Object[] stateTimes = new Object[Uid.NUM_PROCESS_STATE];
+ final Object[] stateTimes = new Object[Uid.NUM_PROCESS_STATE];
long totalStateTime = 0;
for (int ips=0; ips<Uid.NUM_PROCESS_STATE; ips++) {
totalStateTime += u.getProcessStateTime(ips, rawRealtime, which);
@@ -2732,50 +2766,48 @@ public abstract class BatteryStats implements Parcelable {
dumpLine(pw, uid, category, STATE_TIME_DATA, stateTimes);
}
- Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
- if (processStats.size() > 0) {
- for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
- : processStats.entrySet()) {
- Uid.Proc ps = ent.getValue();
-
- final long userMillis = ps.getUserTime(which);
- final long systemMillis = ps.getSystemTime(which);
- final long foregroundMillis = ps.getForegroundTime(which);
- final int starts = ps.getStarts(which);
- final int numCrashes = ps.getNumCrashes(which);
- final int numAnrs = ps.getNumAnrs(which);
-
- if (userMillis != 0 || systemMillis != 0 || foregroundMillis != 0
- || starts != 0 || numAnrs != 0 || numCrashes != 0) {
- dumpLine(pw, uid, category, PROCESS_DATA, ent.getKey(), userMillis,
- systemMillis, foregroundMillis, starts, numAnrs, numCrashes);
- }
+ final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats
+ = u.getProcessStats();
+ for (int ipr=processStats.size()-1; ipr>=0; ipr--) {
+ final Uid.Proc ps = processStats.valueAt(ipr);
+
+ final long userMillis = ps.getUserTime(which);
+ final long systemMillis = ps.getSystemTime(which);
+ final long foregroundMillis = ps.getForegroundTime(which);
+ final int starts = ps.getStarts(which);
+ final int numCrashes = ps.getNumCrashes(which);
+ final int numAnrs = ps.getNumAnrs(which);
+
+ if (userMillis != 0 || systemMillis != 0 || foregroundMillis != 0
+ || starts != 0 || numAnrs != 0 || numCrashes != 0) {
+ dumpLine(pw, uid, category, PROCESS_DATA, processStats.keyAt(ipr), userMillis,
+ systemMillis, foregroundMillis, starts, numAnrs, numCrashes);
}
}
- Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
- if (packageStats.size() > 0) {
- for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
- : packageStats.entrySet()) {
-
- Uid.Pkg ps = ent.getValue();
- int wakeups = ps.getWakeups(which);
- Map<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
- for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
- : serviceStats.entrySet()) {
- BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
- long startTime = ss.getStartTime(batteryUptime, which);
- int starts = ss.getStarts(which);
- int launches = ss.getLaunches(which);
- if (startTime != 0 || starts != 0 || launches != 0) {
- dumpLine(pw, uid, category, APK_DATA,
- wakeups, // wakeup alarms
- ent.getKey(), // Apk
- sent.getKey(), // service
- startTime / 1000, // time spent started, in ms
- starts,
- launches);
- }
+ final ArrayMap<String, ? extends BatteryStats.Uid.Pkg> packageStats
+ = u.getPackageStats();
+ for (int ipkg=packageStats.size()-1; ipkg>=0; ipkg--) {
+ final Uid.Pkg ps = packageStats.valueAt(ipkg);
+ int wakeups = 0;
+ final ArrayMap<String, ? extends Counter> alarms = ps.getWakeupAlarmStats();
+ for (int iwa=alarms.size()-1; iwa>=0; iwa--) {
+ wakeups += alarms.valueAt(iwa).getCountLocked(which);
+ }
+ final ArrayMap<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
+ for (int isvc=serviceStats.size()-1; isvc>=0; isvc--) {
+ final BatteryStats.Uid.Pkg.Serv ss = serviceStats.valueAt(isvc);
+ final long startTime = ss.getStartTime(batteryUptime, which);
+ final int starts = ss.getStarts(which);
+ final int launches = ss.getLaunches(which);
+ if (startTime != 0 || starts != 0 || launches != 0) {
+ dumpLine(pw, uid, category, APK_DATA,
+ wakeups, // wakeup alarms
+ packageStats.keyAt(ipkg), // Apk
+ serviceStats.keyAt(isvc), // service
+ startTime / 1000, // time spent started, in ms
+ starts,
+ launches);
}
}
}
@@ -2824,9 +2856,9 @@ public abstract class BatteryStats implements Parcelable {
final long batteryTimeRemaining = computeBatteryTimeRemaining(rawRealtime);
final long chargeTimeRemaining = computeChargeTimeRemaining(rawRealtime);
- StringBuilder sb = new StringBuilder(128);
+ final StringBuilder sb = new StringBuilder(128);
- SparseArray<? extends Uid> uidStats = getUidStats();
+ final SparseArray<? extends Uid> uidStats = getUidStats();
final int NU = uidStats.size();
sb.setLength(0);
@@ -2879,6 +2911,7 @@ public abstract class BatteryStats implements Parcelable {
final long interactiveTime = getInteractiveTime(rawRealtime, which);
final long powerSaveModeEnabledTime = getPowerSaveModeEnabledTime(rawRealtime, which);
final long deviceIdleModeEnabledTime = getDeviceIdleModeEnabledTime(rawRealtime, which);
+ final long deviceIdlingTime = getDeviceIdlingTime(rawRealtime, which);
final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
final long wifiOnTime = getWifiOnTime(rawRealtime, which);
@@ -2923,10 +2956,21 @@ public abstract class BatteryStats implements Parcelable {
sb.append(")");
pw.println(sb.toString());
}
- if (deviceIdleModeEnabledTime != 0) {
+ if (deviceIdlingTime != 0) {
sb.setLength(0);
sb.append(prefix);
sb.append(" Device idling: ");
+ formatTimeMs(sb, deviceIdlingTime / 1000);
+ sb.append("(");
+ sb.append(formatRatioLocked(deviceIdlingTime, whichBatteryRealtime));
+ sb.append(") "); sb.append(getDeviceIdlingCount(which));
+ sb.append("x");
+ pw.println(sb.toString());
+ }
+ if (deviceIdleModeEnabledTime != 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Idle mode time: ");
formatTimeMs(sb, deviceIdleModeEnabledTime / 1000);
sb.append("(");
sb.append(formatRatioLocked(deviceIdleModeEnabledTime, whichBatteryRealtime));
@@ -2941,7 +2985,7 @@ public abstract class BatteryStats implements Parcelable {
sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime));
sb.append(") "); sb.append(getPhoneOnCount(which)); sb.append("x");
}
- int connChanges = getNumConnectivityChange(which);
+ final int connChanges = getNumConnectivityChange(which);
if (connChanges != 0) {
pw.print(prefix);
pw.print(" Connectivity changes: "); pw.println(connChanges);
@@ -2951,50 +2995,48 @@ public abstract class BatteryStats implements Parcelable {
long fullWakeLockTimeTotalMicros = 0;
long partialWakeLockTimeTotalMicros = 0;
- final ArrayList<TimerEntry> timers = new ArrayList<TimerEntry>();
+ final ArrayList<TimerEntry> timers = new ArrayList<>();
for (int iu = 0; iu < NU; iu++) {
- Uid u = uidStats.valueAt(iu);
-
- Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
- if (wakelocks.size() > 0) {
- for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
- : wakelocks.entrySet()) {
- Uid.Wakelock wl = ent.getValue();
-
- Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
- if (fullWakeTimer != null) {
- fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTimeLocked(
- rawRealtime, which);
- }
+ final Uid u = uidStats.valueAt(iu);
- Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
- if (partialWakeTimer != null) {
- long totalTimeMicros = partialWakeTimer.getTotalTimeLocked(
- rawRealtime, which);
- if (totalTimeMicros > 0) {
- if (reqUid < 0) {
- // Only show the ordered list of all wake
- // locks if the caller is not asking for data
- // about a specific uid.
- timers.add(new TimerEntry(ent.getKey(), u.getUid(),
- partialWakeTimer, totalTimeMicros));
- }
- partialWakeLockTimeTotalMicros += totalTimeMicros;
+ final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
+ = u.getWakelockStats();
+ for (int iw=wakelocks.size()-1; iw>=0; iw--) {
+ final Uid.Wakelock wl = wakelocks.valueAt(iw);
+
+ final Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
+ if (fullWakeTimer != null) {
+ fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTimeLocked(
+ rawRealtime, which);
+ }
+
+ final Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
+ if (partialWakeTimer != null) {
+ final long totalTimeMicros = partialWakeTimer.getTotalTimeLocked(
+ rawRealtime, which);
+ if (totalTimeMicros > 0) {
+ if (reqUid < 0) {
+ // Only show the ordered list of all wake
+ // locks if the caller is not asking for data
+ // about a specific uid.
+ timers.add(new TimerEntry(wakelocks.keyAt(iw), u.getUid(),
+ partialWakeTimer, totalTimeMicros));
}
+ partialWakeLockTimeTotalMicros += totalTimeMicros;
}
}
}
}
- long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
- long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
- long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
- long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
- long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
- long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
- long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
- long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+ final long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
+ final long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
+ final long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
+ final long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
+ final long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
+ final long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
+ final long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
+ final long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
if (fullWakeLockTimeTotalMicros != 0) {
sb.setLength(0);
@@ -3191,9 +3233,9 @@ public abstract class BatteryStats implements Parcelable {
if (!didOne) sb.append(" (no activity)");
pw.println(sb.toString());
- final long wifiIdleTimeMs = getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which);
- final long wifiRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which);
- final long wifiTxTimeMs = getBluetoothControllerActivity(CONTROLLER_TX_TIME, which);
+ final long wifiIdleTimeMs = getWifiControllerActivity(CONTROLLER_IDLE_TIME, which);
+ final long wifiRxTimeMs = getWifiControllerActivity(CONTROLLER_RX_TIME, which);
+ final long wifiTxTimeMs = getWifiControllerActivity(CONTROLLER_TX_TIME, which);
final long wifiTotalTimeMs = wifiIdleTimeMs + wifiRxTimeMs + wifiTxTimeMs;
sb.setLength(0);
@@ -3316,7 +3358,7 @@ public abstract class BatteryStats implements Parcelable {
pw.println();
}
- BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
+ final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
helper.create(this);
helper.refreshStats(which, UserHandle.USER_ALL);
List<BatterySipper> sippers = helper.getUsageList();
@@ -3331,7 +3373,7 @@ public abstract class BatteryStats implements Parcelable {
}
pw.println();
for (int i=0; i<sippers.size(); i++) {
- BatterySipper bs = sippers.get(i);
+ final BatterySipper bs = sippers.get(i);
switch (bs.drainType) {
case IDLE:
pw.print(prefix); pw.print(" Idle: "); printmAh(pw, bs.value);
@@ -3388,7 +3430,7 @@ public abstract class BatteryStats implements Parcelable {
pw.print(prefix); pw.println(" Per-app mobile ms per packet:");
long totalTime = 0;
for (int i=0; i<sippers.size(); i++) {
- BatterySipper bs = sippers.get(i);
+ final BatterySipper bs = sippers.get(i);
sb.setLength(0);
sb.append(prefix); sb.append(" Uid ");
UserHandle.formatUid(sb, bs.uidObj.getUid());
@@ -3425,12 +3467,14 @@ public abstract class BatteryStats implements Parcelable {
};
if (reqUid < 0) {
- Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats();
+ final Map<String, ? extends BatteryStats.Timer> kernelWakelocks
+ = getKernelWakelockStats();
if (kernelWakelocks.size() > 0) {
- final ArrayList<TimerEntry> ktimers = new ArrayList<TimerEntry>();
- for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) {
- BatteryStats.Timer timer = ent.getValue();
- long totalTimeMillis = computeWakeLock(timer, rawRealtime, which);
+ final ArrayList<TimerEntry> ktimers = new ArrayList<>();
+ for (Map.Entry<String, ? extends BatteryStats.Timer> ent
+ : kernelWakelocks.entrySet()) {
+ final BatteryStats.Timer timer = ent.getValue();
+ final long totalTimeMillis = computeWakeLock(timer, rawRealtime, which);
if (totalTimeMillis > 0) {
ktimers.add(new TimerEntry(ent.getKey(), 0, timer, totalTimeMillis));
}
@@ -3439,7 +3483,7 @@ public abstract class BatteryStats implements Parcelable {
Collections.sort(ktimers, timerComparator);
pw.print(prefix); pw.println(" All kernel wake locks:");
for (int i=0; i<ktimers.size(); i++) {
- TimerEntry timer = ktimers.get(i);
+ final TimerEntry timer = ktimers.get(i);
String linePrefix = ": ";
sb.setLength(0);
sb.append(prefix);
@@ -3475,12 +3519,12 @@ public abstract class BatteryStats implements Parcelable {
pw.println();
}
- Map<String, ? extends Timer> wakeupReasons = getWakeupReasonStats();
+ final Map<String, ? extends Timer> wakeupReasons = getWakeupReasonStats();
if (wakeupReasons.size() > 0) {
pw.print(prefix); pw.println(" All wakeup reasons:");
- final ArrayList<TimerEntry> reasons = new ArrayList<TimerEntry>();
+ final ArrayList<TimerEntry> reasons = new ArrayList<>();
for (Map.Entry<String, ? extends Timer> ent : wakeupReasons.entrySet()) {
- Timer timer = ent.getValue();
+ final Timer timer = ent.getValue();
reasons.add(new TimerEntry(ent.getKey(), 0, timer,
timer.getCountLocked(which)));
}
@@ -3506,7 +3550,7 @@ public abstract class BatteryStats implements Parcelable {
continue;
}
- Uid u = uidStats.valueAt(iu);
+ final Uid u = uidStats.valueAt(iu);
pw.print(prefix);
pw.print(" ");
@@ -3514,20 +3558,20 @@ public abstract class BatteryStats implements Parcelable {
pw.println(":");
boolean uidActivity = false;
- long mobileRxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
- long mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
- long wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
- long wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
- long mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
- long mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
- long uidMobileActiveTime = u.getMobileRadioActiveTime(which);
- int uidMobileActiveCount = u.getMobileRadioActiveCount(which);
- long wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
- long wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
- long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
- long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
- int wifiScanCount = u.getWifiScanCount(which);
- long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
+ final long mobileRxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
+ final long mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
+ final long wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
+ final long wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
+ final long mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
+ final long mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
+ final long uidMobileActiveTime = u.getMobileRadioActiveTime(which);
+ final int uidMobileActiveCount = u.getMobileRadioActiveCount(which);
+ final long wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
+ final long wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+ final long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
+ final long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
+ final int wifiScanCount = u.getWifiScanCount(which);
+ final long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
if (mobileRxBytes > 0 || mobileTxBytes > 0
|| mobileRxPackets > 0 || mobileTxPackets > 0) {
@@ -3585,7 +3629,7 @@ public abstract class BatteryStats implements Parcelable {
if (u.hasUserActivity()) {
boolean hasData = false;
for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
- int val = u.getUserActivityCount(i, which);
+ final int val = u.getUserActivityCount(i, which);
if (val != 0) {
if (!hasData) {
sb.setLength(0);
@@ -3604,125 +3648,121 @@ public abstract class BatteryStats implements Parcelable {
}
}
- Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
- if (wakelocks.size() > 0) {
- long totalFull = 0, totalPartial = 0, totalWindow = 0;
- int count = 0;
- for (Map.Entry<String, ? extends Uid.Wakelock> ent : wakelocks.entrySet()) {
- Uid.Wakelock wl = ent.getValue();
- String linePrefix = ": ";
+ final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
+ = u.getWakelockStats();
+ long totalFullWakelock = 0, totalPartialWakelock = 0, totalWindowWakelock = 0;
+ int countWakelock = 0;
+ for (int iw=wakelocks.size()-1; iw>=0; iw--) {
+ final Uid.Wakelock wl = wakelocks.valueAt(iw);
+ String linePrefix = ": ";
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Wake lock ");
+ sb.append(wakelocks.keyAt(iw));
+ linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), rawRealtime,
+ "full", which, linePrefix);
+ linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), rawRealtime,
+ "partial", which, linePrefix);
+ linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), rawRealtime,
+ "window", which, linePrefix);
+ if (true || !linePrefix.equals(": ")) {
+ sb.append(" realtime");
+ // Only print out wake locks that were held
+ pw.println(sb.toString());
+ uidActivity = true;
+ countWakelock++;
+ }
+ totalFullWakelock += computeWakeLock(wl.getWakeTime(WAKE_TYPE_FULL),
+ rawRealtime, which);
+ totalPartialWakelock += computeWakeLock(wl.getWakeTime(WAKE_TYPE_PARTIAL),
+ rawRealtime, which);
+ totalWindowWakelock += computeWakeLock(wl.getWakeTime(WAKE_TYPE_WINDOW),
+ rawRealtime, which);
+ }
+ if (countWakelock > 1) {
+ if (totalFullWakelock != 0 || totalPartialWakelock != 0
+ || totalWindowWakelock != 0) {
sb.setLength(0);
sb.append(prefix);
- sb.append(" Wake lock ");
- sb.append(ent.getKey());
- linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), rawRealtime,
- "full", which, linePrefix);
- linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), rawRealtime,
- "partial", which, linePrefix);
- linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), rawRealtime,
- "window", which, linePrefix);
- if (true || !linePrefix.equals(": ")) {
- sb.append(" realtime");
- // Only print out wake locks that were held
- pw.println(sb.toString());
- uidActivity = true;
- count++;
+ sb.append(" TOTAL wake: ");
+ boolean needComma = false;
+ if (totalFullWakelock != 0) {
+ needComma = true;
+ formatTimeMs(sb, totalFullWakelock);
+ sb.append("full");
}
- totalFull += computeWakeLock(wl.getWakeTime(WAKE_TYPE_FULL),
- rawRealtime, which);
- totalPartial += computeWakeLock(wl.getWakeTime(WAKE_TYPE_PARTIAL),
- rawRealtime, which);
- totalWindow += computeWakeLock(wl.getWakeTime(WAKE_TYPE_WINDOW),
- rawRealtime, which);
- }
- if (count > 1) {
- if (totalFull != 0 || totalPartial != 0 || totalWindow != 0) {
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" TOTAL wake: ");
- boolean needComma = false;
- if (totalFull != 0) {
- needComma = true;
- formatTimeMs(sb, totalFull);
- sb.append("full");
- }
- if (totalPartial != 0) {
- if (needComma) {
- sb.append(", ");
- }
- needComma = true;
- formatTimeMs(sb, totalPartial);
- sb.append("partial");
+ if (totalPartialWakelock != 0) {
+ if (needComma) {
+ sb.append(", ");
}
- if (totalWindow != 0) {
- if (needComma) {
- sb.append(", ");
- }
- needComma = true;
- formatTimeMs(sb, totalWindow);
- sb.append("window");
+ needComma = true;
+ formatTimeMs(sb, totalPartialWakelock);
+ sb.append("partial");
+ }
+ if (totalWindowWakelock != 0) {
+ if (needComma) {
+ sb.append(", ");
}
- sb.append(" realtime");
- pw.println(sb.toString());
+ needComma = true;
+ formatTimeMs(sb, totalWindowWakelock);
+ sb.append("window");
}
+ sb.append(" realtime");
+ pw.println(sb.toString());
}
}
- Map<String, ? extends Timer> syncs = u.getSyncStats();
- if (syncs.size() > 0) {
- for (Map.Entry<String, ? extends Timer> ent : syncs.entrySet()) {
- Timer timer = ent.getValue();
- // Convert from microseconds to milliseconds with rounding
- long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
- int count = timer.getCountLocked(which);
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" Sync ");
- sb.append(ent.getKey());
- sb.append(": ");
- if (totalTime != 0) {
- formatTimeMs(sb, totalTime);
- sb.append("realtime (");
- sb.append(count);
- sb.append(" times)");
- } else {
- sb.append("(not used)");
- }
- pw.println(sb.toString());
- uidActivity = true;
+ final ArrayMap<String, ? extends Timer> syncs = u.getSyncStats();
+ for (int isy=syncs.size()-1; isy>=0; isy--) {
+ final Timer timer = syncs.valueAt(isy);
+ // Convert from microseconds to milliseconds with rounding
+ final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
+ final int count = timer.getCountLocked(which);
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Sync ");
+ sb.append(syncs.keyAt(isy));
+ sb.append(": ");
+ if (totalTime != 0) {
+ formatTimeMs(sb, totalTime);
+ sb.append("realtime (");
+ sb.append(count);
+ sb.append(" times)");
+ } else {
+ sb.append("(not used)");
}
+ pw.println(sb.toString());
+ uidActivity = true;
}
- Map<String, ? extends Timer> jobs = u.getJobStats();
- if (jobs.size() > 0) {
- for (Map.Entry<String, ? extends Timer> ent : jobs.entrySet()) {
- Timer timer = ent.getValue();
- // Convert from microseconds to milliseconds with rounding
- long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
- int count = timer.getCountLocked(which);
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" Job ");
- sb.append(ent.getKey());
- sb.append(": ");
- if (totalTime != 0) {
- formatTimeMs(sb, totalTime);
- sb.append("realtime (");
- sb.append(count);
- sb.append(" times)");
- } else {
- sb.append("(not used)");
- }
- pw.println(sb.toString());
- uidActivity = true;
+ final ArrayMap<String, ? extends Timer> jobs = u.getJobStats();
+ for (int ij=jobs.size()-1; ij>=0; ij--) {
+ final Timer timer = jobs.valueAt(ij);
+ // Convert from microseconds to milliseconds with rounding
+ final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
+ final int count = timer.getCountLocked(which);
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Job ");
+ sb.append(jobs.keyAt(ij));
+ sb.append(": ");
+ if (totalTime != 0) {
+ formatTimeMs(sb, totalTime);
+ sb.append("realtime (");
+ sb.append(count);
+ sb.append(" times)");
+ } else {
+ sb.append("(not used)");
}
+ pw.println(sb.toString());
+ uidActivity = true;
}
- SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
- int NSE = sensors.size();
+ final SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
+ final int NSE = sensors.size();
for (int ise=0; ise<NSE; ise++) {
- Uid.Sensor se = sensors.valueAt(ise);
- int sensorNumber = sensors.keyAt(ise);
+ final Uid.Sensor se = sensors.valueAt(ise);
+ final int sensorNumber = sensors.keyAt(ise);
sb.setLength(0);
sb.append(prefix);
sb.append(" Sensor ");
@@ -3734,12 +3774,12 @@ public abstract class BatteryStats implements Parcelable {
}
sb.append(": ");
- Timer timer = se.getSensorTime();
+ final Timer timer = se.getSensorTime();
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTime = (timer.getTotalTimeLocked(
+ final long totalTime = (timer.getTotalTimeLocked(
rawRealtime, which) + 500) / 1000;
- int count = timer.getCountLocked(which);
+ final int count = timer.getCountLocked(which);
//timer.logState();
if (totalTime != 0) {
formatTimeMs(sb, totalTime);
@@ -3757,12 +3797,12 @@ public abstract class BatteryStats implements Parcelable {
uidActivity = true;
}
- Timer vibTimer = u.getVibratorOnTimer();
+ final Timer vibTimer = u.getVibratorOnTimer();
if (vibTimer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTime = (vibTimer.getTotalTimeLocked(
+ final long totalTime = (vibTimer.getTotalTimeLocked(
rawRealtime, which) + 500) / 1000;
- int count = vibTimer.getCountLocked(which);
+ final int count = vibTimer.getCountLocked(which);
//timer.logState();
if (totalTime != 0) {
sb.setLength(0);
@@ -3777,11 +3817,12 @@ public abstract class BatteryStats implements Parcelable {
}
}
- Timer fgTimer = u.getForegroundActivityTimer();
+ final Timer fgTimer = u.getForegroundActivityTimer();
if (fgTimer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
- int count = fgTimer.getCountLocked(which);
+ final long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500)
+ / 1000;
+ final int count = fgTimer.getCountLocked(which);
if (totalTime != 0) {
sb.setLength(0);
sb.append(prefix);
@@ -3811,125 +3852,121 @@ public abstract class BatteryStats implements Parcelable {
}
}
- Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
- if (processStats.size() > 0) {
- for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
- : processStats.entrySet()) {
- Uid.Proc ps = ent.getValue();
- long userTime;
- long systemTime;
- long foregroundTime;
- int starts;
- int numExcessive;
-
- userTime = ps.getUserTime(which);
- systemTime = ps.getSystemTime(which);
- foregroundTime = ps.getForegroundTime(which);
- starts = ps.getStarts(which);
- final int numCrashes = ps.getNumCrashes(which);
- final int numAnrs = ps.getNumAnrs(which);
- numExcessive = which == STATS_SINCE_CHARGED
- ? ps.countExcessivePowers() : 0;
-
- if (userTime != 0 || systemTime != 0 || foregroundTime != 0 || starts != 0
- || numExcessive != 0 || numCrashes != 0 || numAnrs != 0) {
- sb.setLength(0);
- sb.append(prefix); sb.append(" Proc ");
- sb.append(ent.getKey()); sb.append(":\n");
- sb.append(prefix); sb.append(" CPU: ");
- formatTimeMs(sb, userTime); sb.append("usr + ");
- formatTimeMs(sb, systemTime); sb.append("krn ; ");
- formatTimeMs(sb, foregroundTime); sb.append("fg");
- if (starts != 0 || numCrashes != 0 || numAnrs != 0) {
- sb.append("\n"); sb.append(prefix); sb.append(" ");
- boolean hasOne = false;
- if (starts != 0) {
- hasOne = true;
- sb.append(starts); sb.append(" starts");
- }
- if (numCrashes != 0) {
- if (hasOne) {
- sb.append(", ");
- }
- hasOne = true;
- sb.append(numCrashes); sb.append(" crashes");
- }
- if (numAnrs != 0) {
- if (hasOne) {
- sb.append(", ");
- }
- sb.append(numAnrs); sb.append(" anrs");
+ final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats
+ = u.getProcessStats();
+ for (int ipr=processStats.size()-1; ipr>=0; ipr--) {
+ final Uid.Proc ps = processStats.valueAt(ipr);
+ long userTime;
+ long systemTime;
+ long foregroundTime;
+ int starts;
+ int numExcessive;
+
+ userTime = ps.getUserTime(which);
+ systemTime = ps.getSystemTime(which);
+ foregroundTime = ps.getForegroundTime(which);
+ starts = ps.getStarts(which);
+ final int numCrashes = ps.getNumCrashes(which);
+ final int numAnrs = ps.getNumAnrs(which);
+ numExcessive = which == STATS_SINCE_CHARGED
+ ? ps.countExcessivePowers() : 0;
+
+ if (userTime != 0 || systemTime != 0 || foregroundTime != 0 || starts != 0
+ || numExcessive != 0 || numCrashes != 0 || numAnrs != 0) {
+ sb.setLength(0);
+ sb.append(prefix); sb.append(" Proc ");
+ sb.append(processStats.keyAt(ipr)); sb.append(":\n");
+ sb.append(prefix); sb.append(" CPU: ");
+ formatTimeMs(sb, userTime); sb.append("usr + ");
+ formatTimeMs(sb, systemTime); sb.append("krn ; ");
+ formatTimeMs(sb, foregroundTime); sb.append("fg");
+ if (starts != 0 || numCrashes != 0 || numAnrs != 0) {
+ sb.append("\n"); sb.append(prefix); sb.append(" ");
+ boolean hasOne = false;
+ if (starts != 0) {
+ hasOne = true;
+ sb.append(starts); sb.append(" starts");
+ }
+ if (numCrashes != 0) {
+ if (hasOne) {
+ sb.append(", ");
}
+ hasOne = true;
+ sb.append(numCrashes); sb.append(" crashes");
}
- pw.println(sb.toString());
- for (int e=0; e<numExcessive; e++) {
- Uid.Proc.ExcessivePower ew = ps.getExcessivePower(e);
- if (ew != null) {
- pw.print(prefix); pw.print(" * Killed for ");
- if (ew.type == Uid.Proc.ExcessivePower.TYPE_WAKE) {
- pw.print("wake lock");
- } else if (ew.type == Uid.Proc.ExcessivePower.TYPE_CPU) {
- pw.print("cpu");
- } else {
- pw.print("unknown");
- }
- pw.print(" use: ");
- TimeUtils.formatDuration(ew.usedTime, pw);
- pw.print(" over ");
- TimeUtils.formatDuration(ew.overTime, pw);
- if (ew.overTime != 0) {
- pw.print(" (");
- pw.print((ew.usedTime*100)/ew.overTime);
- pw.println("%)");
- }
+ if (numAnrs != 0) {
+ if (hasOne) {
+ sb.append(", ");
}
+ sb.append(numAnrs); sb.append(" anrs");
}
- uidActivity = true;
}
+ pw.println(sb.toString());
+ for (int e=0; e<numExcessive; e++) {
+ Uid.Proc.ExcessivePower ew = ps.getExcessivePower(e);
+ if (ew != null) {
+ pw.print(prefix); pw.print(" * Killed for ");
+ if (ew.type == Uid.Proc.ExcessivePower.TYPE_WAKE) {
+ pw.print("wake lock");
+ } else if (ew.type == Uid.Proc.ExcessivePower.TYPE_CPU) {
+ pw.print("cpu");
+ } else {
+ pw.print("unknown");
+ }
+ pw.print(" use: ");
+ TimeUtils.formatDuration(ew.usedTime, pw);
+ pw.print(" over ");
+ TimeUtils.formatDuration(ew.overTime, pw);
+ if (ew.overTime != 0) {
+ pw.print(" (");
+ pw.print((ew.usedTime*100)/ew.overTime);
+ pw.println("%)");
+ }
+ }
+ }
+ uidActivity = true;
}
}
- Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
- if (packageStats.size() > 0) {
- for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
- : packageStats.entrySet()) {
- pw.print(prefix); pw.print(" Apk "); pw.print(ent.getKey()); pw.println(":");
- boolean apkActivity = false;
- Uid.Pkg ps = ent.getValue();
- int wakeups = ps.getWakeups(which);
- if (wakeups != 0) {
- pw.print(prefix); pw.print(" ");
- pw.print(wakeups); pw.println(" wakeup alarms");
+ final ArrayMap<String, ? extends BatteryStats.Uid.Pkg> packageStats
+ = u.getPackageStats();
+ for (int ipkg=packageStats.size()-1; ipkg>=0; ipkg--) {
+ pw.print(prefix); pw.print(" Apk "); pw.print(packageStats.keyAt(ipkg));
+ pw.println(":");
+ boolean apkActivity = false;
+ final Uid.Pkg ps = packageStats.valueAt(ipkg);
+ final ArrayMap<String, ? extends Counter> alarms = ps.getWakeupAlarmStats();
+ for (int iwa=alarms.size()-1; iwa>=0; iwa--) {
+ pw.print(prefix); pw.print(" Wakeup alarm ");
+ pw.print(alarms.keyAt(iwa)); pw.print(": ");
+ pw.print(alarms.valueAt(iwa).getCountLocked(which));
+ pw.println(" times");
+ apkActivity = true;
+ }
+ final ArrayMap<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
+ for (int isvc=serviceStats.size()-1; isvc>=0; isvc--) {
+ final BatteryStats.Uid.Pkg.Serv ss = serviceStats.valueAt(isvc);
+ final long startTime = ss.getStartTime(batteryUptime, which);
+ final int starts = ss.getStarts(which);
+ final int launches = ss.getLaunches(which);
+ if (startTime != 0 || starts != 0 || launches != 0) {
+ sb.setLength(0);
+ sb.append(prefix); sb.append(" Service ");
+ sb.append(serviceStats.keyAt(isvc)); sb.append(":\n");
+ sb.append(prefix); sb.append(" Created for: ");
+ formatTimeMs(sb, startTime / 1000);
+ sb.append("uptime\n");
+ sb.append(prefix); sb.append(" Starts: ");
+ sb.append(starts);
+ sb.append(", launches: "); sb.append(launches);
+ pw.println(sb.toString());
apkActivity = true;
}
- Map<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
- if (serviceStats.size() > 0) {
- for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
- : serviceStats.entrySet()) {
- BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
- long startTime = ss.getStartTime(batteryUptime, which);
- int starts = ss.getStarts(which);
- int launches = ss.getLaunches(which);
- if (startTime != 0 || starts != 0 || launches != 0) {
- sb.setLength(0);
- sb.append(prefix); sb.append(" Service ");
- sb.append(sent.getKey()); sb.append(":\n");
- sb.append(prefix); sb.append(" Created for: ");
- formatTimeMs(sb, startTime / 1000);
- sb.append("uptime\n");
- sb.append(prefix); sb.append(" Starts: ");
- sb.append(starts);
- sb.append(", launches: "); sb.append(launches);
- pw.println(sb.toString());
- apkActivity = true;
- }
- }
- }
- if (!apkActivity) {
- pw.print(prefix); pw.println(" (nothing executed)");
- }
- uidActivity = true;
}
+ if (!apkActivity) {
+ pw.print(prefix); pw.println(" (nothing executed)");
+ }
+ uidActivity = true;
}
if (!uidActivity) {
pw.print(prefix); pw.println(" (nothing executed)");
@@ -4403,6 +4440,11 @@ public abstract class BatteryStats implements Parcelable {
} else {
lineArgs[3] = "";
}
+ if ((modMode&STEP_LEVEL_MODE_DEVICE_IDLE) == 0) {
+ lineArgs[3] = (initMode&STEP_LEVEL_MODE_DEVICE_IDLE) != 0 ? "i+" : "i-";
+ } else {
+ lineArgs[3] = "";
+ }
dumpLine(pw, 0 /* uid */, "i" /* category */, header, (Object[])lineArgs);
} else {
pw.print(prefix);
@@ -4427,6 +4469,12 @@ public abstract class BatteryStats implements Parcelable {
? "power-save-on" : "power-save-off");
haveModes = true;
}
+ if ((modMode&STEP_LEVEL_MODE_DEVICE_IDLE) == 0) {
+ pw.print(haveModes ? ", " : " (");
+ pw.print((initMode&STEP_LEVEL_MODE_DEVICE_IDLE) != 0
+ ? "device-idle-on" : "device-idle-off");
+ haveModes = true;
+ }
if (haveModes) {
pw.print(")");
}
@@ -4436,7 +4484,6 @@ public abstract class BatteryStats implements Parcelable {
return true;
}
- public static final int DUMP_UNPLUGGED_ONLY = 1<<0;
public static final int DUMP_CHARGED_ONLY = 1<<1;
public static final int DUMP_DAILY_ONLY = 1<<2;
public static final int DUMP_HISTORY_ONLY = 1<<3;
@@ -4558,6 +4605,23 @@ public abstract class BatteryStats implements Parcelable {
}
}
+ private void dumpDailyPackageChanges(PrintWriter pw, String prefix,
+ ArrayList<PackageChange> changes) {
+ if (changes == null) {
+ return;
+ }
+ pw.print(prefix); pw.println("Package changes:");
+ for (int i=0; i<changes.size(); i++) {
+ PackageChange pc = changes.get(i);
+ if (pc.mUpdate) {
+ pw.print(prefix); pw.print(" Update "); pw.print(pc.mPackageName);
+ pw.print(" vers="); pw.println(pc.mVersionCode);
+ } else {
+ pw.print(prefix); pw.print(" Uninstall "); pw.println(pc.mPackageName);
+ }
+ }
+ }
+
/**
* Dumps a human-readable summary of the battery statistics to the given PrintWriter.
*
@@ -4568,7 +4632,7 @@ public abstract class BatteryStats implements Parcelable {
prepareForDumpLocked();
final boolean filtering = (flags
- & (DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
+ & (DUMP_HISTORY_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
if ((flags&DUMP_HISTORY_ONLY) != 0 || !filtering) {
final long historyTotalSize = getHistoryTotalSize();
@@ -4612,7 +4676,7 @@ public abstract class BatteryStats implements Parcelable {
}
}
- if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
+ if (filtering && (flags&(DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
return;
}
@@ -4688,8 +4752,9 @@ public abstract class BatteryStats implements Parcelable {
int[] outInt = new int[1];
LevelStepTracker dsteps = getDailyDischargeLevelStepTracker();
LevelStepTracker csteps = getDailyChargeLevelStepTracker();
- if (dsteps.mNumStepDurations > 0 || csteps.mNumStepDurations > 0) {
- if ((flags&DUMP_DAILY_ONLY) != 0) {
+ ArrayList<PackageChange> pkgc = getDailyPackageChanges();
+ if (dsteps.mNumStepDurations > 0 || csteps.mNumStepDurations > 0 || pkgc != null) {
+ if ((flags&DUMP_DAILY_ONLY) != 0 || !filtering) {
if (dumpDurationSteps(pw, " ", " Current daily discharge step durations:",
dsteps, false)) {
dumpDailyLevelStepSummary(pw, " ", "Discharge", dsteps,
@@ -4700,6 +4765,7 @@ public abstract class BatteryStats implements Parcelable {
dumpDailyLevelStepSummary(pw, " ", "Charge", csteps,
sb, outInt);
}
+ dumpDailyPackageChanges(pw, " ", pkgc);
} else {
pw.println(" Current daily steps:");
dumpDailyLevelStepSummary(pw, " ", "Discharge", dsteps,
@@ -4720,7 +4786,7 @@ public abstract class BatteryStats implements Parcelable {
pw.print(" to ");
pw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", dit.mEndTime).toString());
pw.println(":");
- if ((flags&DUMP_DAILY_ONLY) != 0) {
+ if ((flags&DUMP_DAILY_ONLY) != 0 || !filtering) {
if (dumpDurationSteps(pw, " ",
" Discharge step durations:", dit.mDischargeSteps, false)) {
dumpDailyLevelStepSummary(pw, " ", "Discharge", dit.mDischargeSteps,
@@ -4731,6 +4797,7 @@ public abstract class BatteryStats implements Parcelable {
dumpDailyLevelStepSummary(pw, " ", "Charge", dit.mChargeSteps,
sb, outInt);
}
+ dumpDailyPackageChanges(pw, " ", dit.mPackageChanges);
} else {
dumpDailyLevelStepSummary(pw, " ", "Discharge", dit.mDischargeSteps,
sb, outInt);
@@ -4748,11 +4815,6 @@ public abstract class BatteryStats implements Parcelable {
(flags&DUMP_DEVICE_WIFI_ONLY) != 0);
pw.println();
}
- if (!filtering || (flags&DUMP_UNPLUGGED_ONLY) != 0) {
- pw.println("Statistics since last unplugged:");
- dumpLocked(context, pw, "", STATS_SINCE_UNPLUGGED, reqUid,
- (flags&DUMP_DEVICE_WIFI_ONLY) != 0);
- }
}
@SuppressWarnings("unused")
@@ -4766,7 +4828,7 @@ public abstract class BatteryStats implements Parcelable {
long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
final boolean filtering = (flags &
- (DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
+ (DUMP_HISTORY_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
if ((flags&DUMP_INCLUDE_HISTORY) != 0 || (flags&DUMP_HISTORY_ONLY) != 0) {
if (startIteratingHistoryLocked()) {
@@ -4792,7 +4854,7 @@ public abstract class BatteryStats implements Parcelable {
}
}
- if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
+ if (filtering && (flags&(DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
return;
}
@@ -4842,9 +4904,5 @@ public abstract class BatteryStats implements Parcelable {
dumpCheckinLocked(context, pw, STATS_SINCE_CHARGED, -1,
(flags&DUMP_DEVICE_WIFI_ONLY) != 0);
}
- if (!filtering || (flags&DUMP_UNPLUGGED_ONLY) != 0) {
- dumpCheckinLocked(context, pw, STATS_SINCE_UNPLUGGED, -1,
- (flags&DUMP_DEVICE_WIFI_ONLY) != 0);
- }
}
}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 16dac7d5ff27..804d3d031817 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -43,6 +43,7 @@ interface IPowerManager
boolean isInteractive();
boolean isPowerSaveMode();
boolean setPowerSaveMode(boolean mode);
+ boolean isDeviceIdleMode();
void reboot(boolean confirm, String reason, boolean wait);
void shutdown(boolean confirm, boolean wait);
@@ -50,6 +51,7 @@ interface IPowerManager
void setStayOnSetting(int val);
void boostScreenBrightness(long time);
+ boolean isScreenBrightnessBoosted();
// temporarily overrides the screen brightness settings to allow the user to
// see the effect of a settings change without applying it immediately
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index de970cbe525a..01c9a21441ab 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -712,6 +712,22 @@ public final class PowerManager {
}
/**
+ * Returns whether the screen brightness is currently boosted to maximum, caused by a call
+ * to {@link #boostScreenBrightness(long)}.
+ * @return {@code True} if the screen brightness is currently boosted. {@code False} otherwise.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean isScreenBrightnessBoosted() {
+ try {
+ return mService.isScreenBrightnessBoosted();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
* Sets the brightness of the backlights (screen, keyboard, button).
* <p>
* Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
@@ -856,6 +872,23 @@ public final class PowerManager {
}
/**
+ * Returns true if the device is currently in idle mode. This happens when a device
+ * has been sitting unused and unmoving for a sufficiently long period of time, so that
+ * it decides to go into a lower power-use state. This may involve things like turning
+ * off network access to apps. You can monitor for changes to this state with
+ * {@link #ACTION_DEVICE_IDLE_MODE_CHANGED}.
+ *
+ * @return Returns true if currently in low power mode, else false.
+ */
+ public boolean isDeviceIdleMode() {
+ try {
+ return mService.isDeviceIdleMode();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
* Turn off the device.
*
* @param confirm If true, shows a shutdown confirmation dialog.
@@ -879,6 +912,14 @@ public final class PowerManager {
= "android.os.action.POWER_SAVE_MODE_CHANGED";
/**
+ * Intent that is broadcast when the state of {@link #isDeviceIdleMode()} changes.
+ * This broadcast is only sent to registered receivers.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_DEVICE_IDLE_MODE_CHANGED
+ = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
+
+ /**
* Intent that is broadcast when the state of {@link #isPowerSaveMode()} is about to change.
* This broadcast is only sent to registered receivers.
*
@@ -892,6 +933,16 @@ public final class PowerManager {
public static final String EXTRA_POWER_SAVE_MODE = "mode";
/**
+ * Intent that is broadcast when the state of {@link #isScreenBrightnessBoosted()} has changed.
+ * This broadcast is only sent to registered receivers.
+ *
+ * @hide
+ **/
+ @SystemApi
+ public static final String ACTION_SCREEN_BRIGHTNESS_BOOST_CHANGED
+ = "android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED";
+
+ /**
* A wake lock is a mechanism to indicate that your application needs
* to have the device stay on.
* <p>
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 6f3176874cab..00ab262fda4e 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -117,7 +117,7 @@ public abstract class PowerManagerInternal {
/**
* Used by the dream manager to override certain properties while dozing.
*
- * @param screenState The overridden screen state, or {@link Display.STATE_UNKNOWN}
+ * @param screenState The overridden screen state, or {@link Display#STATE_UNKNOWN}
* to disable the override.
* @param screenBrightness The overridden screen brightness, or
* {@link PowerManager#BRIGHTNESS_DEFAULT} to disable the override.
@@ -132,4 +132,6 @@ public abstract class PowerManagerInternal {
public interface LowPowerModeListener {
public void onLowPowerModeChanged(boolean enabled);
}
+
+ public abstract void setDeviceIdleMode(boolean enabled);
}
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 116110eba74d..6209c2adaade 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -888,6 +888,21 @@ public interface IMountService extends IInterface {
}
return;
}
+
+ @Override
+ public void waitForAsecScan() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_waitForAsecScan, _data, _reply, 0);
+ _reply.readException();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return;
+ }
}
private static final String DESCRIPTOR = "IMountService";
@@ -978,6 +993,8 @@ public interface IMountService extends IInterface {
static final int TRANSACTION_runMaintenance = IBinder.FIRST_CALL_TRANSACTION + 42;
+ static final int TRANSACTION_waitForAsecScan = IBinder.FIRST_CALL_TRANSACTION + 43;
+
/**
* Cast an IBinder object into an IMountService interface, generating a
* proxy if needed.
@@ -1396,6 +1413,12 @@ public interface IMountService extends IInterface {
reply.writeNoException();
return true;
}
+ case TRANSACTION_waitForAsecScan: {
+ data.enforceInterface(DESCRIPTOR);
+ waitForAsecScan();
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
}
@@ -1680,4 +1703,6 @@ public interface IMountService extends IInterface {
* @throws RemoteException
*/
public void runMaintenance() throws RemoteException;
+
+ public void waitForAsecScan() throws RemoteException;
}
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index ccf2cfabc828..f32e8cf9be5f 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -706,8 +706,10 @@ public class Preference implements Comparable<Preference> {
* @param iconResId The icon as a resource ID.
*/
public void setIcon(@DrawableRes int iconResId) {
- mIconResId = iconResId;
- setIcon(mContext.getDrawable(iconResId));
+ if (mIconResId != iconResId) {
+ mIconResId = iconResId;
+ setIcon(mContext.getDrawable(iconResId));
+ }
}
/**
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 06862d72029d..e4a6f07f323d 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1516,8 +1516,14 @@ public final class ContactsContract {
/**
* Build a {@link #CONTENT_LOOKUP_URI} lookup {@link Uri} using the
* given {@link ContactsContract.Contacts#_ID} and {@link #LOOKUP_KEY}.
+ * <p>
+ * Returns null if unable to construct a valid lookup URI from the
+ * provided parameters.
*/
public static Uri getLookupUri(long contactId, String lookupKey) {
+ if (TextUtils.isEmpty(lookupKey)) {
+ return null;
+ }
return ContentUris.withAppendedId(Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI,
lookupKey), contactId);
}
@@ -4803,6 +4809,14 @@ public final class ContactsContract {
Uri.withAppendedPath(AUTHORITY_URI, "raw_contact_entities");
/**
+ * The content:// style URI for this table in corp profile
+ *
+ * @hide
+ */
+ public static final Uri CORP_CONTENT_URI =
+ Uri.withAppendedPath(AUTHORITY_URI, "raw_contact_entities_corp");
+
+ /**
* The content:// style URI for this table, specific to the user's profile.
*/
public static final Uri PROFILE_CONTENT_URI =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e6b39b576657..fb515288f4e7 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5255,6 +5255,15 @@ public final class Settings {
public static final String SMS_DEFAULT_APPLICATION = "sms_default_application";
/**
+ * Specifies the package name currently configured to be the emergency assistance application
+ *
+ * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE
+ *
+ * @hide
+ */
+ public static final String EMERGENCY_ASSISTANCE_APPLICATION = "emergency_assistance_application";
+
+ /**
* Names of the packages that the current user has explicitly allowed to
* see all of the user's notifications, separated by ':'.
*
@@ -5375,6 +5384,7 @@ public final class Settings {
BACKUP_AUTO_RESTORE,
ENABLED_ACCESSIBILITY_SERVICES,
ENABLED_NOTIFICATION_LISTENERS,
+ ENABLED_INPUT_METHODS,
TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
TOUCH_EXPLORATION_ENABLED,
ACCESSIBILITY_ENABLED,
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
index ac6bbb72e61f..d24bc13a2a66 100644
--- a/core/java/android/security/IKeystoreService.aidl
+++ b/core/java/android/security/IKeystoreService.aidl
@@ -19,6 +19,7 @@ package android.security;
import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterBlob;
import android.security.keymaster.OperationResult;
import android.security.KeystoreArguments;
@@ -61,11 +62,12 @@ interface IKeystoreService {
int addRngEntropy(in byte[] data);
int generateKey(String alias, in KeymasterArguments arguments, int uid, int flags,
out KeyCharacteristics characteristics);
- int getKeyCharacteristics(String alias, in byte[] clientId,
- in byte[] appId, out KeyCharacteristics characteristics);
+ int getKeyCharacteristics(String alias, in KeymasterBlob clientId, in KeymasterBlob appId,
+ out KeyCharacteristics characteristics);
int importKey(String alias, in KeymasterArguments arguments, int format,
in byte[] keyData, int uid, int flags, out KeyCharacteristics characteristics);
- ExportResult exportKey(String alias, int format, in byte[] clientId, in byte[] appId);
+ ExportResult exportKey(String alias, int format, in KeymasterBlob clientId,
+ in KeymasterBlob appId);
OperationResult begin(IBinder appToken, String alias, int purpose, boolean pruneable,
in KeymasterArguments params, out KeymasterArguments operationParams);
OperationResult update(IBinder token, in KeymasterArguments params, in byte[] input);
diff --git a/core/java/android/security/NetworkSecurityPolicy.java b/core/java/android/security/NetworkSecurityPolicy.java
index c7274e84db81..0b3bf453fd9c 100644
--- a/core/java/android/security/NetworkSecurityPolicy.java
+++ b/core/java/android/security/NetworkSecurityPolicy.java
@@ -19,48 +19,57 @@ package android.security;
/**
* Network security policy.
*
- * @hide
+ * <p>Network stacks/components should honor this policy to make it possible to centrally control
+ * the relevant aspects of network security behavior.
+ *
+ * <p>The policy currently consists of a single flag: whether cleartext network traffic is
+ * permitted. See {@link #isCleartextTrafficPermitted()}.
*/
public class NetworkSecurityPolicy {
- private static final NetworkSecurityPolicy INSTANCE = new NetworkSecurityPolicy();
-
- private boolean mCleartextTrafficPermitted = true;
+ private static final NetworkSecurityPolicy INSTANCE = new NetworkSecurityPolicy();
- private NetworkSecurityPolicy() {}
+ private NetworkSecurityPolicy() {}
- /**
- * Gets the policy.
- */
- public static NetworkSecurityPolicy getInstance() {
- return INSTANCE;
- }
+ /**
+ * Gets the policy for this process.
+ *
+ * <p>It's fine to cache this reference. Any changes to the policy will be immediately visible
+ * through the reference.
+ */
+ public static NetworkSecurityPolicy getInstance() {
+ return INSTANCE;
+ }
- /**
- * Checks whether cleartext network traffic (e.g., HTTP, WebSockets, XMPP, IMAP, SMTP -- without
- * TLS or STARTTLS) is permitted for this process.
- *
- * <p>When cleartext network traffic is not permitted, the platform's components (e.g., HTTP
- * stacks, {@code WebView}, {@code MediaPlayer}) will refuse this process's requests to use
- * cleartext traffic. Third-party libraries are encouraged to honor this setting as well.
- */
- public boolean isCleartextTrafficPermitted() {
- synchronized (this) {
- return mCleartextTrafficPermitted;
+ /**
+ * Returns whether cleartext network traffic (e.g. HTTP, FTP, WebSockets, XMPP, IMAP, SMTP --
+ * without TLS or STARTTLS) is permitted for this process.
+ *
+ * <p>When cleartext network traffic is not permitted, the platform's components (e.g. HTTP and
+ * FTP stacks, {@link android.webkit.WebView}, {@link android.media.MediaPlayer}) will refuse
+ * this process's requests to use cleartext traffic. Third-party libraries are strongly
+ * encouraged to honor this setting as well.
+ *
+ * <p>This flag is honored on a best effort basis because it's impossible to prevent all
+ * cleartext traffic from Android applications given the level of access provided to them. For
+ * example, there's no expectation that the {@link java.net.Socket} API will honor this flag
+ * because it cannot determine whether its traffic is in cleartext. However, most network
+ * traffic from applications is handled by higher-level network stacks/components which can
+ * honor this aspect of the policy.
+ */
+ public boolean isCleartextTrafficPermitted() {
+ return libcore.net.NetworkSecurityPolicy.isCleartextTrafficPermitted();
}
- }
- /**
- * Sets whether cleartext network traffic is permitted for this process.
- *
- * <p>This method is used by the platform early on in the application's initialization to set the
- * policy.
- *
- * @hide
- */
- public void setCleartextTrafficPermitted(boolean permitted) {
- synchronized (this) {
- mCleartextTrafficPermitted = permitted;
+ /**
+ * Sets whether cleartext network traffic is permitted for this process.
+ *
+ * <p>This method is used by the platform early on in the application's initialization to set
+ * the policy.
+ *
+ * @hide
+ */
+ public void setCleartextTrafficPermitted(boolean permitted) {
+ libcore.net.NetworkSecurityPolicy.setCleartextTrafficPermitted(permitted);
}
- }
}
diff --git a/core/java/android/security/keymaster/KeymasterBlob.aidl b/core/java/android/security/keymaster/KeymasterBlob.aidl
new file mode 100644
index 000000000000..8f70f7c1ac91
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterBlob.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+/* @hide */
+parcelable KeymasterBlob;
diff --git a/core/java/android/security/keymaster/KeymasterBlob.java b/core/java/android/security/keymaster/KeymasterBlob.java
new file mode 100644
index 000000000000..cb956046d938
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterBlob.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+public class KeymasterBlob implements Parcelable {
+ public byte[] blob;
+
+ public KeymasterBlob(byte[] blob) {
+ this.blob = blob;
+ }
+ public static final Parcelable.Creator<KeymasterBlob> CREATOR = new
+ Parcelable.Creator<KeymasterBlob>() {
+ public KeymasterBlob createFromParcel(Parcel in) {
+ return new KeymasterBlob(in);
+ }
+
+ public KeymasterBlob[] newArray(int length) {
+ return new KeymasterBlob[length];
+ }
+ };
+
+ protected KeymasterBlob(Parcel in) {
+ blob = in.createByteArray();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeByteArray(blob);
+ }
+}
diff --git a/core/java/android/security/keymaster/KeymasterBlobArgument.java b/core/java/android/security/keymaster/KeymasterBlobArgument.java
index 9af444581ea2..7d587bf5b69a 100644
--- a/core/java/android/security/keymaster/KeymasterBlobArgument.java
+++ b/core/java/android/security/keymaster/KeymasterBlobArgument.java
@@ -26,6 +26,13 @@ class KeymasterBlobArgument extends KeymasterArgument {
public KeymasterBlobArgument(int tag, byte[] blob) {
super(tag);
+ switch (KeymasterDefs.getTagType(tag)) {
+ case KeymasterDefs.KM_BIGNUM:
+ case KeymasterDefs.KM_BYTES:
+ break; // OK.
+ default:
+ throw new IllegalArgumentException("Bad blob tag " + tag);
+ }
this.blob = blob;
}
diff --git a/core/java/android/security/keymaster/KeymasterBooleanArgument.java b/core/java/android/security/keymaster/KeymasterBooleanArgument.java
index 5481e8ff6f44..9c0367404881 100644
--- a/core/java/android/security/keymaster/KeymasterBooleanArgument.java
+++ b/core/java/android/security/keymaster/KeymasterBooleanArgument.java
@@ -28,6 +28,12 @@ class KeymasterBooleanArgument extends KeymasterArgument {
public KeymasterBooleanArgument(int tag) {
super(tag);
+ switch (KeymasterDefs.getTagType(tag)) {
+ case KeymasterDefs.KM_BOOL:
+ break; // OK.
+ default:
+ throw new IllegalArgumentException("Bad bool tag " + tag);
+ }
}
public KeymasterBooleanArgument(int tag, Parcel in) {
diff --git a/core/java/android/security/keymaster/KeymasterDateArgument.java b/core/java/android/security/keymaster/KeymasterDateArgument.java
index 310f546753fe..bffd24d0087c 100644
--- a/core/java/android/security/keymaster/KeymasterDateArgument.java
+++ b/core/java/android/security/keymaster/KeymasterDateArgument.java
@@ -27,6 +27,12 @@ class KeymasterDateArgument extends KeymasterArgument {
public KeymasterDateArgument(int tag, Date date) {
super(tag);
+ switch (KeymasterDefs.getTagType(tag)) {
+ case KeymasterDefs.KM_DATE:
+ break; // OK.
+ default:
+ throw new IllegalArgumentException("Bad date tag " + tag);
+ }
this.date = date;
}
diff --git a/core/java/android/security/keymaster/KeymasterIntArgument.java b/core/java/android/security/keymaster/KeymasterIntArgument.java
index c3738d7c90a9..da817158270d 100644
--- a/core/java/android/security/keymaster/KeymasterIntArgument.java
+++ b/core/java/android/security/keymaster/KeymasterIntArgument.java
@@ -26,6 +26,15 @@ class KeymasterIntArgument extends KeymasterArgument {
public KeymasterIntArgument(int tag, int value) {
super(tag);
+ switch (KeymasterDefs.getTagType(tag)) {
+ case KeymasterDefs.KM_INT:
+ case KeymasterDefs.KM_INT_REP:
+ case KeymasterDefs.KM_ENUM:
+ case KeymasterDefs.KM_ENUM_REP:
+ break; // OK.
+ default:
+ throw new IllegalArgumentException("Bad int tag " + tag);
+ }
this.value = value;
}
diff --git a/core/java/android/security/keymaster/KeymasterLongArgument.java b/core/java/android/security/keymaster/KeymasterLongArgument.java
index 3c565b8735f4..9d2be098cdbc 100644
--- a/core/java/android/security/keymaster/KeymasterLongArgument.java
+++ b/core/java/android/security/keymaster/KeymasterLongArgument.java
@@ -26,6 +26,12 @@ class KeymasterLongArgument extends KeymasterArgument {
public KeymasterLongArgument(int tag, long value) {
super(tag);
+ switch (KeymasterDefs.getTagType(tag)) {
+ case KeymasterDefs.KM_LONG:
+ break; // OK.
+ default:
+ throw new IllegalArgumentException("Bad long tag " + tag);
+ }
this.value = value;
}
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/core/java/android/service/fingerprint/Fingerprint.aidl
new file mode 100644
index 000000000000..c9fd9896520f
--- /dev/null
+++ b/core/java/android/service/fingerprint/Fingerprint.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.fingerprint;
+
+// @hide
+parcelable Fingerprint;
diff --git a/core/java/android/service/fingerprint/Fingerprint.java b/core/java/android/service/fingerprint/Fingerprint.java
new file mode 100644
index 000000000000..37552eb21e36
--- /dev/null
+++ b/core/java/android/service/fingerprint/Fingerprint.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.fingerprint;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Container for fingerprint metadata.
+ * @hide
+ */
+public final class Fingerprint implements Parcelable {
+ private CharSequence mName;
+ private int mGroupId;
+ private int mFingerId;
+ private long mDeviceId; // physical device this is associated with
+
+ public Fingerprint(CharSequence name, int groupId, int fingerId, long deviceId) {
+ mName = name;
+ mGroupId = groupId;
+ mFingerId = fingerId;
+ mDeviceId = deviceId;
+ }
+
+ private Fingerprint(Parcel in) {
+ mName = in.readString();
+ mGroupId = in.readInt();
+ mFingerId = in.readInt();
+ mDeviceId = in.readLong();
+ }
+
+ /**
+ * Gets the human-readable name for the given fingerprint.
+ * @return name given to finger
+ */
+ public CharSequence getName() { return mName; }
+
+ /**
+ * Gets the device-specific finger id. Used by Settings to map a name to a specific
+ * fingerprint template.
+ * @return device-specific id for this finger
+ * @hide
+ */
+ public int getFingerId() { return mFingerId; }
+
+ /**
+ * Gets the group id specified when the fingerprint was enrolled.
+ * @return group id for the set of fingerprints this one belongs to.
+ * @hide
+ */
+ public int getGroupId() { return mGroupId; }
+
+ /**
+ * Device this fingerprint belongs to.
+ * @hide
+ */
+ public long getDeviceId() { return mDeviceId; }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mName.toString());
+ out.writeInt(mGroupId);
+ out.writeInt(mFingerId);
+ out.writeLong(mDeviceId);
+ }
+
+ public static final Parcelable.Creator<Fingerprint> CREATOR
+ = new Parcelable.Creator<Fingerprint>() {
+ public Fingerprint createFromParcel(Parcel in) {
+ return new Fingerprint(in);
+ }
+
+ public Fingerprint[] newArray(int size) {
+ return new Fingerprint[size];
+ }
+ };
+}; \ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/service/fingerprint/FingerprintManager.java
index 637566827b82..bb90e4070bfd 100644
--- a/core/java/android/service/fingerprint/FingerprintManager.java
+++ b/core/java/android/service/fingerprint/FingerprintManager.java
@@ -20,17 +20,25 @@ import android.app.ActivityManagerNative;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Binder;
+import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
+import android.service.fingerprint.FingerprintManager.EnrollmentCallback;
import android.util.Log;
import android.util.Slog;
+import java.security.Signature;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import javax.crypto.Cipher;
+
/**
* A class that coordinates access to the fingerprint hardware.
* @hide
@@ -45,9 +53,6 @@ public class FingerprintManager {
private static final int MSG_ERROR = 103;
private static final int MSG_REMOVED = 104;
- // Errors generated by layers above HAL
- public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10;
-
// Message types. Must agree with HAL (fingerprint.h)
public static final int FINGERPRINT_ERROR = -1;
public static final int FINGERPRINT_ACQUIRED = 1;
@@ -60,254 +65,499 @@ public class FingerprintManager {
public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2;
public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
+ public static final int FINGERPRINT_ERROR_CANCELED = 5;
+ public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000;
- // FINGERPRINT_ACQUIRED messages. Must agree with HAL (fingerprint.h)
+ // Image acquisition messages. Must agree with HAL (fingerprint.h)
public static final int FINGERPRINT_ACQUIRED_GOOD = 0;
public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1;
public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2;
- public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 4;
- public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 8;
- public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 16;
+ public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3;
+ public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4;
+ public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5;
+ public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
private IFingerprintService mService;
- private FingerprintManagerReceiver mClientReceiver;
private Context mContext;
private IBinder mToken = new Binder();
+ private AuthenticationCallback mAuthenticationCallback;
+ private EnrollmentCallback mEnrollmentCallback;
+ private RemovalCallback mRemovalCallback;
+ private CryptoObject mCryptoObject;
+ private Fingerprint mRemovalFingerprint;
+ private boolean mListening;
- private Handler mHandler = new Handler() {
- public void handleMessage(android.os.Message msg) {
- if (mClientReceiver != null) {
- switch(msg.what) {
- case MSG_ENROLL_RESULT:
- mClientReceiver.onEnrollResult(msg.arg1, msg.arg2);
- break;
- case MSG_ACQUIRED:
- mClientReceiver.onAcquired(msg.arg1);
- break;
- case MSG_PROCESSED:
- mClientReceiver.onProcessed(msg.arg1);
- break;
- case MSG_ERROR:
- mClientReceiver.onError(msg.arg1);
- break;
- case MSG_REMOVED:
- mClientReceiver.onRemoved(msg.arg1);
- }
- }
- }
+ /**
+ * A wrapper class for a limited number of crypto objects supported by FingerprintManager.
+ */
+ public static class CryptoObject {
+ CryptoObject(Signature signature) { mSignature = signature; }
+ CryptoObject(Cipher cipher) { mCipher = cipher; }
+ private Signature mSignature;
+ private Cipher mCipher;
};
- public static final class FingerprintItem {
- public CharSequence name;
- public int id;
- FingerprintItem(CharSequence name, int id) {
- this.name = name;
- this.id = id;
+ /**
+ * Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
+ * AuthenticationCallback, CancellationSignal, int)}
+ */
+ public static final class AuthenticationResult {
+ private Fingerprint mFingerprint;
+ private CryptoObject mCryptoObject;
+
+ public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint) {
+ mCryptoObject = crypto;
+ mFingerprint = fingerprint;
}
- }
+
+ /**
+ * Obtain the crypto object associated with this transaction
+ * @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject,
+ * AuthenticationCallback, CancellationSignal, int)}
+ */
+ public CryptoObject getCryptoObject() { return mCryptoObject; }
+
+ /**
+ * Obtain the Fingerprint associated with this operation. Applications are discouraged
+ * from associating specific fingers with specific applications or operations. Hence this
+ * is not public.
+ * @hide
+ */
+ public Fingerprint getFingerprint() { return mFingerprint; }
+ };
/**
- * @hide
+ * Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject,
+ * AuthenticationCallback, CancellationSignal, int)}. Users of {@link #FingerprintManager()}
+ * must provide an implementation of this to {@link FingerprintManager#authenticate(
+ * CryptoObject, AuthenticationCallback, CancellationSignal, int) for listening to fingerprint
+ * events.
*/
- public FingerprintManager(Context context, IFingerprintService service) {
- mContext = context;
- mService = service;
- if (mService == null) {
- Slog.v(TAG, "FingerprintManagerService was null");
- }
- }
+ public static abstract class AuthenticationCallback {
+ /**
+ * Called when an unrecoverable error has been encountered and the operation is complete.
+ * No further callbacks will be made on this object.
+ * @param errMsgId an integer identifying the error message.
+ * @param errString a human-readible error string that can be shown in UI.
+ */
+ public abstract void onAuthenticationError(int errMsgId, CharSequence errString);
- private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
+ /**
+ * Called when a recoverable error has been encountered during authentication. The help
+ * string is provided to give the user guidance for what went wrong, such as
+ * "Sensor dirty, please clean it."
+ * @param helpMsgId an integer identifying the error message.
+ * @param helpString a human-readible string that can be shown in UI.
+ */
+ public abstract void onAuthenticationHelp(int helpMsgId, CharSequence helpString);
- public void onEnrollResult(int fingerprintId, int remaining) {
- mHandler.obtainMessage(MSG_ENROLL_RESULT, fingerprintId, remaining).sendToTarget();
- }
+ /**
+ * Called when a fingerprint is recognized.
+ * @param result an object containing authentication-related data.
+ */
+ public abstract void onAuthenticationSucceeded(AuthenticationResult result);
+ };
- public void onAcquired(int acquireInfo) {
- mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0).sendToTarget();
- }
+ /**
+ * Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback,
+ * CancellationSignal, int). Users of {@link #FingerprintManager()}
+ * must provide an implementation of this to {@link FingerprintManager#enroll(long,
+ * EnrollmentCallback, CancellationSignal, int) for listening to fingerprint events.
+ */
+ public static abstract class EnrollmentCallback {
+ /**
+ * Called when an unrecoverable error has been encountered and the operation is complete.
+ * No further callbacks will be made on this object.
+ * @param errMsgId an integer identifying the error message.
+ * @param errString a human-readible error string that can be shown in UI.
+ */
+ public abstract void onEnrollmentError(int errMsgId, CharSequence errString);
- public void onProcessed(int fingerprintId) {
- mHandler.obtainMessage(MSG_PROCESSED, fingerprintId, 0).sendToTarget();
- }
+ /**
+ * Called when a recoverable error has been encountered during enrollment. The help
+ * string is provided to give the user guidance for what went wrong, such as
+ * "Sensor dirty, please clean it" or what they need to do next, such as
+ * "Touch sensor again."
+ * @param helpMsgId an integer identifying the error message.
+ * @param helpString a human-readible string that can be shown in UI.
+ */
+ public abstract void onEnrollmentHelp(int helpMsgId, CharSequence helpString);
- public void onError(int error) {
- mHandler.obtainMessage(MSG_ERROR, error, 0).sendToTarget();
- }
+ /**
+ * Called as each enrollment step progresses. Enrollment is considered complete when
+ * remaining reaches 0. This function will not be called if enrollment fails. See
+ * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)}
+ * @param remaining the number of remaining steps.
+ */
+ public abstract void onEnrollmentProgress(int remaining);
+ };
- public void onRemoved(int fingerprintId) {
- mHandler.obtainMessage(MSG_REMOVED, fingerprintId, 0).sendToTarget();
- }
+ /**
+ * Callback structure provided to {@link FingerprintManager#remove(int). Users of
+ * {@link #FingerprintManager()} may optionally provide an implementation of this to
+ * {@link FingerprintManager#remove(int, int, RemovalCallback)} for listening to
+ * fingerprint template removal events.
+ */
+ public static abstract class RemovalCallback {
+ /**
+ * Called when the given fingerprint can't be removed.
+ * @param fp the fingerprint that the call attempted to remove.
+ * @param errMsgId an associated error message id.
+ * @param errString an error message indicating why the fingerprint id can't be removed.
+ */
+ public abstract void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString);
+
+ /**
+ * Called when a given fingerprint is successfully removed.
+ * @param fingerprint the fingerprint template that was removed.
+ */
+ public abstract void onRemovalSucceeded(Fingerprint fingerprint);
};
/**
- * Determine whether the user has at least one fingerprint enrolled and enabled.
+ * Request authentication of a crypto object. This call warms up the fingerprint hardware
+ * and starts scanning for a fingerprint. It terminates when
+ * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
+ * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult) is called, at
+ * which point the object is no longer valid. The operation can be canceled by using the
+ * provided cancel object.
*
- * @return true if at least one is enrolled and enabled
+ * @param crypto object associated with the call or null if none required.
+ * @param callback an object to receive authentication events
+ * @param cancel an object that can be used to cancel authentication
+ * @param flags optional flags
*/
- public boolean enrolledAndEnabled() {
- ContentResolver res = mContext.getContentResolver();
- return Settings.Secure.getInt(res, "fingerprint_enabled", 0) != 0
- && FingerprintUtils.getFingerprintIdsForUser(res, getCurrentUserId()).length > 0;
+ public void authenticate(CryptoObject crypto, AuthenticationCallback callback,
+ CancellationSignal cancel, int flags) {
+ if (callback == null) {
+ throw new IllegalArgumentException("Must supply an authentication callback");
+ }
+
+ // TODO: handle cancel
+
+ if (mService != null) try {
+ mAuthenticationCallback = callback;
+ mCryptoObject = crypto;
+ long sessionId = 0; // TODO: get from crypto object
+ startListening();
+ mService.authenticate(mToken, sessionId, getCurrentUserId(), flags);
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception while authenticating: ", e);
+ stopListening();
+ }
}
/**
- * Start the enrollment process. Timeout dictates how long to wait for the user to
- * enroll a fingerprint.
- *
- * @param timeout
+ * Request fingerprint enrollment. This call warms up the fingerprint hardware
+ * and starts scanning for fingerprints. Progress will be indicated by callbacks to the
+ * {@link EnrollmentCallback} object. It terminates when
+ * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or
+ * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at
+ * which point the object is no longer valid. The operation can be canceled by using the
+ * provided cancel object.
+ * @param challenge a unique id provided by a recent verification of device credentials
+ * (e.g. pin, pattern or password).
+ * @param callback an object to receive enrollment events
+ * @param cancel an object that can be used to cancel enrollment
+ * @param flags optional flags
*/
- public void enroll(long timeout) {
- if (mServiceReceiver == null) {
- sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
- return;
+ public void enroll(long challenge, EnrollmentCallback callback,
+ CancellationSignal cancel, int flags) {
+ if (callback == null) {
+ throw new IllegalArgumentException("Must supply an enrollment callback");
}
+
+ // TODO: handle cancel
+
if (mService != null) try {
- mService.enroll(mToken, timeout, getCurrentUserId());
+ mEnrollmentCallback = callback;
+ startListening();
+ mService.enroll(mToken, getCurrentUserId(), flags);
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception while enrolling: ", e);
- sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
+ Log.v(TAG, "Remote exception in enroll: ", e);
+ stopListening();
}
}
/**
- * Remove the given fingerprintId from the system. FingerprintId of 0 has special meaning
- * which is to delete all fingerprint data for the current user. Use with caution.
- * @param fingerprintId
+ * Remove given fingerprint template from fingerprint hardware and/or protected storage.
+ * @param fp the fingerprint item to remove
+ * @param callback an optional callback to verify that fingerprint templates have been
+ * successfully removed. May be null of no callback is required.
+ * @hide
*/
- public void remove(int fingerprintId) {
- if (mServiceReceiver == null) {
- sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
- return;
- }
- if (mService != null) {
- try {
- mService.remove(mToken, fingerprintId, getCurrentUserId());
- } catch (RemoteException e) {
- Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e);
- }
- } else {
- Log.w(TAG, "remove(): Service not connected!");
- sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
+ public void remove(Fingerprint fp, RemovalCallback callback) {
+ if (mService != null) try {
+ mRemovalCallback = callback;
+ mRemovalFingerprint = fp;
+ startListening();
+ mService.remove(mToken, fp.getFingerId(), getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote in remove: ", e);
+ stopListening();
}
}
/**
- * Starts listening for fingerprint events. When a finger is scanned or recognized, the
- * client will be notified via the callback.
+ * Renames the given fingerprint template
+ * @param fpId the fingerprint id
+ * @param newName the new name
+ * @hide
*/
- public void startListening(FingerprintManagerReceiver receiver) {
- mClientReceiver = receiver;
+ public void rename(int fpId, String newName) {
+ // Renames the given fpId
if (mService != null) {
try {
- mService.startListening(mToken, mServiceReceiver, getCurrentUserId());
+ mService.rename(fpId, getCurrentUserId(), newName);
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in startListening(): ", e);
+ Log.v(TAG, "Remote exception in rename(): ", e);
}
} else {
- Log.w(TAG, "startListening(): Service not connected!");
- sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
+ Log.w(TAG, "rename(): Service not connected!");
}
}
- private int getCurrentUserId() {
- try {
- return ActivityManagerNative.getDefault().getCurrentUser().id;
+ /**
+ * Obtain the list of enrolled fingerprints templates.
+ * @return list of current fingerprint items
+ */
+ public List<Fingerprint> getEnrolledFingerprints() {
+ if (mService != null) try {
+ return mService.getEnrolledFingerprints(getCurrentUserId());
} catch (RemoteException e) {
- Log.w(TAG, "Failed to get current user id\n");
- return UserHandle.USER_NULL;
+ Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
}
+ return null;
}
/**
- * Stops the client from listening to fingerprint events.
+ * Determine if fingerprint hardware is present and functional.
+ * @return true if hardware is present and functional, false otherwise.
+ * @hide
*/
- public void stopListening() {
+ public boolean isHardwareDetected() {
if (mService != null) {
try {
- mService.stopListening(mToken, getCurrentUserId());
- mClientReceiver = null;
+ long deviceId = 0; /* TODO: plumb hardware id to FPMS */
+ return mService.isHardwareDetected(deviceId);
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in stopListening(): ", e);
+ Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e);
}
} else {
- Log.w(TAG, "stopListening(): Service not connected!");
- sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
+ Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
}
+ return false;
}
- public void enrollCancel() {
- if (mServiceReceiver == null) {
- sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
- return;
+ private Handler mHandler = new Handler() {
+ public void handleMessage(android.os.Message msg) {
+ switch(msg.what) {
+ case MSG_ENROLL_RESULT:
+ sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
+ break;
+ case MSG_ACQUIRED:
+ sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */);
+ break;
+ case MSG_PROCESSED:
+ sendProcessedResult((Fingerprint) msg.obj);
+ break;
+ case MSG_ERROR:
+ sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
+ break;
+ case MSG_REMOVED:
+ sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
+ msg.arg2 /* groupId */);
+ }
}
- if (mService != null) {
- try {
- mService.enrollCancel(mToken, getCurrentUserId());
- mClientReceiver = null;
- } catch (RemoteException e) {
- Log.v(TAG, "Remote exception in enrollCancel(): ", e);
- sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
+
+ private void sendRemovedResult(long deviceId, int fingerId, int groupId) {
+ if (mRemovalCallback != null) {
+ int reqFingerId = mRemovalFingerprint.getFingerId();
+ int reqGroupId = mRemovalFingerprint.getGroupId();
+ if (fingerId != reqFingerId) {
+ Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
+ }
+ if (fingerId != reqFingerId) {
+ Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
+ }
+ mRemovalCallback.onRemovalSucceeded(mRemovalFingerprint);
}
- } else {
- Log.w(TAG, "enrollCancel(): Service not connected!");
}
- }
- private void sendError(int msg, int arg1, int arg2) {
- mHandler.obtainMessage(msg, arg1, arg2);
- }
+ private void sendErrorResult(long deviceId, int errMsgId) {
+ if (mEnrollmentCallback != null) {
+ mEnrollmentCallback.onEnrollmentError(errMsgId, getErrorString(errMsgId));
+ } else if (mAuthenticationCallback != null) {
+ mAuthenticationCallback.onAuthenticationError(errMsgId, getErrorString(errMsgId));
+ } else if (mRemovalCallback != null) {
+ mRemovalCallback.onRemovalError(mRemovalFingerprint, errMsgId,
+ getErrorString(errMsgId));
+ }
+ }
+
+ private void sendEnrollResult(Fingerprint fp, int remaining) {
+ if (mEnrollmentCallback != null) {
+ mEnrollmentCallback.onEnrollmentProgress(remaining);
+ }
+ }
+
+ private void sendProcessedResult(Fingerprint fp) {
+ if (mAuthenticationCallback != null) {
+ AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp);
+ mAuthenticationCallback.onAuthenticationSucceeded(result);
+ }
+ }
+
+ private void sendAcquiredResult(long deviceId, int acquireInfo) {
+ final String msg = getAcquiredString(acquireInfo);
+ if (msg == null) return;
+
+ if (mEnrollmentCallback != null) {
+ mEnrollmentCallback.onEnrollmentHelp(acquireInfo, msg);
+ } else if (mAuthenticationCallback != null) {
+ mAuthenticationCallback.onAuthenticationHelp(acquireInfo, msg);
+ }
+ }
+
+ private String getErrorString(int errMsg) {
+ switch (errMsg) {
+ case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_error_unable_to_process);
+ case FINGERPRINT_ERROR_HW_UNAVAILABLE:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_error_hw_not_available);
+ case FINGERPRINT_ERROR_NO_SPACE:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_error_no_space);
+ case FINGERPRINT_ERROR_TIMEOUT:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_error_timeout);
+ default:
+ if (errMsg >= FINGERPRINT_ERROR_VENDOR_BASE) {
+ int msgNumber = errMsg - FINGERPRINT_ERROR_VENDOR_BASE;
+ String[] msgArray = mContext.getResources().getStringArray(
+ com.android.internal.R.array.fingerprint_error_vendor);
+ if (msgNumber < msgArray.length) {
+ return msgArray[msgNumber];
+ }
+ }
+ return null;
+ }
+ }
+
+ private String getAcquiredString(int acquireInfo) {
+ switch (acquireInfo) {
+ case FINGERPRINT_ACQUIRED_GOOD:
+ return null;
+ case FINGERPRINT_ACQUIRED_PARTIAL:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_acquired_partial);
+ case FINGERPRINT_ACQUIRED_INSUFFICIENT:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_acquired_insufficient);
+ case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_acquired_imager_dirty);
+ case FINGERPRINT_ACQUIRED_TOO_SLOW:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_acquired_too_slow);
+ case FINGERPRINT_ACQUIRED_TOO_FAST:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_acquired_too_fast);
+ default:
+ if (acquireInfo >= FINGERPRINT_ACQUIRED_VENDOR_BASE) {
+ int msgNumber = acquireInfo - FINGERPRINT_ACQUIRED_VENDOR_BASE;
+ String[] msgArray = mContext.getResources().getStringArray(
+ com.android.internal.R.array.fingerprint_acquired_vendor);
+ if (msgNumber < msgArray.length) {
+ return msgArray[msgNumber];
+ }
+ }
+ return null;
+ }
+ }
+ };
/**
- * @return list of current fingerprint items
* @hide
*/
- public List<FingerprintItem> getEnrolledFingerprints() {
- int[] ids = FingerprintUtils.getFingerprintIdsForUser(mContext.getContentResolver(),
- getCurrentUserId());
- List<FingerprintItem> result = new ArrayList<FingerprintItem>();
- for (int i = 0; i < ids.length; i++) {
- // TODO: persist names in Settings
- FingerprintItem item = new FingerprintItem("Finger" + ids[i], ids[i]);
- result.add(item);
+ public FingerprintManager(Context context, IFingerprintService service) {
+ mContext = context;
+ mService = service;
+ if (mService == null) {
+ Slog.v(TAG, "FingerprintManagerService was null");
+ }
+ }
+
+ private int getCurrentUserId() {
+ try {
+ return ActivityManagerNative.getDefault().getCurrentUser().id;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get current user id\n");
+ return UserHandle.USER_NULL;
}
- return result;
}
/**
- * Determine if fingerprint hardware is present and functional.
- * @return true if hardware is present and functional, false otherwise.
- * @hide
+ * Stops the client from listening to fingerprint events.
*/
- public boolean isHardwareDetected() {
+ private void stopListening() {
if (mService != null) {
try {
- return mService.isHardwareDetected();
+ if (mListening) {
+ mService.removeListener(mToken, mServiceReceiver);
+ mListening = false;
+ }
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e);
+ Log.v(TAG, "Remote exception in stopListening(): ", e);
}
} else {
- Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
+ Log.w(TAG, "stopListening(): Service not connected!");
}
- return false;
}
/**
- * Renames the given fingerprint template
- * @param fpId the fingerprint id
- * @param newName the new name
- * @hide
+ * Starts listening for fingerprint events for this client.
*/
- public void rename(int fpId, String newName) {
- // Renames the given fpId
+ private void startListening() {
if (mService != null) {
try {
- mService.rename(fpId, newName);
+ if (!mListening) {
+ mService.addListener(mToken, mServiceReceiver, getCurrentUserId());
+ mListening = true;
+ }
} catch (RemoteException e) {
- Log.v(TAG, "Remote exception in rename(): ", e);
+ Log.v(TAG, "Remote exception in startListening(): ", e);
}
} else {
- Log.w(TAG, "rename(): Service not connected!");
+ Log.w(TAG, "startListening(): Service not connected!");
}
}
+
+ private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
+
+ public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
+ mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
+ new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
+ }
+
+ public void onAcquired(long deviceId, int acquireInfo) {
+ mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
+ }
+
+ public void onProcessed(long deviceId, int fingerId, int groupId) {
+ mHandler.obtainMessage(MSG_PROCESSED,
+ new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
+ }
+
+ public void onError(long deviceId, int error) {
+ mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
+ }
+
+ public void onRemoved(long deviceId, int fingerId, int groupId) {
+ mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
+ }
+ };
+
} \ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
deleted file mode 100644
index 85677badba4b..000000000000
--- a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package android.service.fingerprint;
-/**
- * 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.
- */
-
-/**
- * @hide
- */
-public class FingerprintManagerReceiver {
- /**
- * Fingerprint enrollment progress update. Enrollment is considered complete if
- * remaining hits 0 without {@link #onError(int)} being called.
- *
- * @param fingerprintId the fingerprint we're currently enrolling
- * @param remaining the number of samples required to complete enrollment. It's up to
- * the hardware to define what each step in enrollment means. Some hardware
- * requires multiple samples of the same part of the finger. Others require sampling of
- * different parts of the finger. The enrollment flow can use remaining to
- * mean "step x" of the process or "just need another sample."
- */
- public void onEnrollResult(int fingerprintId, int remaining) { }
-
- /**
- * Fingerprint touch detected, but not processed yet. Clients will use this message to
- * determine a good or bad scan before the fingerprint is processed. This is meant for the
- * client to provide feedback about the scan or alert the user that recognition is to follow.
- *
- * @param acquiredInfo one of:
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_GOOD},
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_PARTIAL},
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_INSUFFICIENT},
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_IMAGER_DIRTY},
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_TOO_SLOW},
- * {@link FingerprintManager#FINGERPRINT_ACQUIRED_TOO_FAST}
- */
- public void onAcquired(int acquiredInfo) { }
-
- /**
- * Fingerprint has been detected and processed. A non-zero return indicates a valid
- * fingerprint was detected.
- *
- * @param fingerprintId the finger id, or 0 if not recognized.
- */
- public void onProcessed(int fingerprintId) { }
-
- /**
- * An error was detected during scan or enrollment. One of
- * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE},
- * {@link FingerprintManager#FINGERPRINT_ERROR_UNABLE_TO_PROCESS} or
- * {@link FingerprintManager#FINGERPRINT_ERROR_TIMEOUT}
- * {@link FingerprintManager#FINGERPRINT_ERROR_NO_SPACE}
- *
- * @param error one of the above error codes
- */
- public void onError(int error) { }
-
- /**
- * The given fingerprint template was successfully removed by the driver.
- * See {@link FingerprintManager#remove(int)}
- *
- * @param fingerprintId id of template to remove.
- */
- public void onRemoved(int fingerprintId) { }
-} \ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintUtils.java b/core/java/android/service/fingerprint/FingerprintUtils.java
index cc17b99adde7..62acbb989c9a 100644
--- a/core/java/android/service/fingerprint/FingerprintUtils.java
+++ b/core/java/android/service/fingerprint/FingerprintUtils.java
@@ -67,7 +67,7 @@ class FingerprintUtils {
return toIntArray(tmp);
}
- public static void addFingerprintIdForUser(int fingerId, ContentResolver res, int userId) {
+ public static void addFingerprintIdForUser(ContentResolver res, int fingerId, int userId) {
// FingerId 0 has special meaning.
if (fingerId == 0) {
Log.w(TAG, "Tried to add fingerId 0");
diff --git a/core/java/android/service/fingerprint/IFingerprintService.aidl b/core/java/android/service/fingerprint/IFingerprintService.aidl
index 9b4750b37df8..e5d3ad4bf360 100644
--- a/core/java/android/service/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintService.aidl
@@ -17,31 +17,42 @@ package android.service.fingerprint;
import android.os.Bundle;
import android.service.fingerprint.IFingerprintServiceReceiver;
+import android.service.fingerprint.Fingerprint;
+import java.util.List;
/**
* Communication channel from client to the fingerprint service.
* @hide
*/
interface IFingerprintService {
- // Any errors resulting from this call will be returned to the listener
- void enroll(IBinder token, long timeout, int userId);
+ // Authenticate the given sessionId with a fingerprint
+ void authenticate(IBinder token, long sessionId, int groupId, int flags);
- // Any errors resulting from this call will be returned to the listener
- void enrollCancel(IBinder token, int userId);
+ // Start fingerprint enrollment
+ void enroll(IBinder token, int groupId, int flags);
// Any errors resulting from this call will be returned to the listener
- void remove(IBinder token, int fingerprintId, int userId);
+ void remove(IBinder token, int fingerId, int groupId);
+
+ // Rename the fingerprint specified by fingerId and groupId to the given name
+ void rename(int fingerId, int groupId, String name);
- // Start listening for fingerprint events. This has the side effect of starting
- // the hardware if not already started.
- void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId);
+ // Get a list of enrolled fingerprints in the given group.
+ List<Fingerprint> getEnrolledFingerprints(int groupId);
- // Stops listening for fingerprints
- void stopListening(IBinder token, int userId);
+ // Register listener for an instance of FingerprintManager
+ void addListener(IBinder token, IFingerprintServiceReceiver receiver, int userId);
+
+ // Unregister listener for an instance of FingerprintManager
+ void removeListener(IBinder token, IFingerprintServiceReceiver receiver);
// Determine if HAL is loaded and ready
- boolean isHardwareDetected();
+ boolean isHardwareDetected(long deviceId);
+
+ // Gets the number of hardware devices
+ // int getHardwareDeviceCount();
+
+ // Gets the unique device id for hardware enumerated at i
+ // long getHardwareDevice(int i);
- // Rename the given fingerprint id
- void rename(int fpId, String name);
}
diff --git a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
index af4128f1122d..f025064e9c61 100644
--- a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
@@ -23,9 +23,9 @@ import android.os.UserHandle;
* @hide
*/
oneway interface IFingerprintServiceReceiver {
- void onEnrollResult(int fingerprintId, int remaining);
- void onAcquired(int acquiredInfo);
- void onProcessed(int fingerprintId);
- void onError(int error);
- void onRemoved(int fingerprintId);
+ void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining);
+ void onAcquired(long deviceId, int acquiredInfo);
+ void onProcessed(long deviceId, int fingerId, int groupId);
+ void onError(long deviceId, int error);
+ void onRemoved(long deviceId, int fingerId, int groupId);
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 4902a7114f0a..1674950e66ce 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -17,15 +17,12 @@
package android.service.wallpaper;
import android.content.res.TypedArray;
-import android.os.Build;
import android.os.SystemProperties;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
-import android.view.ViewRootImpl;
import android.view.WindowInsets;
import com.android.internal.R;
import com.android.internal.os.HandlerCaller;
+import com.android.internal.util.ScreenShapeHelper;
import com.android.internal.view.BaseIWindow;
import com.android.internal.view.BaseSurfaceHolder;
@@ -158,7 +155,6 @@ public abstract class WallpaperService extends Service {
WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS;
int mCurWindowFlags = mWindowFlags;
int mCurWindowPrivateFlags = mWindowPrivateFlags;
- TypedValue mOutsetBottom;
final Rect mVisibleInsets = new Rect();
final Rect mWinFrame = new Rect();
final Rect mOverscanInsets = new Rect();
@@ -171,8 +167,6 @@ public abstract class WallpaperService extends Service {
final Rect mFinalStableInsets = new Rect();
final Configuration mConfiguration = new Configuration();
- private boolean mIsEmulator;
- private boolean mIsCircularEmulator;
private boolean mWindowIsRound;
final WindowManager.LayoutParams mLayout
@@ -629,31 +623,12 @@ public abstract class WallpaperService extends Service {
mLayout.token = mWindowToken;
if (!mCreated) {
- // Retrieve watch round and outset info
- final WindowManager windowService = (WindowManager)getSystemService(
- Context.WINDOW_SERVICE);
+ // Retrieve watch round info
TypedArray windowStyle = obtainStyledAttributes(
com.android.internal.R.styleable.Window);
- final Display display = windowService.getDefaultDisplay();
- final boolean shouldUseBottomOutset =
- display.getDisplayId() == Display.DEFAULT_DISPLAY;
- if (shouldUseBottomOutset && windowStyle.hasValue(
- R.styleable.Window_windowOutsetBottom)) {
- if (mOutsetBottom == null) mOutsetBottom = new TypedValue();
- windowStyle.getValue(R.styleable.Window_windowOutsetBottom,
- mOutsetBottom);
- } else {
- mOutsetBottom = null;
- }
- mWindowIsRound = getResources().getBoolean(
- com.android.internal.R.bool.config_windowIsRound);
+ mWindowIsRound = ScreenShapeHelper.getWindowIsRound(getResources());
windowStyle.recycle();
- // detect emulator
- mIsEmulator = Build.HARDWARE.contains("goldfish");
- mIsCircularEmulator = SystemProperties.getBoolean(
- ViewRootImpl.PROPERTY_EMULATOR_CIRCULAR, false);
-
// Add window
mLayout.type = mIWallpaperEngine.mWindowType;
mLayout.gravity = Gravity.START|Gravity.TOP;
@@ -783,18 +758,11 @@ public abstract class WallpaperService extends Service {
mDispatchedOverscanInsets.set(mOverscanInsets);
mDispatchedContentInsets.set(mContentInsets);
mDispatchedStableInsets.set(mStableInsets);
- final boolean isRound = (mIsEmulator && mIsCircularEmulator)
- || mWindowIsRound;
mFinalSystemInsets.set(mDispatchedOverscanInsets);
mFinalStableInsets.set(mDispatchedStableInsets);
- if (mOutsetBottom != null) {
- final DisplayMetrics metrics = getResources().getDisplayMetrics();
- mFinalSystemInsets.bottom =
- ( (int) mOutsetBottom.getDimension(metrics) )
- + mIWallpaperEngine.mDisplayPadding.bottom;
- }
+ mFinalSystemInsets.bottom = mIWallpaperEngine.mDisplayPadding.bottom;
WindowInsets insets = new WindowInsets(mFinalSystemInsets,
- null, mFinalStableInsets, isRound);
+ null, mFinalStableInsets, mWindowIsRound);
onApplyWindowInsets(insets);
}
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index 8cf1b4b33110..7bebbfb060db 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -244,13 +244,18 @@ public class Html {
next++;
}
- withinParagraph(out, text, i, next - nl, nl, next == end);
+ if (withinParagraph(out, text, i, next - nl, nl, next == end)) {
+ /* Paragraph should be closed */
+ out.append("</p>\n");
+ out.append(getOpenParaTagWithDirection(text, next, end));
+ }
}
out.append("</p>\n");
}
- private static void withinParagraph(StringBuilder out, Spanned text,
+ /* Returns true if the caller should close and reopen the paragraph. */
+ private static boolean withinParagraph(StringBuilder out, Spanned text,
int start, int end, int nl,
boolean last) {
int next;
@@ -363,17 +368,14 @@ public class Html {
}
}
- String p = last ? "" : "</p>\n" + getOpenParaTagWithDirection(text, start, end);
-
if (nl == 1) {
out.append("<br>\n");
- } else if (nl == 2) {
- out.append(p);
+ return false;
} else {
for (int i = 2; i < nl; i++) {
out.append("<br>");
}
- out.append(p);
+ return !last;
}
}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index fcf1828d734d..928bf1661d24 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1153,7 +1153,10 @@ public abstract class Layout {
return end - 1;
}
- if (ch != ' ' && ch != '\t') {
+ // Note: keep this in sync with Minikin LineBreaker::isLineEndSpace()
+ if (!(ch == ' ' || ch == '\t' || ch == 0x1680 ||
+ (0x2000 <= ch && ch <= 0x200A && ch != 0x2007) ||
+ ch == 0x205F || ch == 0x3000)) {
break;
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index ee39e27dfe77..b47418fdc84f 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -170,8 +170,9 @@ public class StaticLayout extends Layout {
* Measurement and break iteration is done in native code. The protocol for using
* the native code is as follows.
*
- * For each paragraph, do a nSetText of the paragraph text. Then, for each run within the
- * paragraph:
+ * For each paragraph, do a nSetText of the paragraph text. Also do nSetLineWidth.
+ *
+ * Then, for each run within the paragraph:
* - setLocale (this must be done at least for the first run, optional afterwards)
* - one of the following, depending on the type of run:
* + addStyleRun (a text run, to be measured in native code)
@@ -459,7 +460,26 @@ public class StaticLayout extends Layout {
byte[] chdirs = measured.mLevels;
int dir = measured.mDir;
boolean easy = measured.mEasy;
- nSetText(b.mNativePtr, chs, paraEnd - paraStart);
+
+ // tab stop locations
+ int[] variableTabStops = null;
+ if (spanned != null) {
+ TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
+ paraEnd, TabStopSpan.class);
+ if (spans.length > 0) {
+ int[] stops = new int[spans.length];
+ for (int i = 0; i < spans.length; i++) {
+ stops[i] = spans[i].getTabStop();
+ }
+ Arrays.sort(stops, 0, stops.length);
+ variableTabStops = stops;
+ }
+ }
+
+ int breakStrategy = 0; // 0 = kBreakStrategy_Greedy
+ nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
+ firstWidth, firstWidthLineCount, restWidth,
+ variableTabStops, TAB_INCREMENT, breakStrategy);
// measurement has to be done before performing line breaking
// but we don't want to recompute fontmetrics or span ranges the
@@ -505,25 +525,9 @@ public class StaticLayout extends Layout {
spanEndCacheCount++;
}
- // tab stop locations
- int[] variableTabStops = null;
- if (spanned != null) {
- TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
- paraEnd, TabStopSpan.class);
- if (spans.length > 0) {
- int[] stops = new int[spans.length];
- for (int i = 0; i < spans.length; i++) {
- stops[i] = spans[i].getTabStop();
- }
- Arrays.sort(stops, 0, stops.length);
- variableTabStops = stops;
- }
- }
-
nGetWidths(b.mNativePtr, widths);
- int breakCount = nComputeLineBreaks(b.mNativePtr, paraEnd - paraStart, firstWidth,
- firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, false, lineBreaks,
- lineBreaks.breaks, lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length);
+ int breakCount = nComputeLineBreaks(b.mNativePtr, lineBreaks, lineBreaks.breaks,
+ lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length);
int[] breaks = lineBreaks.breaks;
float[] lineWidths = lineBreaks.widths;
@@ -966,7 +970,10 @@ public class StaticLayout extends Layout {
private static native void nFinishBuilder(long nativePtr);
private static native void nSetLocale(long nativePtr, String locale);
- private static native void nSetText(long nativePtr, char[] text, int length);
+ // Set up paragraph text and settings; done as one big method to minimize jni crossings
+ private static native void nSetupParagraph(long nativePtr, char[] text, int length,
+ float firstWidth, int firstWidthLineCount, float restWidth,
+ int[] variableTabStops, int defaultTabStop, int breakStrategy);
private static native float nAddStyleRun(long nativePtr, long nativePaint,
long nativeTypeface, int start, int end, boolean isRtl);
@@ -983,9 +990,7 @@ public class StaticLayout extends Layout {
// the arrays inside the LineBreaks objects are passed in as well
// to reduce the number of JNI calls in the common case where the
// arrays do not have to be resized
- private static native int nComputeLineBreaks(long nativePtr,
- int length, float firstWidth, int firstWidthLineCount, float restWidth,
- int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle,
+ private static native int nComputeLineBreaks(long nativePtr, LineBreaks recycle,
int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength);
private int mLineCount;
diff --git a/core/java/android/text/style/URLSpan.java b/core/java/android/text/style/URLSpan.java
index d29bfb65d807..0669b6f568d4 100644
--- a/core/java/android/text/style/URLSpan.java
+++ b/core/java/android/text/style/URLSpan.java
@@ -16,6 +16,7 @@
package android.text.style;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@@ -23,6 +24,7 @@ import android.os.Parcel;
import android.provider.Browser;
import android.text.ParcelableSpan;
import android.text.TextUtils;
+import android.util.Log;
import android.view.View;
public class URLSpan extends ClickableSpan implements ParcelableSpan {
@@ -59,6 +61,10 @@ public class URLSpan extends ClickableSpan implements ParcelableSpan {
Context context = widget.getContext();
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
- context.startActivity(intent);
+ try {
+ context.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.w("URLSpan", "Actvity was not found for intent, " + intent.toString());
+ }
}
}
diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java
index e8d394747b2a..9326203cd923 100644
--- a/core/java/android/util/IntArray.java
+++ b/core/java/android/util/IntArray.java
@@ -18,6 +18,7 @@ package android.util;
import com.android.internal.util.ArrayUtils;
+import java.util.Arrays;
import libcore.util.EmptyArray;
/**
@@ -78,6 +79,24 @@ public class IntArray implements Cloneable {
}
/**
+ * Searches the array for the specified value using the binary search algorithm. The array must
+ * be sorted (as by the {@link Arrays#sort(int[], int, int)} method) prior to making this call.
+ * If it is not sorted, the results are undefined. If the range contains multiple elements with
+ * the specified value, there is no guarantee which one will be found.
+ *
+ * @param value The value to search for.
+ * @return index of the search key, if it is contained in the array; otherwise, <i>(-(insertion
+ * point) - 1)</i>. The insertion point is defined as the point at which the key would
+ * be inserted into the array: the index of the first element greater than the key, or
+ * {@link #size()} if all elements in the array are less than the specified key.
+ * Note that this guarantees that the return value will be >= 0 if and only if the key
+ * is found.
+ */
+ public int binarySearch(int value) {
+ return ContainerHelpers.binarySearch(mValues, mSize, value);
+ }
+
+ /**
* Adds the values in the specified array to this array.
*/
public void addAll(IntArray values) {
@@ -159,4 +178,11 @@ public class IntArray implements Cloneable {
public int size() {
return mSize;
}
+
+ /**
+ * Returns a new array with the contents of this IntArray.
+ */
+ public int[] toArray() {
+ return Arrays.copyOf(mValues, mSize);
+ }
}
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 1a07aee5d482..457d6ad1addd 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -452,9 +452,10 @@ public abstract class LayoutInflater {
synchronized (mConstructorArgs) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
+ final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser);
- Context lastContext = (Context)mConstructorArgs[0];
- mConstructorArgs[0] = mContext;
+ Context lastContext = (Context) mConstructorArgs[0];
+ mConstructorArgs[0] = inflaterContext;
View result = root;
try {
@@ -485,10 +486,10 @@ public abstract class LayoutInflater {
+ "ViewGroup root and attachToRoot=true");
}
- rInflate(parser, root, attrs, false, false);
+ rInflate(parser, root, inflaterContext, attrs, false);
} else {
// Temp is the root view that was found in the xml
- final View temp = createViewFromTag(root, name, attrs, false);
+ final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
@@ -509,8 +510,10 @@ public abstract class LayoutInflater {
if (DEBUG) {
System.out.println("-----> start inflating children");
}
- // Inflate all children under temp
- rInflate(parser, temp, attrs, true, true);
+
+ // Inflate all children under temp against its context.
+ rInflateChildren(parser, temp, attrs, true);
+
if (DEBUG) {
System.out.println("-----> done inflating children");
}
@@ -692,59 +695,68 @@ public abstract class LayoutInflater {
}
/**
+ * Convenience method for calling through to the five-arg createViewFromTag
+ * method. This method passes {@code false} for the {@code ignoreThemeAttr}
+ * argument and should be used for everything except {@code &gt;include>}
+ * tag parsing.
+ */
+ private View createViewFromTag(View parent, String name, Context context, AttributeSet attrs) {
+ return createViewFromTag(parent, name, context, attrs, false);
+ }
+
+ /**
* Creates a view from a tag name using the supplied attribute set.
* <p>
- * If {@code inheritContext} is true and the parent is non-null, the view
- * will be inflated in parent view's context. If the view specifies a
- * &lt;theme&gt; attribute, the inflation context will be wrapped with the
- * specified theme.
- * <p>
- * Note: Default visibility so the BridgeInflater can override it.
+ * <strong>Note:</strong> Default visibility so the BridgeInflater can
+ * override it.
+ *
+ * @param parent the parent view, used to inflate layout params
+ * @param name the name of the XML tag used to define the view
+ * @param context the inflation context for the view, typically the
+ * {@code parent} or base layout inflater context
+ * @param attrs the attribute set for the XML tag used to define the view
+ * @param ignoreThemeAttr {@code true} to ignore the {@code android:theme}
+ * attribute (if set) for the view being inflated,
+ * {@code false} otherwise
*/
- View createViewFromTag(View parent, String name, AttributeSet attrs, boolean inheritContext) {
+ View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
+ boolean ignoreThemeAttr) {
if (name.equals("view")) {
name = attrs.getAttributeValue(null, "class");
}
- Context viewContext;
- if (parent != null && inheritContext) {
- viewContext = parent.getContext();
- } else {
- viewContext = mContext;
- }
-
- // Apply a theme wrapper, if requested.
- final TypedArray ta = viewContext.obtainStyledAttributes(attrs, ATTRS_THEME);
- final int themeResId = ta.getResourceId(0, 0);
- if (themeResId != 0) {
- viewContext = new ContextThemeWrapper(viewContext, themeResId);
+ // Apply a theme wrapper, if allowed and one is specified.
+ if (!ignoreThemeAttr) {
+ final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
+ final int themeResId = ta.getResourceId(0, 0);
+ if (themeResId != 0) {
+ context = new ContextThemeWrapper(context, themeResId);
+ }
+ ta.recycle();
}
- ta.recycle();
if (name.equals(TAG_1995)) {
// Let's party like it's 1995!
- return new BlinkLayout(viewContext, attrs);
+ return new BlinkLayout(context, attrs);
}
- if (DEBUG) System.out.println("******** Creating view: " + name);
-
try {
View view;
if (mFactory2 != null) {
- view = mFactory2.onCreateView(parent, name, viewContext, attrs);
+ view = mFactory2.onCreateView(parent, name, context, attrs);
} else if (mFactory != null) {
- view = mFactory.onCreateView(name, viewContext, attrs);
+ view = mFactory.onCreateView(name, context, attrs);
} else {
view = null;
}
if (view == null && mPrivateFactory != null) {
- view = mPrivateFactory.onCreateView(parent, name, viewContext, attrs);
+ view = mPrivateFactory.onCreateView(parent, name, context, attrs);
}
if (view == null) {
final Object lastContext = mConstructorArgs[0];
- mConstructorArgs[0] = viewContext;
+ mConstructorArgs[0] = context;
try {
if (-1 == name.indexOf('.')) {
view = onCreateView(parent, name, attrs);
@@ -756,20 +768,18 @@ public abstract class LayoutInflater {
}
}
- if (DEBUG) System.out.println("Created view is: " + view);
return view;
-
} catch (InflateException e) {
throw e;
} catch (ClassNotFoundException e) {
- InflateException ie = new InflateException(attrs.getPositionDescription()
+ final InflateException ie = new InflateException(attrs.getPositionDescription()
+ ": Error inflating class " + name);
ie.initCause(e);
throw ie;
} catch (Exception e) {
- InflateException ie = new InflateException(attrs.getPositionDescription()
+ final InflateException ie = new InflateException(attrs.getPositionDescription()
+ ": Error inflating class " + name);
ie.initCause(e);
throw ie;
@@ -777,16 +787,26 @@ public abstract class LayoutInflater {
}
/**
+ * Recursive method used to inflate internal (non-root) children. This
+ * method calls through to {@link #rInflate} using the parent context as
+ * the inflation context.
+ * <strong>Note:</strong> Default visibility so the BridgeInflater can
+ * call it.
+ */
+ final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,
+ boolean finishInflate) throws XmlPullParserException, IOException {
+ rInflate(parser, parent, parent.getContext(), attrs, finishInflate);
+ }
+
+ /**
* Recursive method used to descend down the xml hierarchy and instantiate
* views, instantiate their children, and then call onFinishInflate().
- *
- * @param inheritContext Whether the root view should be inflated in its
- * parent's context. This should be true when called inflating
- * child views recursively, or false otherwise.
+ * <p>
+ * <strong>Note:</strong> Default visibility so the BridgeInflater can
+ * override it.
*/
- void rInflate(XmlPullParser parser, View parent, final AttributeSet attrs,
- boolean finishInflate, boolean inheritContext) throws XmlPullParserException,
- IOException {
+ void rInflate(XmlPullParser parser, View parent, Context context,
+ AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {
final int depth = parser.getDepth();
int type;
@@ -808,19 +828,21 @@ public abstract class LayoutInflater {
if (parser.getDepth() == 0) {
throw new InflateException("<include /> cannot be the root element");
}
- parseInclude(parser, parent, attrs, inheritContext);
+ parseInclude(parser, context, parent, attrs);
} else if (TAG_MERGE.equals(name)) {
throw new InflateException("<merge /> must be the root element");
} else {
- final View view = createViewFromTag(parent, name, attrs, inheritContext);
+ final View view = createViewFromTag(parent, name, context, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
- rInflate(parser, view, attrs, true, true);
+ rInflateChildren(parser, view, attrs, true);
viewGroup.addView(view, params);
}
}
- if (finishInflate) parent.onFinishInflate();
+ if (finishInflate) {
+ parent.onFinishInflate();
+ }
}
/**
@@ -829,13 +851,9 @@ public abstract class LayoutInflater {
*/
private void parseRequestFocus(XmlPullParser parser, View view)
throws XmlPullParserException, IOException {
- int type;
view.requestFocus();
- final int currentDepth = parser.getDepth();
- while (((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) {
- // Empty
- }
+
+ consumeChildElements(parser);
}
/**
@@ -844,33 +862,29 @@ public abstract class LayoutInflater {
*/
private void parseViewTag(XmlPullParser parser, View view, AttributeSet attrs)
throws XmlPullParserException, IOException {
- int type;
-
- final TypedArray ta = view.getContext().obtainStyledAttributes(
- attrs, com.android.internal.R.styleable.ViewTag);
- final int key = ta.getResourceId(com.android.internal.R.styleable.ViewTag_id, 0);
- final CharSequence value = ta.getText(com.android.internal.R.styleable.ViewTag_value);
+ final Context context = view.getContext();
+ final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ViewTag);
+ final int key = ta.getResourceId(R.styleable.ViewTag_id, 0);
+ final CharSequence value = ta.getText(R.styleable.ViewTag_value);
view.setTag(key, value);
ta.recycle();
- final int currentDepth = parser.getDepth();
- while (((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) {
- // Empty
- }
+ consumeChildElements(parser);
}
- private void parseInclude(XmlPullParser parser, View parent, AttributeSet attrs,
- boolean inheritContext) throws XmlPullParserException, IOException {
+ private void parseInclude(XmlPullParser parser, Context context, View parent,
+ AttributeSet attrs) throws XmlPullParserException, IOException {
int type;
if (parent instanceof ViewGroup) {
- Context context = inheritContext ? parent.getContext() : mContext;
-
- // Apply a theme wrapper, if requested.
+ // Apply a theme wrapper, if requested. This is sort of a weird
+ // edge case, since developers think the <include> overwrites
+ // values in the AttributeSet of the included View. So, if the
+ // included View has a theme attribute, we'll need to ignore it.
final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
final int themeResId = ta.getResourceId(0, 0);
- if (themeResId != 0) {
+ final boolean hasThemeOverride = themeResId != 0;
+ if (hasThemeOverride) {
context = new ContextThemeWrapper(context, themeResId);
}
ta.recycle();
@@ -880,11 +894,12 @@ public abstract class LayoutInflater {
int layout = attrs.getAttributeResourceValue(null, ATTR_LAYOUT, 0);
if (layout == 0) {
final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
- if (value == null || value.length() < 1) {
+ if (value == null || value.length() <= 0) {
throw new InflateException("You must specify a layout in the"
+ " include tag: <include layout=\"@layout/layoutID\" />");
}
+ // Attempt to resolve the "?attr/name" string to an identifier.
layout = context.getResources().getIdentifier(value.substring(1), null, null);
}
@@ -901,8 +916,7 @@ public abstract class LayoutInflater {
throw new InflateException("You must specify a valid layout "
+ "reference. The layout ID " + value + " is not valid.");
} else {
- final XmlResourceParser childParser =
- getContext().getResources().getLayout(layout);
+ final XmlResourceParser childParser = context.getResources().getLayout(layout);
try {
final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
@@ -920,11 +934,12 @@ public abstract class LayoutInflater {
final String childName = childParser.getName();
if (TAG_MERGE.equals(childName)) {
- // Inflate all children.
- rInflate(childParser, parent, childAttrs, false, inheritContext);
+ // The <merge> tag doesn't support android:theme, so
+ // nothing special to do here.
+ rInflate(childParser, parent, context, childAttrs, false);
} else {
- final View view = createViewFromTag(parent, childName, childAttrs,
- inheritContext);
+ final View view = createViewFromTag(parent, childName,
+ context, childAttrs, hasThemeOverride);
final ViewGroup group = (ViewGroup) parent;
final TypedArray a = context.obtainStyledAttributes(
@@ -957,7 +972,7 @@ public abstract class LayoutInflater {
view.setLayoutParams(params);
// Inflate all children.
- rInflate(childParser, view, childAttrs, true, true);
+ rInflateChildren(childParser, view, childAttrs, true);
if (id != View.NO_ID) {
view.setId(id);
@@ -985,6 +1000,16 @@ public abstract class LayoutInflater {
throw new InflateException("<include /> can only be used inside of a ViewGroup");
}
+ LayoutInflater.consumeChildElements(parser);
+ }
+
+ /**
+ * <strong>Note:</strong> default visibility so that
+ * LayoutInflater_Delegate can call it.
+ */
+ final static void consumeChildElements(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ int type;
final int currentDepth = parser.getDepth();
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) {
diff --git a/core/java/android/view/PhoneFallbackEventHandler.java b/core/java/android/view/PhoneFallbackEventHandler.java
index fbf5732f93d6..350650dfaa9e 100644
--- a/core/java/android/view/PhoneFallbackEventHandler.java
+++ b/core/java/android/view/PhoneFallbackEventHandler.java
@@ -25,8 +25,13 @@ import android.content.res.Configuration;
import android.media.AudioManager;
import android.media.session.MediaSessionLegacyHelper;
import android.os.UserHandle;
+import android.provider.Settings;
import android.telephony.TelephonyManager;
-import android.util.Slog;
+import android.util.Log;
+import android.view.View;
+import android.view.HapticFeedbackConstants;
+import android.view.FallbackEventHandler;
+import android.view.KeyEvent;
/**
* @hide
@@ -112,15 +117,20 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
dispatcher.startTracking(event, this);
} else if (event.isLongPress() && dispatcher.isTracking(event)) {
dispatcher.performedLongPress(event);
- mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- // launch the VoiceDialer
- Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- sendCloseSystemWindows();
- mContext.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- startCallActivity();
+ if (isUserSetupComplete()) {
+ mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ // launch the VoiceDialer
+ Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ sendCloseSystemWindows();
+ mContext.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ startCallActivity();
+ }
+ } else {
+ Log.i(TAG, "Not starting call activity because user "
+ + "setup is in progress.");
}
}
return true;
@@ -134,13 +144,18 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
dispatcher.startTracking(event, this);
} else if (event.isLongPress() && dispatcher.isTracking(event)) {
dispatcher.performedLongPress(event);
- mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- sendCloseSystemWindows();
- // Broadcast an intent that the Camera button was longpressed
- Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
- intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
- mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF,
- null, null, null, 0, null, null);
+ if (isUserSetupComplete()) {
+ mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ sendCloseSystemWindows();
+ // Broadcast an intent that the Camera button was longpressed
+ Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
+ intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
+ mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF,
+ null, null, null, 0, null, null);
+ } else {
+ Log.i(TAG, "Not dispatching CAMERA long press because user "
+ + "setup is in progress.");
+ }
}
return true;
}
@@ -155,21 +170,26 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
Configuration config = mContext.getResources().getConfiguration();
if (config.keyboard == Configuration.KEYBOARD_NOKEYS
|| config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
- // launch the search activity
- Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- sendCloseSystemWindows();
- getSearchManager().stopSearch();
- mContext.startActivity(intent);
- // Only clear this if we successfully start the
- // activity; otherwise we will allow the normal short
- // press action to be performed.
- dispatcher.performedLongPress(event);
- return true;
- } catch (ActivityNotFoundException e) {
- // Ignore
+ if (isUserSetupComplete()) {
+ // launch the search activity
+ Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ sendCloseSystemWindows();
+ getSearchManager().stopSearch();
+ mContext.startActivity(intent);
+ // Only clear this if we successfully start the
+ // activity; otherwise we will allow the normal short
+ // press action to be performed.
+ dispatcher.performedLongPress(event);
+ return true;
+ } catch (ActivityNotFoundException e) {
+ // Ignore
+ }
+ } else {
+ Log.i(TAG, "Not dispatching SEARCH long press because user "
+ + "setup is in progress.");
}
}
}
@@ -181,7 +201,7 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
boolean onKeyUp(int keyCode, KeyEvent event) {
if (DEBUG) {
- Slog.d(TAG, "up " + keyCode);
+ Log.d(TAG, "up " + keyCode);
}
final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState();
if (dispatcher != null) {
@@ -229,7 +249,12 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
break;
}
if (event.isTracking() && !event.isCanceled()) {
- startCallActivity();
+ if (isUserSetupComplete()) {
+ startCallActivity();
+ } else {
+ Log.i(TAG, "Not starting call activity because user "
+ + "setup is in progress.");
+ }
}
return true;
}
@@ -244,7 +269,7 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
try {
mContext.startActivity(intent);
} catch (ActivityNotFoundException e) {
- Slog.w(TAG, "No activity found for android.intent.action.CALL_BUTTON.");
+ Log.w(TAG, "No activity found for android.intent.action.CALL_BUTTON.");
}
}
@@ -284,5 +309,10 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
private void handleMediaKeyEvent(KeyEvent keyEvent) {
MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
}
+
+ private boolean isUserSetupComplete() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0) != 0;
+ }
}
diff --git a/core/java/android/view/PhoneWindow.java b/core/java/android/view/PhoneWindow.java
index 05796bb12ea6..cb326977cdde 100644
--- a/core/java/android/view/PhoneWindow.java
+++ b/core/java/android/view/PhoneWindow.java
@@ -28,6 +28,7 @@ import android.app.SearchManager;
import android.os.UserHandle;
import com.android.internal.R;
+import com.android.internal.util.ScreenShapeHelper;
import com.android.internal.view.RootViewSurfaceTaker;
import com.android.internal.view.StandaloneActionMode;
import com.android.internal.view.menu.ContextMenuBuilder;
@@ -64,6 +65,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.transition.Scene;
import android.transition.Transition;
import android.transition.TransitionInflater;
@@ -125,7 +127,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
TypedValue mFixedWidthMinor;
TypedValue mFixedHeightMajor;
TypedValue mFixedHeightMinor;
- TypedValue mOutsetBottom;
+ int mOutsetBottomPx;
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
@@ -2368,12 +2370,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
- if (mOutsetBottom != null) {
- final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
- int bottom = (int) mOutsetBottom.getDimension(metrics);
+ if (mOutsetBottomPx != 0) {
WindowInsets newInsets = insets.replaceSystemWindowInsets(
insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
- insets.getSystemWindowInsetRight(), bottom);
+ insets.getSystemWindowInsetRight(), mOutsetBottomPx);
return super.dispatchApplyWindowInsets(newInsets);
} else {
return super.dispatchApplyWindowInsets(insets);
@@ -2592,12 +2592,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
- if (mOutsetBottom != null) {
+ if (mOutsetBottomPx != 0) {
int mode = MeasureSpec.getMode(heightMeasureSpec);
if (mode != MeasureSpec.UNSPECIFIED) {
- int outset = (int) mOutsetBottom.getDimension(metrics);
int height = MeasureSpec.getSize(heightMeasureSpec);
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + outset, mode);
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + mOutsetBottomPx, mode);
}
}
@@ -3472,10 +3471,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
final boolean shouldUseBottomOutset =
display.getDisplayId() == Display.DEFAULT_DISPLAY
|| (getForcedWindowFlags() & FLAG_FULLSCREEN) != 0;
- if (shouldUseBottomOutset && a.hasValue(R.styleable.Window_windowOutsetBottom)) {
- if (mOutsetBottom == null) mOutsetBottom = new TypedValue();
- a.getValue(R.styleable.Window_windowOutsetBottom,
- mOutsetBottom);
+ if (shouldUseBottomOutset) {
+ mOutsetBottomPx = ScreenShapeHelper.getWindowOutsetBottomPx(
+ getContext().getResources().getDisplayMetrics(), a);
}
}
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 59ec058b35dd..ad34f020fa9d 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -723,6 +723,12 @@ public class TextureView extends View {
mSurface.release();
}
mSurface = surfaceTexture;
+
+ // If the view is visible, update the listener in the new surface to use
+ // the existing listener in the view.
+ if (((mViewFlags & VISIBILITY_MASK) == VISIBLE)) {
+ mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
+ }
mUpdateSurface = true;
invalidateParentIfNeeded();
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f5de8e3d505c..cfcc6fe69565 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -83,6 +83,7 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityEventSource;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
@@ -3168,6 +3169,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private Drawable mBackground;
private TintInfo mBackgroundTint;
+ @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_")
+ private ForegroundInfo mForegroundInfo;
+
/**
* RenderNode used for backgrounds.
* <p>
@@ -3182,13 +3186,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private String mTransitionName;
- private static class TintInfo {
+ static class TintInfo {
ColorStateList mTintList;
PorterDuff.Mode mTintMode;
boolean mHasTintMode;
boolean mHasTintList;
}
+ private static class ForegroundInfo {
+ private Drawable mDrawable;
+ private TintInfo mTintInfo;
+ private int mGravity = Gravity.FILL;
+ private boolean mInsidePadding = true;
+ private boolean mBoundsChanged = true;
+ private final Rect mSelfBounds = new Rect();
+ private final Rect mOverlayBounds = new Rect();
+ }
+
static class ListenerInfo {
/**
* Listener used to dispatch focus change events.
@@ -4056,6 +4070,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider,
PROVIDER_BACKGROUND));
break;
+ case R.styleable.View_foreground:
+ setForeground(a.getDrawable(attr));
+ break;
+ case R.styleable.View_foregroundGravity:
+ setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY));
+ break;
+ case R.styleable.View_foregroundTintMode:
+ setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null));
+ break;
+ case R.styleable.View_foregroundTint:
+ setForegroundTintList(a.getColorStateList(attr));
+ break;
+ case R.styleable.View_foregroundInsidePadding:
+ if (mForegroundInfo == null) {
+ mForegroundInfo = new ForegroundInfo();
+ }
+ mForegroundInfo.mInsidePadding = a.getBoolean(attr,
+ mForegroundInfo.mInsidePadding);
+ break;
}
}
@@ -4813,10 +4846,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @hide
*/
protected boolean performButtonActionOnTouchDown(MotionEvent event) {
- if ((event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) {
- if (showContextMenu(event.getX(), event.getY(), event.getMetaState())) {
- return true;
- }
+ if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE &&
+ (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) {
+ showContextMenu(event.getX(), event.getY(), event.getMetaState());
+ mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT;
+ return true;
}
return false;
}
@@ -5781,6 +5815,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
| AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
| AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
}
+
+ info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN);
}
private View findLabelForView(View view, int labeledId) {
@@ -8228,6 +8264,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return true;
}
} break;
+ case R.id.accessibility_action_show_on_screen: {
+ if (mAttachInfo != null) {
+ final Rect r = mAttachInfo.mTmpInvalRect;
+ getDrawingRect(r);
+ return requestRectangleOnScreen(r, true);
+ }
+ } break;
}
return false;
}
@@ -8801,6 +8844,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (dr != null && visible != dr.isVisible()) {
dr.setVisible(visible, false);
}
+ final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
+ if (fg != null && visible != fg.isVisible()) {
+ fg.setVisible(visible, false);
+ }
}
/**
@@ -9917,6 +9964,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
mBackgroundSizeChanged = true;
+ if (mForegroundInfo != null) {
+ mForegroundInfo.mBoundsChanged = true;
+ }
final AttachInfo ai = mAttachInfo;
if (ai != null) {
@@ -10755,6 +10805,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
invalidate(true);
}
mBackgroundSizeChanged = true;
+ if (mForegroundInfo != null) {
+ mForegroundInfo.mBoundsChanged = true;
+ }
invalidateParentIfNeeded();
if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
// View was rejected last time it was drawn by its parent; this may have changed
@@ -10820,6 +10873,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
invalidate(true);
}
mBackgroundSizeChanged = true;
+ if (mForegroundInfo != null) {
+ mForegroundInfo.mBoundsChanged = true;
+ }
invalidateParentIfNeeded();
if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
// View was rejected last time it was drawn by its parent; this may have changed
@@ -10879,6 +10935,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
invalidate(true);
}
mBackgroundSizeChanged = true;
+ if (mForegroundInfo != null) {
+ mForegroundInfo.mBoundsChanged = true;
+ }
invalidateParentIfNeeded();
if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
// View was rejected last time it was drawn by its parent; this may have changed
@@ -10935,6 +10994,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
invalidate(true);
}
mBackgroundSizeChanged = true;
+ if (mForegroundInfo != null) {
+ mForegroundInfo.mBoundsChanged = true;
+ }
invalidateParentIfNeeded();
if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
// View was rejected last time it was drawn by its parent; this may have changed
@@ -15313,13 +15375,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// Step 4, draw the children
dispatchDraw(canvas);
- // Step 6, draw decorations (scrollbars)
- onDrawScrollBars(canvas);
-
+ // Overlay is part of the content and draws beneath Foreground
if (mOverlay != null && !mOverlay.isEmpty()) {
mOverlay.getOverlayView().dispatchDraw(canvas);
}
+ // Step 6, draw decorations (foreground, scrollbars)
+ onDrawForeground(canvas);
+
// we're done...
return;
}
@@ -15461,12 +15524,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
canvas.restoreToCount(saveCount);
- // Step 6, draw decorations (scrollbars)
- onDrawScrollBars(canvas);
-
+ // Overlay is part of the content and draws beneath Foreground
if (mOverlay != null && !mOverlay.isEmpty()) {
mOverlay.getOverlayView().dispatchDraw(canvas);
}
+
+ // Step 6, draw decorations (foreground, scrollbars)
+ onDrawForeground(canvas);
}
/**
@@ -15849,6 +15913,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags |= drawn;
mBackgroundSizeChanged = true;
+ if (mForegroundInfo != null) {
+ mForegroundInfo.mBoundsChanged = true;
+ }
notifySubtreeAccessibilityStateChangedIfNeeded();
}
@@ -15992,6 +16059,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (mBackground != null) {
mBackground.setLayoutDirection(layoutDirection);
}
+ if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) {
+ mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection);
+ }
mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED;
onResolveDrawables(layoutDirection);
}
@@ -16047,7 +16117,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@CallSuper
protected boolean verifyDrawable(Drawable who) {
- return who == mBackground || (mScrollCache != null && mScrollCache.scrollBar == who);
+ return who == mBackground || (mScrollCache != null && mScrollCache.scrollBar == who)
+ || (mForegroundInfo != null && mForegroundInfo.mDrawable == who);
}
/**
@@ -16065,9 +16136,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
protected void drawableStateChanged() {
final int[] state = getDrawableState();
- final Drawable d = mBackground;
- if (d != null && d.isStateful()) {
- d.setState(state);
+ final Drawable bg = mBackground;
+ if (bg != null && bg.isStateful()) {
+ bg.setState(state);
+ }
+
+ final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
+ if (fg != null && fg.isStateful()) {
+ fg.setState(state);
}
if (mScrollCache != null) {
@@ -16099,6 +16175,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (mBackground != null) {
mBackground.setHotspot(x, y);
}
+ if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) {
+ mForegroundInfo.mDrawable.setHotspot(x, y);
+ }
dispatchDrawableHotspotChanged(x, y);
}
@@ -16270,6 +16349,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (mStateListAnimator != null) {
mStateListAnimator.jumpToCurrentState();
}
+ if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) {
+ mForegroundInfo.mDrawable.jumpToCurrentState();
+ }
}
/**
@@ -16554,6 +16636,249 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Returns the drawable used as the foreground of this View. The
+ * foreground drawable, if non-null, is always drawn on top of the view's content.
+ *
+ * @return a Drawable or null if no foreground was set
+ *
+ * @see #onDrawForeground(Canvas)
+ */
+ public Drawable getForeground() {
+ return mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
+ }
+
+ /**
+ * Supply a Drawable that is to be rendered on top of all of the content in the view.
+ *
+ * @param foreground the Drawable to be drawn on top of the children
+ *
+ * @attr ref android.R.styleable#View_foreground
+ */
+ public void setForeground(Drawable foreground) {
+ if (mForegroundInfo == null) {
+ if (foreground == null) {
+ // Nothing to do.
+ return;
+ }
+ mForegroundInfo = new ForegroundInfo();
+ }
+
+ if (foreground == mForegroundInfo.mDrawable) {
+ // Nothing to do
+ return;
+ }
+
+ if (mForegroundInfo.mDrawable != null) {
+ mForegroundInfo.mDrawable.setCallback(null);
+ unscheduleDrawable(mForegroundInfo.mDrawable);
+ }
+
+ mForegroundInfo.mDrawable = foreground;
+ mForegroundInfo.mBoundsChanged = true;
+ if (foreground != null) {
+ setWillNotDraw(false);
+ foreground.setCallback(this);
+ foreground.setLayoutDirection(getLayoutDirection());
+ if (foreground.isStateful()) {
+ foreground.setState(getDrawableState());
+ }
+ applyForegroundTint();
+ }
+ requestLayout();
+ invalidate();
+ }
+
+ /**
+ * Magic bit used to support features of framework-internal window decor implementation details.
+ * This used to live exclusively in FrameLayout.
+ *
+ * @return true if the foreground should draw inside the padding region or false
+ * if it should draw inset by the view's padding
+ * @hide internal use only; only used by FrameLayout and internal screen layouts.
+ */
+ public boolean isForegroundInsidePadding() {
+ return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true;
+ }
+
+ /**
+ * Describes how the foreground is positioned.
+ *
+ * @return foreground gravity.
+ *
+ * @see #setForegroundGravity(int)
+ *
+ * @attr ref android.R.styleable#View_foregroundGravity
+ */
+ public int getForegroundGravity() {
+ return mForegroundInfo != null ? mForegroundInfo.mGravity
+ : Gravity.START | Gravity.TOP;
+ }
+
+ /**
+ * Describes how the foreground is positioned. Defaults to START and TOP.
+ *
+ * @param gravity see {@link android.view.Gravity}
+ *
+ * @see #getForegroundGravity()
+ *
+ * @attr ref android.R.styleable#View_foregroundGravity
+ */
+ public void setForegroundGravity(int gravity) {
+ if (mForegroundInfo == null) {
+ mForegroundInfo = new ForegroundInfo();
+ }
+
+ if (mForegroundInfo.mGravity != gravity) {
+ if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
+ gravity |= Gravity.START;
+ }
+
+ if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
+ gravity |= Gravity.TOP;
+ }
+
+ mForegroundInfo.mGravity = gravity;
+ requestLayout();
+ }
+ }
+
+ /**
+ * Applies a tint to the foreground drawable. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+ * <p>
+ * Subsequent calls to {@link #setForeground(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTintList(ColorStateList)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#View_foregroundTint
+ * @see #getForegroundTintList()
+ * @see Drawable#setTintList(ColorStateList)
+ */
+ public void setForegroundTintList(@Nullable ColorStateList tint) {
+ if (mForegroundInfo == null) {
+ mForegroundInfo = new ForegroundInfo();
+ }
+ if (mForegroundInfo.mTintInfo == null) {
+ mForegroundInfo.mTintInfo = new TintInfo();
+ }
+ mForegroundInfo.mTintInfo.mTintList = tint;
+ mForegroundInfo.mTintInfo.mHasTintList = true;
+
+ applyForegroundTint();
+ }
+
+ /**
+ * Return the tint applied to the foreground drawable, if specified.
+ *
+ * @return the tint applied to the foreground drawable
+ * @attr ref android.R.styleable#View_foregroundTint
+ * @see #setForegroundTintList(ColorStateList)
+ */
+ @Nullable
+ public ColorStateList getForegroundTintList() {
+ return mForegroundInfo != null && mForegroundInfo.mTintInfo != null
+ ? mBackgroundTint.mTintList : null;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setForegroundTintList(ColorStateList)}} to the background
+ * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#View_foregroundTintMode
+ * @see #getForegroundTintMode()
+ * @see Drawable#setTintMode(PorterDuff.Mode)
+ */
+ public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+ if (mBackgroundTint == null) {
+ mBackgroundTint = new TintInfo();
+ }
+ mBackgroundTint.mTintMode = tintMode;
+ mBackgroundTint.mHasTintMode = true;
+
+ applyBackgroundTint();
+ }
+
+ /**
+ * Return the blending mode used to apply the tint to the foreground
+ * drawable, if specified.
+ *
+ * @return the blending mode used to apply the tint to the foreground
+ * drawable
+ * @attr ref android.R.styleable#View_foregroundTintMode
+ * @see #setBackgroundTintMode(PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getForegroundTintMode() {
+ return mForegroundInfo != null && mForegroundInfo.mTintInfo != null
+ ? mForegroundInfo.mTintInfo.mTintMode : null;
+ }
+
+ private void applyForegroundTint() {
+ if (mForegroundInfo != null && mForegroundInfo.mDrawable != null
+ && mForegroundInfo.mTintInfo != null) {
+ final TintInfo tintInfo = mForegroundInfo.mTintInfo;
+ if (tintInfo.mHasTintList || tintInfo.mHasTintMode) {
+ mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate();
+
+ if (tintInfo.mHasTintList) {
+ mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList);
+ }
+
+ if (tintInfo.mHasTintMode) {
+ mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode);
+ }
+
+ // The drawable (or one of its children) may not have been
+ // stateful before applying the tint, so let's try again.
+ if (mForegroundInfo.mDrawable.isStateful()) {
+ mForegroundInfo.mDrawable.setState(getDrawableState());
+ }
+ }
+ }
+ }
+
+ /**
+ * Draw any foreground content for this view.
+ *
+ * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground}
+ * drawable or other view-specific decorations. The foreground is drawn on top of the
+ * primary view content.</p>
+ *
+ * @param canvas canvas to draw into
+ */
+ public void onDrawForeground(Canvas canvas) {
+ onDrawScrollBars(canvas);
+
+ final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
+ if (foreground != null) {
+ if (mForegroundInfo.mBoundsChanged) {
+ mForegroundInfo.mBoundsChanged = false;
+ final Rect selfBounds = mForegroundInfo.mSelfBounds;
+ final Rect overlayBounds = mForegroundInfo.mOverlayBounds;
+
+ if (mForegroundInfo.mInsidePadding) {
+ selfBounds.set(0, 0, getWidth(), getHeight());
+ } else {
+ selfBounds.set(getPaddingLeft(), getPaddingTop(),
+ getWidth() - getPaddingRight(), getHeight() - getPaddingBottom());
+ }
+
+ final int ld = getLayoutDirection();
+ Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(),
+ foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld);
+ foreground.setBounds(overlayBounds);
+ }
+
+ foreground.draw(canvas);
+ }
+ }
+
+ /**
* Sets the padding. The view may add on the space required to display
* the scrollbars, depending on the style and visibility of the scrollbars.
* So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop},
@@ -18090,6 +18415,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// parts from this transparent region.
applyDrawableToTransparentRegion(mBackground, region);
}
+ final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
+ if (foreground != null) {
+ applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region);
+ }
}
return true;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e790d4cb8d3b..294174ab9cb5 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -40,7 +40,6 @@ import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.media.AudioManager;
import android.os.Binder;
-import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
@@ -77,6 +76,7 @@ import android.widget.Scroller;
import com.android.internal.R;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.ScreenShapeHelper;
import com.android.internal.view.BaseSurfaceHolder;
import com.android.internal.view.RootViewSurfaceTaker;
@@ -118,10 +118,11 @@ public final class ViewRootImpl implements ViewParent,
* at 60 Hz. This can be used to measure the potential framerate.
*/
private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering";
- private static final String PROPERTY_MEDIA_DISABLED = "config.disable_media";
- // property used by emulator to determine display shape
+ // properties used by emulator to determine display shape
public static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular";
+ public static final String PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX =
+ "ro.emu.win_outset_bottom_px";
/**
* Maximum time we allow the user to roll the trackball enough to generate
@@ -299,8 +300,6 @@ public final class ViewRootImpl implements ViewParent,
private Choreographer.FrameCallback mRenderProfiler;
private boolean mRenderProfilingEnabled;
- private boolean mMediaDisabled;
-
// Variables to track frames per second, enabled via DEBUG_FPS flag
private long mFpsStartTime = -1;
private long mFpsPrevTime = -1;
@@ -334,8 +333,6 @@ public final class ViewRootImpl implements ViewParent,
/** Set to true once doDie() has been called. */
private boolean mRemoved;
- private boolean mIsEmulator;
- private boolean mIsCircularEmulator;
private final boolean mWindowIsRound;
/**
@@ -392,8 +389,7 @@ public final class ViewRootImpl implements ViewParent,
mChoreographer = Choreographer.getInstance();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
loadSystemProperties();
- mWindowIsRound = context.getResources().getBoolean(
- com.android.internal.R.bool.config_windowIsRound);
+ mWindowIsRound = ScreenShapeHelper.getWindowIsRound(context.getResources());
}
public static void addFirstDrawHandler(Runnable callback) {
@@ -1248,9 +1244,8 @@ public final class ViewRootImpl implements ViewParent,
contentInsets = mPendingContentInsets;
stableInsets = mPendingStableInsets;
}
- final boolean isRound = (mIsEmulator && mIsCircularEmulator) || mWindowIsRound;
mLastWindowInsets = new WindowInsets(contentInsets,
- null /* windowDecorInsets */, stableInsets, isRound);
+ null /* windowDecorInsets */, stableInsets, mWindowIsRound);
}
return mLastWindowInsets;
}
@@ -5362,10 +5357,6 @@ public final class ViewRootImpl implements ViewParent,
public void playSoundEffect(int effectId) {
checkThread();
- if (mMediaDisabled) {
- return;
- }
-
try {
final AudioManager audioManager = getAudioManager();
@@ -5572,9 +5563,6 @@ public final class ViewRootImpl implements ViewParent,
mProfileRendering = SystemProperties.getBoolean(PROPERTY_PROFILE_RENDERING, false);
profileRendering(mAttachInfo.mHasWindowFocus);
- // Media (used by sound effects)
- mMediaDisabled = SystemProperties.getBoolean(PROPERTY_MEDIA_DISABLED, false);
-
// Hardware rendering
if (mAttachInfo.mHardwareRenderer != null) {
if (mAttachInfo.mHardwareRenderer.loadSystemProperties()) {
@@ -5590,11 +5578,6 @@ public final class ViewRootImpl implements ViewParent,
mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200);
}
}
-
- // detect emulator
- mIsEmulator = Build.HARDWARE.contains("goldfish");
- mIsCircularEmulator =
- SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false);
}
});
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 9a929323f864..36f047e92de9 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1856,14 +1856,14 @@ public abstract class Window {
public abstract int getStatusBarColor();
/**
- * Sets the color of the status bar to {@param color}.
+ * Sets the color of the status bar to {@code color}.
*
* For this to take effect,
* the window must be drawing the system bar backgrounds with
* {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} and
* {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS} must not be set.
*
- * If {@param color} is not opaque, consider setting
+ * If {@code color} is not opaque, consider setting
* {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
* {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
* <p>
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 6096d7d1d8bc..77082b01803e 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -29,6 +29,8 @@ import android.util.LongArray;
import android.util.Pools.SynchronizedPool;
import android.view.View;
+import com.android.internal.R;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -3402,6 +3404,15 @@ public class AccessibilityNodeInfo implements Parcelable {
new AccessibilityAction(
AccessibilityNodeInfo.ACTION_SET_TEXT, null);
+ /**
+ * Action that requests the node make its bounding rectangle visible
+ * on the screen, scrolling if necessary just enough.
+ *
+ * @see View#requestRectangleOnScreen(Rect)
+ */
+ public static final AccessibilityAction ACTION_SHOW_ON_SCREEN =
+ new AccessibilityAction(R.id.accessibility_action_show_on_screen, null);
+
private static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<AccessibilityAction>();
static {
sStandardActions.add(ACTION_FOCUS);
@@ -3426,6 +3437,7 @@ public class AccessibilityNodeInfo implements Parcelable {
sStandardActions.add(ACTION_COLLAPSE);
sStandardActions.add(ACTION_DISMISS);
sStandardActions.add(ACTION_SET_TEXT);
+ sStandardActions.add(ACTION_SHOW_ON_SCREEN);
}
private final int mActionId;
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 4737e9be3f99..0b18bb8c4dde 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -284,13 +284,19 @@ public class WebChromeClient {
* currently set for that origin. The host application should invoke the
* specified callback with the desired permission state. See
* {@link GeolocationPermissions} for details.
+ *
+ * If this method isn't overridden, the callback is invoked with permission
+ * denied state.
+ *
* @param origin The origin of the web content attempting to use the
* Geolocation API.
* @param callback The callback to use to set the permission state for the
* origin.
*/
public void onGeolocationPermissionsShowPrompt(String origin,
- GeolocationPermissions.Callback callback) {}
+ GeolocationPermissions.Callback callback) {
+ callback.invoke(origin, false, false);
+ }
/**
* Notify the host application that a request for Geolocation permissions,
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 5c05b5a3d367..6feb94b11c1f 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -16,6 +16,7 @@
*/
package android.widget;
+import android.os.UserHandle;
import com.android.internal.R;
import android.app.AlertDialog;
@@ -243,7 +244,8 @@ public class AppSecurityPermissions {
@Override
public void onClick(DialogInterface dialog, int which) {
PackageManager pm = getContext().getPackageManager();
- pm.revokePermission(mPackageName, mPerm.name);
+ pm.revokePermission(mPackageName, mPerm.name,
+ new UserHandle(mContext.getUserId()));
PermissionItemView.this.setVisibility(View.GONE);
}
};
@@ -298,7 +300,7 @@ public class AppSecurityPermissions {
}
extractPerms(info, permSet, installedPkgInfo);
}
- // Get permissions related to shared user if any
+ // Get permissions related to shared user if any
if (info.sharedUserId != null) {
int sharedUid;
try {
@@ -358,7 +360,7 @@ public class AppSecurityPermissions {
String permName = strList[i];
// If we are only looking at an existing app, then we only
// care about permissions that have actually been granted to it.
- if (installedPkgInfo != null && info == installedPkgInfo) {
+ if (installedPkgInfo != null && info != installedPkgInfo) {
if ((flagsList[i]&PackageInfo.REQUESTED_PERMISSION_GRANTED) == 0) {
continue;
}
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index 5bc16cb63a5a..2aaa356cb00a 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -18,6 +18,7 @@ package android.widget;
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
+import android.annotation.StyleRes;
import android.annotation.Widget;
import android.content.Context;
import android.content.res.Configuration;
@@ -31,6 +32,7 @@ import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
+import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
@@ -118,7 +120,9 @@ public class CalendarView extends FrameLayout {
* @param count The shown week count.
*
* @attr ref android.R.styleable#CalendarView_shownWeekCount
+ * @deprecated No longer used by Material-style CalendarView.
*/
+ @Deprecated
public void setShownWeekCount(int count) {
mDelegate.setShownWeekCount(count);
}
@@ -129,7 +133,9 @@ public class CalendarView extends FrameLayout {
* @return The shown week count.
*
* @attr ref android.R.styleable#CalendarView_shownWeekCount
+ * @deprecated No longer used by Material-style CalendarView.
*/
+ @Deprecated
public int getShownWeekCount() {
return mDelegate.getShownWeekCount();
}
@@ -140,7 +146,9 @@ public class CalendarView extends FrameLayout {
* @param color The week background color.
*
* @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor
+ * @deprecated No longer used by Material-style CalendarView.
*/
+ @Deprecated
public void setSelectedWeekBackgroundColor(@ColorInt int color) {
mDelegate.setSelectedWeekBackgroundColor(color);
}
@@ -151,8 +159,10 @@ public class CalendarView extends FrameLayout {
* @return The week background color.
*
* @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor
+ * @deprecated No longer used by Material-style CalendarView.
*/
@ColorInt
+ @Deprecated
public int getSelectedWeekBackgroundColor() {
return mDelegate.getSelectedWeekBackgroundColor();
}
@@ -163,7 +173,9 @@ public class CalendarView extends FrameLayout {
* @param color The focused month date color.
*
* @attr ref android.R.styleable#CalendarView_focusedMonthDateColor
+ * @deprecated No longer used by Material-style CalendarView.
*/
+ @Deprecated
public void setFocusedMonthDateColor(@ColorInt int color) {
mDelegate.setFocusedMonthDateColor(color);
}
@@ -174,8 +186,10 @@ public class CalendarView extends FrameLayout {
* @return The focused month date color.
*
* @attr ref android.R.styleable#CalendarView_focusedMonthDateColor
+ * @deprecated No longer used by Material-style CalendarView.
*/
@ColorInt
+ @Deprecated
public int getFocusedMonthDateColor() {
return mDelegate.getFocusedMonthDateColor();
}
@@ -186,7 +200,9 @@ public class CalendarView extends FrameLayout {
* @param color A not focused month date color.
*
* @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor
+ * @deprecated No longer used by Material-style CalendarView.
*/
+ @Deprecated
public void setUnfocusedMonthDateColor(@ColorInt int color) {
mDelegate.setUnfocusedMonthDateColor(color);
}
@@ -197,8 +213,10 @@ public class CalendarView extends FrameLayout {
* @return A not focused month date color.
*
* @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor
+ * @deprecated No longer used by Material-style CalendarView.
*/
@ColorInt
+ @Deprecated
public int getUnfocusedMonthDateColor() {
return mDelegate.getUnfocusedMonthDateColor();
}
@@ -209,7 +227,9 @@ public class CalendarView extends FrameLayout {
* @param color The week number color.
*
* @attr ref android.R.styleable#CalendarView_weekNumberColor
+ * @deprecated No longer used by Material-style CalendarView.
*/
+ @Deprecated
public void setWeekNumberColor(@ColorInt int color) {
mDelegate.setWeekNumberColor(color);
}
@@ -220,8 +240,10 @@ public class CalendarView extends FrameLayout {
* @return The week number color.
*
* @attr ref android.R.styleable#CalendarView_weekNumberColor
+ * @deprecated No longer used by Material-style CalendarView.
*/
@ColorInt
+ @Deprecated
public int getWeekNumberColor() {
return mDelegate.getWeekNumberColor();
}
@@ -232,7 +254,9 @@ public class CalendarView extends FrameLayout {
* @param color The week separator color.
*
* @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor
+ * @deprecated No longer used by Material-style CalendarView.
*/
+ @Deprecated
public void setWeekSeparatorLineColor(@ColorInt int color) {
mDelegate.setWeekSeparatorLineColor(color);
}
@@ -243,8 +267,10 @@ public class CalendarView extends FrameLayout {
* @return The week separator color.
*
* @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor
+ * @deprecated No longer used by Material-style CalendarView.
*/
@ColorInt
+ @Deprecated
public int getWeekSeparatorLineColor() {
return mDelegate.getWeekSeparatorLineColor();
}
@@ -256,7 +282,9 @@ public class CalendarView extends FrameLayout {
* @param resourceId The vertical bar drawable resource id.
*
* @attr ref android.R.styleable#CalendarView_selectedDateVerticalBar
+ * @deprecated No longer used by Material-style CalendarView.
*/
+ @Deprecated
public void setSelectedDateVerticalBar(@DrawableRes int resourceId) {
mDelegate.setSelectedDateVerticalBar(resourceId);
}
@@ -268,7 +296,9 @@ public class CalendarView extends FrameLayout {
* @param drawable The vertical bar drawable.
*
* @attr ref android.R.styleable#CalendarView_selectedDateVerticalBar
+ * @deprecated No longer used by Material-style CalendarView.
*/
+ @Deprecated
public void setSelectedDateVerticalBar(Drawable drawable) {
mDelegate.setSelectedDateVerticalBar(drawable);
}
@@ -278,7 +308,9 @@ public class CalendarView extends FrameLayout {
* the end of the selected date.
*
* @return The vertical bar drawable.
+ * @deprecated No longer used by Material-style CalendarView.
*/
+ @Deprecated
public Drawable getSelectedDateVerticalBar() {
return mDelegate.getSelectedDateVerticalBar();
}
@@ -519,29 +551,36 @@ public class CalendarView extends FrameLayout {
void setShownWeekCount(int count);
int getShownWeekCount();
- void setSelectedWeekBackgroundColor(int color);
+ void setSelectedWeekBackgroundColor(@ColorInt int color);
+ @ColorInt
int getSelectedWeekBackgroundColor();
- void setFocusedMonthDateColor(int color);
+ void setFocusedMonthDateColor(@ColorInt int color);
+ @ColorInt
int getFocusedMonthDateColor();
- void setUnfocusedMonthDateColor(int color);
+ void setUnfocusedMonthDateColor(@ColorInt int color);
+ @ColorInt
int getUnfocusedMonthDateColor();
- void setWeekNumberColor(int color);
+ void setWeekNumberColor(@ColorInt int color);
+ @ColorInt
int getWeekNumberColor();
- void setWeekSeparatorLineColor(int color);
+ void setWeekSeparatorLineColor(@ColorInt int color);
+ @ColorInt
int getWeekSeparatorLineColor();
- void setSelectedDateVerticalBar(int resourceId);
+ void setSelectedDateVerticalBar(@DrawableRes int resourceId);
void setSelectedDateVerticalBar(Drawable drawable);
Drawable getSelectedDateVerticalBar();
- void setWeekDayTextAppearance(int resourceId);
+ void setWeekDayTextAppearance(@StyleRes int resourceId);
+ @StyleRes
int getWeekDayTextAppearance();
- void setDateTextAppearance(int resourceId);
+ void setDateTextAppearance(@StyleRes int resourceId);
+ @StyleRes
int getDateTextAppearance();
void setMinDate(long minDate);
@@ -569,18 +608,12 @@ public class CalendarView extends FrameLayout {
* An abstract class which can be used as a start for CalendarView implementations
*/
abstract static class AbstractCalendarViewDelegate implements CalendarViewDelegate {
- /** String for parsing dates. */
- private static final String DATE_FORMAT = "MM/dd/yyyy";
-
/** The default minimal date. */
protected static final String DEFAULT_MIN_DATE = "01/01/1900";
/** The default maximal date. */
protected static final String DEFAULT_MAX_DATE = "01/01/2100";
- /** Date format for parsing dates. */
- protected static final DateFormat DATE_FORMATTER = new SimpleDateFormat(DATE_FORMAT);
-
protected CalendarView mDelegator;
protected Context mContext;
protected Locale mCurrentLocale;
@@ -600,21 +633,131 @@ public class CalendarView extends FrameLayout {
mCurrentLocale = locale;
}
- /**
- * Parses the given <code>date</code> and in case of success sets
- * the result to the <code>outDate</code>.
- *
- * @return True if the date was parsed.
- */
- protected boolean parseDate(String date, Calendar outDate) {
- try {
- outDate.setTime(DATE_FORMATTER.parse(date));
- return true;
- } catch (ParseException e) {
- Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT);
- return false;
- }
+ @Override
+ public void setShownWeekCount(int count) {
+ // Deprecated.
+ }
+
+ @Override
+ public int getShownWeekCount() {
+ // Deprecated.
+ return 0;
+ }
+
+ @Override
+ public void setSelectedWeekBackgroundColor(@ColorInt int color) {
+ // Deprecated.
+ }
+
+ @ColorInt
+ @Override
+ public int getSelectedWeekBackgroundColor() {
+ return 0;
+ }
+
+ @Override
+ public void setFocusedMonthDateColor(@ColorInt int color) {
+ // Deprecated.
+ }
+
+ @ColorInt
+ @Override
+ public int getFocusedMonthDateColor() {
+ return 0;
+ }
+
+ @Override
+ public void setUnfocusedMonthDateColor(@ColorInt int color) {
+ // Deprecated.
+ }
+
+ @ColorInt
+ @Override
+ public int getUnfocusedMonthDateColor() {
+ return 0;
+ }
+
+ @Override
+ public void setWeekNumberColor(@ColorInt int color) {
+ // Deprecated.
+ }
+
+ @ColorInt
+ @Override
+ public int getWeekNumberColor() {
+ // Deprecated.
+ return 0;
+ }
+
+ @Override
+ public void setWeekSeparatorLineColor(@ColorInt int color) {
+ // Deprecated.
+ }
+
+ @ColorInt
+ @Override
+ public int getWeekSeparatorLineColor() {
+ // Deprecated.
+ return 0;
+ }
+
+ @Override
+ public void setSelectedDateVerticalBar(@DrawableRes int resId) {
+ // Deprecated.
+ }
+
+ @Override
+ public void setSelectedDateVerticalBar(Drawable drawable) {
+ // Deprecated.
+ }
+
+ @Override
+ public Drawable getSelectedDateVerticalBar() {
+ // Deprecated.
+ return null;
+ }
+
+ @Override
+ public void setShowWeekNumber(boolean showWeekNumber) {
+ // Deprecated.
+ }
+
+ @Override
+ public boolean getShowWeekNumber() {
+ // Deprecated.
+ return false;
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ // Nothing to do here, configuration changes are already propagated
+ // by ViewGroup.
}
}
+ /** String for parsing dates. */
+ private static final String DATE_FORMAT = "MM/dd/yyyy";
+
+ /** Date format for parsing dates. */
+ private static final DateFormat DATE_FORMATTER = new SimpleDateFormat(DATE_FORMAT);
+
+ /**
+ * Utility method for the date format used by CalendarView's min/max date.
+ *
+ * @hide Use only as directed. For internal use only.
+ */
+ public static boolean parseDate(String date, Calendar outDate) {
+ if (date == null || date.isEmpty()) {
+ return false;
+ }
+
+ try {
+ final Date parsedDate = DATE_FORMATTER.parse(date);
+ outDate.setTime(parsedDate);
+ return true;
+ } catch (ParseException e) {
+ Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT);
+ return false;
+ }
+ }
}
diff --git a/core/java/android/widget/CalendarViewLegacyDelegate.java b/core/java/android/widget/CalendarViewLegacyDelegate.java
index 2ab35482bf56..6ab3828e03e2 100644
--- a/core/java/android/widget/CalendarViewLegacyDelegate.java
+++ b/core/java/android/widget/CalendarViewLegacyDelegate.java
@@ -27,7 +27,6 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
@@ -267,12 +266,12 @@ class CalendarViewLegacyDelegate extends CalendarView.AbstractCalendarViewDelega
mFirstDayOfWeek = a.getInt(R.styleable.CalendarView_firstDayOfWeek,
LocaleData.get(Locale.getDefault()).firstDayOfWeek);
final String minDate = a.getString(R.styleable.CalendarView_minDate);
- if (TextUtils.isEmpty(minDate) || !parseDate(minDate, mMinDate)) {
- parseDate(DEFAULT_MIN_DATE, mMinDate);
+ if (!CalendarView.parseDate(minDate, mMinDate)) {
+ CalendarView.parseDate(DEFAULT_MIN_DATE, mMinDate);
}
final String maxDate = a.getString(R.styleable.CalendarView_maxDate);
- if (TextUtils.isEmpty(maxDate) || !parseDate(maxDate, mMaxDate)) {
- parseDate(DEFAULT_MAX_DATE, mMaxDate);
+ if (!CalendarView.parseDate(maxDate, mMaxDate)) {
+ CalendarView.parseDate(DEFAULT_MAX_DATE, mMaxDate);
}
if (mMaxDate.before(mMinDate)) {
throw new IllegalArgumentException("Max date cannot be before min date.");
diff --git a/core/java/android/widget/CalendarViewMaterialDelegate.java b/core/java/android/widget/CalendarViewMaterialDelegate.java
index b0f3740ac620..7bce7568585f 100644
--- a/core/java/android/widget/CalendarViewMaterialDelegate.java
+++ b/core/java/android/widget/CalendarViewMaterialDelegate.java
@@ -16,20 +16,11 @@
package android.widget;
-import com.android.internal.R;
-
+import android.annotation.StyleRes;
import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.text.TextUtils;
import android.util.AttributeSet;
-import android.util.MathUtils;
import java.util.Calendar;
-import java.util.Locale;
-
-import libcore.icu.LocaleData;
class CalendarViewMaterialDelegate extends CalendarView.AbstractCalendarViewDelegate {
private final DayPickerView mDayPickerView;
@@ -40,142 +31,32 @@ class CalendarViewMaterialDelegate extends CalendarView.AbstractCalendarViewDele
int defStyleAttr, int defStyleRes) {
super(delegator, context);
- final TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.CalendarView, defStyleAttr, defStyleRes);
- final int firstDayOfWeek = a.getInt(R.styleable.CalendarView_firstDayOfWeek,
- LocaleData.get(Locale.getDefault()).firstDayOfWeek);
-
- final long minDate = parseDateToMillis(a.getString(
- R.styleable.CalendarView_minDate), DEFAULT_MIN_DATE);
- final long maxDate = parseDateToMillis(a.getString(
- R.styleable.CalendarView_maxDate), DEFAULT_MAX_DATE);
- if (maxDate < minDate) {
- throw new IllegalArgumentException("max date cannot be before min date");
- }
-
- final long setDate = MathUtils.constrain(System.currentTimeMillis(), minDate, maxDate);
- final int dateTextAppearanceResId = a.getResourceId(
- R.styleable.CalendarView_dateTextAppearance,
- R.style.TextAppearance_DeviceDefault_Small);
-
- a.recycle();
-
- mDayPickerView = new DayPickerView(context);
- mDayPickerView.setFirstDayOfWeek(firstDayOfWeek);
- mDayPickerView.setCalendarTextAppearance(dateTextAppearanceResId);
- mDayPickerView.setMinDate(minDate);
- mDayPickerView.setMaxDate(maxDate);
- mDayPickerView.setDate(setDate, false, true);
+ mDayPickerView = new DayPickerView(context, attrs, defStyleAttr, defStyleRes);
mDayPickerView.setOnDaySelectedListener(mOnDaySelectedListener);
delegator.addView(mDayPickerView);
}
- private long parseDateToMillis(String dateStr, String defaultDateStr) {
- final Calendar tempCalendar = Calendar.getInstance();
- if (TextUtils.isEmpty(dateStr) || !parseDate(dateStr, tempCalendar)) {
- parseDate(defaultDateStr, tempCalendar);
- }
- return tempCalendar.getTimeInMillis();
- }
-
@Override
- public void setShownWeekCount(int count) {
- // Deprecated.
- }
-
- @Override
- public int getShownWeekCount() {
- // Deprecated.
- return 0;
- }
-
- @Override
- public void setSelectedWeekBackgroundColor(int color) {
- // TODO: Should use a ColorStateList. Deprecate?
- }
-
- @Override
- public int getSelectedWeekBackgroundColor() {
- return 0;
- }
-
- @Override
- public void setFocusedMonthDateColor(int color) {
- // TODO: Should use a ColorStateList. Deprecate?
- }
-
- @Override
- public int getFocusedMonthDateColor() {
- return 0;
- }
-
- @Override
- public void setUnfocusedMonthDateColor(int color) {
- // TODO: Should use a ColorStateList. Deprecate?
- }
-
- @Override
- public int getUnfocusedMonthDateColor() {
- return 0;
- }
-
- @Override
- public void setWeekDayTextAppearance(int resourceId) {
-
+ public void setWeekDayTextAppearance(@StyleRes int resId) {
+ mDayPickerView.setDayOfWeekTextAppearance(resId);
}
+ @StyleRes
@Override
public int getWeekDayTextAppearance() {
- return 0;
+ return mDayPickerView.getDayOfWeekTextAppearance();
}
@Override
- public void setDateTextAppearance(int resourceId) {
-
+ public void setDateTextAppearance(@StyleRes int resId) {
+ mDayPickerView.setDayTextAppearance(resId);
}
+ @StyleRes
@Override
public int getDateTextAppearance() {
- return 0;
- }
-
- @Override
- public void setWeekNumberColor(int color) {
- // Deprecated.
- }
-
- @Override
- public int getWeekNumberColor() {
- // Deprecated.
- return 0;
- }
-
- @Override
- public void setWeekSeparatorLineColor(int color) {
- // Deprecated.
- }
-
- @Override
- public int getWeekSeparatorLineColor() {
- // Deprecated.
- return 0;
- }
-
- @Override
- public void setSelectedDateVerticalBar(int resourceId) {
- // Deprecated.
- }
-
- @Override
- public void setSelectedDateVerticalBar(Drawable drawable) {
- // Deprecated.
- }
-
- @Override
- public Drawable getSelectedDateVerticalBar() {
- // Deprecated.
- return null;
+ return mDayPickerView.getDayTextAppearance();
}
@Override
@@ -199,17 +80,6 @@ class CalendarViewMaterialDelegate extends CalendarView.AbstractCalendarViewDele
}
@Override
- public void setShowWeekNumber(boolean showWeekNumber) {
- // Deprecated.
- }
-
- @Override
- public boolean getShowWeekNumber() {
- // Deprecated.
- return false;
- }
-
- @Override
public void setFirstDayOfWeek(int firstDayOfWeek) {
mDayPickerView.setFirstDayOfWeek(firstDayOfWeek);
}
@@ -221,12 +91,12 @@ class CalendarViewMaterialDelegate extends CalendarView.AbstractCalendarViewDele
@Override
public void setDate(long date) {
- mDayPickerView.setDate(date, true, false);
+ mDayPickerView.setDate(date, true);
}
@Override
public void setDate(long date, boolean animate, boolean center) {
- mDayPickerView.setDate(date, animate, center);
+ mDayPickerView.setDate(date, animate);
}
@Override
@@ -239,12 +109,6 @@ class CalendarViewMaterialDelegate extends CalendarView.AbstractCalendarViewDele
mOnDateChangeListener = listener;
}
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- // Nothing to do here, configuration changes are already propagated
- // by ViewGroup.
- }
-
private final DayPickerView.OnDaySelectedListener mOnDaySelectedListener =
new DayPickerView.OnDaySelectedListener() {
@Override
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 45998f7b4e6c..5f5943fe7472 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -98,7 +98,7 @@ public class DatePicker extends FrameLayout {
private final DatePickerDelegate mDelegate;
/**
- * The callback used to indicate the user changes\d the date.
+ * The callback used to indicate the user changed the date.
*/
public interface OnDateChangedListener {
@@ -348,9 +348,13 @@ public class DatePicker extends FrameLayout {
}
/**
- * Gets whether the {@link CalendarView} is shown.
+ * Returns whether the {@link CalendarView} is shown.
+ * <p>
+ * <strong>Note:</strong> This method returns {@code false} when the
+ * {@link android.R.styleable#DatePicker_datePickerMode} attribute is set
+ * to {@code calendar}.
*
- * @return True if the calendar view is shown.
+ * @return {@code true} if the calendar view is shown
* @see #getCalendarView()
*/
public boolean getCalendarViewShown() {
@@ -358,13 +362,13 @@ public class DatePicker extends FrameLayout {
}
/**
- * Gets the {@link CalendarView}.
+ * Returns the {@link CalendarView} used by this picker.
* <p>
- * This method returns {@code null} when the
+ * <strong>Note:</strong> This method returns {@code null} when the
* {@link android.R.styleable#DatePicker_datePickerMode} attribute is set
* to {@code calendar}.
*
- * @return The calendar view.
+ * @return the calendar view
* @see #getCalendarViewShown()
*/
public CalendarView getCalendarView() {
@@ -374,20 +378,25 @@ public class DatePicker extends FrameLayout {
/**
* Sets whether the {@link CalendarView} is shown.
* <p>
- * Calling this method has no effect when the
+ * <strong>Note:</strong> Calling this method has no effect when the
* {@link android.R.styleable#DatePicker_datePickerMode} attribute is set
* to {@code calendar}.
*
- * @param shown True if the calendar view is to be shown.
+ * @param shown {@code true} to show the calendar view, {@code false} to
+ * hide it
*/
public void setCalendarViewShown(boolean shown) {
mDelegate.setCalendarViewShown(shown);
}
/**
- * Gets whether the spinners are shown.
+ * Returns whether the spinners are shown.
+ * <p>
+ * <strong>Note:</strong> his method returns {@code false} when the
+ * {@link android.R.styleable#DatePicker_datePickerMode} attribute is set
+ * to {@code calendar}.
*
- * @return True if the spinners are shown.
+ * @return {@code true} if the spinners are shown
*/
public boolean getSpinnersShown() {
return mDelegate.getSpinnersShown();
@@ -395,8 +404,13 @@ public class DatePicker extends FrameLayout {
/**
* Sets whether the spinners are shown.
+ * <p>
+ * Calling this method has no effect when the
+ * {@link android.R.styleable#DatePicker_datePickerMode} attribute is set
+ * to {@code calendar}.
*
- * @param shown True if the spinners are to be shown.
+ * @param shown {@code true} to show the spinners, {@code false} to hide
+ * them
*/
public void setSpinnersShown(boolean shown) {
mDelegate.setSpinnersShown(shown);
@@ -489,15 +503,14 @@ public class DatePicker extends FrameLayout {
mDelegator = delegator;
mContext = context;
- // initialization based on locale
setCurrentLocale(Locale.getDefault());
}
protected void setCurrentLocale(Locale locale) {
- if (locale.equals(mCurrentLocale)) {
- return;
+ if (!locale.equals(mCurrentLocale)) {
+ mCurrentLocale = locale;
+ onLocaleChanged(locale);
}
- mCurrentLocale = locale;
}
@Override
@@ -510,6 +523,10 @@ public class DatePicker extends FrameLayout {
mValidationCallback.onValidationChanged(valid);
}
}
+
+ protected void onLocaleChanged(Locale locale) {
+ // Stub.
+ }
}
/**
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 0e3ec7fddc90..7b8a9797ffb2 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
@@ -26,90 +27,84 @@ import android.os.Parcelable;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.util.AttributeSet;
+import android.util.StateSet;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
+import android.widget.DayPickerView.OnDaySelectedListener;
+import android.widget.YearPickerView.OnYearSelectedListener;
import com.android.internal.R;
-import com.android.internal.widget.AccessibleDateAnimator;
import java.text.SimpleDateFormat;
import java.util.Calendar;
-import java.util.HashSet;
import java.util.Locale;
/**
* A delegate for picking up a date (day / month / year).
*/
-class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate implements
- View.OnClickListener, DatePickerController {
+class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate {
+
private static final int USE_LOCALE = 0;
private static final int UNINITIALIZED = -1;
- private static final int MONTH_AND_DAY_VIEW = 0;
- private static final int YEAR_VIEW = 1;
+ private static final int VIEW_MONTH_DAY = 0;
+ private static final int VIEW_YEAR = 1;
private static final int DEFAULT_START_YEAR = 1900;
private static final int DEFAULT_END_YEAR = 2100;
private static final int ANIMATION_DURATION = 300;
- private static final int MONTH_INDEX = 0;
- private static final int DAY_INDEX = 1;
- private static final int YEAR_INDEX = 2;
+ public static final int[] ATTRS_TEXT_COLOR = new int[]{com.android.internal.R.attr.textColor};
- private SimpleDateFormat mYearFormat = new SimpleDateFormat("y", Locale.getDefault());
- private SimpleDateFormat mDayFormat = new SimpleDateFormat("d", Locale.getDefault());
+ public static final int[] ATTRS_DISABLED_ALPHA = new int[]{
+ com.android.internal.R.attr.disabledAlpha};
- private TextView mDayOfWeekView;
+ private SimpleDateFormat mYearFormat;
+ private SimpleDateFormat mMonthDayFormat;
- /** Layout that contains the current month, day, and year. */
- private LinearLayout mMonthDayYearLayout;
+ // Top-level container.
+ private ViewGroup mContainer;
- /** Clickable layout that contains the current day and year. */
- private LinearLayout mMonthAndDayLayout;
+ // Header views.
+ private TextView mHeaderYear;
+ private TextView mHeaderMonthDay;
- private TextView mHeaderMonthTextView;
- private TextView mHeaderDayOfMonthTextView;
- private TextView mHeaderYearTextView;
+ // Picker views.
+ private ViewAnimator mAnimator;
private DayPickerView mDayPickerView;
private YearPickerView mYearPickerView;
- private boolean mIsEnabled = true;
-
// Accessibility strings.
- private String mDayPickerDescription;
private String mSelectDay;
- private String mYearPickerDescription;
private String mSelectYear;
- private AccessibleDateAnimator mAnimator;
-
private DatePicker.OnDateChangedListener mDateChangedListener;
private int mCurrentView = UNINITIALIZED;
- private Calendar mCurrentDate;
- private Calendar mTempDate;
- private Calendar mMinDate;
- private Calendar mMaxDate;
+ private final Calendar mCurrentDate;
+ private final Calendar mTempDate;
+ private final Calendar mMinDate;
+ private final Calendar mMaxDate;
private int mFirstDayOfWeek = USE_LOCALE;
- private HashSet<OnDateChangedListener> mListeners = new HashSet<OnDateChangedListener>();
-
public DatePickerCalendarDelegate(DatePicker delegator, Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(delegator, context);
- final Locale locale = Locale.getDefault();
- mMinDate = getCalendarForLocale(mMinDate, locale);
- mMaxDate = getCalendarForLocale(mMaxDate, locale);
- mTempDate = getCalendarForLocale(mMaxDate, locale);
- mCurrentDate = getCalendarForLocale(mCurrentDate, locale);
+ final Locale locale = mCurrentLocale;
+ mCurrentDate = Calendar.getInstance(locale);
+ mTempDate = Calendar.getInstance(locale);
+ mMinDate = Calendar.getInstance(locale);
+ mMaxDate = Calendar.getInstance(locale);
mMinDate.set(DEFAULT_START_YEAR, Calendar.JANUARY, 1);
mMaxDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER, 31);
@@ -120,71 +115,64 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
final int layoutResourceId = a.getResourceId(
- R.styleable.DatePicker_internalLayout, R.layout.date_picker_holo);
- final View mainView = inflater.inflate(layoutResourceId, null);
- mDelegator.addView(mainView);
+ R.styleable.DatePicker_internalLayout, R.layout.date_picker_material);
- mDayOfWeekView = (TextView) mainView.findViewById(R.id.date_picker_header);
+ // Set up and attach container.
+ mContainer = (ViewGroup) inflater.inflate(layoutResourceId, mDelegator);
- // Layout that contains the current date and day name header.
- final LinearLayout dateLayout = (LinearLayout) mainView.findViewById(
- R.id.day_picker_selector_layout);
- mMonthDayYearLayout = (LinearLayout) mainView.findViewById(
- R.id.date_picker_month_day_year_layout);
- mMonthAndDayLayout = (LinearLayout) mainView.findViewById(
- R.id.date_picker_month_and_day_layout);
- mMonthAndDayLayout.setOnClickListener(this);
- mHeaderMonthTextView = (TextView) mainView.findViewById(R.id.date_picker_month);
- mHeaderDayOfMonthTextView = (TextView) mainView.findViewById(R.id.date_picker_day);
- mHeaderYearTextView = (TextView) mainView.findViewById(R.id.date_picker_year);
- mHeaderYearTextView.setOnClickListener(this);
+ // Set up header views.
+ final ViewGroup header = (ViewGroup) mContainer.findViewById(R.id.date_picker_header);
+ mHeaderYear = (TextView) header.findViewById(R.id.date_picker_header_year);
+ mHeaderYear.setOnClickListener(mOnHeaderClickListener);
+ mHeaderMonthDay = (TextView) header.findViewById(R.id.date_picker_header_date);
+ mHeaderMonthDay.setOnClickListener(mOnHeaderClickListener);
- // Obtain default highlight color from the theme.
- final int defaultHighlightColor = mHeaderYearTextView.getHighlightColor();
+ // For the sake of backwards compatibility, attempt to extract the text
+ // color from the header month text appearance. If it's set, we'll let
+ // that override the "real" header text color.
+ ColorStateList headerTextColor = null;
- // Use Theme attributes if possible
- final int dayOfWeekTextAppearanceResId = a.getResourceId(
- R.styleable.DatePicker_dayOfWeekTextAppearance, 0);
- if (dayOfWeekTextAppearanceResId != 0) {
- mDayOfWeekView.setTextAppearance(context, dayOfWeekTextAppearanceResId);
+ @SuppressWarnings("deprecation")
+ final int monthHeaderTextAppearance = a.getResourceId(
+ R.styleable.DatePicker_headerMonthTextAppearance, 0);
+ if (monthHeaderTextAppearance != 0) {
+ final TypedArray textAppearance = mContext.obtainStyledAttributes(null,
+ ATTRS_TEXT_COLOR, 0, monthHeaderTextAppearance);
+ final ColorStateList legacyHeaderTextColor = textAppearance.getColorStateList(0);
+ headerTextColor = applyLegacyColorFixes(legacyHeaderTextColor);
+ textAppearance.recycle();
}
- mDayOfWeekView.setBackground(a.getDrawable(R.styleable.DatePicker_dayOfWeekBackground));
-
- dateLayout.setBackground(a.getDrawable(R.styleable.DatePicker_headerBackground));
-
- final int monthTextAppearanceResId = a.getResourceId(
- R.styleable.DatePicker_headerMonthTextAppearance, 0);
- if (monthTextAppearanceResId != 0) {
- mHeaderMonthTextView.setTextAppearance(context, monthTextAppearanceResId);
+ if (headerTextColor == null) {
+ headerTextColor = a.getColorStateList(R.styleable.DatePicker_headerTextColor);
}
- final int dayOfMonthTextAppearanceResId = a.getResourceId(
- R.styleable.DatePicker_headerDayOfMonthTextAppearance, 0);
- if (dayOfMonthTextAppearanceResId != 0) {
- mHeaderDayOfMonthTextView.setTextAppearance(context, dayOfMonthTextAppearanceResId);
+ if (headerTextColor != null) {
+ mHeaderYear.setTextColor(headerTextColor);
+ mHeaderMonthDay.setTextColor(headerTextColor);
}
- final int headerYearTextAppearanceResId = a.getResourceId(
- R.styleable.DatePicker_headerYearTextAppearance, 0);
- if (headerYearTextAppearanceResId != 0) {
- mHeaderYearTextView.setTextAppearance(context, headerYearTextAppearanceResId);
+ // Set up header background, if available.
+ if (a.hasValueOrEmpty(R.styleable.DatePicker_headerBackground)) {
+ header.setBackground(a.getDrawable(R.styleable.DatePicker_headerBackground));
}
- mDayPickerView = new DayPickerView(mContext);
+ // Set up picker container.
+ mAnimator = (ViewAnimator) mContainer.findViewById(R.id.animator);
+
+ // Set up day picker view.
+ mDayPickerView = (DayPickerView) mAnimator.findViewById(R.id.date_picker_day_picker);
mDayPickerView.setFirstDayOfWeek(mFirstDayOfWeek);
mDayPickerView.setMinDate(mMinDate.getTimeInMillis());
mDayPickerView.setMaxDate(mMaxDate.getTimeInMillis());
mDayPickerView.setDate(mCurrentDate.getTimeInMillis());
mDayPickerView.setOnDaySelectedListener(mOnDaySelectedListener);
- mYearPickerView = new YearPickerView(mContext);
- mYearPickerView.init(this);
+ // Set up year picker view.
+ mYearPickerView = (YearPickerView) mAnimator.findViewById(R.id.date_picker_year_picker);
mYearPickerView.setRange(mMinDate, mMaxDate);
-
- final ColorStateList yearBackgroundColor = a.getColorStateList(
- R.styleable.DatePicker_yearListSelectorColor);
- mYearPickerView.setYearBackgroundColor(yearBackgroundColor);
+ mYearPickerView.setDate(mCurrentDate.getTimeInMillis());
+ mYearPickerView.setOnYearSelectedListener(mOnYearSelectedListener);
final int yearTextAppearanceResId = a.getResourceId(
R.styleable.DatePicker_yearListItemTextAppearance, 0);
@@ -192,170 +180,201 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
mYearPickerView.setYearTextAppearance(yearTextAppearanceResId);
}
- final ColorStateList calendarTextColor = a.getColorStateList(
- R.styleable.DatePicker_calendarTextColor);
- mDayPickerView.setCalendarTextColor(calendarTextColor);
+ final int yearActivatedTextAppearanceResId = a.getResourceId(
+ R.styleable.DatePicker_yearListItemActivatedTextAppearance, 0);
+ if (yearActivatedTextAppearanceResId != 0) {
+ mYearPickerView.setYearActivatedTextAppearance(yearActivatedTextAppearanceResId);
+ }
- final ColorStateList calendarDayBackgroundColor = a.getColorStateList(
- R.styleable.DatePicker_calendarDayBackgroundColor);
- mDayPickerView.setCalendarDayBackgroundColor(calendarDayBackgroundColor);
+ a.recycle();
- mDayPickerDescription = res.getString(R.string.day_picker_description);
+ // Set up content descriptions.
mSelectDay = res.getString(R.string.select_day);
- mYearPickerDescription = res.getString(R.string.year_picker_description);
mSelectYear = res.getString(R.string.select_year);
- mAnimator = (AccessibleDateAnimator) mainView.findViewById(R.id.animator);
- mAnimator.addView(mDayPickerView);
- mAnimator.addView(mYearPickerView);
- mAnimator.setDateMillis(mCurrentDate.getTimeInMillis());
+ final Animation inAnim = new AlphaAnimation(0, 1);
+ inAnim.setDuration(ANIMATION_DURATION);
+ mAnimator.setInAnimation(inAnim);
- final Animation animation = new AlphaAnimation(0.0f, 1.0f);
- animation.setDuration(ANIMATION_DURATION);
- mAnimator.setInAnimation(animation);
+ final Animation outAnim = new AlphaAnimation(1, 0);
+ outAnim.setDuration(ANIMATION_DURATION);
+ mAnimator.setOutAnimation(outAnim);
- final Animation animation2 = new AlphaAnimation(1.0f, 0.0f);
- animation2.setDuration(ANIMATION_DURATION);
- mAnimator.setOutAnimation(animation2);
+ // Initialize for current locale. This also initializes the date, so no
+ // need to call onDateChanged.
+ onLocaleChanged(mCurrentLocale);
- updateDisplay(false);
- setCurrentView(MONTH_AND_DAY_VIEW);
+ setCurrentView(VIEW_MONTH_DAY);
}
/**
- * Gets a calendar for locale bootstrapped with the value of a given calendar.
+ * The legacy text color might have been poorly defined. Ensures that it
+ * has an appropriate activated state, using the selected state if one
+ * exists or modifying the default text color otherwise.
*
- * @param oldCalendar The old calendar.
- * @param locale The locale.
+ * @param color a legacy text color, or {@code null}
+ * @return a color state list with an appropriate activated state, or
+ * {@code null} if a valid activated state could not be generated
*/
- private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) {
- if (oldCalendar == null) {
- return Calendar.getInstance(locale);
+ @Nullable
+ private ColorStateList applyLegacyColorFixes(@Nullable ColorStateList color) {
+ if (color == null || color.hasState(R.attr.state_activated)) {
+ return color;
+ }
+
+ final int activatedColor;
+ final int defaultColor;
+ if (color.hasState(R.attr.state_selected)) {
+ activatedColor = color.getColorForState(StateSet.get(
+ StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_SELECTED), 0);
+ defaultColor = color.getColorForState(StateSet.get(
+ StateSet.VIEW_STATE_ENABLED), 0);
} else {
- final long currentTimeMillis = oldCalendar.getTimeInMillis();
- Calendar newCalendar = Calendar.getInstance(locale);
- newCalendar.setTimeInMillis(currentTimeMillis);
- return newCalendar;
+ activatedColor = color.getDefaultColor();
+
+ // Generate a non-activated color using the disabled alpha.
+ final TypedArray ta = mContext.obtainStyledAttributes(ATTRS_DISABLED_ALPHA);
+ final float disabledAlpha = ta.getFloat(0, 0.30f);
+ defaultColor = multiplyAlphaComponent(activatedColor, disabledAlpha);
+ }
+
+ if (activatedColor == 0 || defaultColor == 0) {
+ // We somehow failed to obtain the colors.
+ return null;
}
+
+ final int[][] stateSet = new int[][] {{ R.attr.state_activated }, {}};
+ final int[] colors = new int[] { activatedColor, defaultColor };
+ return new ColorStateList(stateSet, colors);
+ }
+
+ private int multiplyAlphaComponent(int color, float alphaMod) {
+ final int srcRgb = color & 0xFFFFFF;
+ final int srcAlpha = (color >> 24) & 0xFF;
+ final int dstAlpha = (int) (srcAlpha * alphaMod + 0.5f);
+ return srcRgb | (dstAlpha << 24);
}
/**
- * Compute the array representing the order of Month / Day / Year views in their layout.
- * Will be used for I18N purpose as the order of them depends on the Locale.
+ * Listener called when the user selects a day in the day picker view.
+ */
+ private final OnDaySelectedListener mOnDaySelectedListener = new OnDaySelectedListener() {
+ @Override
+ public void onDaySelected(DayPickerView view, Calendar day) {
+ mCurrentDate.setTimeInMillis(day.getTimeInMillis());
+ onDateChanged(true, true);
+ }
+ };
+
+ /**
+ * Listener called when the user selects a year in the year picker view.
*/
- private int[] getMonthDayYearIndexes(String pattern) {
- int[] result = new int[3];
+ private final OnYearSelectedListener mOnYearSelectedListener = new OnYearSelectedListener() {
+ @Override
+ public void onYearChanged(YearPickerView view, int year) {
+ // If the newly selected month / year does not contain the
+ // currently selected day number, change the selected day number
+ // to the last day of the selected month or year.
+ // e.g. Switching from Mar to Apr when Mar 31 is selected -> Apr 30
+ // e.g. Switching from 2012 to 2013 when Feb 29, 2012 is selected -> Feb 28, 2013
+ final int day = mCurrentDate.get(Calendar.DAY_OF_MONTH);
+ final int month = mCurrentDate.get(Calendar.MONTH);
+ final int daysInMonth = getDaysInMonth(month, year);
+ if (day > daysInMonth) {
+ mCurrentDate.set(Calendar.DAY_OF_MONTH, daysInMonth);
+ }
- final String filteredPattern = pattern.replaceAll("'.*?'", "");
+ mCurrentDate.set(Calendar.YEAR, year);
+ onDateChanged(true, true);
- final int dayIndex = filteredPattern.indexOf('d');
- final int monthMIndex = filteredPattern.indexOf("M");
- final int monthIndex = (monthMIndex != -1) ? monthMIndex : filteredPattern.indexOf("L");
- final int yearIndex = filteredPattern.indexOf("y");
+ // Automatically switch to day picker.
+ setCurrentView(VIEW_MONTH_DAY);
+ }
+ };
- if (yearIndex < monthIndex) {
- result[YEAR_INDEX] = 0;
+ /**
+ * Listener called when the user clicks on a header item.
+ */
+ private final OnClickListener mOnHeaderClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ tryVibrate();
- if (monthIndex < dayIndex) {
- result[MONTH_INDEX] = 1;
- result[DAY_INDEX] = 2;
- } else {
- result[MONTH_INDEX] = 2;
- result[DAY_INDEX] = 1;
- }
- } else {
- result[YEAR_INDEX] = 2;
-
- if (monthIndex < dayIndex) {
- result[MONTH_INDEX] = 0;
- result[DAY_INDEX] = 1;
- } else {
- result[MONTH_INDEX] = 1;
- result[DAY_INDEX] = 0;
+ switch (v.getId()) {
+ case R.id.date_picker_header_year:
+ setCurrentView(VIEW_YEAR);
+ break;
+ case R.id.date_picker_header_date:
+ setCurrentView(VIEW_MONTH_DAY);
+ break;
}
}
- return result;
- }
+ };
- private void updateDisplay(boolean announce) {
- if (mDayOfWeekView != null) {
- mDayOfWeekView.setText(mCurrentDate.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG,
- Locale.getDefault()));
+ @Override
+ protected void onLocaleChanged(Locale locale) {
+ final TextView headerYear = mHeaderYear;
+ if (headerYear == null) {
+ // Abort, we haven't initialized yet. This method will get called
+ // again later after everything has been set up.
+ return;
}
- // Compute indices of Month, Day and Year views
- final String bestDateTimePattern =
- DateFormat.getBestDateTimePattern(mCurrentLocale, "yMMMd");
- final int[] viewIndices = getMonthDayYearIndexes(bestDateTimePattern);
+ // Update the date formatter.
+ final String datePattern = DateFormat.getBestDateTimePattern(locale, "EMMMd");
+ mMonthDayFormat = new SimpleDateFormat(datePattern, locale);
+ mYearFormat = new SimpleDateFormat("y", locale);
- // Position the Year and MonthAndDay views within the header.
- mMonthDayYearLayout.removeAllViews();
- if (viewIndices[YEAR_INDEX] == 0) {
- mMonthDayYearLayout.addView(mHeaderYearTextView);
- mMonthDayYearLayout.addView(mMonthAndDayLayout);
- } else {
- mMonthDayYearLayout.addView(mMonthAndDayLayout);
- mMonthDayYearLayout.addView(mHeaderYearTextView);
- }
+ // Update the header text.
+ onCurrentDateChanged(false);
+ }
- // Position Day and Month views within the MonthAndDay view.
- mMonthAndDayLayout.removeAllViews();
- if (viewIndices[MONTH_INDEX] > viewIndices[DAY_INDEX]) {
- mMonthAndDayLayout.addView(mHeaderDayOfMonthTextView);
- mMonthAndDayLayout.addView(mHeaderMonthTextView);
- } else {
- mMonthAndDayLayout.addView(mHeaderMonthTextView);
- mMonthAndDayLayout.addView(mHeaderDayOfMonthTextView);
+ private void onCurrentDateChanged(boolean announce) {
+ if (mHeaderYear == null) {
+ // Abort, we haven't initialized yet. This method will get called
+ // again later after everything has been set up.
+ return;
}
- mHeaderMonthTextView.setText(mCurrentDate.getDisplayName(Calendar.MONTH, Calendar.SHORT,
- Locale.getDefault()).toUpperCase(Locale.getDefault()));
- mHeaderDayOfMonthTextView.setText(mDayFormat.format(mCurrentDate.getTime()));
- mHeaderYearTextView.setText(mYearFormat.format(mCurrentDate.getTime()));
+ final String year = mYearFormat.format(mCurrentDate.getTime());
+ mHeaderYear.setText(year);
- // Accessibility.
- long millis = mCurrentDate.getTimeInMillis();
- mAnimator.setDateMillis(millis);
- int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR;
- String monthAndDayText = DateUtils.formatDateTime(mContext, millis, flags);
- mMonthAndDayLayout.setContentDescription(monthAndDayText);
+ final String monthDay = mMonthDayFormat.format(mCurrentDate.getTime());
+ mHeaderMonthDay.setText(monthDay);
+ // TODO: This should use live regions.
if (announce) {
- flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
- String fullDateText = DateUtils.formatDateTime(mContext, millis, flags);
+ final long millis = mCurrentDate.getTimeInMillis();
+ final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
+ final String fullDateText = DateUtils.formatDateTime(mContext, millis, flags);
mAnimator.announceForAccessibility(fullDateText);
}
}
private void setCurrentView(final int viewIndex) {
- long millis = mCurrentDate.getTimeInMillis();
-
switch (viewIndex) {
- case MONTH_AND_DAY_VIEW:
- mDayPickerView.setDate(getSelectedDay().getTimeInMillis());
+ case VIEW_MONTH_DAY:
+ mDayPickerView.setDate(mCurrentDate.getTimeInMillis());
+
if (mCurrentView != viewIndex) {
- mMonthAndDayLayout.setSelected(true);
- mHeaderYearTextView.setSelected(false);
- mAnimator.setDisplayedChild(MONTH_AND_DAY_VIEW);
+ mHeaderMonthDay.setActivated(true);
+ mHeaderYear.setActivated(false);
+ mAnimator.setDisplayedChild(VIEW_MONTH_DAY);
mCurrentView = viewIndex;
}
- final int flags = DateUtils.FORMAT_SHOW_DATE;
- final String dayString = DateUtils.formatDateTime(mContext, millis, flags);
- mAnimator.setContentDescription(mDayPickerDescription + ": " + dayString);
mAnimator.announceForAccessibility(mSelectDay);
break;
- case YEAR_VIEW:
- mYearPickerView.onDateChanged();
+ case VIEW_YEAR:
+ mYearPickerView.setDate(mCurrentDate.getTimeInMillis());
+
if (mCurrentView != viewIndex) {
- mMonthAndDayLayout.setSelected(false);
- mHeaderYearTextView.setSelected(true);
- mAnimator.setDisplayedChild(YEAR_VIEW);
+ mHeaderMonthDay.setActivated(false);
+ mHeaderYear.setActivated(true);
+ mAnimator.setDisplayedChild(VIEW_YEAR);
mCurrentView = viewIndex;
}
- final CharSequence yearString = mYearFormat.format(millis);
- mAnimator.setContentDescription(mYearPickerDescription + ": " + yearString);
mAnimator.announceForAccessibility(mSelectYear);
break;
}
@@ -383,20 +402,18 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
}
private void onDateChanged(boolean fromUser, boolean callbackToClient) {
+ final int year = mCurrentDate.get(Calendar.YEAR);
+
if (callbackToClient && mDateChangedListener != null) {
- final int year = mCurrentDate.get(Calendar.YEAR);
final int monthOfYear = mCurrentDate.get(Calendar.MONTH);
final int dayOfMonth = mCurrentDate.get(Calendar.DAY_OF_MONTH);
mDateChangedListener.onDateChanged(mDelegator, year, monthOfYear, dayOfMonth);
}
- for (OnDateChangedListener listener : mListeners) {
- listener.onDateChanged();
- }
-
- mDayPickerView.setDate(getSelectedDay().getTimeInMillis());
+ mDayPickerView.setDate(mCurrentDate.getTimeInMillis());
+ mYearPickerView.setYear(year);
- updateDisplay(fromUser);
+ onCurrentDateChanged(fromUser);
if (fromUser) {
tryVibrate();
@@ -477,15 +494,12 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
@Override
public void setEnabled(boolean enabled) {
- mMonthAndDayLayout.setEnabled(enabled);
- mHeaderYearTextView.setEnabled(enabled);
- mAnimator.setEnabled(enabled);
- mIsEnabled = enabled;
+ mContainer.setEnabled(false);
}
@Override
public boolean isEnabled() {
- return mIsEnabled;
+ return mContainer.isEnabled();
}
@Override
@@ -516,8 +530,7 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
@Override
public void onConfigurationChanged(Configuration newConfig) {
- mYearFormat = new SimpleDateFormat("y", newConfig.locale);
- mDayFormat = new SimpleDateFormat("d", newConfig.locale);
+ setCurrentLocale(newConfig.locale);
}
@Override
@@ -529,9 +542,9 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
int listPosition = -1;
int listPositionOffset = -1;
- if (mCurrentView == MONTH_AND_DAY_VIEW) {
+ if (mCurrentView == VIEW_MONTH_DAY) {
listPosition = mDayPickerView.getMostVisiblePosition();
- } else if (mCurrentView == YEAR_VIEW) {
+ } else if (mCurrentView == VIEW_YEAR) {
listPosition = mYearPickerView.getFirstVisiblePosition();
listPositionOffset = mYearPickerView.getFirstPositionOffset();
}
@@ -544,20 +557,22 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
public void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
+ // TODO: Move instance state into DayPickerView, YearPickerView.
mCurrentDate.set(ss.getSelectedYear(), ss.getSelectedMonth(), ss.getSelectedDay());
mCurrentView = ss.getCurrentView();
mMinDate.setTimeInMillis(ss.getMinDate());
mMaxDate.setTimeInMillis(ss.getMaxDate());
- updateDisplay(false);
+ onCurrentDateChanged(false);
setCurrentView(mCurrentView);
final int listPosition = ss.getListPosition();
if (listPosition != -1) {
- if (mCurrentView == MONTH_AND_DAY_VIEW) {
- mDayPickerView.postSetSelection(listPosition);
- } else if (mCurrentView == YEAR_VIEW) {
- mYearPickerView.postSetSelectionFromTop(listPosition, ss.getListPositionOffset());
+ if (mCurrentView == VIEW_MONTH_DAY) {
+ mDayPickerView.setCurrentItem(listPosition);
+ } else if (mCurrentView == VIEW_YEAR) {
+ final int listPositionOffset = ss.getListPositionOffset();
+ mYearPickerView.setSelectionFromTop(listPosition, listPositionOffset);
}
}
}
@@ -577,28 +592,6 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
return DatePicker.class.getName();
}
- @Override
- public void onYearSelected(int year) {
- adjustDayInMonthIfNeeded(mCurrentDate.get(Calendar.MONTH), year);
- mCurrentDate.set(Calendar.YEAR, year);
- onDateChanged(true, true);
-
- // Auto-advance to month and day view.
- setCurrentView(MONTH_AND_DAY_VIEW);
- }
-
- // If the newly selected month / year does not contain the currently selected day number,
- // change the selected day number to the last day of the selected month or year.
- // e.g. Switching from Mar to Apr when Mar 31 is selected -> Apr 30
- // e.g. Switching from 2012 to 2013 when Feb 29, 2012 is selected -> Feb 28, 2013
- private void adjustDayInMonthIfNeeded(int month, int year) {
- int day = mCurrentDate.get(Calendar.DAY_OF_MONTH);
- int daysInMonth = getDaysInMonth(month, year);
- if (day > daysInMonth) {
- mCurrentDate.set(Calendar.DAY_OF_MONTH, daysInMonth);
- }
- }
-
public static int getDaysInMonth(int month, int year) {
switch (month) {
case Calendar.JANUARY:
@@ -621,43 +614,10 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
}
}
- @Override
- public void registerOnDateChangedListener(OnDateChangedListener listener) {
- mListeners.add(listener);
- }
-
- @Override
- public Calendar getSelectedDay() {
- return mCurrentDate;
- }
-
- @Override
- public void tryVibrate() {
+ private void tryVibrate() {
mDelegator.performHapticFeedback(HapticFeedbackConstants.CALENDAR_DATE);
}
- @Override
- public void onClick(View v) {
- tryVibrate();
- if (v.getId() == R.id.date_picker_year) {
- setCurrentView(YEAR_VIEW);
- } else if (v.getId() == R.id.date_picker_month_and_day_layout) {
- setCurrentView(MONTH_AND_DAY_VIEW);
- }
- }
-
- /**
- * Listener called when the user selects a day in the day picker view.
- */
- private final DayPickerView.OnDaySelectedListener
- mOnDaySelectedListener = new DayPickerView.OnDaySelectedListener() {
- @Override
- public void onDaySelected(DayPickerView view, Calendar day) {
- mCurrentDate.setTimeInMillis(day.getTimeInMillis());
- onDateChanged(true, true);
- }
- };
-
/**
* Class for managing state storing/restoring.
*/
diff --git a/core/java/android/widget/DayPickerAdapter.java b/core/java/android/widget/DayPickerAdapter.java
new file mode 100644
index 000000000000..4f9f09e315c2
--- /dev/null
+++ b/core/java/android/widget/DayPickerAdapter.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import com.android.internal.widget.PagerAdapter;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.util.SparseArray;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.SimpleMonthView.OnDayClickListener;
+
+import java.util.Calendar;
+
+/**
+ * An adapter for a list of {@link android.widget.SimpleMonthView} items.
+ */
+class DayPickerAdapter extends PagerAdapter {
+ private static final int MONTHS_IN_YEAR = 12;
+
+ private final Calendar mMinDate = Calendar.getInstance();
+ private final Calendar mMaxDate = Calendar.getInstance();
+
+ private final SparseArray<SimpleMonthView> mItems = new SparseArray<>();
+
+ private Calendar mSelectedDay = Calendar.getInstance();
+
+ private int mMonthTextAppearance;
+ private int mDayOfWeekTextAppearance;
+ private int mDayTextAppearance;
+
+ private ColorStateList mCalendarTextColor;
+ private ColorStateList mDaySelectorColor;
+ private ColorStateList mDayHighlightColor;
+
+ private OnDaySelectedListener mOnDaySelectedListener;
+
+ private int mFirstDayOfWeek;
+
+ public DayPickerAdapter(Context context) {
+ final TypedArray ta = context.obtainStyledAttributes(new int[] {
+ com.android.internal.R.attr.colorControlHighlight});
+ mDayHighlightColor = ta.getColorStateList(0);
+ ta.recycle();
+ }
+
+ public void setRange(Calendar min, Calendar max) {
+ mMinDate.setTimeInMillis(min.getTimeInMillis());
+ mMaxDate.setTimeInMillis(max.getTimeInMillis());
+
+ // Positions are now invalid, clear everything and start over.
+ notifyDataSetChanged();
+ }
+
+ /**
+ * Sets the first day of the week.
+ *
+ * @param weekStart which day the week should start on, valid values are
+ * {@link Calendar#SUNDAY} through {@link Calendar#SATURDAY}
+ */
+ public void setFirstDayOfWeek(int weekStart) {
+ mFirstDayOfWeek = weekStart;
+
+ // Update displayed views.
+ final int count = mItems.size();
+ for (int i = 0; i < count; i++) {
+ final SimpleMonthView monthView = mItems.valueAt(i);
+ monthView.setFirstDayOfWeek(weekStart);
+ }
+ }
+
+ public int getFirstDayOfWeek() {
+ return mFirstDayOfWeek;
+ }
+
+ /**
+ * Sets the selected day.
+ *
+ * @param day the selected day
+ */
+ public void setSelectedDay(Calendar day) {
+ final int oldPosition = getPositionForDay(mSelectedDay);
+ final int newPosition = getPositionForDay(day);
+
+ // Clear the old position if necessary.
+ if (oldPosition != newPosition) {
+ final SimpleMonthView oldMonthView = mItems.get(oldPosition, null);
+ if (oldMonthView != null) {
+ oldMonthView.setSelectedDay(-1);
+ }
+ }
+
+ // Set the new position.
+ final SimpleMonthView newMonthView = mItems.get(newPosition, null);
+ if (newMonthView != null) {
+ final int dayOfMonth = day.get(Calendar.DAY_OF_MONTH);
+ newMonthView.setSelectedDay(dayOfMonth);
+ }
+
+ mSelectedDay = day;
+ }
+
+ /**
+ * Sets the listener to call when the user selects a day.
+ *
+ * @param listener The listener to call.
+ */
+ public void setOnDaySelectedListener(OnDaySelectedListener listener) {
+ mOnDaySelectedListener = listener;
+ }
+
+ void setCalendarTextColor(ColorStateList calendarTextColor) {
+ mCalendarTextColor = calendarTextColor;
+ }
+
+ void setDaySelectorColor(ColorStateList selectorColor) {
+ mDaySelectorColor = selectorColor;
+ }
+
+ void setMonthTextAppearance(int resId) {
+ mMonthTextAppearance = resId;
+ }
+
+ void setDayOfWeekTextAppearance(int resId) {
+ mDayOfWeekTextAppearance = resId;
+ }
+
+ int getDayOfWeekTextAppearance() {
+ return mDayOfWeekTextAppearance;
+ }
+
+ void setDayTextAppearance(int resId) {
+ mDayTextAppearance = resId;
+ }
+
+ int getDayTextAppearance() {
+ return mDayTextAppearance;
+ }
+
+ @Override
+ public int getCount() {
+ final int diffYear = mMaxDate.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR);
+ final int diffMonth = mMaxDate.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH);
+ return diffMonth + MONTHS_IN_YEAR * diffYear + 1;
+ }
+
+ @Override
+ public boolean isViewFromObject(View view, Object object) {
+ return view == object;
+ }
+
+ private int getMonthForPosition(int position) {
+ return position % MONTHS_IN_YEAR + mMinDate.get(Calendar.MONTH);
+ }
+
+ private int getYearForPosition(int position) {
+ return position / MONTHS_IN_YEAR + mMinDate.get(Calendar.YEAR);
+ }
+
+ private int getPositionForDay(Calendar day) {
+ final int yearOffset = (day.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR));
+ final int monthOffset = (day.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH));
+ return yearOffset * MONTHS_IN_YEAR + monthOffset;
+ }
+
+ @Override
+ public Object instantiateItem(ViewGroup container, int position) {
+ final SimpleMonthView v = new SimpleMonthView(container.getContext());
+ v.setOnDayClickListener(mOnDayClickListener);
+ v.setMonthTextAppearance(mMonthTextAppearance);
+ v.setDayOfWeekTextAppearance(mDayOfWeekTextAppearance);
+ v.setDayTextAppearance(mDayTextAppearance);
+
+ if (mDaySelectorColor != null) {
+ v.setDaySelectorColor(mDaySelectorColor);
+ }
+
+ if (mDayHighlightColor != null) {
+ v.setDayHighlightColor(mDayHighlightColor);
+ }
+
+ if (mCalendarTextColor != null) {
+ v.setMonthTextColor(mCalendarTextColor);
+ v.setDayOfWeekTextColor(mCalendarTextColor);
+ v.setDayTextColor(mCalendarTextColor);
+ }
+
+ final int month = getMonthForPosition(position);
+ final int year = getYearForPosition(position);
+
+ final int selectedDay;
+ if (mSelectedDay.get(Calendar.MONTH) == month) {
+ selectedDay = mSelectedDay.get(Calendar.DAY_OF_MONTH);
+ } else {
+ selectedDay = -1;
+ }
+
+ final int enabledDayRangeStart;
+ if (mMinDate.get(Calendar.MONTH) == month && mMinDate.get(Calendar.YEAR) == year) {
+ enabledDayRangeStart = mMinDate.get(Calendar.DAY_OF_MONTH);
+ } else {
+ enabledDayRangeStart = 1;
+ }
+
+ final int enabledDayRangeEnd;
+ if (mMaxDate.get(Calendar.MONTH) == month && mMaxDate.get(Calendar.YEAR) == year) {
+ enabledDayRangeEnd = mMaxDate.get(Calendar.DAY_OF_MONTH);
+ } else {
+ enabledDayRangeEnd = 31;
+ }
+
+ v.setMonthParams(selectedDay, month, year, mFirstDayOfWeek,
+ enabledDayRangeStart, enabledDayRangeEnd);
+
+ mItems.put(position, v);
+
+ container.addView(v);
+
+ return v;
+ }
+
+ @Override
+ public void destroyItem(ViewGroup container, int position, Object object) {
+ container.removeView(mItems.get(position));
+
+ mItems.remove(position);
+ }
+
+ @Override
+ public int getItemPosition(Object object) {
+ final int index = mItems.indexOfValue((SimpleMonthView) object);
+ if (index < 0) {
+ return mItems.keyAt(index);
+ }
+ return -1;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ final SimpleMonthView v = mItems.get(position);
+ if (v != null) {
+ return v.getTitle();
+ }
+ return null;
+ }
+
+ private boolean isCalendarInRange(Calendar value) {
+ return value.compareTo(mMinDate) >= 0 && value.compareTo(mMaxDate) <= 0;
+ }
+
+ private final OnDayClickListener mOnDayClickListener = new OnDayClickListener() {
+ @Override
+ public void onDayClick(SimpleMonthView view, Calendar day) {
+ if (day != null && isCalendarInRange(day)) {
+ setSelectedDay(day);
+
+ if (mOnDaySelectedListener != null) {
+ mOnDaySelectedListener.onDaySelected(DayPickerAdapter.this, day);
+ }
+ }
+ }
+ };
+
+ public interface OnDaySelectedListener {
+ public void onDaySelected(DayPickerAdapter view, Calendar day);
+ }
+}
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index 65af45d7b115..a7ae926ed467 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -16,87 +16,177 @@
package android.widget;
+import com.android.internal.widget.ViewPager;
+import com.android.internal.R;
+
import android.content.Context;
import android.content.res.ColorStateList;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.util.Log;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
import android.util.MathUtils;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
+import libcore.icu.LocaleData;
+
/**
* This displays a list of months in a calendar format with selectable days.
*/
-class DayPickerView extends ListView implements AbsListView.OnScrollListener {
- private static final String TAG = "DayPickerView";
+class DayPickerView extends ViewPager {
+ private static final int DEFAULT_START_YEAR = 1900;
+ private static final int DEFAULT_END_YEAR = 2100;
- // How long the GoTo fling animation should last
- private static final int GOTO_SCROLL_DURATION = 250;
+ private final Calendar mSelectedDay = Calendar.getInstance();
+ private final Calendar mMinDate = Calendar.getInstance();
+ private final Calendar mMaxDate = Calendar.getInstance();
- // How long to wait after receiving an onScrollStateChanged notification before acting on it
- private static final int SCROLL_CHANGE_DELAY = 40;
+ private final DayPickerAdapter mAdapter;
- // so that the top line will be under the separator
- private static final int LIST_TOP_OFFSET = -1;
+ /** Temporary calendar used for date calculations. */
+ private Calendar mTempCalendar;
- private final SimpleMonthAdapter mAdapter = new SimpleMonthAdapter(getContext());
+ private OnDaySelectedListener mOnDaySelectedListener;
- private final ScrollStateRunnable mScrollStateChangedRunnable = new ScrollStateRunnable(this);
+ public DayPickerView(Context context) {
+ this(context, null);
+ }
- private SimpleDateFormat mYearFormat = new SimpleDateFormat("yyyy", Locale.getDefault());
+ public DayPickerView(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.calendarViewStyle);
+ }
- // highlighted time
- private Calendar mSelectedDay = Calendar.getInstance();
- private Calendar mTempDay = Calendar.getInstance();
- private Calendar mMinDate = Calendar.getInstance();
- private Calendar mMaxDate = Calendar.getInstance();
+ public DayPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
- private Calendar mTempCalendar;
+ public DayPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
- private OnDaySelectedListener mOnDaySelectedListener;
+ final TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.CalendarView, defStyleAttr, defStyleRes);
- // which month should be displayed/highlighted [0-11]
- private int mCurrentMonthDisplayed;
- // used for tracking what state listview is in
- private int mPreviousScrollState = OnScrollListener.SCROLL_STATE_IDLE;
- // used for tracking what state listview is in
- private int mCurrentScrollState = OnScrollListener.SCROLL_STATE_IDLE;
+ final int firstDayOfWeek = a.getInt(R.styleable.CalendarView_firstDayOfWeek,
+ LocaleData.get(Locale.getDefault()).firstDayOfWeek);
- private boolean mPerformingScroll;
+ final String minDate = a.getString(R.styleable.CalendarView_minDate);
+ final String maxDate = a.getString(R.styleable.CalendarView_maxDate);
- public DayPickerView(Context context) {
- super(context);
+ final int monthTextAppearanceResId = a.getResourceId(
+ R.styleable.CalendarView_monthTextAppearance,
+ R.style.TextAppearance_Material_Widget_Calendar_Month);
+ final int dayOfWeekTextAppearanceResId = a.getResourceId(
+ R.styleable.CalendarView_weekDayTextAppearance,
+ R.style.TextAppearance_Material_Widget_Calendar_DayOfWeek);
+ final int dayTextAppearanceResId = a.getResourceId(
+ R.styleable.CalendarView_dateTextAppearance,
+ R.style.TextAppearance_Material_Widget_Calendar_Day);
+
+ final ColorStateList daySelectorColor = a.getColorStateList(
+ R.styleable.CalendarView_daySelectorColor);
+
+ a.recycle();
+
+ // Set up adapter.
+ mAdapter = new DayPickerAdapter(context);
+ mAdapter.setMonthTextAppearance(monthTextAppearanceResId);
+ mAdapter.setDayOfWeekTextAppearance(dayOfWeekTextAppearanceResId);
+ mAdapter.setDayTextAppearance(dayTextAppearanceResId);
+ mAdapter.setDaySelectorColor(daySelectorColor);
setAdapter(mAdapter);
- setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- setDrawSelectorOnTop(false);
- setUpListView();
- goTo(mSelectedDay.getTimeInMillis(), false, false, true);
+ // Set up min and max dates.
+ final Calendar tempDate = Calendar.getInstance();
+ if (!CalendarView.parseDate(minDate, tempDate)) {
+ tempDate.set(DEFAULT_START_YEAR, Calendar.JANUARY, 1);
+ }
+ final long minDateMillis = tempDate.getTimeInMillis();
+
+ if (!CalendarView.parseDate(maxDate, tempDate)) {
+ tempDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER, 31);
+ }
+ final long maxDateMillis = tempDate.getTimeInMillis();
+
+ if (maxDateMillis < minDateMillis) {
+ throw new IllegalArgumentException("maxDate must be >= minDate");
+ }
+
+ final long setDateMillis = MathUtils.constrain(
+ System.currentTimeMillis(), minDateMillis, maxDateMillis);
- mAdapter.setOnDaySelectedListener(mProxyOnDaySelectedListener);
+ setFirstDayOfWeek(firstDayOfWeek);
+ setMinDate(minDateMillis);
+ setMaxDate(maxDateMillis);
+ setDate(setDateMillis, false);
+
+ // Proxy selection callbacks to our own listener.
+ mAdapter.setOnDaySelectedListener(new DayPickerAdapter.OnDaySelectedListener() {
+ @Override
+ public void onDaySelected(DayPickerAdapter adapter, Calendar day) {
+ if (mOnDaySelectedListener != null) {
+ mOnDaySelectedListener.onDaySelected(DayPickerView.this, day);
+ }
+ }
+ });
+ }
+
+ public void setDayOfWeekTextAppearance(int resId) {
+ mAdapter.setDayOfWeekTextAppearance(resId);
+ }
+
+ public int getDayOfWeekTextAppearance() {
+ return mAdapter.getDayOfWeekTextAppearance();
+ }
+
+ public void setDayTextAppearance(int resId) {
+ mAdapter.setDayTextAppearance(resId);
+ }
+
+ public int getDayTextAppearance() {
+ return mAdapter.getDayTextAppearance();
}
/**
* Sets the currently selected date to the specified timestamp. Jumps
* immediately to the new date. To animate to the new date, use
- * {@link #setDate(long, boolean, boolean)}.
+ * {@link #setDate(long, boolean)}.
*
- * @param timeInMillis
+ * @param timeInMillis the target day in milliseconds
*/
public void setDate(long timeInMillis) {
- setDate(timeInMillis, false, true);
+ setDate(timeInMillis, false);
}
- public void setDate(long timeInMillis, boolean animate, boolean forceScroll) {
- goTo(timeInMillis, animate, true, forceScroll);
+ /**
+ * Sets the currently selected date to the specified timestamp. Jumps
+ * immediately to the new date, optionally animating the transition.
+ *
+ * @param timeInMillis the target day in milliseconds
+ * @param animate whether to smooth scroll to the new position
+ */
+ public void setDate(long timeInMillis, boolean animate) {
+ setDate(timeInMillis, animate, true);
+ }
+
+ /**
+ * Moves to the month containing the specified day, optionally setting the
+ * day as selected.
+ *
+ * @param timeInMillis the target day in milliseconds
+ * @param animate whether to smooth scroll to the new position
+ * @param setSelected whether to set the specified day as selected
+ */
+ private void setDate(long timeInMillis, boolean animate, boolean setSelected) {
+ // Set the selected day
+ if (setSelected) {
+ mSelectedDay.setTimeInMillis(timeInMillis);
+ }
+
+ final int position = getPositionFromDay(timeInMillis);
+ if (position != getCurrentItem()) {
+ setCurrentItem(position, animate);
+ }
}
public long getDate() {
@@ -137,7 +227,7 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener {
// Changing the min/max date changes the selection position since we
// don't really have stable IDs. Jumps immediately to the new position.
- goTo(mSelectedDay.getTimeInMillis(), false, false, true);
+ setDate(mSelectedDay.getTimeInMillis(), false, false);
}
/**
@@ -149,30 +239,9 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener {
mOnDaySelectedListener = listener;
}
- /*
- * Sets all the required fields for the list view. Override this method to
- * set a different list view behavior.
- */
- private void setUpListView() {
- // Transparent background on scroll
- setCacheColorHint(0);
- // No dividers
- setDivider(null);
- // Items are clickable
- setItemsCanFocus(true);
- // The thumb gets in the way, so disable it
- setFastScrollEnabled(false);
- setVerticalScrollBarEnabled(false);
- setOnScrollListener(this);
- setFadingEdgeLength(0);
- // Make the scrolling behavior nicer
- setFriction(ViewConfiguration.getScrollFriction());
- }
-
private int getDiffMonths(Calendar start, Calendar end) {
final int diffYears = end.get(Calendar.YEAR) - start.get(Calendar.YEAR);
- final int diffMonths = end.get(Calendar.MONTH) - start.get(Calendar.MONTH) + 12 * diffYears;
- return diffMonths;
+ return end.get(Calendar.MONTH) - start.get(Calendar.MONTH) + 12 * diffYears;
}
private int getPositionFromDay(long timeInMillis) {
@@ -190,366 +259,13 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener {
}
/**
- * This moves to the specified time in the view. If the time is not already
- * in range it will move the list so that the first of the month containing
- * the time is at the top of the view. If the new time is already in view
- * the list will not be scrolled unless forceScroll is true. This time may
- * optionally be highlighted as selected as well.
- *
- * @param day The day to move to
- * @param animate Whether to scroll to the given time or just redraw at the
- * new location
- * @param setSelected Whether to set the given time as selected
- * @param forceScroll Whether to recenter even if the time is already
- * visible
- * @return Whether or not the view animated to the new location
- */
- private boolean goTo(long day, boolean animate, boolean setSelected, boolean forceScroll) {
-
- // Set the selected day
- if (setSelected) {
- mSelectedDay.setTimeInMillis(day);
- }
-
- mTempDay.setTimeInMillis(day);
- final int position = getPositionFromDay(day);
-
- View child;
- int i = 0;
- int top = 0;
- // Find a child that's completely in the view
- do {
- child = getChildAt(i++);
- if (child == null) {
- break;
- }
- top = child.getTop();
- } while (top < 0);
-
- // Compute the first and last position visible
- int selectedPosition;
- if (child != null) {
- selectedPosition = getPositionForView(child);
- } else {
- selectedPosition = 0;
- }
-
- if (setSelected) {
- mAdapter.setSelectedDay(mSelectedDay);
- }
-
- // Check if the selected day is now outside of our visible range
- // and if so scroll to the month that contains it
- if (position != selectedPosition || forceScroll) {
- setMonthDisplayed(mTempDay);
- mPreviousScrollState = OnScrollListener.SCROLL_STATE_FLING;
- if (animate) {
- smoothScrollToPositionFromTop(
- position, LIST_TOP_OFFSET, GOTO_SCROLL_DURATION);
- return true;
- } else {
- postSetSelection(position);
- }
- } else if (setSelected) {
- setMonthDisplayed(mSelectedDay);
- }
- return false;
- }
-
- public void postSetSelection(final int position) {
- clearFocus();
- post(new Runnable() {
-
- @Override
- public void run() {
- setSelection(position);
- }
- });
- onScrollStateChanged(this, OnScrollListener.SCROLL_STATE_IDLE);
- }
-
- /**
- * Updates the title and selected month if the view has moved to a new
- * month.
- */
- @Override
- public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
- int totalItemCount) {
- SimpleMonthView child = (SimpleMonthView) view.getChildAt(0);
- if (child == null) {
- return;
- }
-
- mPreviousScrollState = mCurrentScrollState;
- }
-
- /**
- * Sets the month displayed at the top of this view based on time. Override
- * to add custom events when the title is changed.
- */
- protected void setMonthDisplayed(Calendar date) {
- if (mCurrentMonthDisplayed != date.get(Calendar.MONTH)) {
- mCurrentMonthDisplayed = date.get(Calendar.MONTH);
- invalidateViews();
- }
- }
-
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- // use a post to prevent re-entering onScrollStateChanged before it
- // exits
- mScrollStateChangedRunnable.doScrollStateChange(view, scrollState);
- }
-
- void setCalendarTextColor(ColorStateList colors) {
- mAdapter.setCalendarTextColor(colors);
- }
-
- void setCalendarDayBackgroundColor(ColorStateList dayBackgroundColor) {
- mAdapter.setCalendarDayBackgroundColor(dayBackgroundColor);
- }
-
- void setCalendarTextAppearance(int resId) {
- mAdapter.setCalendarTextAppearance(resId);
- }
-
- protected class ScrollStateRunnable implements Runnable {
- private int mNewState;
- private View mParent;
-
- ScrollStateRunnable(View view) {
- mParent = view;
- }
-
- /**
- * Sets up the runnable with a short delay in case the scroll state
- * immediately changes again.
- *
- * @param view The list view that changed state
- * @param scrollState The new state it changed to
- */
- public void doScrollStateChange(AbsListView view, int scrollState) {
- mParent.removeCallbacks(this);
- mNewState = scrollState;
- mParent.postDelayed(this, SCROLL_CHANGE_DELAY);
- }
-
- @Override
- public void run() {
- mCurrentScrollState = mNewState;
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG,
- "new scroll state: " + mNewState + " old state: " + mPreviousScrollState);
- }
- // Fix the position after a scroll or a fling ends
- if (mNewState == OnScrollListener.SCROLL_STATE_IDLE
- && mPreviousScrollState != OnScrollListener.SCROLL_STATE_IDLE
- && mPreviousScrollState != OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
- mPreviousScrollState = mNewState;
- int i = 0;
- View child = getChildAt(i);
- while (child != null && child.getBottom() <= 0) {
- child = getChildAt(++i);
- }
- if (child == null) {
- // The view is no longer visible, just return
- return;
- }
- int firstPosition = getFirstVisiblePosition();
- int lastPosition = getLastVisiblePosition();
- boolean scroll = firstPosition != 0 && lastPosition != getCount() - 1;
- final int top = child.getTop();
- final int bottom = child.getBottom();
- final int midpoint = getHeight() / 2;
- if (scroll && top < LIST_TOP_OFFSET) {
- if (bottom > midpoint) {
- smoothScrollBy(top, GOTO_SCROLL_DURATION);
- } else {
- smoothScrollBy(bottom, GOTO_SCROLL_DURATION);
- }
- }
- } else {
- mPreviousScrollState = mNewState;
- }
- }
- }
-
- /**
* Gets the position of the view that is most prominently displayed within the list view.
*/
public int getMostVisiblePosition() {
- final int firstPosition = getFirstVisiblePosition();
- final int height = getHeight();
-
- int maxDisplayedHeight = 0;
- int mostVisibleIndex = 0;
- int i=0;
- int bottom = 0;
- while (bottom < height) {
- View child = getChildAt(i);
- if (child == null) {
- break;
- }
- bottom = child.getBottom();
- int displayedHeight = Math.min(bottom, height) - Math.max(0, child.getTop());
- if (displayedHeight > maxDisplayedHeight) {
- mostVisibleIndex = i;
- maxDisplayedHeight = displayedHeight;
- }
- i++;
- }
- return firstPosition + mostVisibleIndex;
- }
-
- /**
- * Attempts to return the date that has accessibility focus.
- *
- * @return The date that has accessibility focus, or {@code null} if no date
- * has focus.
- */
- private Calendar findAccessibilityFocus() {
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
- if (child instanceof SimpleMonthView) {
- final Calendar focus = ((SimpleMonthView) child).getAccessibilityFocus();
- if (focus != null) {
- return focus;
- }
- }
- }
-
- return null;
- }
-
- /**
- * Attempts to restore accessibility focus to a given date. No-op if
- * {@code day} is {@code null}.
- *
- * @param day The date that should receive accessibility focus
- * @return {@code true} if focus was restored
- */
- private boolean restoreAccessibilityFocus(Calendar day) {
- if (day == null) {
- return false;
- }
-
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
- if (child instanceof SimpleMonthView) {
- if (((SimpleMonthView) child).restoreAccessibilityFocus(day)) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- @Override
- protected void layoutChildren() {
- final Calendar focusedDay = findAccessibilityFocus();
- super.layoutChildren();
- if (mPerformingScroll) {
- mPerformingScroll = false;
- } else {
- restoreAccessibilityFocus(focusedDay);
- }
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- mYearFormat = new SimpleDateFormat("yyyy", Locale.getDefault());
- }
-
- /** @hide */
- @Override
- public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
- super.onInitializeAccessibilityEventInternal(event);
- event.setItemCount(-1);
- }
-
- private String getMonthAndYearString(Calendar day) {
- final StringBuilder sbuf = new StringBuilder();
- sbuf.append(day.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault()));
- sbuf.append(" ");
- sbuf.append(mYearFormat.format(day.getTime()));
- return sbuf.toString();
- }
-
- /**
- * Necessary for accessibility, to ensure we support "scrolling" forward and backward
- * in the month list.
- *
- * @hide
- */
- @Override
- public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfoInternal(info);
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
- }
-
- /**
- * When scroll forward/backward events are received, announce the newly scrolled-to month.
- *
- * @hide
- */
- @Override
- public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
- if (action != AccessibilityNodeInfo.ACTION_SCROLL_FORWARD &&
- action != AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) {
- return super.performAccessibilityActionInternal(action, arguments);
- }
-
- // Figure out what month is showing.
- final int firstVisiblePosition = getFirstVisiblePosition();
- final int month = firstVisiblePosition % 12;
- final int year = firstVisiblePosition / 12 + mMinDate.get(Calendar.YEAR);
- final Calendar day = Calendar.getInstance();
- day.set(year, month, 1);
-
- // Scroll either forward or backward one month.
- if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD) {
- day.add(Calendar.MONTH, 1);
- if (day.get(Calendar.MONTH) == 12) {
- day.set(Calendar.MONTH, 0);
- day.add(Calendar.YEAR, 1);
- }
- } else if (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) {
- View firstVisibleView = getChildAt(0);
- // If the view is fully visible, jump one month back. Otherwise, we'll just jump
- // to the first day of first visible month.
- if (firstVisibleView != null && firstVisibleView.getTop() >= -1) {
- // There's an off-by-one somewhere, so the top of the first visible item will
- // actually be -1 when it's at the exact top.
- day.add(Calendar.MONTH, -1);
- if (day.get(Calendar.MONTH) == -1) {
- day.set(Calendar.MONTH, 11);
- day.add(Calendar.YEAR, -1);
- }
- }
- }
-
- // Go to that month.
- announceForAccessibility(getMonthAndYearString(day));
- goTo(day.getTimeInMillis(), true, false, true);
- mPerformingScroll = true;
- return true;
+ return getCurrentItem();
}
public interface OnDaySelectedListener {
public void onDaySelected(DayPickerView view, Calendar day);
}
-
- private final SimpleMonthAdapter.OnDaySelectedListener
- mProxyOnDaySelectedListener = new SimpleMonthAdapter.OnDaySelectedListener() {
- @Override
- public void onDaySelected(SimpleMonthAdapter adapter, Calendar day) {
- if (mOnDaySelectedListener != null) {
- mOnDaySelectedListener.onDaySelected(DayPickerView.this, day);
- }
- }
- };
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 3fca463ee9f3..6e2483735a11 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3348,7 +3348,7 @@ public class Editor {
// Minimum touch target size for handles
private int mMinSize;
// Indicates the line of text that the handle is on.
- protected int mLine = -1;
+ protected int mPrevLine = -1;
public HandleView(Drawable drawableLtr, Drawable drawableRtl) {
super(mTextView.getContext());
@@ -3499,7 +3499,7 @@ public class Editor {
addPositionToTouchUpFilter(offset);
}
final int line = layout.getLineForOffset(offset);
- mLine = line;
+ mPrevLine = line;
mPositionX = (int) (layout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX -
getHorizontalOffset() + getCursorOffset());
@@ -3839,19 +3839,22 @@ public class Editor {
public void updatePosition(float x, float y) {
final int trueOffset = mTextView.getOffsetForPosition(x, y);
final int currLine = mTextView.getLineAtCoordinate(y);
- int offset = trueOffset;
- boolean positionCursor = false;
+ // Don't select white space on different lines.
+ if (isWhitespaceLine(mPrevLine, currLine, trueOffset)) return;
+
+ boolean positionCursor = false;
+ int offset = trueOffset;
int end = getWordEnd(offset, true);
int start = getWordStart(offset);
if (offset < mPrevOffset) {
// User is increasing the selection.
- if (!mInWord || currLine < mLine) {
+ if (!mInWord || currLine < mPrevLine) {
// We're not in a word, or we're on a different line so we'll expand by
// word. First ensure the user has at least entered the next word.
int offsetToWord = Math.min((end - start) / 2, 2);
- if (offset <= end - offsetToWord || currLine < mLine) {
+ if (offset <= end - offsetToWord || currLine < mPrevLine) {
offset = start;
} else {
offset = mPrevOffset;
@@ -3863,7 +3866,7 @@ public class Editor {
positionCursor = true;
} else if (offset - mTouchWordOffset > mPrevOffset) {
// User is shrinking the selection.
- if (currLine > mLine) {
+ if (currLine > mPrevLine) {
// We're on a different line, so we'll snap to word boundaries.
offset = end;
}
@@ -3878,7 +3881,7 @@ public class Editor {
final int selectionEnd = mTextView.getSelectionEnd();
if (offset >= selectionEnd) {
// We can't cross the handles so let's just constrain the Y value.
- int alteredOffset = mTextView.getOffsetAtCoordinate(mLine, x);
+ int alteredOffset = mTextView.getOffsetAtCoordinate(mPrevLine, x);
if (alteredOffset >= selectionEnd) {
// Can't pass the other drag handle.
offset = Math.max(0, selectionEnd - 1);
@@ -3939,6 +3942,10 @@ public class Editor {
public void updatePosition(float x, float y) {
final int trueOffset = mTextView.getOffsetForPosition(x, y);
final int currLine = mTextView.getLineAtCoordinate(y);
+
+ // Don't select white space on different lines.
+ if (isWhitespaceLine(mPrevLine, currLine, trueOffset)) return;
+
int offset = trueOffset;
boolean positionCursor = false;
@@ -3947,11 +3954,11 @@ public class Editor {
if (offset > mPrevOffset) {
// User is increasing the selection.
- if (!mInWord || currLine > mLine) {
+ if (!mInWord || currLine > mPrevLine) {
// We're not in a word, or we're on a different line so we'll expand by
// word. First ensure the user has at least entered the next word.
int midPoint = Math.min((end - start) / 2, 2);
- if (offset >= start + midPoint || currLine > mLine) {
+ if (offset >= start + midPoint || currLine > mPrevLine) {
offset = end;
} else {
offset = mPrevOffset;
@@ -3963,7 +3970,7 @@ public class Editor {
positionCursor = true;
} else if (offset + mTouchWordOffset < mPrevOffset) {
// User is shrinking the selection.
- if (currLine > mLine) {
+ if (currLine > mPrevLine) {
// We're on a different line, so we'll snap to word boundaries.
offset = getWordStart(offset);
}
@@ -3977,7 +3984,7 @@ public class Editor {
final int selectionStart = mTextView.getSelectionStart();
if (offset <= selectionStart) {
// We can't cross the handles so let's just constrain the Y value.
- int alteredOffset = mTextView.getOffsetAtCoordinate(mLine, x);
+ int alteredOffset = mTextView.getOffsetAtCoordinate(mPrevLine, x);
int length = mTextView.getText().length();
if (alteredOffset <= selectionStart) {
// Can't pass the other drag handle.
@@ -4002,6 +4009,36 @@ public class Editor {
}
/**
+ * Checks whether selection is happening on a different line than previous and
+ * if that line only contains whitespace up to the touch location.
+ *
+ * @param prevLine The previous line the selection was on.
+ * @param currLine The current line being selected.
+ * @param offset The offset in the text where the touch occurred.
+ * @return Whether or not it was just a white space line being selected.
+ */
+ private boolean isWhitespaceLine(int prevLine, int currLine, int offset) {
+ if (prevLine == currLine) {
+ // Same line; don't care.
+ return false;
+ }
+ CharSequence text = mTextView.getText();
+ if (offset == text.length()) {
+ // No character at the last position.
+ return false;
+ }
+ int lineEndOffset = mTextView.getLayout().getLineEnd(currLine);
+ for (int cp, i = offset; i < lineEndOffset; i += Character.charCount(cp)) {
+ cp = Character.codePointAt(text, i);
+ if (!Character.isSpaceChar(cp) && !Character.isWhitespace(cp)) {
+ // There are non white space chars on the line.
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
* A CursorController instance can be used to control a cursor in the text.
*/
private interface CursorController extends ViewTreeObserver.OnTouchModeChangeListener {
@@ -4081,6 +4118,8 @@ public class Editor {
private int mStartOffset = -1;
// Indicates whether the user is selecting text and using the drag accelerator.
private boolean mDragAcceleratorActive;
+ // Indicates the line of text the drag accelerator is on.
+ private int mPrevLine = -1;
SelectionModifierCursorController() {
resetTouchOffsets();
@@ -4173,6 +4212,8 @@ public class Editor {
}
}
+ // New selection, reset line.
+ mPrevLine = mTextView.getLineAtCoordinate(y);
mDownPositionX = x;
mDownPositionY = y;
mGestureStayedInTapRegion = true;
@@ -4229,6 +4270,13 @@ public class Editor {
if (my > fingerOffset) my -= fingerOffset;
offset = mTextView.getOffsetForPosition(mx, my);
+ int currLine = mTextView.getLineAtCoordinate(my);
+
+ // Don't select white space on different lines.
+ if (isWhitespaceLine(mPrevLine, currLine, offset)) return;
+
+ mPrevLine = currLine;
+
// Perform the check for closeness at edge of view, if we're very close
// don't adjust the offset to be in front of the finger - otherwise the
// user can't select words at the edge.
@@ -4616,8 +4664,8 @@ public class Editor {
// Otherwise the user inserted the composition.
String newText = TextUtils.substring(source, start, end);
- EditOperation edit = new EditOperation(mEditor, false, "", dstart, newText);
- recordEdit(edit);
+ EditOperation edit = new EditOperation(mEditor, "", dstart, newText);
+ recordEdit(edit, false /* forceMerge */);
return true;
}
@@ -4636,11 +4684,15 @@ public class Editor {
// Build a new operation with all the information from this edit.
String newText = TextUtils.substring(source, start, end);
String oldText = TextUtils.substring(dest, dstart, dend);
- EditOperation edit = new EditOperation(mEditor, forceMerge, oldText, dstart, newText);
- recordEdit(edit);
+ EditOperation edit = new EditOperation(mEditor, oldText, dstart, newText);
+ recordEdit(edit, forceMerge);
}
- private void recordEdit(EditOperation edit) {
+ /**
+ * Fetches the last undo operation and checks to see if a new edit should be merged into it.
+ * If forceMerge is true then the new edit is always merged.
+ */
+ private void recordEdit(EditOperation edit, boolean forceMerge) {
// Fetch the last edit operation and attempt to merge in the new edit.
final UndoManager um = mEditor.mUndoManager;
um.beginUpdate("Edit text");
@@ -4650,6 +4702,11 @@ public class Editor {
// Add this as the first edit.
if (DEBUG_UNDO) Log.d(TAG, "filter: adding first op " + edit);
um.addOperation(edit, UndoManager.MERGE_MODE_NONE);
+ } else if (forceMerge) {
+ // Forced merges take priority because they could be the result of a non-user-edit
+ // change and this case should not create a new undo operation.
+ if (DEBUG_UNDO) Log.d(TAG, "filter: force merge " + edit);
+ lastEdit.forceMergeWith(edit);
} else if (!mIsUserEdit) {
// An application directly modified the Editable outside of a text edit. Treat this
// as a new change and don't attempt to merge.
@@ -4725,7 +4782,6 @@ public class Editor {
private static final int TYPE_REPLACE = 2;
private int mType;
- private boolean mForceMerge;
private String mOldText;
private int mOldTextStart;
private String mNewText;
@@ -4736,13 +4792,10 @@ public class Editor {
/**
* Constructs an edit operation from a text input operation on editor that replaces the
- * oldText starting at dstart with newText. If forceMerge is true then always forcibly
- * merge this operation with any previous one.
+ * oldText starting at dstart with newText.
*/
- public EditOperation(Editor editor, boolean forceMerge, String oldText, int dstart,
- String newText) {
+ public EditOperation(Editor editor, String oldText, int dstart, String newText) {
super(editor.mUndoOwner);
- mForceMerge = forceMerge;
mOldText = oldText;
mNewText = newText;
@@ -4769,7 +4822,6 @@ public class Editor {
public EditOperation(Parcel src, ClassLoader loader) {
super(src, loader);
mType = src.readInt();
- mForceMerge = src.readInt() != 0;
mOldText = src.readString();
mOldTextStart = src.readInt();
mNewText = src.readString();
@@ -4781,7 +4833,6 @@ public class Editor {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
- dest.writeInt(mForceMerge ? 1 : 0);
dest.writeString(mOldText);
dest.writeInt(mOldTextStart);
dest.writeString(mNewText);
@@ -4833,10 +4884,6 @@ public class Editor {
Log.d(TAG, "mergeWith old " + this);
Log.d(TAG, "mergeWith new " + edit);
}
- if (edit.mForceMerge) {
- forceMergeWith(edit);
- return true;
- }
switch (mType) {
case TYPE_INSERT:
return mergeInsertWith(edit);
@@ -4894,7 +4941,7 @@ public class Editor {
* Forcibly creates a single merged edit operation by simulating the entire text
* contents being replaced.
*/
- private void forceMergeWith(EditOperation edit) {
+ public void forceMergeWith(EditOperation edit) {
if (DEBUG_UNDO) Log.d(TAG, "forceMerge");
Editor editor = getOwnerData();
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index f6d198b214e9..0602944e0de6 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -53,8 +53,6 @@ import com.android.internal.R;
* only if {@link #setMeasureAllChildren(boolean) setConsiderGoneChildrenWhenMeasuring()}
* is set to true.
*
- * @attr ref android.R.styleable#FrameLayout_foreground
- * @attr ref android.R.styleable#FrameLayout_foregroundGravity
* @attr ref android.R.styleable#FrameLayout_measureAllChildren
*/
@RemoteView
@@ -64,13 +62,6 @@ public class FrameLayout extends ViewGroup {
@ViewDebug.ExportedProperty(category = "measurement")
boolean mMeasureAllChildren = false;
- @ViewDebug.ExportedProperty(category = "drawing")
- private Drawable mForeground;
- private ColorStateList mForegroundTintList = null;
- private PorterDuff.Mode mForegroundTintMode = null;
- private boolean mHasForegroundTint = false;
- private boolean mHasForegroundTintMode = false;
-
@ViewDebug.ExportedProperty(category = "padding")
private int mForegroundPaddingLeft = 0;
@@ -85,15 +76,6 @@ public class FrameLayout extends ViewGroup {
private final Rect mSelfBounds = new Rect();
private final Rect mOverlayBounds = new Rect();
-
- @ViewDebug.ExportedProperty(category = "drawing")
- private int mForegroundGravity = Gravity.FILL;
-
- /** {@hide} */
- @ViewDebug.ExportedProperty(category = "drawing")
- protected boolean mForegroundInPadding = true;
-
- boolean mForegroundBoundsChanged = false;
private final ArrayList<View> mMatchParentChildren = new ArrayList<View>(1);
@@ -115,48 +97,12 @@ public class FrameLayout extends ViewGroup {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.FrameLayout, defStyleAttr, defStyleRes);
-
- mForegroundGravity = a.getInt(
- com.android.internal.R.styleable.FrameLayout_foregroundGravity, mForegroundGravity);
-
- final Drawable d = a.getDrawable(com.android.internal.R.styleable.FrameLayout_foreground);
- if (d != null) {
- setForeground(d);
- }
if (a.getBoolean(com.android.internal.R.styleable.FrameLayout_measureAllChildren, false)) {
setMeasureAllChildren(true);
}
- if (a.hasValue(R.styleable.FrameLayout_foregroundTintMode)) {
- mForegroundTintMode = Drawable.parseTintMode(a.getInt(
- R.styleable.FrameLayout_foregroundTintMode, -1), mForegroundTintMode);
- mHasForegroundTintMode = true;
- }
-
- if (a.hasValue(R.styleable.FrameLayout_foregroundTint)) {
- mForegroundTintList = a.getColorStateList(R.styleable.FrameLayout_foregroundTint);
- mHasForegroundTint = true;
- }
-
- mForegroundInPadding = a.getBoolean(R.styleable.FrameLayout_foregroundInsidePadding, true);
-
a.recycle();
-
- applyForegroundTint();
- }
-
- /**
- * Describes how the foreground is positioned.
- *
- * @return foreground gravity.
- *
- * @see #setForegroundGravity(int)
- *
- * @attr ref android.R.styleable#FrameLayout_foregroundGravity
- */
- public int getForegroundGravity() {
- return mForegroundGravity;
}
/**
@@ -166,25 +112,18 @@ public class FrameLayout extends ViewGroup {
*
* @see #getForegroundGravity()
*
- * @attr ref android.R.styleable#FrameLayout_foregroundGravity
+ * @attr ref android.R.styleable#View_foregroundGravity
*/
@android.view.RemotableViewMethod
public void setForegroundGravity(int foregroundGravity) {
- if (mForegroundGravity != foregroundGravity) {
- if ((foregroundGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
- foregroundGravity |= Gravity.START;
- }
-
- if ((foregroundGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
- foregroundGravity |= Gravity.TOP;
- }
-
- mForegroundGravity = foregroundGravity;
-
+ if (getForegroundGravity() != foregroundGravity) {
+ super.setForegroundGravity(foregroundGravity);
- if (mForegroundGravity == Gravity.FILL && mForeground != null) {
+ // calling get* again here because the set above may apply default constraints
+ final Drawable foreground = getForeground();
+ if (getForegroundGravity() == Gravity.FILL && foreground != null) {
Rect padding = new Rect();
- if (mForeground.getPadding(padding)) {
+ if (foreground.getPadding(padding)) {
mForegroundPaddingLeft = padding.left;
mForegroundPaddingTop = padding.top;
mForegroundPaddingRight = padding.right;
@@ -201,53 +140,6 @@ public class FrameLayout extends ViewGroup {
}
}
- @Override
- protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) {
- super.onVisibilityChanged(changedView, visibility);
-
- final Drawable dr = mForeground;
- if (dr != null) {
- final boolean visible = visibility == VISIBLE && getVisibility() == VISIBLE;
- if (visible != dr.isVisible()) {
- dr.setVisible(visible, false);
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected boolean verifyDrawable(Drawable who) {
- return super.verifyDrawable(who) || (who == mForeground);
- }
-
- @Override
- public void jumpDrawablesToCurrentState() {
- super.jumpDrawablesToCurrentState();
- if (mForeground != null) mForeground.jumpToCurrentState();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void drawableStateChanged() {
- super.drawableStateChanged();
- if (mForeground != null && mForeground.isStateful()) {
- mForeground.setState(getDrawableState());
- }
- }
-
- @Override
- public void drawableHotspotChanged(float x, float y) {
- super.drawableHotspotChanged(x, y);
-
- if (mForeground != null) {
- mForeground.setHotspot(x, y);
- }
- }
-
/**
* Returns a set of layout parameters with a width of
* {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT},
@@ -258,161 +150,23 @@ public class FrameLayout extends ViewGroup {
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
- /**
- * Supply a Drawable that is to be rendered on top of all of the child
- * views in the frame layout. Any padding in the Drawable will be taken
- * into account by ensuring that the children are inset to be placed
- * inside of the padding area.
- *
- * @param d The Drawable to be drawn on top of the children.
- *
- * @attr ref android.R.styleable#FrameLayout_foreground
- */
- public void setForeground(Drawable d) {
- if (mForeground != d) {
- if (mForeground != null) {
- mForeground.setCallback(null);
- unscheduleDrawable(mForeground);
- }
-
- mForeground = d;
- mForegroundPaddingLeft = 0;
- mForegroundPaddingTop = 0;
- mForegroundPaddingRight = 0;
- mForegroundPaddingBottom = 0;
-
- if (d != null) {
- setWillNotDraw(false);
- d.setCallback(this);
- d.setLayoutDirection(getLayoutDirection());
- if (d.isStateful()) {
- d.setState(getDrawableState());
- }
- applyForegroundTint();
- if (mForegroundGravity == Gravity.FILL) {
- Rect padding = new Rect();
- if (d.getPadding(padding)) {
- mForegroundPaddingLeft = padding.left;
- mForegroundPaddingTop = padding.top;
- mForegroundPaddingRight = padding.right;
- mForegroundPaddingBottom = padding.bottom;
- }
- }
- } else {
- setWillNotDraw(true);
- }
- requestLayout();
- invalidate();
- }
- }
-
- /**
- * Returns the drawable used as the foreground of this FrameLayout. The
- * foreground drawable, if non-null, is always drawn on top of the children.
- *
- * @return A Drawable or null if no foreground was set.
- */
- public Drawable getForeground() {
- return mForeground;
- }
-
- /**
- * Applies a tint to the foreground drawable. Does not modify the current
- * tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
- * <p>
- * Subsequent calls to {@link #setForeground(Drawable)} will automatically
- * mutate the drawable and apply the specified tint and tint mode using
- * {@link Drawable#setTintList(ColorStateList)}.
- *
- * @param tint the tint to apply, may be {@code null} to clear tint
- *
- * @attr ref android.R.styleable#FrameLayout_foregroundTint
- * @see #getForegroundTintList()
- * @see Drawable#setTintList(ColorStateList)
- */
- public void setForegroundTintList(@Nullable ColorStateList tint) {
- mForegroundTintList = tint;
- mHasForegroundTint = true;
-
- applyForegroundTint();
- }
-
- /**
- * @return the tint applied to the foreground drawable
- * @attr ref android.R.styleable#FrameLayout_foregroundTint
- * @see #setForegroundTintList(ColorStateList)
- */
- @Nullable
- public ColorStateList getForegroundTintList() {
- return mForegroundTintList;
- }
-
- /**
- * Specifies the blending mode used to apply the tint specified by
- * {@link #setForegroundTintList(ColorStateList)}} to the foreground drawable.
- * The default mode is {@link PorterDuff.Mode#SRC_IN}.
- *
- * @param tintMode the blending mode used to apply the tint, may be
- * {@code null} to clear tint
- * @attr ref android.R.styleable#FrameLayout_foregroundTintMode
- * @see #getForegroundTintMode()
- * @see Drawable#setTintMode(PorterDuff.Mode)
- */
- public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) {
- mForegroundTintMode = tintMode;
- mHasForegroundTintMode = true;
-
- applyForegroundTint();
- }
-
- /**
- * @return the blending mode used to apply the tint to the foreground
- * drawable
- * @attr ref android.R.styleable#FrameLayout_foregroundTintMode
- * @see #setForegroundTintMode(PorterDuff.Mode)
- */
- @Nullable
- public PorterDuff.Mode getForegroundTintMode() {
- return mForegroundTintMode;
- }
-
- private void applyForegroundTint() {
- if (mForeground != null && (mHasForegroundTint || mHasForegroundTintMode)) {
- mForeground = mForeground.mutate();
-
- if (mHasForegroundTint) {
- mForeground.setTintList(mForegroundTintList);
- }
-
- if (mHasForegroundTintMode) {
- mForeground.setTintMode(mForegroundTintMode);
- }
-
- // The drawable (or one of its children) may not have been
- // stateful before applying the tint, so let's try again.
- if (mForeground.isStateful()) {
- mForeground.setState(getDrawableState());
- }
- }
- }
-
int getPaddingLeftWithForeground() {
- return mForegroundInPadding ? Math.max(mPaddingLeft, mForegroundPaddingLeft) :
+ return isForegroundInsidePadding() ? Math.max(mPaddingLeft, mForegroundPaddingLeft) :
mPaddingLeft + mForegroundPaddingLeft;
}
int getPaddingRightWithForeground() {
- return mForegroundInPadding ? Math.max(mPaddingRight, mForegroundPaddingRight) :
+ return isForegroundInsidePadding() ? Math.max(mPaddingRight, mForegroundPaddingRight) :
mPaddingRight + mForegroundPaddingRight;
}
private int getPaddingTopWithForeground() {
- return mForegroundInPadding ? Math.max(mPaddingTop, mForegroundPaddingTop) :
+ return isForegroundInsidePadding() ? Math.max(mPaddingTop, mForegroundPaddingTop) :
mPaddingTop + mForegroundPaddingTop;
}
private int getPaddingBottomWithForeground() {
- return mForegroundInPadding ? Math.max(mPaddingBottom, mForegroundPaddingBottom) :
+ return isForegroundInsidePadding() ? Math.max(mPaddingBottom, mForegroundPaddingBottom) :
mPaddingBottom + mForegroundPaddingBottom;
}
@@ -527,8 +281,6 @@ public class FrameLayout extends ViewGroup {
final int parentTop = getPaddingTopWithForeground();
final int parentBottom = bottom - top - getPaddingBottomWithForeground();
- mForegroundBoundsChanged = true;
-
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
@@ -585,62 +337,6 @@ public class FrameLayout extends ViewGroup {
}
/**
- * {@inheritDoc}
- */
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- mForegroundBoundsChanged = true;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
-
- if (mForeground != null) {
- final Drawable foreground = mForeground;
-
- if (mForegroundBoundsChanged) {
- mForegroundBoundsChanged = false;
- final Rect selfBounds = mSelfBounds;
- final Rect overlayBounds = mOverlayBounds;
-
- final int w = mRight-mLeft;
- final int h = mBottom-mTop;
-
- if (mForegroundInPadding) {
- selfBounds.set(0, 0, w, h);
- } else {
- selfBounds.set(mPaddingLeft, mPaddingTop, w - mPaddingRight, h - mPaddingBottom);
- }
-
- final int layoutDirection = getLayoutDirection();
- Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
- foreground.getIntrinsicHeight(), selfBounds, overlayBounds,
- layoutDirection);
- foreground.setBounds(overlayBounds);
- }
-
- foreground.draw(canvas);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean gatherTransparentRegion(Region region) {
- boolean opaque = super.gatherTransparentRegion(region);
- if (region != null && mForeground != null) {
- applyDrawableToTransparentRegion(mForeground, region);
- }
- return opaque;
- }
-
- /**
* Sets whether to consider all children, or just those in
* the VISIBLE or INVISIBLE state, when measuring. Defaults to false.
*
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index af5a8bf1072b..b187c1c47ac9 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -1209,13 +1209,13 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_LEFT:
- if (movePrevious()) {
+ if (moveDirection(-1)) {
playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
return true;
}
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (moveNext()) {
+ if (moveDirection(1)) {
playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
return true;
}
@@ -1255,18 +1255,12 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
return super.onKeyUp(keyCode, event);
}
- boolean movePrevious() {
- if (mItemCount > 0 && mSelectedPosition > 0) {
- scrollToChild(mSelectedPosition - mFirstPosition - 1);
- return true;
- } else {
- return false;
- }
- }
+ boolean moveDirection(int direction) {
+ direction = isLayoutRtl() ? -direction : direction;
+ int targetPosition = mSelectedPosition + direction;
- boolean moveNext() {
- if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
- scrollToChild(mSelectedPosition - mFirstPosition + 1);
+ if (mItemCount > 0 && targetPosition >= 0 && targetPosition < mItemCount) {
+ scrollToChild(targetPosition - mFirstPosition);
return true;
} else {
return false;
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index d85bbb9e1571..310412f9ba02 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -567,13 +567,11 @@ public class ListPopupWindow {
public void show() {
int height = buildDropDown();
- int widthSpec = 0;
- int heightSpec = 0;
-
boolean noInputMethod = isInputMethodNotNeeded();
mPopup.setAllowScrollingAnchorParent(!noInputMethod);
if (mPopup.isShowing()) {
+ final int widthSpec;
if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
// The call to PopupWindow's update method below can accept -1 for any
// value you do not want to update.
@@ -584,19 +582,19 @@ public class ListPopupWindow {
widthSpec = mDropDownWidth;
}
+ final int heightSpec;
if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
// The call to PopupWindow's update method below can accept -1 for any
// value you do not want to update.
heightSpec = noInputMethod ? height : ViewGroup.LayoutParams.MATCH_PARENT;
if (noInputMethod) {
- mPopup.setWindowLayoutMode(
- mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
- ViewGroup.LayoutParams.MATCH_PARENT : 0, 0);
+ mPopup.setWidth(mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
+ ViewGroup.LayoutParams.MATCH_PARENT : 0);
+ mPopup.setHeight(0);
} else {
- mPopup.setWindowLayoutMode(
- mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
- ViewGroup.LayoutParams.MATCH_PARENT : 0,
- ViewGroup.LayoutParams.MATCH_PARENT);
+ mPopup.setWidth(mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
+ ViewGroup.LayoutParams.MATCH_PARENT : 0);
+ mPopup.setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
}
} else if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
heightSpec = height;
@@ -604,32 +602,37 @@ public class ListPopupWindow {
heightSpec = mDropDownHeight;
}
+ mPopup.setWidth(widthSpec);
+ mPopup.setHeight(heightSpec);
mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
mPopup.update(getAnchorView(), mDropDownHorizontalOffset,
- mDropDownVerticalOffset, widthSpec, heightSpec);
+ mDropDownVerticalOffset, -1, -1);
} else {
+ final int widthSpec;
if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
widthSpec = ViewGroup.LayoutParams.MATCH_PARENT;
} else {
if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
- mPopup.setWidth(getAnchorView().getWidth());
+ widthSpec = getAnchorView().getWidth();
} else {
- mPopup.setWidth(mDropDownWidth);
+ widthSpec = mDropDownWidth;
}
}
+ final int heightSpec;
if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
heightSpec = ViewGroup.LayoutParams.MATCH_PARENT;
} else {
if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
- mPopup.setHeight(height);
+ heightSpec = height;
} else {
- mPopup.setHeight(mDropDownHeight);
+ heightSpec = mDropDownHeight;
}
}
- mPopup.setWindowLayoutMode(widthSpec, heightSpec);
+ mPopup.setWidth(widthSpec);
+ mPopup.setHeight(heightSpec);
mPopup.setClipToScreenEnabled(true);
// use outside touchable to dismiss drop down when touching outside of it, so
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index f67625457708..87923231a0e0 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -46,6 +46,7 @@ import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.ViewTreeObserver.OnScrollChangedListener;
import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
import java.lang.ref.WeakReference;
@@ -126,10 +127,10 @@ public class PopupWindow {
private OnTouchListener mTouchInterceptor;
private int mWidthMode;
- private int mWidth;
+ private int mWidth = LayoutParams.WRAP_CONTENT;
private int mLastWidth;
private int mHeightMode;
- private int mHeight;
+ private int mHeight = LayoutParams.WRAP_CONTENT;
private int mLastHeight;
private int mPopupWidth;
@@ -907,17 +908,19 @@ public class PopupWindow {
* {@link ViewGroup.LayoutParams#WRAP_CONTENT},
* {@link ViewGroup.LayoutParams#MATCH_PARENT}, or 0 to use the absolute
* height.
+ *
+ * @deprecated Use {@link #setWidth(int)} and {@link #setHeight(int)}.
*/
+ @Deprecated
public void setWindowLayoutMode(int widthSpec, int heightSpec) {
mWidthMode = widthSpec;
mHeightMode = heightSpec;
}
/**
- * <p>Return this popup's height MeasureSpec</p>
+ * Returns the popup's height MeasureSpec.
*
* @return the height MeasureSpec of the popup
- *
* @see #setHeight(int)
*/
public int getHeight() {
@@ -925,13 +928,12 @@ public class PopupWindow {
}
/**
- * <p>Change the popup's height MeasureSpec</p>
- *
- * <p>If the popup is showing, calling this method will take effect only
- * the next time the popup is shown.</p>
+ * Sets the popup's height MeasureSpec.
+ * <p>
+ * If the popup is showing, calling this method will take effect the next
+ * time the popup is shown.
*
* @param height the height MeasureSpec of the popup
- *
* @see #getHeight()
* @see #isShowing()
*/
@@ -940,10 +942,9 @@ public class PopupWindow {
}
/**
- * <p>Return this popup's width MeasureSpec</p>
+ * Returns the popup's width MeasureSpec.
*
* @return the width MeasureSpec of the popup
- *
* @see #setWidth(int)
*/
public int getWidth() {
@@ -951,13 +952,12 @@ public class PopupWindow {
}
/**
- * <p>Change the popup's width MeasureSpec</p>
- *
- * <p>If the popup is showing, calling this method will take effect only
- * the next time the popup is shown.</p>
+ * Sets the popup's width MeasureSpec.
+ * <p>
+ * If the popup is showing, calling this method will take effect the next
+ * time the popup is shown.
*
* @param width the width MeasureSpec of the popup
- *
* @see #getWidth()
* @see #isShowing()
*/
@@ -1658,10 +1658,17 @@ public class PopupWindow {
/**
* Updates the state of the popup window, if it is currently being displayed,
- * from the currently set state. This includes:
- * {@link #setClippingEnabled(boolean)}, {@link #setFocusable(boolean)},
- * {@link #setIgnoreCheekPress()}, {@link #setInputMethodMode(int)},
- * {@link #setTouchable(boolean)}, and {@link #setAnimationStyle(int)}.
+ * from the currently set state.
+ * <p>
+ * This includes:
+ * <ul>
+ * <li>{@link #setClippingEnabled(boolean)}</li>
+ * <li>{@link #setFocusable(boolean)}</li>
+ * <li>{@link #setIgnoreCheekPress()}</li>
+ * <li>{@link #setInputMethodMode(int)}</li>
+ * <li>{@link #setTouchable(boolean)}</li>
+ * <li>{@link #setAnimationStyle(int)}</li>
+ * </ul>
*/
public void update() {
if (!isShowing() || mContentView == null) {
@@ -1692,12 +1699,13 @@ public class PopupWindow {
}
/**
- * <p>Updates the dimension of the popup window. Calling this function
- * also updates the window with the current popup state as described
- * for {@link #update()}.</p>
+ * Updates the dimension of the popup window.
+ * <p>
+ * Calling this function also updates the window with the current popup
+ * state as described for {@link #update()}.
*
- * @param width the new width
- * @param height the new height
+ * @param width the new width, must be >= 0 or -1 to ignore
+ * @param height the new height, must be >= 0 or -1 to ignore
*/
public void update(int width, int height) {
final WindowManager.LayoutParams p =
@@ -1706,40 +1714,43 @@ public class PopupWindow {
}
/**
- * <p>Updates the position and the dimension of the popup window. Width and
- * height can be set to -1 to update location only. Calling this function
- * also updates the window with the current popup state as
- * described for {@link #update()}.</p>
+ * Updates the position and the dimension of the popup window.
+ * <p>
+ * Width and height can be set to -1 to update location only. Calling this
+ * function also updates the window with the current popup state as
+ * described for {@link #update()}.
*
* @param x the new x location
* @param y the new y location
- * @param width the new width, can be -1 to ignore
- * @param height the new height, can be -1 to ignore
+ * @param width the new width, must be >= 0 or -1 to ignore
+ * @param height the new height, must be >= 0 or -1 to ignore
*/
public void update(int x, int y, int width, int height) {
update(x, y, width, height, false);
}
/**
- * <p>Updates the position and the dimension of the popup window. Width and
- * height can be set to -1 to update location only. Calling this function
- * also updates the window with the current popup state as
- * described for {@link #update()}.</p>
+ * Updates the position and the dimension of the popup window.
+ * <p>
+ * Width and height can be set to -1 to update location only. Calling this
+ * function also updates the window with the current popup state as
+ * described for {@link #update()}.
*
* @param x the new x location
* @param y the new y location
- * @param width the new width, can be -1 to ignore
- * @param height the new height, can be -1 to ignore
- * @param force reposition the window even if the specified position
- * already seems to correspond to the LayoutParams
+ * @param width the new width, must be >= 0 or -1 to ignore
+ * @param height the new height, must be >= 0 or -1 to ignore
+ * @param force {@code true} to reposition the window even if the specified
+ * position already seems to correspond to the LayoutParams,
+ * {@code false} to only reposition if needed
*/
public void update(int x, int y, int width, int height, boolean force) {
- if (width != -1) {
+ if (width >= 0) {
mLastWidth = width;
setWidth(width);
}
- if (height != -1) {
+ if (height >= 0) {
mLastHeight = height;
setHeight(height);
}
@@ -1794,32 +1805,34 @@ public class PopupWindow {
}
/**
- * <p>Updates the position and the dimension of the popup window. Calling this
- * function also updates the window with the current popup state as described
- * for {@link #update()}.</p>
+ * Updates the position and the dimension of the popup window.
+ * <p>
+ * Calling this function also updates the window with the current popup
+ * state as described for {@link #update()}.
*
* @param anchor the popup's anchor view
- * @param width the new width, can be -1 to ignore
- * @param height the new height, can be -1 to ignore
+ * @param width the new width, must be >= 0 or -1 to ignore
+ * @param height the new height, must be >= 0 or -1 to ignore
*/
public void update(View anchor, int width, int height) {
update(anchor, false, 0, 0, true, width, height);
}
/**
- * <p>Updates the position and the dimension of the popup window. Width and
- * height can be set to -1 to update location only. Calling this function
- * also updates the window with the current popup state as
- * described for {@link #update()}.</p>
- *
- * <p>If the view later scrolls to move <code>anchor</code> to a different
- * location, the popup will be moved correspondingly.</p>
+ * Updates the position and the dimension of the popup window.
+ * <p>
+ * Width and height can be set to -1 to update location only. Calling this
+ * function also updates the window with the current popup state as
+ * described for {@link #update()}.
+ * <p>
+ * If the view later scrolls to move {@code anchor} to a different
+ * location, the popup will be moved correspondingly.
*
* @param anchor the popup's anchor view
* @param xoff x offset from the view's left edge
* @param yoff y offset from the view's bottom edge
- * @param width the new width, can be -1 to ignore
- * @param height the new height, can be -1 to ignore
+ * @param width the new width, must be >= 0 or -1 to ignore
+ * @param height the new height, must be >= 0 or -1 to ignore
*/
public void update(View anchor, int xoff, int yoff, int width, int height) {
update(anchor, true, xoff, yoff, true, width, height);
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 28b4db251302..20aa972da214 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -641,7 +641,7 @@ public class RadialTimePickerView extends View {
mCircleRadius = Math.min(mXCenter, mYCenter);
mMinHypotenuseForInnerNumber = mCircleRadius - mTextInset[HOURS_INNER] - mSelectorRadius;
- mMaxHypotenuseForOuterNumber = mCircleRadius - mTextInset[HOURS] - mSelectorRadius;
+ mMaxHypotenuseForOuterNumber = mCircleRadius - mTextInset[HOURS] + mSelectorRadius;
mHalfwayHypotenusePoint = mCircleRadius - (mTextInset[HOURS] + mTextInset[HOURS_INNER]) / 2;
calculatePositionsHours();
@@ -1144,30 +1144,31 @@ public class RadialTimePickerView extends View {
private void adjustPicker(int step) {
final int stepSize;
- final int initialValue;
+ final int initialStep;
final int maxValue;
final int minValue;
if (mShowHours) {
- stepSize = DEGREES_FOR_ONE_HOUR;
- initialValue = getCurrentHour() % 12;
+ stepSize = 1;
+ final int currentHour24 = getCurrentHour();
if (mIs24HourMode) {
- maxValue = 23;
+ initialStep = currentHour24;
minValue = 0;
+ maxValue = 23;
} else {
- maxValue = 12;
+ initialStep = hour24To12(currentHour24);
minValue = 1;
+ maxValue = 12;
}
} else {
- stepSize = DEGREES_FOR_ONE_MINUTE;
- initialValue = getCurrentMinute();
-
- maxValue = 55;
+ stepSize = 5;
+ initialStep = getCurrentMinute() / stepSize;
minValue = 0;
+ maxValue = 55;
}
- final int steppedValue = snapOnly30s(initialValue * stepSize, step) / stepSize;
- final int clampedValue = MathUtils.constrain(steppedValue, minValue, maxValue);
+ final int nextValue = (initialStep + step) * stepSize;
+ final int clampedValue = MathUtils.constrain(nextValue, minValue, maxValue);
if (mShowHours) {
setCurrentHour(clampedValue);
} else {
diff --git a/core/java/android/widget/SimpleMonthAdapter.java b/core/java/android/widget/SimpleMonthAdapter.java
deleted file mode 100644
index c807d560968f..000000000000
--- a/core/java/android/widget/SimpleMonthAdapter.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget;
-
-import com.android.internal.R;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.SimpleMonthView.OnDayClickListener;
-
-import java.util.Calendar;
-
-/**
- * An adapter for a list of {@link android.widget.SimpleMonthView} items.
- */
-class SimpleMonthAdapter extends BaseAdapter {
- private final Calendar mMinDate = Calendar.getInstance();
- private final Calendar mMaxDate = Calendar.getInstance();
-
- private final Context mContext;
-
- private Calendar mSelectedDay = Calendar.getInstance();
- private ColorStateList mCalendarTextColors = ColorStateList.valueOf(Color.BLACK);
- private ColorStateList mCalendarDayBackgroundColor = ColorStateList.valueOf(Color.MAGENTA);
- private OnDaySelectedListener mOnDaySelectedListener;
-
- private int mFirstDayOfWeek;
-
- public SimpleMonthAdapter(Context context) {
- mContext = context;
- }
-
- public void setRange(Calendar min, Calendar max) {
- mMinDate.setTimeInMillis(min.getTimeInMillis());
- mMaxDate.setTimeInMillis(max.getTimeInMillis());
-
- notifyDataSetInvalidated();
- }
-
- public void setFirstDayOfWeek(int firstDayOfWeek) {
- mFirstDayOfWeek = firstDayOfWeek;
-
- notifyDataSetInvalidated();
- }
-
- public int getFirstDayOfWeek() {
- return mFirstDayOfWeek;
- }
-
- /**
- * Updates the selected day and related parameters.
- *
- * @param day The day to highlight
- */
- public void setSelectedDay(Calendar day) {
- mSelectedDay = day;
-
- notifyDataSetChanged();
- }
-
- /**
- * Sets the listener to call when the user selects a day.
- *
- * @param listener The listener to call.
- */
- public void setOnDaySelectedListener(OnDaySelectedListener listener) {
- mOnDaySelectedListener = listener;
- }
-
- void setCalendarTextColor(ColorStateList colors) {
- mCalendarTextColors = colors;
- }
-
- void setCalendarDayBackgroundColor(ColorStateList dayBackgroundColor) {
- mCalendarDayBackgroundColor = dayBackgroundColor;
- }
-
- /**
- * Sets the text color, size, style, hint color, and highlight color from
- * the specified TextAppearance resource. This is mostly copied from
- * {@link TextView#setTextAppearance(Context, int)}.
- */
- void setCalendarTextAppearance(int resId) {
- final TypedArray a = mContext.obtainStyledAttributes(resId, R.styleable.TextAppearance);
-
- final ColorStateList textColor = a.getColorStateList(R.styleable.TextAppearance_textColor);
- if (textColor != null) {
- mCalendarTextColors = textColor;
- }
-
- // TODO: Support font size, etc.
-
- a.recycle();
- }
-
- @Override
- public int getCount() {
- final int diffYear = mMaxDate.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR);
- final int diffMonth = mMaxDate.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH);
- return diffMonth + 12 * diffYear + 1;
- }
-
- @Override
- public Object getItem(int position) {
- return null;
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public boolean hasStableIds() {
- return true;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- final SimpleMonthView v;
- if (convertView != null) {
- v = (SimpleMonthView) convertView;
- } else {
- v = new SimpleMonthView(mContext);
-
- // Set up the new view
- final AbsListView.LayoutParams params = new AbsListView.LayoutParams(
- AbsListView.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.MATCH_PARENT);
- v.setLayoutParams(params);
- v.setClickable(true);
- v.setOnDayClickListener(mOnDayClickListener);
-
- v.setMonthTextColor(mCalendarTextColors);
- v.setDayOfWeekTextColor(mCalendarTextColors);
- v.setDayTextColor(mCalendarTextColors);
-
- v.setDayBackgroundColor(mCalendarDayBackgroundColor);
- }
-
- final int minMonth = mMinDate.get(Calendar.MONTH);
- final int minYear = mMinDate.get(Calendar.YEAR);
- final int currentMonth = position + minMonth;
- final int month = currentMonth % 12;
- final int year = currentMonth / 12 + minYear;
- final int selectedDay;
- if (isSelectedDayInMonth(year, month)) {
- selectedDay = mSelectedDay.get(Calendar.DAY_OF_MONTH);
- } else {
- selectedDay = -1;
- }
-
- // Invokes requestLayout() to ensure that the recycled view is set with the appropriate
- // height/number of weeks before being displayed.
- v.reuse();
-
- final int enabledDayRangeStart;
- if (minMonth == month && minYear == year) {
- enabledDayRangeStart = mMinDate.get(Calendar.DAY_OF_MONTH);
- } else {
- enabledDayRangeStart = 1;
- }
-
- final int enabledDayRangeEnd;
- if (mMaxDate.get(Calendar.MONTH) == month && mMaxDate.get(Calendar.YEAR) == year) {
- enabledDayRangeEnd = mMaxDate.get(Calendar.DAY_OF_MONTH);
- } else {
- enabledDayRangeEnd = 31;
- }
-
- v.setMonthParams(selectedDay, month, year, mFirstDayOfWeek,
- enabledDayRangeStart, enabledDayRangeEnd);
- v.invalidate();
-
- return v;
- }
-
- private boolean isSelectedDayInMonth(int year, int month) {
- return mSelectedDay.get(Calendar.YEAR) == year && mSelectedDay.get(Calendar.MONTH) == month;
- }
-
- private boolean isCalendarInRange(Calendar value) {
- return value.compareTo(mMinDate) >= 0 && value.compareTo(mMaxDate) <= 0;
- }
-
- private final OnDayClickListener mOnDayClickListener = new OnDayClickListener() {
- @Override
- public void onDayClick(SimpleMonthView view, Calendar day) {
- if (day != null && isCalendarInRange(day)) {
- setSelectedDay(day);
-
- if (mOnDaySelectedListener != null) {
- mOnDaySelectedListener.onDaySelected(SimpleMonthAdapter.this, day);
- }
- }
- }
- };
-
- public interface OnDaySelectedListener {
- public void onDaySelected(SimpleMonthAdapter view, Calendar day);
- }
-}
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 58ad515521d3..4e5a39a90f71 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -18,8 +18,8 @@ package android.widget;
import android.content.Context;
import android.content.res.ColorStateList;
-import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
@@ -29,8 +29,6 @@ import android.graphics.Typeface;
import android.os.Bundle;
import android.text.TextPaint;
import android.text.format.DateFormat;
-import android.text.format.DateUtils;
-import android.text.format.Time;
import android.util.AttributeSet;
import android.util.IntArray;
import android.util.StateSet;
@@ -38,13 +36,13 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import com.android.internal.R;
import com.android.internal.widget.ExploreByTouchHelper;
import java.text.SimpleDateFormat;
import java.util.Calendar;
-import java.util.Formatter;
import java.util.Locale;
/**
@@ -52,93 +50,80 @@ import java.util.Locale;
* within the specified month.
*/
class SimpleMonthView extends View {
- private static final int MIN_ROW_HEIGHT = 10;
+ private static final int DAYS_IN_WEEK = 7;
+ private static final int MAX_WEEKS_IN_MONTH = 6;
private static final int DEFAULT_SELECTED_DAY = -1;
private static final int DEFAULT_WEEK_START = Calendar.SUNDAY;
- private static final int DEFAULT_NUM_DAYS = 7;
- private static final int DEFAULT_NUM_ROWS = 6;
- private static final int MAX_NUM_ROWS = 6;
- private final Formatter mFormatter;
- private final StringBuilder mStringBuilder;
-
- private final int mMonthTextSize;
- private final int mDayOfWeekTextSize;
- private final int mDayTextSize;
-
- /** Height of the header containing the month and day of week labels. */
- private final int mMonthHeaderHeight;
+ private static final String DEFAULT_TITLE_FORMAT = "MMMMy";
+ private static final String DAY_OF_WEEK_FORMAT = "EEEEE";
private final TextPaint mMonthPaint = new TextPaint();
private final TextPaint mDayOfWeekPaint = new TextPaint();
private final TextPaint mDayPaint = new TextPaint();
+ private final Paint mDaySelectorPaint = new Paint();
+ private final Paint mDayHighlightPaint = new Paint();
- private final Paint mDayBackgroundPaint = new Paint();
+ private final Calendar mCalendar = Calendar.getInstance();
+ private final Calendar mDayLabelCalendar = Calendar.getInstance();
- /** Single-letter (when available) formatter for the day of week label. */
- private SimpleDateFormat mDayFormatter = new SimpleDateFormat("EEEEE", Locale.getDefault());
+ private final MonthViewTouchHelper mTouchHelper;
- // affects the padding on the sides of this view
- private int mPadding = 0;
+ private final SimpleDateFormat mTitleFormatter;
+ private final SimpleDateFormat mDayOfWeekFormatter;
- private String mDayOfWeekTypeface;
- private String mMonthTypeface;
+ private CharSequence mTitle;
private int mMonth;
private int mYear;
- // Quick reference to the width of this view, matches parent
- private int mWidth;
-
- // The height this view should draw at in pixels, set by height param
- private final int mRowHeight;
+ private int mPaddedWidth;
+ private int mPaddedHeight;
- // If this view contains the today
- private boolean mHasToday = false;
+ private final int mMonthHeight;
+ private final int mDayOfWeekHeight;
+ private final int mDayHeight;
+ private final int mCellWidth;
+ private final int mDaySelectorRadius;
- // Which day is selected [0-6] or -1 if no day is selected
+ /** The day of month for the selected day, or -1 if no day is selected. */
private int mActivatedDay = -1;
- // Which day is today [0-6] or -1 if no day is today
+ /**
+ * The day of month for today, or -1 if the today is not in the current
+ * month.
+ */
private int mToday = DEFAULT_SELECTED_DAY;
- // Which day of the week to start on [0-6]
+ /** The first day of the week (ex. Calendar.SUNDAY). */
private int mWeekStart = DEFAULT_WEEK_START;
- // How many days to display
- private int mNumDays = DEFAULT_NUM_DAYS;
-
- // The number of days + a spot for week number if it is displayed
- private int mNumCells = mNumDays;
+ /** The number of days (ex. 28) in the current month. */
+ private int mDaysInMonth;
- private int mDayOfWeekStart = 0;
+ /**
+ * The day of week (ex. Calendar.SUNDAY) for the first day of the current
+ * month.
+ */
+ private int mDayOfWeekStart;
- // First enabled day
+ /** The day of month for the first (inclusive) enabled day. */
private int mEnabledDayStart = 1;
- // Last enabled day
+ /** The day of month for the last (inclusive) enabled day. */
private int mEnabledDayEnd = 31;
- private final Calendar mCalendar = Calendar.getInstance();
- private final Calendar mDayLabelCalendar = Calendar.getInstance();
-
- private final MonthViewTouchHelper mTouchHelper;
-
- private int mNumRows = DEFAULT_NUM_ROWS;
+ /** The number of week rows needed to display the current month. */
+ private int mNumWeeks = MAX_WEEKS_IN_MONTH;
- // Optional listener for handling day click actions
+ /** Optional listener for handling day click actions. */
private OnDayClickListener mOnDayClickListener;
- // Whether to prevent setting the accessibility delegate
- private boolean mLockAccessibilityDelegate;
-
- private int mNormalTextColor;
- private int mDisabledTextColor;
- private int mSelectedDayColor;
-
private ColorStateList mDayTextColor;
+ private int mTouchedDay = -1;
+
public SimpleMonthView(Context context) {
this(context, null);
}
@@ -155,64 +140,123 @@ class SimpleMonthView extends View {
super(context, attrs, defStyleAttr, defStyleRes);
final Resources res = context.getResources();
- mDayOfWeekTypeface = res.getString(R.string.day_of_week_label_typeface);
- mMonthTypeface = res.getString(R.string.sans_serif);
-
- mStringBuilder = new StringBuilder(50);
- mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
-
- mDayTextSize = res.getDimensionPixelSize(R.dimen.datepicker_day_number_size);
- mMonthTextSize = res.getDimensionPixelSize(R.dimen.datepicker_month_label_size);
- mDayOfWeekTextSize = res.getDimensionPixelSize(
- R.dimen.datepicker_month_day_label_text_size);
- mMonthHeaderHeight = res.getDimensionPixelOffset(
- R.dimen.datepicker_month_list_item_header_height);
-
- mRowHeight = Math.max(MIN_ROW_HEIGHT,
- (res.getDimensionPixelOffset(R.dimen.datepicker_view_animator_height)
- - mMonthHeaderHeight) / MAX_NUM_ROWS);
+ mMonthHeight = res.getDimensionPixelSize(R.dimen.date_picker_month_height);
+ mDayOfWeekHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_of_week_height);
+ mDayHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_height);
+ mCellWidth = res.getDimensionPixelSize(R.dimen.date_picker_day_width);
+ mDaySelectorRadius = res.getDimensionPixelSize(R.dimen.date_picker_day_selector_radius);
// Set up accessibility components.
mTouchHelper = new MonthViewTouchHelper(this);
setAccessibilityDelegate(mTouchHelper);
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
- mLockAccessibilityDelegate = true;
- initPaints();
+ final Locale locale = res.getConfiguration().locale;
+ final String titleFormat = DateFormat.getBestDateTimePattern(locale, DEFAULT_TITLE_FORMAT);
+ mTitleFormatter = new SimpleDateFormat(titleFormat, locale);
+ mDayOfWeekFormatter = new SimpleDateFormat(DAY_OF_WEEK_FORMAT, locale);
+
+ setClickable(true);
+ initPaints(res);
+ }
+
+ /**
+ * Applies the specified text appearance resource to a paint, returning the
+ * text color if one is set in the text appearance.
+ *
+ * @param p the paint to modify
+ * @param resId the resource ID of the text appearance
+ * @return the text color, if available
+ */
+ private ColorStateList applyTextAppearance(Paint p, int resId) {
+ final TypedArray ta = mContext.obtainStyledAttributes(null,
+ R.styleable.TextAppearance, 0, resId);
+
+ final String fontFamily = ta.getString(R.styleable.TextAppearance_fontFamily);
+ if (fontFamily != null) {
+ p.setTypeface(Typeface.create(fontFamily, 0));
+ }
+
+ p.setTextSize(ta.getDimensionPixelSize(
+ R.styleable.TextAppearance_textSize, (int) p.getTextSize()));
+
+ final ColorStateList textColor = ta.getColorStateList(R.styleable.TextAppearance_textColor);
+ if (textColor != null) {
+ final int enabledColor = textColor.getColorForState(ENABLED_STATE_SET, 0);
+ p.setColor(enabledColor);
+ }
+
+ ta.recycle();
+
+ return textColor;
+ }
+
+ public void setMonthTextAppearance(int resId) {
+ applyTextAppearance(mMonthPaint, resId);
+ invalidate();
+ }
+
+ public void setDayOfWeekTextAppearance(int resId) {
+ applyTextAppearance(mDayOfWeekPaint, resId);
+ invalidate();
+ }
+
+ public void setDayTextAppearance(int resId) {
+ final ColorStateList textColor = applyTextAppearance(mDayPaint, resId);
+ if (textColor != null) {
+ mDayTextColor = textColor;
+ }
+
+ invalidate();
+ }
+
+ public CharSequence getTitle() {
+ if (mTitle == null) {
+ mTitle = mTitleFormatter.format(mCalendar.getTime());
+ }
+ return mTitle;
}
/**
* Sets up the text and style properties for painting.
*/
- private void initPaints() {
+ private void initPaints(Resources res) {
+ final String monthTypeface = res.getString(R.string.date_picker_month_typeface);
+ final String dayOfWeekTypeface = res.getString(R.string.date_picker_day_of_week_typeface);
+ final String dayTypeface = res.getString(R.string.date_picker_day_typeface);
+
+ final int monthTextSize = res.getDimensionPixelSize(
+ R.dimen.date_picker_month_text_size);
+ final int dayOfWeekTextSize = res.getDimensionPixelSize(
+ R.dimen.date_picker_day_of_week_text_size);
+ final int dayTextSize = res.getDimensionPixelSize(
+ R.dimen.date_picker_day_text_size);
+
mMonthPaint.setAntiAlias(true);
- mMonthPaint.setTextSize(mMonthTextSize);
- mMonthPaint.setTypeface(Typeface.create(mMonthTypeface, Typeface.BOLD));
+ mMonthPaint.setTextSize(monthTextSize);
+ mMonthPaint.setTypeface(Typeface.create(monthTypeface, 0));
mMonthPaint.setTextAlign(Align.CENTER);
mMonthPaint.setStyle(Style.FILL);
mDayOfWeekPaint.setAntiAlias(true);
- mDayOfWeekPaint.setTextSize(mDayOfWeekTextSize);
- mDayOfWeekPaint.setTypeface(Typeface.create(mDayOfWeekTypeface, Typeface.BOLD));
+ mDayOfWeekPaint.setTextSize(dayOfWeekTextSize);
+ mDayOfWeekPaint.setTypeface(Typeface.create(dayOfWeekTypeface, 0));
mDayOfWeekPaint.setTextAlign(Align.CENTER);
mDayOfWeekPaint.setStyle(Style.FILL);
- mDayBackgroundPaint.setAntiAlias(true);
- mDayBackgroundPaint.setStyle(Style.FILL);
+ mDaySelectorPaint.setAntiAlias(true);
+ mDaySelectorPaint.setStyle(Style.FILL);
+
+ mDayHighlightPaint.setAntiAlias(true);
+ mDayHighlightPaint.setStyle(Style.FILL);
mDayPaint.setAntiAlias(true);
- mDayPaint.setTextSize(mDayTextSize);
+ mDayPaint.setTextSize(dayTextSize);
+ mDayPaint.setTypeface(Typeface.create(dayTypeface, 0));
mDayPaint.setTextAlign(Align.CENTER);
mDayPaint.setStyle(Style.FILL);
}
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
-
- mDayFormatter = new SimpleDateFormat("EEEEE", newConfig.locale);
- }
-
void setMonthTextColor(ColorStateList monthTextColor) {
final int enabledColor = monthTextColor.getColorForState(ENABLED_STATE_SET, 0);
mMonthPaint.setColor(enabledColor);
@@ -230,20 +274,18 @@ class SimpleMonthView extends View {
invalidate();
}
- void setDayBackgroundColor(ColorStateList dayBackgroundColor) {
+ void setDaySelectorColor(ColorStateList dayBackgroundColor) {
final int activatedColor = dayBackgroundColor.getColorForState(
StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED), 0);
- mDayBackgroundPaint.setColor(activatedColor);
+ mDaySelectorPaint.setColor(activatedColor);
invalidate();
}
- @Override
- public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
- // Workaround for a JB MR1 issue where accessibility delegates on
- // top-level ListView items are overwritten.
- if (!mLockAccessibilityDelegate) {
- super.setAccessibilityDelegate(delegate);
- }
+ void setDayHighlightColor(ColorStateList dayHighlightColor) {
+ final int pressedColor = dayHighlightColor.getColorForState(
+ StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED), 0);
+ mDayHighlightPaint.setColor(pressedColor);
+ invalidate();
}
public void setOnDayClickListener(OnDayClickListener listener) {
@@ -253,30 +295,124 @@ class SimpleMonthView extends View {
@Override
public boolean dispatchHoverEvent(MotionEvent event) {
// First right-of-refusal goes the touch exploration helper.
- if (mTouchHelper.dispatchHoverEvent(event)) {
- return true;
- }
- return super.dispatchHoverEvent(event);
+ return mTouchHelper.dispatchHoverEvent(event) || super.dispatchHoverEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
- case MotionEvent.ACTION_UP:
- final int day = getDayFromLocation(event.getX(), event.getY());
- if (day >= 0) {
- onDayClick(day);
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_MOVE:
+ final int touchedDay = getDayAtLocation(event.getX(), event.getY());
+ if (mTouchedDay != touchedDay) {
+ mTouchedDay = touchedDay;
+ invalidate();
}
break;
+
+ case MotionEvent.ACTION_UP:
+ final int clickedDay = getDayAtLocation(event.getX(), event.getY());
+ onDayClicked(clickedDay);
+ // Fall through.
+ case MotionEvent.ACTION_CANCEL:
+ // Reset touched day on stream end.
+ mTouchedDay = -1;
+ invalidate();
+ break;
}
return true;
}
@Override
protected void onDraw(Canvas canvas) {
- drawMonthTitle(canvas);
- drawWeekDayLabels(canvas);
+ final int paddingLeft = getPaddingLeft();
+ final int paddingTop = getPaddingTop();
+ canvas.translate(paddingLeft, paddingTop);
+
+ drawMonth(canvas);
+ drawDaysOfWeek(canvas);
drawDays(canvas);
+
+ canvas.translate(-paddingLeft, -paddingTop);
+ }
+
+ private void drawMonth(Canvas canvas) {
+ final float x = mPaddedWidth / 2f;
+
+ // Vertically centered within the month header height.
+ final float lineHeight = mMonthPaint.ascent() + mMonthPaint.descent();
+ final float y = (mMonthHeight - lineHeight) / 2f;
+
+ canvas.drawText(getTitle().toString(), x, y, mMonthPaint);
+ }
+
+ private void drawDaysOfWeek(Canvas canvas) {
+ final float cellWidthHalf = mPaddedWidth / (DAYS_IN_WEEK * 2);
+
+ // Vertically centered within the cell height.
+ final float lineHeight = mDayOfWeekPaint.ascent() + mDayOfWeekPaint.descent();
+ final float y = mMonthHeight + (mDayOfWeekHeight - lineHeight) / 2f;
+
+ for (int i = 0; i < DAYS_IN_WEEK; i++) {
+ final int calendarDay = (i + mWeekStart) % DAYS_IN_WEEK;
+ mDayLabelCalendar.set(Calendar.DAY_OF_WEEK, calendarDay);
+
+ final String dayLabel = mDayOfWeekFormatter.format(mDayLabelCalendar.getTime());
+ final float x = (2 * i + 1) * cellWidthHalf;
+ canvas.drawText(dayLabel, x, y, mDayOfWeekPaint);
+ }
+ }
+
+ /**
+ * Draws the month days.
+ */
+ private void drawDays(Canvas canvas) {
+ final int cellWidthHalf = mPaddedWidth / (DAYS_IN_WEEK * 2);
+
+ // Vertically centered within the cell height.
+ final float halfLineHeight = (mDayPaint.ascent() + mDayPaint.descent()) / 2;
+ float centerY = mMonthHeight + mDayOfWeekHeight + mDayHeight / 2f;
+
+ for (int day = 1, j = findDayOffset(); day <= mDaysInMonth; day++) {
+ final int x = (2 * j + 1) * cellWidthHalf;
+ int stateMask = 0;
+
+ if (day >= mEnabledDayStart && day <= mEnabledDayEnd) {
+ stateMask |= StateSet.VIEW_STATE_ENABLED;
+ }
+
+ final boolean isDayActivated = mActivatedDay == day;
+ if (isDayActivated) {
+ stateMask |= StateSet.VIEW_STATE_ACTIVATED;
+
+ // Adjust the circle to be centered on the row.
+ canvas.drawCircle(x, centerY, mDaySelectorRadius, mDaySelectorPaint);
+ } else if (mTouchedDay == day) {
+ stateMask |= StateSet.VIEW_STATE_PRESSED;
+
+ // Adjust the circle to be centered on the row.
+ canvas.drawCircle(x, centerY, mDaySelectorRadius, mDayHighlightPaint);
+ }
+
+ final boolean isDayToday = mToday == day;
+ final int dayTextColor;
+ if (isDayToday && !isDayActivated) {
+ dayTextColor = mDaySelectorPaint.getColor();
+ } else {
+ final int[] stateSet = StateSet.get(stateMask);
+ dayTextColor = mDayTextColor.getColorForState(stateSet, 0);
+ }
+ mDayPaint.setColor(dayTextColor);
+
+ canvas.drawText("" + day, x, centerY - halfLineHeight, mDayPaint);
+
+ j++;
+
+ if (j == DAYS_IN_WEEK) {
+ j = 0;
+ centerY += mDayHeight;
+ }
+ }
}
private static boolean isValidDayOfWeek(int day) {
@@ -288,18 +424,52 @@ class SimpleMonthView extends View {
}
/**
- * Sets all the parameters for displaying this week. Parameters have a default value and
- * will only update if a new value is included, except for focus month, which will always
- * default to no focus month if no value is passed in. The only required parameter is the
- * week start.
+ * Sets the selected day.
*
- * @param selectedDay the selected day of the month, or -1 for no selection.
- * @param month the month.
- * @param year the year.
- * @param weekStart which day the week should start on. {@link Calendar#SUNDAY} through
- * {@link Calendar#SATURDAY}.
- * @param enabledDayStart the first enabled day.
- * @param enabledDayEnd the last enabled day.
+ * @param dayOfMonth the selected day of the month, or {@code -1} to clear
+ * the selection
+ */
+ public void setSelectedDay(int dayOfMonth) {
+ mActivatedDay = dayOfMonth;
+
+ // Invalidate cached accessibility information.
+ mTouchHelper.invalidateRoot();
+ invalidate();
+ }
+
+ /**
+ * Sets the first day of the week.
+ *
+ * @param weekStart which day the week should start on, valid values are
+ * {@link Calendar#SUNDAY} through {@link Calendar#SATURDAY}
+ */
+ public void setFirstDayOfWeek(int weekStart) {
+ if (isValidDayOfWeek(weekStart)) {
+ mWeekStart = weekStart;
+ } else {
+ mWeekStart = mCalendar.getFirstDayOfWeek();
+ }
+
+ // Invalidate cached accessibility information.
+ mTouchHelper.invalidateRoot();
+ invalidate();
+ }
+
+ /**
+ * Sets all the parameters for displaying this week.
+ * <p>
+ * Parameters have a default value and will only update if a new value is
+ * included, except for focus month, which will always default to no focus
+ * month if no value is passed in. The only required parameter is the week
+ * start.
+ *
+ * @param selectedDay the selected day of the month, or -1 for no selection
+ * @param month the month
+ * @param year the year
+ * @param weekStart which day the week should start on, valid values are
+ * {@link Calendar#SUNDAY} through {@link Calendar#SATURDAY}
+ * @param enabledDayStart the first enabled day
+ * @param enabledDayEnd the last enabled day
*/
void setMonthParams(int selectedDay, int month, int year, int weekStart, int enabledDayStart,
int enabledDayEnd) {
@@ -310,12 +480,6 @@ class SimpleMonthView extends View {
}
mYear = year;
- // Figure out what day today is
- final Time today = new Time(Time.getCurrentTimezone());
- today.setToNow();
- mHasToday = false;
- mToday = -1;
-
mCalendar.set(Calendar.MONTH, mMonth);
mCalendar.set(Calendar.YEAR, mYear);
mCalendar.set(Calendar.DAY_OF_MONTH, 1);
@@ -334,15 +498,20 @@ class SimpleMonthView extends View {
mEnabledDayEnd = enabledDayEnd;
}
- mNumCells = getDaysInMonth(mMonth, mYear);
- for (int i = 0; i < mNumCells; i++) {
+ // Figure out what day today is.
+ final Calendar today = Calendar.getInstance();
+ mToday = -1;
+ mDaysInMonth = getDaysInMonth(mMonth, mYear);
+ for (int i = 0; i < mDaysInMonth; i++) {
final int day = i + 1;
if (sameDay(day, today)) {
- mHasToday = true;
mToday = day;
}
}
- mNumRows = calculateNumRows();
+ mNumWeeks = calculateNumRows();
+
+ // Invalidate the old title.
+ mTitle = null;
// Invalidate cached accessibility information.
mTouchHelper.invalidateRoot();
@@ -371,154 +540,118 @@ class SimpleMonthView extends View {
}
public void reuse() {
- mNumRows = DEFAULT_NUM_ROWS;
+ mNumWeeks = MAX_WEEKS_IN_MONTH;
requestLayout();
}
private int calculateNumRows() {
- int offset = findDayOffset();
- int dividend = (offset + mNumCells) / mNumDays;
- int remainder = (offset + mNumCells) % mNumDays;
- return (dividend + (remainder > 0 ? 1 : 0));
+ final int offset = findDayOffset();
+ final int dividend = (offset + mDaysInMonth) / DAYS_IN_WEEK;
+ final int remainder = (offset + mDaysInMonth) % DAYS_IN_WEEK;
+ return dividend + (remainder > 0 ? 1 : 0);
}
- private boolean sameDay(int day, Time today) {
- return mYear == today.year &&
- mMonth == today.month &&
- day == today.monthDay;
+ private boolean sameDay(int day, Calendar today) {
+ return mYear == today.get(Calendar.YEAR) && mMonth == today.get(Calendar.MONTH)
+ && day == today.get(Calendar.DAY_OF_MONTH);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mRowHeight * mNumRows
- + mMonthHeaderHeight);
+ final int preferredHeight = mDayHeight * mNumWeeks + mDayOfWeekHeight + mMonthHeight
+ + getPaddingTop() + getPaddingBottom();
+ final int preferredWidth = mCellWidth * DAYS_IN_WEEK
+ + getPaddingStart() + getPaddingEnd();
+ final int resolvedWidth = resolveSize(preferredWidth, widthMeasureSpec);
+ final int resolvedHeight = resolveSize(preferredHeight, heightMeasureSpec);
+ setMeasuredDimension(resolvedWidth, resolvedHeight);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- mWidth = w;
+ mPaddedWidth = w - getPaddingLeft() - getPaddingRight();
+ mPaddedHeight = w - getPaddingTop() - getPaddingBottom();
// Invalidate cached accessibility information.
mTouchHelper.invalidateRoot();
}
- private String getMonthAndYearString() {
- int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR
- | DateUtils.FORMAT_NO_MONTH_DAY;
- mStringBuilder.setLength(0);
- long millis = mCalendar.getTimeInMillis();
- return DateUtils.formatDateRange(getContext(), mFormatter, millis, millis, flags,
- Time.getCurrentTimezone()).toString();
- }
-
- private void drawMonthTitle(Canvas canvas) {
- final float x = (mWidth + 2 * mPadding) / 2f;
-
- // Centered on the upper half of the month header.
- final float lineHeight = mMonthPaint.ascent() + mMonthPaint.descent();
- final float y = mMonthHeaderHeight * 0.25f - lineHeight / 2f;
-
- canvas.drawText(getMonthAndYearString(), x, y, mMonthPaint);
- }
-
- private void drawWeekDayLabels(Canvas canvas) {
- final float dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2);
-
- // Centered on the lower half of the month header.
- final float lineHeight = mDayOfWeekPaint.ascent() + mDayOfWeekPaint.descent();
- final float y = mMonthHeaderHeight * 0.75f - lineHeight / 2f;
-
- for (int i = 0; i < mNumDays; i++) {
- final int calendarDay = (i + mWeekStart) % mNumDays;
- mDayLabelCalendar.set(Calendar.DAY_OF_WEEK, calendarDay);
-
- final String dayLabel = mDayFormatter.format(mDayLabelCalendar.getTime());
- final float x = (2 * i + 1) * dayWidthHalf + mPadding;
- canvas.drawText(dayLabel, x, y, mDayOfWeekPaint);
+ private int findDayOffset() {
+ final int offset = mDayOfWeekStart - mWeekStart;
+ if (mDayOfWeekStart < mWeekStart) {
+ return offset + DAYS_IN_WEEK;
}
+ return offset;
}
/**
- * Draws the month days.
+ * Calculates the day of the month at the specified touch position. Returns
+ * the day of the month or -1 if the position wasn't in a valid day.
+ *
+ * @param x the x position of the touch event
+ * @param y the y position of the touch event
+ * @return the day of the month at (x, y) or -1 if the position wasn't in a
+ * valid day
*/
- private void drawDays(Canvas canvas) {
- final int dayWidthHalf = (mWidth - mPadding * 2) / (mNumDays * 2);
-
- // Centered within the row.
- final float lineHeight = mDayOfWeekPaint.ascent() + mDayOfWeekPaint.descent();
- float y = mMonthHeaderHeight + (mRowHeight - lineHeight) / 2f;
-
- for (int day = 1, j = findDayOffset(); day <= mNumCells; day++) {
- final int x = (2 * j + 1) * dayWidthHalf + mPadding;
- int stateMask = 0;
-
- if (day >= mEnabledDayStart && day <= mEnabledDayEnd) {
- stateMask |= StateSet.VIEW_STATE_ENABLED;
- }
-
- if (mActivatedDay == day) {
- stateMask |= StateSet.VIEW_STATE_ACTIVATED;
-
- // Adjust the circle to be centered the row.
- final float rowCenterY = y + lineHeight / 2;
- canvas.drawCircle(x, rowCenterY, mRowHeight / 2,
- mDayBackgroundPaint);
- }
-
- final int[] stateSet = StateSet.get(stateMask);
- final int dayTextColor = mDayTextColor.getColorForState(stateSet, 0);
- mDayPaint.setColor(dayTextColor);
-
- final boolean isDayToday = mHasToday && mToday == day;
- mDayPaint.setFakeBoldText(isDayToday);
-
- canvas.drawText(String.format("%d", day), x, y, mDayPaint);
+ private int getDayAtLocation(float x, float y) {
+ final int paddedX = (int) (x - getPaddingLeft() + 0.5f);
+ if (paddedX < 0 || paddedX >= mPaddedWidth) {
+ return -1;
+ }
- j++;
+ final int headerHeight = mMonthHeight + mDayOfWeekHeight;
+ final int paddedY = (int) (y - getPaddingTop() + 0.5f);
+ if (paddedY < headerHeight || paddedY >= mPaddedHeight) {
+ return -1;
+ }
- if (j == mNumDays) {
- j = 0;
- y += mRowHeight;
- }
+ final int row = (paddedY - headerHeight) / mDayHeight;
+ final int col = (paddedX * DAYS_IN_WEEK) / mPaddedWidth;
+ final int index = col + row * DAYS_IN_WEEK;
+ final int day = index + 1 - findDayOffset();
+ if (day < 1 || day > mDaysInMonth) {
+ return -1;
}
- }
- private int findDayOffset() {
- return (mDayOfWeekStart < mWeekStart ? (mDayOfWeekStart + mNumDays) : mDayOfWeekStart)
- - mWeekStart;
+ return day;
}
/**
- * Calculates the day that the given x position is in, accounting for week
- * number. Returns the day or -1 if the position wasn't in a day.
+ * Calculates the bounds of the specified day.
*
- * @param x The x position of the touch event
- * @return The day number, or -1 if the position wasn't in a day
+ * @param day the day of the month
+ * @param outBounds the rect to populate with bounds
*/
- private int getDayFromLocation(float x, float y) {
- int dayStart = mPadding;
- if (x < dayStart || x > mWidth - mPadding) {
- return -1;
+ private boolean getBoundsForDay(int day, Rect outBounds) {
+ if (day < 1 || day > mDaysInMonth) {
+ return false;
}
- // Selection is (x - start) / (pixels/day) == (x -s) * day / pixels
- int row = (int) (y - mMonthHeaderHeight) / mRowHeight;
- int column = (int) ((x - dayStart) * mNumDays / (mWidth - dayStart - mPadding));
- int day = column - findDayOffset() + 1;
- day += row * mNumDays;
- if (day < 1 || day > mNumCells) {
- return -1;
- }
- return day;
+ final int index = day - 1 + findDayOffset();
+ final int row = index / DAYS_IN_WEEK;
+ final int col = index % DAYS_IN_WEEK;
+
+ final int headerHeight = mMonthHeight + mDayOfWeekHeight;
+ final int paddedY = row * mDayHeight + headerHeight;
+ final int paddedX = col * mPaddedWidth;
+
+ final int y = paddedY + getPaddingTop();
+ final int x = paddedX + getPaddingLeft();
+
+ final int cellHeight = mDayHeight;
+ final int cellWidth = mPaddedWidth / DAYS_IN_WEEK;
+ outBounds.set(x, y, (x + cellWidth), (y + cellHeight));
+
+ return true;
}
/**
* Called when the user clicks on a day. Handles callbacks to the
* {@link OnDayClickListener} if one is set.
*
- * @param day The day that was clicked
+ * @param day the day that was clicked
*/
- private void onDayClick(int day) {
+ private void onDayClicked(int day) {
if (mOnDayClickListener != null) {
Calendar date = Calendar.getInstance();
date.set(mYear, mMonth, day);
@@ -530,44 +663,6 @@ class SimpleMonthView extends View {
}
/**
- * @return The date that has accessibility focus, or {@code null} if no date
- * has focus
- */
- Calendar getAccessibilityFocus() {
- final int day = mTouchHelper.getFocusedVirtualView();
- Calendar date = null;
- if (day >= 0) {
- date = Calendar.getInstance();
- date.set(mYear, mMonth, day);
- }
- return date;
- }
-
- /**
- * Clears accessibility focus within the view. No-op if the view does not
- * contain accessibility focus.
- */
- public void clearAccessibilityFocus() {
- mTouchHelper.clearFocusedVirtualView();
- }
-
- /**
- * Attempts to restore accessibility focus to the specified date.
- *
- * @param day The date which should receive focus
- * @return {@code false} if the date is not valid for this month view, or
- * {@code true} if the date received focus
- */
- boolean restoreAccessibilityFocus(Calendar day) {
- if ((day.get(Calendar.YEAR) != mYear) || (day.get(Calendar.MONTH) != mMonth) ||
- (day.get(Calendar.DAY_OF_MONTH) > mNumCells)) {
- return false;
- }
- mTouchHelper.setFocusedVirtualView(day.get(Calendar.DAY_OF_MONTH));
- return true;
- }
-
- /**
* Provides a virtual view hierarchy for interfacing with an accessibility
* service.
*/
@@ -581,24 +676,9 @@ class SimpleMonthView extends View {
super(host);
}
- public void setFocusedVirtualView(int virtualViewId) {
- getAccessibilityNodeProvider(SimpleMonthView.this).performAction(
- virtualViewId, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
- }
-
- public void clearFocusedVirtualView() {
- final int focusedVirtualView = getFocusedVirtualView();
- if (focusedVirtualView != ExploreByTouchHelper.INVALID_ID) {
- getAccessibilityNodeProvider(SimpleMonthView.this).performAction(
- focusedVirtualView,
- AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS,
- null);
- }
- }
-
@Override
protected int getVirtualViewAt(float x, float y) {
- final int day = getDayFromLocation(x, y);
+ final int day = getDayAtLocation(x, y);
if (day >= 0) {
return day;
}
@@ -607,7 +687,7 @@ class SimpleMonthView extends View {
@Override
protected void getVisibleVirtualViews(IntArray virtualViewIds) {
- for (int day = 1; day <= mNumCells; day++) {
+ for (int day = 1; day <= mDaysInMonth; day++) {
virtualViewIds.add(day);
}
}
@@ -619,11 +699,20 @@ class SimpleMonthView extends View {
@Override
protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfo node) {
- getItemBounds(virtualViewId, mTempRect);
+ final boolean hasBounds = getBoundsForDay(virtualViewId, mTempRect);
+
+ if (!hasBounds) {
+ // The day is invalid, kill the node.
+ mTempRect.setEmpty();
+ node.setContentDescription("");
+ node.setBoundsInParent(mTempRect);
+ node.setVisibleToUser(false);
+ return;
+ }
node.setContentDescription(getItemDescription(virtualViewId));
node.setBoundsInParent(mTempRect);
- node.addAction(AccessibilityNodeInfo.ACTION_CLICK);
+ node.addAction(AccessibilityAction.ACTION_CLICK);
if (virtualViewId == mActivatedDay) {
node.setSelected(true);
@@ -636,7 +725,7 @@ class SimpleMonthView extends View {
Bundle arguments) {
switch (action) {
case AccessibilityNodeInfo.ACTION_CLICK:
- onDayClick(virtualViewId);
+ onDayClicked(virtualViewId);
return true;
}
@@ -644,26 +733,6 @@ class SimpleMonthView extends View {
}
/**
- * Calculates the bounding rectangle of a given time object.
- *
- * @param day The day to calculate bounds for
- * @param rect The rectangle in which to store the bounds
- */
- private void getItemBounds(int day, Rect rect) {
- final int offsetX = mPadding;
- final int offsetY = mMonthHeaderHeight;
- final int cellHeight = mRowHeight;
- final int cellWidth = ((mWidth - (2 * mPadding)) / mNumDays);
- final int index = ((day - 1) + findDayOffset());
- final int row = (index / mNumDays);
- final int column = (index % mNumDays);
- final int x = (offsetX + (column * cellWidth));
- final int y = (offsetY + (row * cellHeight));
-
- rect.set(x, y, (x + cellWidth), (y + cellHeight));
- }
-
- /**
* Generates a description for a given time object. Since this
* description will be spoken, the components are ordered by descending
* specificity as DAY MONTH YEAR.
diff --git a/core/java/android/widget/TextViewWithCircularIndicator.java b/core/java/android/widget/TextViewWithCircularIndicator.java
deleted file mode 100644
index d3c786c6e261..000000000000
--- a/core/java/android/widget/TextViewWithCircularIndicator.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Typeface;
-import android.util.AttributeSet;
-
-import com.android.internal.R;
-
-class TextViewWithCircularIndicator extends TextView {
- private final Paint mCirclePaint = new Paint();
- private final String mItemIsSelectedText;
-
- public TextViewWithCircularIndicator(Context context) {
- this(context, null);
- }
-
- public TextViewWithCircularIndicator(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public TextViewWithCircularIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public TextViewWithCircularIndicator(Context context, AttributeSet attrs,
- int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
-
- final Resources res = context.getResources();
- mItemIsSelectedText = res.getString(R.string.item_is_selected);
-
- init();
- }
-
- private void init() {
- mCirclePaint.setTypeface(Typeface.create(mCirclePaint.getTypeface(), Typeface.BOLD));
- mCirclePaint.setAntiAlias(true);
- mCirclePaint.setTextAlign(Paint.Align.CENTER);
- mCirclePaint.setStyle(Paint.Style.FILL);
- }
-
- public void setCircleColor(int color) {
- mCirclePaint.setColor(color);
- invalidate();
- }
-
- @Override
- public void onDraw(Canvas canvas) {
- if (isActivated()) {
- final int width = getWidth();
- final int height = getHeight();
- final int radius = Math.min(width, height) / 2;
- canvas.drawCircle(width / 2, height / 2, radius, mCirclePaint);
- }
-
- super.onDraw(canvas);
- }
-
- @Override
- public CharSequence getContentDescription() {
- final CharSequence itemText = getText();
- if (isActivated()) {
- return String.format(mItemIsSelectedText, itemText);
- } else {
- return itemText;
- }
- }
-} \ No newline at end of file
diff --git a/core/java/android/widget/YearPickerView.java b/core/java/android/widget/YearPickerView.java
index 6f0465fa9352..7bd502e29b21 100644
--- a/core/java/android/widget/YearPickerView.java
+++ b/core/java/android/widget/YearPickerView.java
@@ -17,10 +17,9 @@
package android.widget;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.util.AttributeSet;
-import android.util.StateSet;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
@@ -32,23 +31,14 @@ import com.android.internal.R;
/**
* Displays a selectable list of years.
*/
-class YearPickerView extends ListView implements AdapterView.OnItemClickListener,
- OnDateChangedListener {
- private final Calendar mMinDate = Calendar.getInstance();
- private final Calendar mMaxDate = Calendar.getInstance();
-
+class YearPickerView extends ListView {
private final YearAdapter mAdapter;
private final int mViewSize;
private final int mChildSize;
- private DatePickerController mController;
-
- private int mSelectedPosition = -1;
- private int mYearActivatedColor;
+ private OnYearSelectedListener mOnYearSelectedListener;
- public YearPickerView(Context context) {
- this(context, null);
- }
+ private long mCurrentTimeMillis;
public YearPickerView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.listViewStyle);
@@ -69,104 +59,187 @@ class YearPickerView extends ListView implements AdapterView.OnItemClickListener
mViewSize = res.getDimensionPixelOffset(R.dimen.datepicker_view_animator_height);
mChildSize = res.getDimensionPixelOffset(R.dimen.datepicker_year_label_height);
- setVerticalFadingEdgeEnabled(true);
- setFadingEdgeLength(mChildSize / 3);
-
- final int paddingTop = res.getDimensionPixelSize(
- R.dimen.datepicker_year_picker_padding_top);
- setPadding(0, paddingTop, 0, 0);
+ setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ final int year = mAdapter.getYearForPosition(position);
+ mAdapter.setSelection(year);
- setOnItemClickListener(this);
- setDividerHeight(0);
+ if (mOnYearSelectedListener != null) {
+ mOnYearSelectedListener.onYearChanged(YearPickerView.this, year);
+ }
+ }
+ });
- mAdapter = new YearAdapter(getContext(), R.layout.year_label_text_view);
+ mAdapter = new YearAdapter(getContext());
setAdapter(mAdapter);
}
- public void setRange(Calendar min, Calendar max) {
- mMinDate.setTimeInMillis(min.getTimeInMillis());
- mMaxDate.setTimeInMillis(max.getTimeInMillis());
+ public void setOnYearSelectedListener(OnYearSelectedListener listener) {
+ mOnYearSelectedListener = listener;
+ }
- updateAdapterData();
+ public void setDate(long currentTimeMillis) {
+ mCurrentTimeMillis = currentTimeMillis;
}
- public void init(DatePickerController controller) {
- mController = controller;
- mController.registerOnDateChangedListener(this);
+ /**
+ * Sets the currently selected year. Jumps immediately to the new year.
+ *
+ * @param year the target year
+ */
+ public void setYear(final int year) {
+ mAdapter.setSelection(year);
- updateAdapterData();
+ post(new Runnable() {
+ @Override
+ public void run() {
+ final int position = mAdapter.getPositionForYear(year);
+ if (position >= 0 && position < getCount()) {
+ setSelectionCentered(position);
+ }
+ }
+ });
+ }
- onDateChanged();
+ public void setSelectionCentered(int position) {
+ final int offset = mViewSize / 2 - mChildSize / 2;
+ setSelectionFromTop(position, offset);
}
- public void setYearBackgroundColor(ColorStateList yearBackgroundColor) {
- mYearActivatedColor = yearBackgroundColor.getColorForState(
- StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED), 0);
- invalidate();
+ public void setRange(Calendar min, Calendar max) {
+ mAdapter.setRange(min, max);
}
public void setYearTextAppearance(int resId) {
mAdapter.setItemTextAppearance(resId);
}
- private void updateAdapterData() {
- mAdapter.clear();
+ public void setYearActivatedTextAppearance(int resId) {
+ mAdapter.setItemActivatedTextAppearance(resId);
+ }
+
+ private static class YearAdapter extends BaseAdapter {
+ private static final int ITEM_LAYOUT = R.layout.year_label_text_view;
+
+ private final LayoutInflater mInflater;
+
+ private int mActivatedYear;
+ private int mMinYear;
+ private int mCount;
- final int maxYear = mMaxDate.get(Calendar.YEAR);
- for (int year = mMinDate.get(Calendar.YEAR); year <= maxYear; year++) {
- mAdapter.add(year);
+ private int mItemTextAppearanceResId;
+ private int mItemActivatedTextAppearanceResId;
+
+ public YearAdapter(Context context) {
+ mInflater = LayoutInflater.from(context);
}
- }
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- mController.tryVibrate();
- if (position != mSelectedPosition) {
- mSelectedPosition = position;
- mAdapter.notifyDataSetChanged();
+ public void setRange(Calendar minDate, Calendar maxDate) {
+ final int minYear = minDate.get(Calendar.YEAR);
+ final int count = maxDate.get(Calendar.YEAR) - minYear + 1;
+
+ if (mMinYear != minYear || mCount != count) {
+ mMinYear = minYear;
+ mCount = count;
+ notifyDataSetInvalidated();
+ }
}
- mController.onYearSelected(mAdapter.getItem(position));
- }
- private class YearAdapter extends ArrayAdapter<Integer> {
- private int mItemTextAppearanceResId;
+ public boolean setSelection(int year) {
+ if (mActivatedYear != year) {
+ mActivatedYear = year;
+ notifyDataSetChanged();
+ return true;
+ }
+ return false;
+ }
+
+ public void setItemTextAppearance(int resId) {
+ mItemTextAppearanceResId = resId;
+ notifyDataSetChanged();
+ }
+
+ public void setItemActivatedTextAppearance(int resId) {
+ mItemActivatedTextAppearanceResId = resId;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount() {
+ return mCount;
+ }
- public YearAdapter(Context context, int resource) {
- super(context, resource);
+ @Override
+ public Integer getItem(int position) {
+ return getYearForPosition(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return getYearForPosition(position);
+ }
+
+ public int getPositionForYear(int year) {
+ return year - mMinYear;
+ }
+
+ public int getYearForPosition(int position) {
+ return mMinYear + position;
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return true;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- final TextViewWithCircularIndicator v = (TextViewWithCircularIndicator)
- super.getView(position, convertView, parent);
- v.setTextAppearance(v.getContext(), mItemTextAppearanceResId);
- v.setCircleColor(mYearActivatedColor);
+ if (convertView == null) {
+ convertView = mInflater.inflate(ITEM_LAYOUT, parent, false);
+ }
- final int year = getItem(position);
- final boolean selected = mController.getSelectedDay().get(Calendar.YEAR) == year;
- v.setActivated(selected);
+ final int year = getYearForPosition(position);
+ final boolean activated = mActivatedYear == year;
+ final int textAppearanceResId;
+ if (activated && mItemActivatedTextAppearanceResId != 0) {
+ textAppearanceResId = mItemActivatedTextAppearanceResId;
+ } else {
+ textAppearanceResId = mItemTextAppearanceResId;
+ }
+
+ final TextView v = (TextView) convertView;
+ v.setText("" + year);
+ v.setTextAppearance(v.getContext(), textAppearanceResId);
+ v.setActivated(activated);
return v;
}
- public void setItemTextAppearance(int resId) {
- mItemTextAppearanceResId = resId;
+ @Override
+ public int getItemViewType(int position) {
+ return 0;
}
- }
- public void postSetSelectionCentered(final int position) {
- postSetSelectionFromTop(position, mViewSize / 2 - mChildSize / 2);
- }
+ @Override
+ public int getViewTypeCount() {
+ return 1;
+ }
- public void postSetSelectionFromTop(final int position, final int offset) {
- post(new Runnable() {
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
- @Override
- public void run() {
- setSelectionFromTop(position, offset);
- requestLayout();
- }
- });
+ @Override
+ public boolean areAllItemsEnabled() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return true;
+ }
}
public int getFirstPositionOffset() {
@@ -177,22 +250,28 @@ class YearPickerView extends ListView implements AdapterView.OnItemClickListener
return firstChild.getTop();
}
- @Override
- public void onDateChanged() {
- updateAdapterData();
- mAdapter.notifyDataSetChanged();
- postSetSelectionCentered(
- mController.getSelectedDay().get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR));
- }
-
/** @hide */
@Override
public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
super.onInitializeAccessibilityEventInternal(event);
+ // There are a bunch of years, so don't bother.
if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
event.setFromIndex(0);
event.setToIndex(0);
}
}
+
+ /**
+ * The callback used to indicate the user changed the year.
+ */
+ public interface OnYearSelectedListener {
+ /**
+ * Called upon a year change.
+ *
+ * @param view The view associated with this listener.
+ * @param year The year that was set.
+ */
+ void onYearChanged(YearPickerView view, int year);
+ }
} \ No newline at end of file
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 02f675c3aaac..f479f4feca35 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -33,6 +33,7 @@ import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.os.Build;
import android.os.SELinux;
+import android.os.SystemProperties;
import android.system.ErrnoException;
import android.system.Os;
import android.util.Slog;
@@ -74,6 +75,7 @@ public class NativeLibraryHelper {
final long[] apkHandles;
final boolean multiArch;
+ final boolean extractNativeLibs;
public static Handle create(File packageFile) throws IOException {
try {
@@ -86,14 +88,16 @@ public class NativeLibraryHelper {
public static Handle create(Package pkg) throws IOException {
return create(pkg.getAllCodePaths(),
- (pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0);
+ (pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0,
+ (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0);
}
public static Handle create(PackageLite lite) throws IOException {
- return create(lite.getAllCodePaths(), lite.multiArch);
+ return create(lite.getAllCodePaths(), lite.multiArch, lite.extractNativeLibs);
}
- private static Handle create(List<String> codePaths, boolean multiArch) throws IOException {
+ private static Handle create(List<String> codePaths, boolean multiArch,
+ boolean extractNativeLibs) throws IOException {
final int size = codePaths.size();
final long[] apkHandles = new long[size];
for (int i = 0; i < size; i++) {
@@ -108,12 +112,13 @@ public class NativeLibraryHelper {
}
}
- return new Handle(apkHandles, multiArch);
+ return new Handle(apkHandles, multiArch, extractNativeLibs);
}
- Handle(long[] apkHandles, boolean multiArch) {
+ Handle(long[] apkHandles, boolean multiArch, boolean extractNativeLibs) {
this.apkHandles = apkHandles;
this.multiArch = multiArch;
+ this.extractNativeLibs = extractNativeLibs;
mGuard.open("close");
}
@@ -146,8 +151,8 @@ public class NativeLibraryHelper {
private static native long nativeSumNativeBinaries(long handle, String cpuAbi);
- private native static int nativeCopyNativeBinaries(long handle,
- String sharedLibraryPath, String abiToCopy);
+ private native static int nativeCopyNativeBinaries(long handle, String sharedLibraryPath,
+ String abiToCopy, boolean extractNativeLibs, boolean hasNativeBridge);
private static long sumNativeBinaries(Handle handle, String abi) {
long sum = 0;
@@ -167,7 +172,8 @@ public class NativeLibraryHelper {
*/
public static int copyNativeBinaries(Handle handle, File sharedLibraryDir, String abi) {
for (long apkHandle : handle.apkHandles) {
- int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi);
+ int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi,
+ handle.extractNativeLibs, HAS_NATIVE_BRIDGE);
if (res != INSTALL_SUCCEEDED) {
return res;
}
@@ -218,7 +224,8 @@ public class NativeLibraryHelper {
/**
* Remove the native binaries of a given package. This deletes the files
*/
- public static void removeNativeBinariesFromDirLI(File nativeLibraryRoot, boolean deleteRootDir) {
+ public static void removeNativeBinariesFromDirLI(File nativeLibraryRoot,
+ boolean deleteRootDir) {
if (DEBUG_NATIVE) {
Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryRoot.getPath());
}
@@ -247,7 +254,8 @@ public class NativeLibraryHelper {
// asked to or this will prevent installation of future updates.
if (deleteRootDir) {
if (!nativeLibraryRoot.delete()) {
- Slog.w(TAG, "Could not delete native binary directory: " + nativeLibraryRoot.getPath());
+ Slog.w(TAG, "Could not delete native binary directory: " +
+ nativeLibraryRoot.getPath());
}
}
}
@@ -416,6 +424,9 @@ public class NativeLibraryHelper {
// We don't care about the other return values for now.
private static final int BITCODE_PRESENT = 1;
+ private static final boolean HAS_NATIVE_BRIDGE =
+ !"0".equals(SystemProperties.get("ro.dalvik.vm.native.bridge", "0"));
+
private static native int hasRenderscriptBitcode(long apkHandle);
public static boolean hasRenderscriptBitcode(Handle handle) throws IOException {
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 57fcf5787356..06bdb24f5959 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -764,17 +764,55 @@ public class InputMethodUtils {
private int[] mCurrentProfileIds = new int[0];
private static void buildEnabledInputMethodsSettingString(
- StringBuilder builder, Pair<String, ArrayList<String>> pair) {
- String id = pair.first;
- ArrayList<String> subtypes = pair.second;
- builder.append(id);
+ StringBuilder builder, Pair<String, ArrayList<String>> ime) {
+ builder.append(ime.first);
// Inputmethod and subtypes are saved in the settings as follows:
// ime0;subtype0;subtype1:ime1;subtype0:ime2:ime3;subtype0;subtype1
- for (String subtypeId: subtypes) {
+ for (String subtypeId: ime.second) {
builder.append(INPUT_METHOD_SUBTYPE_SEPARATER).append(subtypeId);
}
}
+ public static String buildInputMethodsSettingString(
+ List<Pair<String, ArrayList<String>>> allImeSettingsMap) {
+ final StringBuilder b = new StringBuilder();
+ boolean needsSeparator = false;
+ for (Pair<String, ArrayList<String>> ime : allImeSettingsMap) {
+ if (needsSeparator) {
+ b.append(INPUT_METHOD_SEPARATER);
+ }
+ buildEnabledInputMethodsSettingString(b, ime);
+ needsSeparator = true;
+ }
+ return b.toString();
+ }
+
+ public static List<Pair<String, ArrayList<String>>> buildInputMethodsAndSubtypeList(
+ String enabledInputMethodsStr,
+ TextUtils.SimpleStringSplitter inputMethodSplitter,
+ TextUtils.SimpleStringSplitter subtypeSplitter) {
+ ArrayList<Pair<String, ArrayList<String>>> imsList =
+ new ArrayList<Pair<String, ArrayList<String>>>();
+ if (TextUtils.isEmpty(enabledInputMethodsStr)) {
+ return imsList;
+ }
+ inputMethodSplitter.setString(enabledInputMethodsStr);
+ while (inputMethodSplitter.hasNext()) {
+ String nextImsStr = inputMethodSplitter.next();
+ subtypeSplitter.setString(nextImsStr);
+ if (subtypeSplitter.hasNext()) {
+ ArrayList<String> subtypeHashes = new ArrayList<String>();
+ // The first element is ime id.
+ String imeId = subtypeSplitter.next();
+ while (subtypeSplitter.hasNext()) {
+ subtypeHashes.add(subtypeSplitter.next());
+ }
+ imsList.add(new Pair<String, ArrayList<String>>(imeId, subtypeHashes));
+ }
+ }
+ return imsList;
+ }
+
public InputMethodSettings(
Resources res, ContentResolver resolver,
HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList,
@@ -875,27 +913,9 @@ public class InputMethodUtils {
}
public List<Pair<String, ArrayList<String>>> getEnabledInputMethodsAndSubtypeListLocked() {
- ArrayList<Pair<String, ArrayList<String>>> imsList
- = new ArrayList<Pair<String, ArrayList<String>>>();
- final String enabledInputMethodsStr = getEnabledInputMethodsStr();
- if (TextUtils.isEmpty(enabledInputMethodsStr)) {
- return imsList;
- }
- mInputMethodSplitter.setString(enabledInputMethodsStr);
- while (mInputMethodSplitter.hasNext()) {
- String nextImsStr = mInputMethodSplitter.next();
- mSubtypeSplitter.setString(nextImsStr);
- if (mSubtypeSplitter.hasNext()) {
- ArrayList<String> subtypeHashes = new ArrayList<String>();
- // The first element is ime id.
- String imeId = mSubtypeSplitter.next();
- while (mSubtypeSplitter.hasNext()) {
- subtypeHashes.add(mSubtypeSplitter.next());
- }
- imsList.add(new Pair<String, ArrayList<String>>(imeId, subtypeHashes));
- }
- }
- return imsList;
+ return buildInputMethodsAndSubtypeList(getEnabledInputMethodsStr(),
+ mInputMethodSplitter,
+ mSubtypeSplitter);
}
public void appendAndPutEnabledInputMethodLocked(String id, boolean reloadInputMethodStr) {
diff --git a/core/java/com/android/internal/logging/EventLogTags.logtags b/core/java/com/android/internal/logging/EventLogTags.logtags
new file mode 100644
index 000000000000..9e178df8314a
--- /dev/null
+++ b/core/java/com/android/internal/logging/EventLogTags.logtags
@@ -0,0 +1,7 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+option java_package com.android.internal.logging;
+
+# interaction logs
+524287 sysui_view_visibility (category|1|5),(visible|1|6)
+524288 sysui_action (category|1|5),(type|1|6)
diff --git a/core/java/com/android/internal/logging/MetricsConstants.java b/core/java/com/android/internal/logging/MetricsConstants.java
new file mode 100644
index 000000000000..e5cba8415110
--- /dev/null
+++ b/core/java/com/android/internal/logging/MetricsConstants.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.logging;
+
+/**
+ * Constants for mestrics logs.
+ *
+ * @hide
+ */
+public interface MetricsConstants {
+ // These constants must match those in the analytic pipeline.
+ public static final int ACCESSIBILITY = 2;
+ public static final int ACCESSIBILITY_CAPTION_PROPERTIES = 3;
+ public static final int ACCESSIBILITY_SERVICE = 4;
+ public static final int ACCESSIBILITY_TOGGLE_DALTONIZER = 5;
+ public static final int ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE = 6;
+ public static final int ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 7;
+ public static final int ACCOUNT = 8;
+ public static final int ACCOUNTS_ACCOUNT_SYNC = 9;
+ public static final int ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY = 10;
+ public static final int ACCOUNTS_MANAGE_ACCOUNTS = 11;
+ public static final int APN = 12;
+ public static final int APN_EDITOR = 13;
+ public static final int APPLICATION = 16;
+ public static final int APPLICATIONS_APP_LAUNCH = 17;
+ public static final int APPLICATIONS_APP_PERMISSION = 18;
+ public static final int APPLICATIONS_APP_STORAGE = 19;
+ public static final int APPLICATIONS_INSTALLED_APP_DETAILS = 20;
+ public static final int APPLICATIONS_PROCESS_STATS_DETAIL = 21;
+ public static final int APPLICATIONS_PROCESS_STATS_MEM_DETAIL = 22;
+ public static final int APPLICATIONS_PROCESS_STATS_UI = 23;
+ public static final int APP_OPS_DETAILS = 14;
+ public static final int APP_OPS_SUMMARY = 15;
+ public static final int BLUETOOTH = 24;
+ public static final int BLUETOOTH_DEVICE_PICKER = 25;
+ public static final int BLUETOOTH_DEVICE_PROFILES = 26;
+ public static final int CHOOSE_LOCK_GENERIC = 27;
+ public static final int CHOOSE_LOCK_PASSWORD = 28;
+ public static final int CHOOSE_LOCK_PATTERN = 29;
+ public static final int CONFIRM_LOCK_PASSWORD = 30;
+ public static final int CONFIRM_LOCK_PATTERN = 31;
+ public static final int CRYPT_KEEPER = 32;
+ public static final int CRYPT_KEEPER_CONFIRM = 33;
+ public static final int DASHBOARD_SEARCH_RESULTS = 34;
+ public static final int DASHBOARD_SUMMARY = 35;
+ public static final int DATA_USAGE = 36;
+ public static final int DATA_USAGE_SUMMARY = 37;
+ public static final int DATE_TIME = 38;
+ public static final int DEVELOPMENT = 39;
+ public static final int DEVICEINFO = 40;
+ public static final int DEVICEINFO_IMEI_INFORMATION = 41;
+ public static final int DEVICEINFO_MEMORY = 42;
+ public static final int DEVICEINFO_SIM_STATUS = 43;
+ public static final int DEVICEINFO_STATUS = 44;
+ public static final int DEVICEINFO_USB = 45;
+ public static final int DISPLAY = 46;
+ public static final int DREAM = 47;
+ public static final int ENCRYPTION = 48;
+ public static final int FINGERPRINT = 49;
+ public static final int FINGERPRINT_ENROLL = 50;
+ public static final int FUELGAUGE_BATTERY_HISTORY_DETAIL = 51;
+ public static final int FUELGAUGE_BATTERY_SAVER = 52;
+ public static final int FUELGAUGE_POWER_USAGE_DETAIL = 53;
+ public static final int FUELGAUGE_POWER_USAGE_SUMMARY = 54;
+ public static final int HOME = 55;
+ public static final int ICC_LOCK = 56;
+ public static final int INPUTMETHOD_KEYBOARD = 58;
+ public static final int INPUTMETHOD_LANGUAGE = 57;
+ public static final int INPUTMETHOD_SPELL_CHECKERS = 59;
+ public static final int INPUTMETHOD_SUBTYPE_ENABLER = 60;
+ public static final int INPUTMETHOD_USER_DICTIONARY = 61;
+ public static final int INPUTMETHOD_USER_DICTIONARY_ADD_WORD = 62;
+ public static final int LOCATION = 63;
+ public static final int LOCATION_MODE = 64;
+ public static final int MAIN_SETTINGS = 1;
+ public static final int MANAGE_APPLICATIONS = 65;
+ public static final int MASTER_CLEAR = 66;
+ public static final int MASTER_CLEAR_CONFIRM = 67;
+ public static final int NET_DATA_USAGE_METERED = 68;
+ public static final int NFC_BEAM = 69;
+ public static final int NFC_PAYMENT = 70;
+ public static final int NOTIFICATION = 71;
+ public static final int NOTIFICATION_APP_NOTIFICATION = 72;
+ public static final int NOTIFICATION_OTHER_SOUND = 73;
+ public static final int NOTIFICATION_REDACTION = 74;
+ public static final int NOTIFICATION_STATION = 75;
+ public static final int NOTIFICATION_ZEN_MODE = 76;
+ public static final int OWNER_INFO = 77;
+ public static final int PRINT_JOB_SETTINGS = 78;
+ public static final int PRINT_SERVICE_SETTINGS = 79;
+ public static final int PRINT_SETTINGS = 80;
+ public static final int PRIVACY = 81;
+ public static final int PROXY_SELECTOR = 82;
+ public static final int QS_AIRPLANEMODE = 112;
+ public static final int QS_BLUETOOTH = 113;
+ public static final int QS_CAST = 114;
+ public static final int QS_CELLULAR = 115;
+ public static final int QS_COLORINVERSION = 116;
+ public static final int QS_DATAUSAGEDETAIL = 117;
+ public static final int QS_DND = 118;
+ public static final int QS_FLASHLIGHT = 119;
+ public static final int QS_HOTSPOT = 120;
+ public static final int QS_INTENT = 121;
+ public static final int QS_LOCATION = 122;
+ public static final int QS_PANEL = 111;
+ public static final int QS_ROTATIONLOCK = 123;
+ public static final int QS_USERDETAIL = 125;
+ public static final int QS_USERDETAILITE = 124;
+ public static final int QS_WIFI = 126;
+ public static final int RESET_NETWORK = 83;
+ public static final int RESET_NETWORK_CONFIRM = 84;
+ public static final int RUNNING_SERVICE_DETAILS = 85;
+ public static final int SCREEN_PINNING = 86;
+ public static final int SECURITY = 87;
+ public static final int SIM = 88;
+ public static final int TESTING = 89;
+ public static final int TETHER = 90;
+ public static final int TRUSTED_CREDENTIALS = 92;
+ public static final int TRUST_AGENT = 91;
+ public static final int TTS_ENGINE_SETTINGS = 93;
+ public static final int TTS_TEXT_TO_SPEECH = 94;
+ public static final int TYPE_UNKNOWN = 0;
+ public static final int USAGE_ACCESS = 95;
+ public static final int USER = 96;
+ public static final int USERS_APP_RESTRICTIONS = 97;
+ public static final int USER_DETAILS = 98;
+ public static final int VIEW_UNKNOWN = 0;
+ public static final int VOICE_INPUT = 99;
+ public static final int VPN = 100;
+ public static final int WALLPAPER_TYPE = 101;
+ public static final int WFD_WIFI_DISPLAY = 102;
+ public static final int WIFI = 103;
+ public static final int WIFI_ADVANCED = 104;
+ public static final int WIFI_APITEST = 107;
+ public static final int WIFI_CALLING = 105;
+ public static final int WIFI_INFO = 108;
+ public static final int WIFI_P2P = 109;
+ public static final int WIFI_SAVED_ACCESS_POINTS = 106;
+ public static final int WIRELESS = 110;
+}
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
new file mode 100644
index 000000000000..2de739426654
--- /dev/null
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.logging;
+
+
+import android.content.Context;
+import android.os.Build;
+
+/**
+ * Log all the things.
+ *
+ * @hide
+ */
+public class MetricsLogger implements MetricsConstants {
+ // These constants are temporary, they should migrate to MetricsConstants.
+ public static final int APPLICATIONS_ADVANCED = 132;
+ public static final int LOCATION_SCANNING = 133;
+ public static final int MANAGE_APPLICATIONS_ALL = 134;
+ public static final int MANAGE_APPLICATIONS_NOTIFICATIONS = 135;
+
+ public static void visible(Context context, int category) throws IllegalArgumentException {
+ if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
+ throw new IllegalArgumentException("Must define metric category");
+ }
+ EventLogTags.writeSysuiViewVisibility(category, 100);
+ }
+
+ public static void hidden(Context context, int category) {
+ if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
+ throw new IllegalArgumentException("Must define metric category");
+ }
+ EventLogTags.writeSysuiViewVisibility(category, 0);
+ }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 65a970a3c55f..93dc995b0ce4 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -16,18 +16,14 @@
package com.android.internal.os;
-import static android.net.NetworkStats.UID_ALL;
-import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
-
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.bluetooth.BluetoothActivityEnergyInfo;
-import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkStats;
-import android.net.wifi.IWifiManager;
import android.net.wifi.WifiActivityEnergyInfo;
import android.net.wifi.WifiManager;
import android.os.BadParcelableException;
@@ -42,8 +38,6 @@ import android.os.Parcel;
import android.os.ParcelFormatException;
import android.os.Parcelable;
import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.WorkSource;
@@ -65,13 +59,14 @@ import android.util.TimeUtils;
import android.util.Xml;
import android.view.Display;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
+import com.android.server.NetworkManagementSocketTagger;
+import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -109,7 +104,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 120 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 122 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -132,6 +127,9 @@ public final class BatteryStatsImpl extends BatteryStats {
static final int MSG_REPORT_POWER_CHANGE = 2;
static final long DELAY_UPDATE_WAKELOCKS = 5*1000;
+ private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
+ private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
+
public interface BatteryCallback {
public void batteryNeedsCpuUpdate();
public void batteryPowerChanged(boolean onBattery);
@@ -160,7 +158,12 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ public interface ExternalStatsSync {
+ void scheduleSync();
+ }
+
public final MyHandler mHandler;
+ private final ExternalStatsSync mExternalSync;
private BatteryCallback mCallback;
@@ -310,6 +313,9 @@ public final class BatteryStatsImpl extends BatteryStats {
boolean mPowerSaveModeEnabled;
StopwatchTimer mPowerSaveModeEnabledTimer;
+ boolean mDeviceIdling;
+ StopwatchTimer mDeviceIdlingTimer;
+
boolean mDeviceIdleModeEnabled;
StopwatchTimer mDeviceIdleModeEnabledTimer;
@@ -327,7 +333,7 @@ public final class BatteryStatsImpl extends BatteryStats {
int mPhoneSignalStrengthBin = -1;
int mPhoneSignalStrengthBinRaw = -1;
- final StopwatchTimer[] mPhoneSignalStrengthsTimer =
+ final StopwatchTimer[] mPhoneSignalStrengthsTimer =
new StopwatchTimer[SignalStrength.NUM_SIGNAL_STRENGTH_BINS];
StopwatchTimer mPhoneSignalScanningTimer;
@@ -414,6 +420,7 @@ public final class BatteryStatsImpl extends BatteryStats {
int mMinDischargeStepLevel;
final LevelStepTracker mDischargeStepTracker = new LevelStepTracker(MAX_LEVEL_STEPS);
final LevelStepTracker mDailyDischargeStepTracker = new LevelStepTracker(MAX_LEVEL_STEPS*2);
+ ArrayList<PackageChange> mDailyPackageChanges;
int mLastChargeStepLevel;
int mMaxChargeStepLevel;
@@ -441,18 +448,17 @@ public final class BatteryStatsImpl extends BatteryStats {
private int mLoadedNumConnectivityChange;
private int mUnpluggedNumConnectivityChange;
+ private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
+
/*
* Holds a SamplingTimer associated with each kernel wakelock name being tracked.
*/
- private final HashMap<String, SamplingTimer> mKernelWakelockStats =
- new HashMap<String, SamplingTimer>();
+ private final HashMap<String, SamplingTimer> mKernelWakelockStats = new HashMap<>();
public Map<String, ? extends Timer> getKernelWakelockStats() {
return mKernelWakelockStats;
}
- private static int sKernelWakelockUpdateVersion = 0;
-
String mLastWakeupReason = null;
long mLastWakeupUptimeMs = 0;
private final HashMap<String, SamplingTimer> mWakeupReasonStats = new HashMap<>();
@@ -461,56 +467,12 @@ public final class BatteryStatsImpl extends BatteryStats {
return mWakeupReasonStats;
}
- private static final int[] PROC_WAKELOCKS_FORMAT = new int[] {
- Process.PROC_TAB_TERM|Process.PROC_OUT_STRING| // 0: name
- Process.PROC_QUOTES,
- Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 1: count
- Process.PROC_TAB_TERM,
- Process.PROC_TAB_TERM,
- Process.PROC_TAB_TERM,
- Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 5: totalTime
- };
-
- private static final int[] WAKEUP_SOURCES_FORMAT = new int[] {
- Process.PROC_TAB_TERM|Process.PROC_OUT_STRING, // 0: name
- Process.PROC_TAB_TERM|Process.PROC_COMBINE|
- Process.PROC_OUT_LONG, // 1: count
- Process.PROC_TAB_TERM|Process.PROC_COMBINE,
- Process.PROC_TAB_TERM|Process.PROC_COMBINE,
- Process.PROC_TAB_TERM|Process.PROC_COMBINE,
- Process.PROC_TAB_TERM|Process.PROC_COMBINE,
- Process.PROC_TAB_TERM|Process.PROC_COMBINE
- |Process.PROC_OUT_LONG, // 6: totalTime
- };
-
- private final String[] mProcWakelocksName = new String[3];
- private final long[] mProcWakelocksData = new long[3];
-
- /*
- * Used as a buffer for reading in data from /proc/wakelocks before it is processed and added
- * to mKernelWakelockStats.
- */
- private final Map<String, KernelWakelockStats> mProcWakelockFileStats =
- new HashMap<String, KernelWakelockStats>();
-
- private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
- private NetworkStats mCurMobileSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
- private NetworkStats mLastMobileSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
- private NetworkStats mCurWifiSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
- private NetworkStats mLastWifiSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
- private NetworkStats mTmpNetworkStats;
- private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
-
- @GuardedBy("this")
- private String[] mMobileIfaces = new String[0];
- @GuardedBy("this")
- private String[] mWifiIfaces = new String[0];
-
public BatteryStatsImpl() {
mFile = null;
mCheckinFile = null;
mDailyFile = null;
mHandler = null;
+ mExternalSync = null;
clearHistoryLocked();
}
@@ -520,7 +482,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
static class TimeBase {
- private final ArrayList<TimeBaseObs> mObservers = new ArrayList<TimeBaseObs>();
+ private final ArrayList<TimeBaseObs> mObservers = new ArrayList<>();
private long mUptime;
private long mRealtime;
@@ -1775,147 +1737,6 @@ public final class BatteryStatsImpl extends BatteryStats {
return timer;
}
- private final Map<String, KernelWakelockStats> readKernelWakelockStats() {
-
- FileInputStream is;
- byte[] buffer = new byte[32*1024];
- int len;
- boolean wakeup_sources;
-
- try {
- try {
- is = new FileInputStream("/d/wakeup_sources");
- wakeup_sources = true;
- } catch (java.io.FileNotFoundException e) {
- try {
- is = new FileInputStream("/proc/wakelocks");
- wakeup_sources = false;
- } catch (java.io.FileNotFoundException e2) {
- return null;
- }
- }
-
- len = is.read(buffer);
- is.close();
- } catch (java.io.IOException e) {
- return null;
- }
-
- if (len > 0) {
- if (len >= buffer.length) {
- Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length);
- }
- int i;
- for (i=0; i<len; i++) {
- if (buffer[i] == '\0') {
- len = i;
- break;
- }
- }
- }
-
- return parseProcWakelocks(buffer, len, wakeup_sources);
- }
-
- private final Map<String, KernelWakelockStats> parseProcWakelocks(
- byte[] wlBuffer, int len, boolean wakeup_sources) {
- String name;
- int count;
- long totalTime;
- int startIndex;
- int endIndex;
- int numUpdatedWlNames = 0;
-
- // Advance past the first line.
- int i;
- for (i = 0; i < len && wlBuffer[i] != '\n' && wlBuffer[i] != '\0'; i++);
- startIndex = endIndex = i + 1;
-
- synchronized(this) {
- Map<String, KernelWakelockStats> m = mProcWakelockFileStats;
-
- sKernelWakelockUpdateVersion++;
- while (endIndex < len) {
- for (endIndex=startIndex;
- endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0';
- endIndex++);
- endIndex++; // endIndex is an exclusive upper bound.
- // Don't go over the end of the buffer, Process.parseProcLine might
- // write to wlBuffer[endIndex]
- if (endIndex >= (len - 1) ) {
- return m;
- }
-
- String[] nameStringArray = mProcWakelocksName;
- long[] wlData = mProcWakelocksData;
- // Stomp out any bad characters since this is from a circular buffer
- // A corruption is seen sometimes that results in the vm crashing
- // This should prevent crashes and the line will probably fail to parse
- for (int j = startIndex; j < endIndex; j++) {
- if ((wlBuffer[j] & 0x80) != 0) wlBuffer[j] = (byte) '?';
- }
- boolean parsed = Process.parseProcLine(wlBuffer, startIndex, endIndex,
- wakeup_sources ? WAKEUP_SOURCES_FORMAT :
- PROC_WAKELOCKS_FORMAT,
- nameStringArray, wlData, null);
-
- name = nameStringArray[0];
- count = (int) wlData[1];
-
- if (wakeup_sources) {
- // convert milliseconds to microseconds
- totalTime = wlData[2] * 1000;
- } else {
- // convert nanoseconds to microseconds with rounding.
- totalTime = (wlData[2] + 500) / 1000;
- }
-
- if (parsed && name.length() > 0) {
- if (!m.containsKey(name)) {
- m.put(name, new KernelWakelockStats(count, totalTime,
- sKernelWakelockUpdateVersion));
- numUpdatedWlNames++;
- } else {
- KernelWakelockStats kwlStats = m.get(name);
- if (kwlStats.mVersion == sKernelWakelockUpdateVersion) {
- kwlStats.mCount += count;
- kwlStats.mTotalTime += totalTime;
- } else {
- kwlStats.mCount = count;
- kwlStats.mTotalTime = totalTime;
- kwlStats.mVersion = sKernelWakelockUpdateVersion;
- numUpdatedWlNames++;
- }
- }
- }
- startIndex = endIndex;
- }
-
- if (m.size() != numUpdatedWlNames) {
- // Don't report old data.
- Iterator<KernelWakelockStats> itr = m.values().iterator();
- while (itr.hasNext()) {
- if (itr.next().mVersion != sKernelWakelockUpdateVersion) {
- itr.remove();
- }
- }
- }
- return m;
- }
- }
-
- private class KernelWakelockStats {
- public int mCount;
- public long mTotalTime;
- public int mVersion;
-
- KernelWakelockStats(int count, long totalTime, int version) {
- mCount = count;
- mTotalTime = totalTime;
- mVersion = version;
- }
- }
-
/*
* Get the KernelWakelockTimer associated with name, and create a new one if one
* doesn't already exist.
@@ -3387,7 +3208,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtime);
} else {
mMobileRadioActiveTimer.stopRunningLocked(realElapsedRealtimeMs);
- updateNetworkActivityLocked(NET_UPDATE_MOBILE, realElapsedRealtimeMs);
+ updateMobileRadioStateLocked(realElapsedRealtimeMs);
mMobileRadioActivePerAppTimer.stopRunningLocked(realElapsedRealtimeMs);
}
}
@@ -3417,9 +3238,26 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public void noteDeviceIdleModeLocked(boolean enabled, boolean fromActive, boolean fromMotion) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ boolean nowIdling = enabled;
+ if (mDeviceIdling && !enabled && !fromActive && !fromMotion) {
+ // We don't go out of general idling mode until explicitly taken out of
+ // device idle through going active or significant motion.
+ nowIdling = true;
+ }
+ if (mDeviceIdling != nowIdling) {
+ mDeviceIdling = nowIdling;
+ int stepState = nowIdling ? STEP_LEVEL_MODE_DEVICE_IDLE : 0;
+ mModStepMode |= (mCurStepMode&STEP_LEVEL_MODE_DEVICE_IDLE) ^ stepState;
+ mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_DEVICE_IDLE) | stepState;
+ if (enabled) {
+ mDeviceIdlingTimer.startRunningLocked(elapsedRealtime);
+ } else {
+ mDeviceIdlingTimer.stopRunningLocked(elapsedRealtime);
+ }
+ }
if (mDeviceIdleModeEnabled != enabled) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
mDeviceIdleModeEnabled = enabled;
if (fromMotion) {
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_SIGNIFICANT_MOTION,
@@ -3449,7 +3287,11 @@ public final class BatteryStatsImpl extends BatteryStats {
final long uptime = SystemClock.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PACKAGE_INSTALLED,
pkgName, versionCode);
- mNumConnectivityChange++;
+ PackageChange pc = new PackageChange();
+ pc.mPackageName = pkgName;
+ pc.mUpdate = true;
+ pc.mVersionCode = versionCode;
+ addPackageChange(pc);
}
public void notePackageUninstalledLocked(String pkgName) {
@@ -3457,7 +3299,17 @@ public final class BatteryStatsImpl extends BatteryStats {
final long uptime = SystemClock.uptimeMillis();
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PACKAGE_UNINSTALLED,
pkgName, 0);
- mNumConnectivityChange++;
+ PackageChange pc = new PackageChange();
+ pc.mPackageName = pkgName;
+ pc.mUpdate = true;
+ addPackageChange(pc);
+ }
+
+ private void addPackageChange(PackageChange pc) {
+ if (mDailyPackageChanges == null) {
+ mDailyPackageChanges = new ArrayList<>();
+ }
+ mDailyPackageChanges.add(pc);
}
public void notePhoneOnLocked() {
@@ -3694,6 +3546,7 @@ public final class BatteryStatsImpl extends BatteryStats {
addHistoryRecordLocked(elapsedRealtime, uptime);
mWifiOn = true;
mWifiOnTimer.startRunningLocked(elapsedRealtime);
+ scheduleSyncExternalStatsLocked();
}
}
@@ -3707,6 +3560,7 @@ public final class BatteryStatsImpl extends BatteryStats {
addHistoryRecordLocked(elapsedRealtime, uptime);
mWifiOn = false;
mWifiOnTimer.stopRunningLocked(elapsedRealtime);
+ scheduleSyncExternalStatsLocked();
}
}
@@ -3869,6 +3723,7 @@ public final class BatteryStatsImpl extends BatteryStats {
int uid = mapUid(ws.get(i));
getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
}
+ scheduleSyncExternalStatsLocked();
} else {
Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
}
@@ -3907,6 +3762,7 @@ public final class BatteryStatsImpl extends BatteryStats {
int uid = mapUid(ws.get(i));
getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
}
+ scheduleSyncExternalStatsLocked();
} else {
Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
}
@@ -3921,6 +3777,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
mWifiState = wifiState;
mWifiStateTimer[wifiState].startRunningLocked(elapsedRealtime);
+ scheduleSyncExternalStatsLocked();
}
}
@@ -3992,6 +3849,7 @@ public final class BatteryStatsImpl extends BatteryStats {
addHistoryRecordLocked(elapsedRealtime, uptime);
mBluetoothOn = true;
mBluetoothOnTimer.startRunningLocked(elapsedRealtime);
+ scheduleSyncExternalStatsLocked();
}
}
@@ -4005,6 +3863,7 @@ public final class BatteryStatsImpl extends BatteryStats {
addHistoryRecordLocked(elapsedRealtime, uptime);
mBluetoothOn = false;
mBluetoothOnTimer.stopRunningLocked(elapsedRealtime);
+ scheduleSyncExternalStatsLocked();
}
}
@@ -4031,6 +3890,7 @@ public final class BatteryStatsImpl extends BatteryStats {
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
+ scheduleSyncExternalStatsLocked();
}
mWifiFullLockNesting++;
getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked(elapsedRealtime);
@@ -4046,6 +3906,7 @@ public final class BatteryStatsImpl extends BatteryStats {
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
+ scheduleSyncExternalStatsLocked();
}
getUidStatsLocked(uid).noteFullWifiLockReleasedLocked(elapsedRealtime);
}
@@ -4103,6 +3964,7 @@ public final class BatteryStatsImpl extends BatteryStats {
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
+ scheduleSyncExternalStatsLocked();
}
mWifiMulticastNesting++;
getUidStatsLocked(uid).noteWifiMulticastEnabledLocked(elapsedRealtime);
@@ -4118,6 +3980,7 @@ public final class BatteryStatsImpl extends BatteryStats {
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
+ scheduleSyncExternalStatsLocked();
}
getUidStatsLocked(uid).noteWifiMulticastDisabledLocked(elapsedRealtime);
}
@@ -4225,7 +4088,8 @@ public final class BatteryStatsImpl extends BatteryStats {
// During device boot, qtaguid isn't enabled until after the inital
// loading of battery stats. Now that they're enabled, take our initial
// snapshot for future delta calculation.
- updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime());
+ updateMobileRadioStateLocked(SystemClock.elapsedRealtime());
+ updateWifiStateLocked(null);
}
@Override public long getScreenOnTime(long elapsedRealtimeUs, int which) {
@@ -4262,6 +4126,14 @@ public final class BatteryStatsImpl extends BatteryStats {
return mDeviceIdleModeEnabledTimer.getCountLocked(which);
}
+ @Override public long getDeviceIdlingTime(long elapsedRealtimeUs, int which) {
+ return mDeviceIdlingTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
+ }
+
+ @Override public int getDeviceIdlingCount(int which) {
+ return mDeviceIdlingTimer.getCountLocked(which);
+ }
+
@Override public int getNumConnectivityChange(int which) {
int val = mNumConnectivityChange;
if (which == STATS_CURRENT) {
@@ -4564,17 +4436,17 @@ public final class BatteryStatsImpl extends BatteryStats {
}
@Override
- public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
+ public ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
return mWakelockStats.getMap();
}
@Override
- public Map<String, ? extends BatteryStats.Timer> getSyncStats() {
+ public ArrayMap<String, ? extends BatteryStats.Timer> getSyncStats() {
return mSyncStats.getMap();
}
@Override
- public Map<String, ? extends BatteryStats.Timer> getJobStats() {
+ public ArrayMap<String, ? extends BatteryStats.Timer> getJobStats() {
return mJobStats.getMap();
}
@@ -4584,12 +4456,12 @@ public final class BatteryStatsImpl extends BatteryStats {
}
@Override
- public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
+ public ArrayMap<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
return mProcessStats;
}
@Override
- public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
+ public ArrayMap<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
return mPackageStats;
}
@@ -5907,7 +5779,7 @@ public final class BatteryStatsImpl extends BatteryStats {
Slog.w(TAG, "File corrupt: too many excessive power entries " + N);
return false;
}
-
+
mExcessivePower = new ArrayList<ExcessivePower>();
for (int i=0; i<N; i++) {
ExcessivePower ew = new ExcessivePower();
@@ -6110,40 +5982,20 @@ public final class BatteryStatsImpl extends BatteryStats {
*/
public final class Pkg extends BatteryStats.Uid.Pkg implements TimeBaseObs {
/**
- * Number of times this package has done something that could wake up the
- * device from sleep.
- */
- int mWakeups;
-
- /**
- * Number of things that could wake up the device loaded from a
- * previous save.
+ * Number of times wakeup alarms have occurred for this app.
*/
- int mLoadedWakeups;
-
- /**
- * Number of things that could wake up the device as of the
- * last run.
- */
- int mLastWakeups;
-
- /**
- * Number of things that could wake up the device as of the
- * last run.
- */
- int mUnpluggedWakeups;
+ ArrayMap<String, Counter> mWakeupAlarms = new ArrayMap<>();
/**
* The statics we have collected for this package's services.
*/
- final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
+ final ArrayMap<String, Serv> mServiceStats = new ArrayMap<>();
Pkg() {
mOnBatteryScreenOffTimeBase.add(this);
}
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
- mUnpluggedWakeups = mWakeups;
}
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
@@ -6154,10 +6006,12 @@ public final class BatteryStatsImpl extends BatteryStats {
}
void readFromParcelLocked(Parcel in) {
- mWakeups = in.readInt();
- mLoadedWakeups = in.readInt();
- mLastWakeups = 0;
- mUnpluggedWakeups = in.readInt();
+ int numWA = in.readInt();
+ mWakeupAlarms.clear();
+ for (int i=0; i<numWA; i++) {
+ String tag = in.readString();
+ mWakeupAlarms.put(tag, new Counter(mOnBatteryTimeBase, in));
+ }
int numServs = in.readInt();
mServiceStats.clear();
@@ -6171,34 +6025,39 @@ public final class BatteryStatsImpl extends BatteryStats {
}
void writeToParcelLocked(Parcel out) {
- out.writeInt(mWakeups);
- out.writeInt(mLoadedWakeups);
- out.writeInt(mUnpluggedWakeups);
-
- out.writeInt(mServiceStats.size());
- for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
- out.writeString(servEntry.getKey());
- Uid.Pkg.Serv serv = servEntry.getValue();
-
+ int numWA = mWakeupAlarms.size();
+ out.writeInt(numWA);
+ for (int i=0; i<numWA; i++) {
+ out.writeString(mWakeupAlarms.keyAt(i));
+ mWakeupAlarms.valueAt(i).writeToParcel(out);
+ }
+
+ final int NS = mServiceStats.size();
+ out.writeInt(NS);
+ for (int i=0; i<NS; i++) {
+ out.writeString(mServiceStats.keyAt(i));
+ Uid.Pkg.Serv serv = mServiceStats.valueAt(i);
serv.writeToParcelLocked(out);
}
}
@Override
- public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
- return mServiceStats;
+ public ArrayMap<String, ? extends BatteryStats.Counter> getWakeupAlarmStats() {
+ return mWakeupAlarms;
}
- @Override
- public int getWakeups(int which) {
- int val = mWakeups;
- if (which == STATS_CURRENT) {
- val -= mLoadedWakeups;
- } else if (which == STATS_SINCE_UNPLUGGED) {
- val -= mUnpluggedWakeups;
+ public void noteWakeupAlarmLocked(String tag) {
+ Counter c = mWakeupAlarms.get(tag);
+ if (c == null) {
+ c = new Counter(mOnBatteryTimeBase);
+ mWakeupAlarms.put(tag, c);
}
+ c.stepAtomic();
+ }
- return val;
+ @Override
+ public ArrayMap<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
+ return mServiceStats;
}
/**
@@ -6440,14 +6299,6 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- public BatteryStatsImpl getBatteryStats() {
- return BatteryStatsImpl.this;
- }
-
- public void incWakeupsLocked() {
- mWakeups++;
- }
-
final Serv newServiceStatsLocked() {
return new Serv();
}
@@ -6706,7 +6557,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- public BatteryStatsImpl(File systemDir, Handler handler) {
+ public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) {
if (systemDir != null) {
mFile = new JournaledFile(new File(systemDir, "batterystats.bin"),
new File(systemDir, "batterystats.bin.tmp"));
@@ -6715,6 +6566,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin"));
mDailyFile = new AtomicFile(new File(systemDir, "batterystats-daily.xml"));
+ mExternalSync = externalSync;
mHandler = new MyHandler(handler.getLooper());
mStartCount++;
mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase);
@@ -6724,6 +6576,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mInteractiveTimer = new StopwatchTimer(null, -10, null, mOnBatteryTimeBase);
mPowerSaveModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase);
mDeviceIdleModeEnabledTimer = new StopwatchTimer(null, -11, null, mOnBatteryTimeBase);
+ mDeviceIdlingTimer = new StopwatchTimer(null, -12, null, mOnBatteryTimeBase);
mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null,
@@ -6786,6 +6639,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mCheckinFile = null;
mDailyFile = null;
mHandler = null;
+ mExternalSync = null;
clearHistoryLocked();
readFromParcel(p);
}
@@ -6849,6 +6703,11 @@ public final class BatteryStatsImpl extends BatteryStats {
mDailyChargeStepTracker.mNumStepDurations,
mDailyChargeStepTracker.mStepDurations);
}
+ if (mDailyPackageChanges != null) {
+ hasData = true;
+ item.mPackageChanges = mDailyPackageChanges;
+ mDailyPackageChanges = null;
+ }
mDailyDischargeStepTracker.init();
mDailyChargeStepTracker.init();
updateDailyDeadlineLocked();
@@ -6899,6 +6758,21 @@ public final class BatteryStatsImpl extends BatteryStats {
out.attribute(null, "end", Long.toString(dit.mEndTime));
writeDailyLevelSteps(out, "dis", dit.mDischargeSteps, sb);
writeDailyLevelSteps(out, "chg", dit.mChargeSteps, sb);
+ if (dit.mPackageChanges != null) {
+ for (int j=0; j<dit.mPackageChanges.size(); j++) {
+ PackageChange pc = dit.mPackageChanges.get(j);
+ if (pc.mUpdate) {
+ out.startTag(null, "upd");
+ out.attribute(null, "pkg", pc.mPackageName);
+ out.attribute(null, "ver", Integer.toString(pc.mVersionCode));
+ out.endTag(null, "upd");
+ } else {
+ out.startTag(null, "rem");
+ out.attribute(null, "pkg", pc.mPackageName);
+ out.endTag(null, "rem");
+ }
+ }
+ }
out.endTag(null, "item");
}
out.endTag(null, "daily-items");
@@ -7011,6 +6885,26 @@ public final class BatteryStatsImpl extends BatteryStats {
readDailyItemTagDetailsLocked(parser, dit, false, "dis");
} else if (tagName.equals("chg")) {
readDailyItemTagDetailsLocked(parser, dit, true, "chg");
+ } else if (tagName.equals("upd")) {
+ if (dit.mPackageChanges == null) {
+ dit.mPackageChanges = new ArrayList<>();
+ }
+ PackageChange pc = new PackageChange();
+ pc.mUpdate = true;
+ pc.mPackageName = parser.getAttributeValue(null, "pkg");
+ String verStr = parser.getAttributeValue(null, "ver");
+ pc.mVersionCode = verStr != null ? Integer.parseInt(verStr) : 0;
+ dit.mPackageChanges.add(pc);
+ XmlUtils.skipCurrentTag(parser);
+ } else if (tagName.equals("rem")) {
+ if (dit.mPackageChanges == null) {
+ dit.mPackageChanges = new ArrayList<>();
+ }
+ PackageChange pc = new PackageChange();
+ pc.mUpdate = false;
+ pc.mPackageName = parser.getAttributeValue(null, "pkg");
+ dit.mPackageChanges.add(pc);
+ XmlUtils.skipCurrentTag(parser);
} else {
Slog.w(TAG, "Unknown element under <item>: "
+ parser.getName());
@@ -7295,6 +7189,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mInteractiveTimer.reset(false);
mPowerSaveModeEnabledTimer.reset(false);
mDeviceIdleModeEnabledTimer.reset(false);
+ mDeviceIdlingTimer.reset(false);
mPhoneOnTimer.reset(false);
mAudioOnTimer.reset(false);
mVideoOnTimer.reset(false);
@@ -7416,21 +7311,233 @@ public final class BatteryStatsImpl extends BatteryStats {
mDischargeScreenOffUnplugLevel = mDischargeCurrentLevel;
}
}
-
+
public void pullPendingStateUpdatesLocked() {
- updateKernelWakelocksLocked();
- updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime());
- // TODO(adamlesinski): enable when bluedroid stops deadlocking. b/19248786
- // updateBluetoothControllerActivityLocked();
- // TODO(adamlesinski): disabled to avoid deadlock. Need to change how external
- // data is pulled/accessed from BatteryStats. b/19729960
- // updateWifiControllerActivityLocked();
if (mOnBatteryInternal) {
final boolean screenOn = mScreenState == Display.STATE_ON;
updateDischargeScreenLevelsLocked(screenOn, screenOn);
}
}
+ private String[] mMobileIfaces = EmptyArray.STRING;
+ private String[] mWifiIfaces = EmptyArray.STRING;
+
+ private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
+
+ private static final int NETWORK_STATS_LAST = 0;
+ private static final int NETWORK_STATS_NEXT = 1;
+ private static final int NETWORK_STATS_DELTA = 2;
+
+ private final NetworkStats[] mMobileNetworkStats = new NetworkStats[] {
+ new NetworkStats(SystemClock.elapsedRealtime(), 50),
+ new NetworkStats(SystemClock.elapsedRealtime(), 50),
+ new NetworkStats(SystemClock.elapsedRealtime(), 50)
+ };
+
+ private final NetworkStats[] mWifiNetworkStats = new NetworkStats[] {
+ new NetworkStats(SystemClock.elapsedRealtime(), 50),
+ new NetworkStats(SystemClock.elapsedRealtime(), 50),
+ new NetworkStats(SystemClock.elapsedRealtime(), 50)
+ };
+
+ /**
+ * Retrieves the delta of network stats for the given network ifaces. Uses networkStatsBuffer
+ * as a buffer of NetworkStats objects to cycle through when computing deltas.
+ */
+ private NetworkStats getNetworkStatsDeltaLocked(String[] ifaces,
+ NetworkStats[] networkStatsBuffer)
+ throws IOException {
+ if (!SystemProperties.getBoolean(NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED,
+ false)) {
+ return null;
+ }
+
+ final NetworkStats stats = mNetworkStatsFactory.readNetworkStatsDetail(NetworkStats.UID_ALL,
+ ifaces, NetworkStats.TAG_NONE, networkStatsBuffer[NETWORK_STATS_NEXT]);
+ networkStatsBuffer[NETWORK_STATS_DELTA] = NetworkStats.subtract(stats,
+ networkStatsBuffer[NETWORK_STATS_LAST], null, null,
+ networkStatsBuffer[NETWORK_STATS_DELTA]);
+ networkStatsBuffer[NETWORK_STATS_NEXT] = networkStatsBuffer[NETWORK_STATS_LAST];
+ networkStatsBuffer[NETWORK_STATS_LAST] = stats;
+ return networkStatsBuffer[NETWORK_STATS_DELTA];
+ }
+
+ /**
+ * Distribute WiFi energy info and network traffic to apps.
+ * @param info The energy information from the WiFi controller.
+ */
+ public void updateWifiStateLocked(@Nullable final WifiActivityEnergyInfo info) {
+ final NetworkStats delta;
+ try {
+ delta = getNetworkStatsDeltaLocked(mWifiIfaces, mWifiNetworkStats);
+ } catch (IOException e) {
+ Slog.wtf(TAG, "Failed to get wifi network stats", e);
+ return;
+ }
+
+ if (!mOnBatteryInternal) {
+ return;
+ }
+
+ if (delta != null) {
+ final int size = delta.size();
+ for (int i = 0; i < size; i++) {
+ final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
+
+ if (DEBUG) {
+ Slog.d(TAG, "Wifi uid " + entry.uid + ": delta rx=" + entry.rxBytes
+ + " tx=" + entry.txBytes);
+ }
+
+ if (entry.rxBytes == 0 || entry.txBytes == 0) {
+ continue;
+ }
+
+ final Uid u = getUidStatsLocked(mapUid(entry.uid));
+ u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes,
+ entry.rxPackets);
+ u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes,
+ entry.txPackets);
+
+ mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
+ entry.rxBytes);
+ mNetworkByteActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
+ entry.txBytes);
+ mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
+ entry.rxPackets);
+ mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
+ entry.txPackets);
+ }
+ }
+
+ if (info != null) {
+ // Update WiFi controller stats.
+ mWifiActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
+ info.getControllerRxTimeMillis());
+ mWifiActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
+ info.getControllerTxTimeMillis());
+ mWifiActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
+ info.getControllerIdleTimeMillis());
+ mWifiActivityCounters[CONTROLLER_ENERGY].addCountLocked(
+ info.getControllerEnergyUsed());
+ }
+ }
+
+ /**
+ * Distribute Cell radio energy info and network traffic to apps.
+ */
+ public void updateMobileRadioStateLocked(long elapsedRealtimeMs) {
+ final NetworkStats delta;
+
+ try {
+ delta = getNetworkStatsDeltaLocked(mMobileIfaces, mMobileNetworkStats);
+ } catch (IOException e) {
+ Slog.wtf(TAG, "Failed to get mobile network stats", e);
+ return;
+ }
+
+ if (delta == null || !mOnBatteryInternal) {
+ return;
+ }
+
+ long radioTime = mMobileRadioActivePerAppTimer.checkpointRunningLocked(elapsedRealtimeMs);
+ long totalPackets = delta.getTotalPackets();
+
+ final int size = delta.size();
+ for (int i = 0; i < size; i++) {
+ final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
+
+ if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
+
+ final Uid u = getUidStatsLocked(mapUid(entry.uid));
+ u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes,
+ entry.rxPackets);
+ u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes,
+ entry.txPackets);
+
+ if (radioTime > 0) {
+ // Distribute total radio active time in to this app.
+ long appPackets = entry.rxPackets + entry.txPackets;
+ long appRadioTime = (radioTime*appPackets)/totalPackets;
+ u.noteMobileRadioActiveTimeLocked(appRadioTime);
+ // Remove this app from the totals, so that we don't lose any time
+ // due to rounding.
+ radioTime -= appRadioTime;
+ totalPackets -= appPackets;
+ }
+
+ mNetworkByteActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
+ entry.rxBytes);
+ mNetworkByteActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
+ entry.txBytes);
+ mNetworkPacketActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
+ entry.rxPackets);
+ mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
+ entry.txPackets);
+ }
+
+ if (radioTime > 0) {
+ // Whoops, there is some radio time we can't blame on an app!
+ mMobileRadioActiveUnknownTime.addCountLocked(radioTime);
+ mMobileRadioActiveUnknownCount.addCountLocked(1);
+ }
+ }
+
+ /**
+ * Distribute Bluetooth energy info and network traffic to apps.
+ * @param info The energy information from the bluetooth controller.
+ */
+ public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) {
+ if (info != null && mOnBatteryInternal) {
+ mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
+ info.getControllerRxTimeMillis());
+ mBluetoothActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
+ info.getControllerTxTimeMillis());
+ mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
+ info.getControllerIdleTimeMillis());
+ mBluetoothActivityCounters[CONTROLLER_ENERGY].addCountLocked(
+ info.getControllerEnergyUsed());
+ }
+ }
+
+ /**
+ * Read and distribute kernel wake lock use across apps.
+ */
+ public void updateKernelWakelocksLocked() {
+ final KernelWakelockStats wakelockStats = mKernelWakelockReader.readKernelWakelockStats(
+ mTmpWakelockStats);
+ if (wakelockStats == null) {
+ // Not crashing might make board bringup easier.
+ Slog.w(TAG, "Couldn't get kernel wake lock stats");
+ return;
+ }
+
+ for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
+ String name = ent.getKey();
+ KernelWakelockStats.Entry kws = ent.getValue();
+
+ SamplingTimer kwlt = mKernelWakelockStats.get(name);
+ if (kwlt == null) {
+ kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase,
+ true /* track reported val */);
+ mKernelWakelockStats.put(name, kwlt);
+ }
+ kwlt.updateCurrentReportedCount(kws.mCount);
+ kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
+ kwlt.setUpdateVersion(kws.mVersion);
+ }
+
+ if (wakelockStats.size() != mKernelWakelockStats.size()) {
+ // Set timers to stale if they didn't appear in /proc/wakelocks this time.
+ for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
+ SamplingTimer st = ent.getValue();
+ if (st.getUpdateVersion() != wakelockStats.kernelWakelockVersion) {
+ st.setStale();
+ }
+ }
+ }
+ }
+
void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery,
final int oldStatus, final int level) {
boolean doWrite = false;
@@ -7584,340 +7691,132 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ private void scheduleSyncExternalStatsLocked() {
+ if (mExternalSync != null) {
+ mExternalSync.scheduleSync();
+ }
+ }
+
// This should probably be exposed in the API, though it's not critical
- private static final int BATTERY_PLUGGED_NONE = 0;
+ public static final int BATTERY_PLUGGED_NONE = 0;
- public void setBatteryState(int status, int health, int plugType, int level,
+ public void setBatteryStateLocked(int status, int health, int plugType, int level,
int temp, int volt) {
- synchronized(this) {
- final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
- final long uptime = SystemClock.uptimeMillis();
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- if (!mHaveBatteryLevel) {
- mHaveBatteryLevel = true;
- // We start out assuming that the device is plugged in (not
- // on battery). If our first report is now that we are indeed
- // plugged in, then twiddle our state to correctly reflect that
- // since we won't be going through the full setOnBattery().
- if (onBattery == mOnBattery) {
- if (onBattery) {
- mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
- } else {
- mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
- }
- }
- mHistoryCur.batteryStatus = (byte)status;
- mHistoryCur.batteryLevel = (byte)level;
- mMaxChargeStepLevel = mMinDischargeStepLevel =
- mLastChargeStepLevel = mLastDischargeStepLevel = level;
- } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) {
- recordDailyStatsIfNeededLocked(level >= 100 && onBattery);
- }
- int oldStatus = mHistoryCur.batteryStatus;
- if (onBattery) {
- mDischargeCurrentLevel = level;
- if (!mRecordingHistory) {
- mRecordingHistory = true;
- startRecordingHistory(elapsedRealtime, uptime, true);
- }
- } else if (level < 96) {
- if (!mRecordingHistory) {
- mRecordingHistory = true;
- startRecordingHistory(elapsedRealtime, uptime, true);
- }
- }
- mCurrentBatteryLevel = level;
- if (mDischargePlugLevel < 0) {
- mDischargePlugLevel = level;
- }
- if (onBattery != mOnBattery) {
- mHistoryCur.batteryLevel = (byte)level;
- mHistoryCur.batteryStatus = (byte)status;
- mHistoryCur.batteryHealth = (byte)health;
- mHistoryCur.batteryPlugType = (byte)plugType;
- mHistoryCur.batteryTemperature = (short)temp;
- mHistoryCur.batteryVoltage = (char)volt;
- setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level);
- } else {
- boolean changed = false;
- if (mHistoryCur.batteryLevel != level) {
- mHistoryCur.batteryLevel = (byte)level;
- changed = true;
- }
- if (mHistoryCur.batteryStatus != status) {
- mHistoryCur.batteryStatus = (byte)status;
- changed = true;
- }
- if (mHistoryCur.batteryHealth != health) {
- mHistoryCur.batteryHealth = (byte)health;
- changed = true;
- }
- if (mHistoryCur.batteryPlugType != plugType) {
- mHistoryCur.batteryPlugType = (byte)plugType;
- changed = true;
- }
- if (temp >= (mHistoryCur.batteryTemperature+10)
- || temp <= (mHistoryCur.batteryTemperature-10)) {
- mHistoryCur.batteryTemperature = (short)temp;
- changed = true;
- }
- if (volt > (mHistoryCur.batteryVoltage+20)
- || volt < (mHistoryCur.batteryVoltage-20)) {
- mHistoryCur.batteryVoltage = (char)volt;
- changed = true;
- }
- if (changed) {
- addHistoryRecordLocked(elapsedRealtime, uptime);
- }
- long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT)
- | (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT)
- | (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT);
+ final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
+ final long uptime = SystemClock.uptimeMillis();
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ if (!mHaveBatteryLevel) {
+ mHaveBatteryLevel = true;
+ // We start out assuming that the device is plugged in (not
+ // on battery). If our first report is now that we are indeed
+ // plugged in, then twiddle our state to correctly reflect that
+ // since we won't be going through the full setOnBattery().
+ if (onBattery == mOnBattery) {
if (onBattery) {
- if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) {
- mDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
- modeBits, elapsedRealtime);
- mDailyDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
- modeBits, elapsedRealtime);
- mLastDischargeStepLevel = level;
- mMinDischargeStepLevel = level;
- mInitStepMode = mCurStepMode;
- mModStepMode = 0;
- }
+ mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
} else {
- if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
- mChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
- modeBits, elapsedRealtime);
- mDailyChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
- modeBits, elapsedRealtime);
- mLastChargeStepLevel = level;
- mMaxChargeStepLevel = level;
- mInitStepMode = mCurStepMode;
- mModStepMode = 0;
- }
+ mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
}
}
- if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
- // We don't record history while we are plugged in and fully charged.
- // The next time we are unplugged, history will be cleared.
- mRecordingHistory = DEBUG;
+ mHistoryCur.batteryStatus = (byte)status;
+ mHistoryCur.batteryLevel = (byte)level;
+ mMaxChargeStepLevel = mMinDischargeStepLevel =
+ mLastChargeStepLevel = mLastDischargeStepLevel = level;
+ } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) {
+ recordDailyStatsIfNeededLocked(level >= 100 && onBattery);
+ }
+ int oldStatus = mHistoryCur.batteryStatus;
+ if (onBattery) {
+ mDischargeCurrentLevel = level;
+ if (!mRecordingHistory) {
+ mRecordingHistory = true;
+ startRecordingHistory(elapsedRealtime, uptime, true);
+ }
+ } else if (level < 96) {
+ if (!mRecordingHistory) {
+ mRecordingHistory = true;
+ startRecordingHistory(elapsedRealtime, uptime, true);
}
}
- }
-
- public void updateKernelWakelocksLocked() {
- Map<String, KernelWakelockStats> m = readKernelWakelockStats();
-
- if (m == null) {
- // Not crashing might make board bringup easier.
- Slog.w(TAG, "Couldn't get kernel wake lock stats");
- return;
+ mCurrentBatteryLevel = level;
+ if (mDischargePlugLevel < 0) {
+ mDischargePlugLevel = level;
}
+ if (onBattery != mOnBattery) {
+ mHistoryCur.batteryLevel = (byte)level;
+ mHistoryCur.batteryStatus = (byte)status;
+ mHistoryCur.batteryHealth = (byte)health;
+ mHistoryCur.batteryPlugType = (byte)plugType;
+ mHistoryCur.batteryTemperature = (short)temp;
+ mHistoryCur.batteryVoltage = (char)volt;
+ setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level);
+ } else {
+ boolean changed = false;
+ if (mHistoryCur.batteryLevel != level) {
+ mHistoryCur.batteryLevel = (byte)level;
+ changed = true;
- for (Map.Entry<String, KernelWakelockStats> ent : m.entrySet()) {
- String name = ent.getKey();
- KernelWakelockStats kws = ent.getValue();
-
- SamplingTimer kwlt = mKernelWakelockStats.get(name);
- if (kwlt == null) {
- kwlt = new SamplingTimer(mOnBatteryScreenOffTimeBase,
- true /* track reported val */);
- mKernelWakelockStats.put(name, kwlt);
+ // TODO(adamlesinski): Schedule the creation of a HistoryStepDetails record
+ // which will pull external stats.
+ scheduleSyncExternalStatsLocked();
}
- kwlt.updateCurrentReportedCount(kws.mCount);
- kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
- kwlt.setUpdateVersion(sKernelWakelockUpdateVersion);
- }
-
- if (m.size() != mKernelWakelockStats.size()) {
- // Set timers to stale if they didn't appear in /proc/wakelocks this time.
- for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
- SamplingTimer st = ent.getValue();
- if (st.getUpdateVersion() != sKernelWakelockUpdateVersion) {
- st.setStale();
- }
+ if (mHistoryCur.batteryStatus != status) {
+ mHistoryCur.batteryStatus = (byte)status;
+ changed = true;
}
- }
- }
-
- static final int NET_UPDATE_MOBILE = 1<<0;
- static final int NET_UPDATE_WIFI = 1<<1;
- static final int NET_UPDATE_ALL = 0xffff;
-
- private void updateNetworkActivityLocked(int which, long elapsedRealtimeMs) {
- if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return;
-
- if ((which&NET_UPDATE_MOBILE) != 0 && mMobileIfaces.length > 0) {
- final NetworkStats snapshot;
- final NetworkStats last = mCurMobileSnapshot;
- try {
- snapshot = mNetworkStatsFactory.readNetworkStatsDetail(UID_ALL,
- mMobileIfaces, NetworkStats.TAG_NONE, mLastMobileSnapshot);
- } catch (IOException e) {
- Log.wtf(TAG, "Failed to read mobile network stats", e);
- return;
+ if (mHistoryCur.batteryHealth != health) {
+ mHistoryCur.batteryHealth = (byte)health;
+ changed = true;
}
-
- mCurMobileSnapshot = snapshot;
- mLastMobileSnapshot = last;
-
- if (mOnBatteryInternal) {
- final NetworkStats delta = NetworkStats.subtract(snapshot, last,
- null, null, mTmpNetworkStats);
- mTmpNetworkStats = delta;
-
- long radioTime = mMobileRadioActivePerAppTimer.checkpointRunningLocked(
- elapsedRealtimeMs);
- long totalPackets = delta.getTotalPackets();
-
- final int size = delta.size();
- for (int i = 0; i < size; i++) {
- final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
-
- if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
-
- final Uid u = getUidStatsLocked(mapUid(entry.uid));
- u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes,
- entry.rxPackets);
- u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes,
- entry.txPackets);
-
- if (radioTime > 0) {
- // Distribute total radio active time in to this app.
- long appPackets = entry.rxPackets + entry.txPackets;
- long appRadioTime = (radioTime*appPackets)/totalPackets;
- u.noteMobileRadioActiveTimeLocked(appRadioTime);
- // Remove this app from the totals, so that we don't lose any time
- // due to rounding.
- radioTime -= appRadioTime;
- totalPackets -= appPackets;
- }
-
- mNetworkByteActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
- entry.rxBytes);
- mNetworkByteActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
- entry.txBytes);
- mNetworkPacketActivityCounters[NETWORK_MOBILE_RX_DATA].addCountLocked(
- entry.rxPackets);
- mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
- entry.txPackets);
- }
-
- if (radioTime > 0) {
- // Whoops, there is some radio time we can't blame on an app!
- mMobileRadioActiveUnknownTime.addCountLocked(radioTime);
- mMobileRadioActiveUnknownCount.addCountLocked(1);
- }
+ if (mHistoryCur.batteryPlugType != plugType) {
+ mHistoryCur.batteryPlugType = (byte)plugType;
+ changed = true;
}
- }
-
- if ((which&NET_UPDATE_WIFI) != 0 && mWifiIfaces.length > 0) {
- final NetworkStats snapshot;
- final NetworkStats last = mCurWifiSnapshot;
- try {
- snapshot = mNetworkStatsFactory.readNetworkStatsDetail(UID_ALL,
- mWifiIfaces, NetworkStats.TAG_NONE, mLastWifiSnapshot);
- } catch (IOException e) {
- Log.wtf(TAG, "Failed to read wifi network stats", e);
- return;
+ if (temp >= (mHistoryCur.batteryTemperature+10)
+ || temp <= (mHistoryCur.batteryTemperature-10)) {
+ mHistoryCur.batteryTemperature = (short)temp;
+ changed = true;
}
-
- mCurWifiSnapshot = snapshot;
- mLastWifiSnapshot = last;
-
- if (mOnBatteryInternal) {
- final NetworkStats delta = NetworkStats.subtract(snapshot, last,
- null, null, mTmpNetworkStats);
- mTmpNetworkStats = delta;
-
- final int size = delta.size();
- for (int i = 0; i < size; i++) {
- final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
-
- if (DEBUG) {
- final NetworkStats.Entry cur = snapshot.getValues(i, null);
- Slog.d(TAG, "Wifi uid " + entry.uid + ": delta rx=" + entry.rxBytes
- + " tx=" + entry.txBytes + ", cur rx=" + cur.rxBytes
- + " tx=" + cur.txBytes);
- }
-
- if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
-
- final Uid u = getUidStatsLocked(mapUid(entry.uid));
- u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes,
- entry.rxPackets);
- u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes,
- entry.txPackets);
-
- mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
- entry.rxBytes);
- mNetworkByteActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
- entry.txBytes);
- mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
- entry.rxPackets);
- mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
- entry.txPackets);
+ if (volt > (mHistoryCur.batteryVoltage+20)
+ || volt < (mHistoryCur.batteryVoltage-20)) {
+ mHistoryCur.batteryVoltage = (char)volt;
+ changed = true;
+ }
+ if (changed) {
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ }
+ long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT)
+ | (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT)
+ | (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT);
+ if (onBattery) {
+ if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) {
+ mDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
+ modeBits, elapsedRealtime);
+ mDailyDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
+ modeBits, elapsedRealtime);
+ mLastDischargeStepLevel = level;
+ mMinDischargeStepLevel = level;
+ mInitStepMode = mCurStepMode;
+ mModStepMode = 0;
+ }
+ } else {
+ if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
+ mChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
+ modeBits, elapsedRealtime);
+ mDailyChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
+ modeBits, elapsedRealtime);
+ mLastChargeStepLevel = level;
+ mMaxChargeStepLevel = level;
+ mInitStepMode = mCurStepMode;
+ mModStepMode = 0;
}
}
}
- }
-
- private void updateBluetoothControllerActivityLocked() {
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- if (adapter == null) {
- return;
- }
-
- // We read the data even if we are not on battery. Each read clears
- // the previous data, so we must always read to make sure the
- // data is for the current interval.
- BluetoothActivityEnergyInfo info = adapter.getControllerActivityEnergyInfo(
- BluetoothAdapter.ACTIVITY_ENERGY_INFO_REFRESHED);
- if (info == null || !info.isValid() || !mOnBatteryInternal) {
- // Bad info or we are not on battery.
- return;
- }
-
- mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
- info.getControllerRxTimeMillis());
- mBluetoothActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
- info.getControllerTxTimeMillis());
- mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
- info.getControllerIdleTimeMillis());
- mBluetoothActivityCounters[CONTROLLER_ENERGY].addCountLocked(
- info.getControllerEnergyUsed());
- }
-
- private void updateWifiControllerActivityLocked() {
- IWifiManager wifiManager = IWifiManager.Stub.asInterface(
- ServiceManager.getService(Context.WIFI_SERVICE));
- if (wifiManager == null) {
- return;
- }
-
- WifiActivityEnergyInfo info;
- try {
- // We read the data even if we are not on battery. Each read clears
- // the previous data, so we must always read to make sure the
- // data is for the current interval.
- info = wifiManager.reportActivityInfo();
- } catch (RemoteException e) {
- // Nothing to report, WiFi is dead.
- return;
- }
-
- if (info == null || !info.isValid() || !mOnBatteryInternal) {
- // Bad info or we are not on battery.
- return;
+ if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
+ // We don't record history while we are plugged in and fully charged.
+ // The next time we are unplugged, history will be cleared.
+ mRecordingHistory = DEBUG;
}
-
- mWifiActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
- info.getControllerRxTimeMillis());
- mWifiActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
- info.getControllerTxTimeMillis());
- mWifiActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
- info.getControllerIdleTimeMillis());
- mWifiActivityCounters[CONTROLLER_ENERGY].addCountLocked(
- info.getControllerEnergyUsed());
}
public long getAwakeTimeBattery() {
@@ -8083,6 +7982,11 @@ public final class BatteryStatsImpl extends BatteryStats {
return mDailyChargeStepTracker;
}
+ @Override
+ public ArrayList<PackageChange> getDailyPackageChanges() {
+ return mDailyPackageChanges;
+ }
+
long getBatteryUptimeLocked() {
return mOnBatteryTimeBase.getUptime(SystemClock.uptimeMillis() * 1000);
}
@@ -8583,6 +8487,20 @@ public final class BatteryStatsImpl extends BatteryStats {
mChargeStepTracker.readFromParcel(in);
mDailyDischargeStepTracker.readFromParcel(in);
mDailyChargeStepTracker.readFromParcel(in);
+ int NPKG = in.readInt();
+ if (NPKG > 0) {
+ mDailyPackageChanges = new ArrayList<>(NPKG);
+ while (NPKG > 0) {
+ NPKG--;
+ PackageChange pc = new PackageChange();
+ pc.mPackageName = in.readString();
+ pc.mUpdate = in.readInt() != 0;
+ pc.mVersionCode = in.readInt();
+ mDailyPackageChanges.add(pc);
+ }
+ } else {
+ mDailyPackageChanges = null;
+ }
mDailyStartTime = in.readLong();
mNextMinDailyDeadline = in.readLong();
mNextMaxDailyDeadline = in.readLong();
@@ -8599,6 +8517,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mPhoneOn = false;
mPowerSaveModeEnabledTimer.readSummaryFromParcelLocked(in);
mDeviceIdleModeEnabledTimer.readSummaryFromParcelLocked(in);
+ mDeviceIdlingTimer.readSummaryFromParcelLocked(in);
mPhoneOnTimer.readSummaryFromParcelLocked(in);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
@@ -8833,7 +8752,18 @@ public final class BatteryStatsImpl extends BatteryStats {
for (int ip = 0; ip < NP; ip++) {
String pkgName = in.readString();
Uid.Pkg p = u.getPackageStatsLocked(pkgName);
- p.mWakeups = p.mLoadedWakeups = in.readInt();
+ final int NWA = in.readInt();
+ if (NWA > 1000) {
+ Slog.w(TAG, "File corrupt: too many wakeup alarms " + NWA);
+ return;
+ }
+ p.mWakeupAlarms.clear();
+ for (int iwa=0; iwa<NWA; iwa++) {
+ String tag = in.readString();
+ Counter c = new Counter(mOnBatteryTimeBase);
+ c.readSummaryFromParcelLocked(in);
+ p.mWakeupAlarms.put(tag, c);
+ }
NS = in.readInt();
if (NS > 1000) {
Slog.w(TAG, "File corrupt: too many services " + NS);
@@ -8890,6 +8820,18 @@ public final class BatteryStatsImpl extends BatteryStats {
mChargeStepTracker.writeToParcel(out);
mDailyDischargeStepTracker.writeToParcel(out);
mDailyChargeStepTracker.writeToParcel(out);
+ if (mDailyPackageChanges != null) {
+ final int NPKG = mDailyPackageChanges.size();
+ out.writeInt(NPKG);
+ for (int i=0; i<NPKG; i++) {
+ PackageChange pc = mDailyPackageChanges.get(i);
+ out.writeString(pc.mPackageName);
+ out.writeInt(pc.mUpdate ? 1 : 0);
+ out.writeInt(pc.mVersionCode);
+ }
+ } else {
+ out.writeInt(0);
+ }
out.writeLong(mDailyStartTime);
out.writeLong(mNextMinDailyDeadline);
out.writeLong(mNextMaxDailyDeadline);
@@ -8901,6 +8843,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mInteractiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mPowerSaveModeEnabledTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mDeviceIdleModeEnabledTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mDeviceIdlingTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -9145,20 +9088,22 @@ public final class BatteryStatsImpl extends BatteryStats {
: u.mPackageStats.entrySet()) {
out.writeString(ent.getKey());
Uid.Pkg ps = ent.getValue();
- out.writeInt(ps.mWakeups);
+ final int NWA = ps.mWakeupAlarms.size();
+ out.writeInt(NWA);
+ for (int iwa=0; iwa<NWA; iwa++) {
+ out.writeString(ps.mWakeupAlarms.keyAt(iwa));
+ ps.mWakeupAlarms.valueAt(iwa).writeSummaryFromParcelLocked(out);
+ }
NS = ps.mServiceStats.size();
out.writeInt(NS);
- if (NS > 0) {
- for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
- : ps.mServiceStats.entrySet()) {
- out.writeString(sent.getKey());
- BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
- long time = ss.getStartTimeToNowLocked(
- mOnBatteryTimeBase.getUptime(NOW_SYS));
- out.writeLong(time);
- out.writeInt(ss.mStarts);
- out.writeInt(ss.mLaunches);
- }
+ for (int is=0; is<NS; is++) {
+ out.writeString(ps.mServiceStats.keyAt(is));
+ BatteryStatsImpl.Uid.Pkg.Serv ss = ps.mServiceStats.valueAt(is);
+ long time = ss.getStartTimeToNowLocked(
+ mOnBatteryTimeBase.getUptime(NOW_SYS));
+ out.writeLong(time);
+ out.writeInt(ss.mStarts);
+ out.writeInt(ss.mLaunches);
}
}
}
@@ -9201,6 +9146,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mPhoneOn = false;
mPowerSaveModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
mDeviceIdleModeEnabledTimer = new StopwatchTimer(null, -11, null, mOnBatteryTimeBase, in);
+ mDeviceIdlingTimer = new StopwatchTimer(null, -12, null, mOnBatteryTimeBase, in);
mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase, in);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
@@ -9367,6 +9313,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mInteractiveTimer.writeToParcel(out, uSecRealtime);
mPowerSaveModeEnabledTimer.writeToParcel(out, uSecRealtime);
mDeviceIdleModeEnabledTimer.writeToParcel(out, uSecRealtime);
+ mDeviceIdlingTimer.writeToParcel(out, uSecRealtime);
mPhoneOnTimer.writeToParcel(out, uSecRealtime);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
@@ -9507,6 +9454,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mPowerSaveModeEnabledTimer.logState(pr, " ");
pr.println("*** Device idle mode timer:");
mDeviceIdleModeEnabledTimer.logState(pr, " ");
+ pr.println("*** Device idling timer:");
+ mDeviceIdlingTimer.logState(pr, " ");
pr.println("*** Phone timer:");
mPhoneOnTimer.logState(pr, " ");
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
new file mode 100644
index 000000000000..768d586b6f1a
--- /dev/null
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import android.os.Process;
+import android.util.Slog;
+
+import java.io.FileInputStream;
+import java.util.Iterator;
+
+/**
+ * Reads and parses wakelock stats from the kernel (/proc/wakelocks).
+ */
+public class KernelWakelockReader {
+ private static final String TAG = "KernelWakelockReader";
+ private static int sKernelWakelockUpdateVersion = 0;
+ private static final String sWakelockFile = "/proc/wakelocks";
+ private static final String sWakeupSourceFile = "/d/wakeup_sources";
+
+ private static final int[] PROC_WAKELOCKS_FORMAT = new int[] {
+ Process.PROC_TAB_TERM|Process.PROC_OUT_STRING| // 0: name
+ Process.PROC_QUOTES,
+ Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 1: count
+ Process.PROC_TAB_TERM,
+ Process.PROC_TAB_TERM,
+ Process.PROC_TAB_TERM,
+ Process.PROC_TAB_TERM|Process.PROC_OUT_LONG, // 5: totalTime
+ };
+
+ private static final int[] WAKEUP_SOURCES_FORMAT = new int[] {
+ Process.PROC_TAB_TERM|Process.PROC_OUT_STRING, // 0: name
+ Process.PROC_TAB_TERM|Process.PROC_COMBINE|
+ Process.PROC_OUT_LONG, // 1: count
+ Process.PROC_TAB_TERM|Process.PROC_COMBINE,
+ Process.PROC_TAB_TERM|Process.PROC_COMBINE,
+ Process.PROC_TAB_TERM|Process.PROC_COMBINE,
+ Process.PROC_TAB_TERM|Process.PROC_COMBINE,
+ Process.PROC_TAB_TERM|Process.PROC_COMBINE
+ |Process.PROC_OUT_LONG, // 6: totalTime
+ };
+
+ private final String[] mProcWakelocksName = new String[3];
+ private final long[] mProcWakelocksData = new long[3];
+
+ /**
+ * Reads kernel wakelock stats and updates the staleStats with the new information.
+ * @param staleStats Existing object to update.
+ * @return the updated data.
+ */
+ public final KernelWakelockStats readKernelWakelockStats(KernelWakelockStats staleStats) {
+ byte[] buffer = new byte[32*1024];
+ int len;
+ boolean wakeup_sources;
+
+ try {
+ FileInputStream is;
+ try {
+ is = new FileInputStream(sWakeupSourceFile);
+ wakeup_sources = true;
+ } catch (java.io.FileNotFoundException e) {
+ try {
+ is = new FileInputStream(sWakelockFile);
+ wakeup_sources = false;
+ } catch (java.io.FileNotFoundException e2) {
+ return null;
+ }
+ }
+
+ len = is.read(buffer);
+ is.close();
+ } catch (java.io.IOException e) {
+ return null;
+ }
+
+ if (len > 0) {
+ if (len >= buffer.length) {
+ Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length);
+ }
+ int i;
+ for (i=0; i<len; i++) {
+ if (buffer[i] == '\0') {
+ len = i;
+ break;
+ }
+ }
+ }
+ return parseProcWakelocks(buffer, len, wakeup_sources, staleStats);
+ }
+
+ /**
+ * Reads the wakelocks and updates the staleStats with the new information.
+ */
+ private KernelWakelockStats parseProcWakelocks(byte[] wlBuffer, int len, boolean wakeup_sources,
+ final KernelWakelockStats staleStats) {
+ String name;
+ int count;
+ long totalTime;
+ int startIndex;
+ int endIndex;
+ int numUpdatedWlNames = 0;
+
+ // Advance past the first line.
+ int i;
+ for (i = 0; i < len && wlBuffer[i] != '\n' && wlBuffer[i] != '\0'; i++);
+ startIndex = endIndex = i + 1;
+
+ synchronized(this) {
+ sKernelWakelockUpdateVersion++;
+ while (endIndex < len) {
+ for (endIndex=startIndex;
+ endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0';
+ endIndex++);
+ endIndex++; // endIndex is an exclusive upper bound.
+ // Don't go over the end of the buffer, Process.parseProcLine might
+ // write to wlBuffer[endIndex]
+ if (endIndex >= (len - 1) ) {
+ return staleStats;
+ }
+
+ String[] nameStringArray = mProcWakelocksName;
+ long[] wlData = mProcWakelocksData;
+ // Stomp out any bad characters since this is from a circular buffer
+ // A corruption is seen sometimes that results in the vm crashing
+ // This should prevent crashes and the line will probably fail to parse
+ for (int j = startIndex; j < endIndex; j++) {
+ if ((wlBuffer[j] & 0x80) != 0) wlBuffer[j] = (byte) '?';
+ }
+ boolean parsed = Process.parseProcLine(wlBuffer, startIndex, endIndex,
+ wakeup_sources ? WAKEUP_SOURCES_FORMAT :
+ PROC_WAKELOCKS_FORMAT,
+ nameStringArray, wlData, null);
+
+ name = nameStringArray[0];
+ count = (int) wlData[1];
+
+ if (wakeup_sources) {
+ // convert milliseconds to microseconds
+ totalTime = wlData[2] * 1000;
+ } else {
+ // convert nanoseconds to microseconds with rounding.
+ totalTime = (wlData[2] + 500) / 1000;
+ }
+
+ if (parsed && name.length() > 0) {
+ if (!staleStats.containsKey(name)) {
+ staleStats.put(name, new KernelWakelockStats.Entry(count, totalTime,
+ sKernelWakelockUpdateVersion));
+ numUpdatedWlNames++;
+ } else {
+ KernelWakelockStats.Entry kwlStats = staleStats.get(name);
+ if (kwlStats.mVersion == sKernelWakelockUpdateVersion) {
+ kwlStats.mCount += count;
+ kwlStats.mTotalTime += totalTime;
+ } else {
+ kwlStats.mCount = count;
+ kwlStats.mTotalTime = totalTime;
+ kwlStats.mVersion = sKernelWakelockUpdateVersion;
+ numUpdatedWlNames++;
+ }
+ }
+ }
+ startIndex = endIndex;
+ }
+
+ if (staleStats.size() != numUpdatedWlNames) {
+ // Don't report old data.
+ Iterator<KernelWakelockStats.Entry> itr = staleStats.values().iterator();
+ while (itr.hasNext()) {
+ if (itr.next().mVersion != sKernelWakelockUpdateVersion) {
+ itr.remove();
+ }
+ }
+ }
+
+ staleStats.kernelWakelockVersion = sKernelWakelockUpdateVersion;
+ return staleStats;
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/KernelWakelockStats.java b/core/java/com/android/internal/os/KernelWakelockStats.java
new file mode 100644
index 000000000000..144ea00ea06e
--- /dev/null
+++ b/core/java/com/android/internal/os/KernelWakelockStats.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import java.util.HashMap;
+
+/**
+ * Kernel wakelock stats object.
+ */
+public class KernelWakelockStats extends HashMap<String, KernelWakelockStats.Entry> {
+ public static class Entry {
+ public int mCount;
+ public long mTotalTime;
+ public int mVersion;
+
+ Entry(int count, long totalTime, int version) {
+ mCount = count;
+ mTotalTime = totalTime;
+ mVersion = version;
+ }
+ }
+
+ int kernelWakelockVersion;
+}
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index d9ebc258a8b1..a106f48745cf 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -52,6 +52,7 @@ public class Protocol {
public static final int BASE_WIFI_RTT_SERVICE = 0x00027300;
public static final int BASE_WIFI_PASSPOINT_MANAGER = 0x00028000;
public static final int BASE_WIFI_PASSPOINT_SERVICE = 0x00028100;
+ public static final int BASE_WIFI_LOGGER = 0x00028300;
public static final int BASE_DHCP = 0x00030000;
public static final int BASE_DATA_CONNECTION = 0x00040000;
public static final int BASE_DATA_CONNECTION_AC = 0x00041000;
diff --git a/core/java/com/android/internal/util/ScreenShapeHelper.java b/core/java/com/android/internal/util/ScreenShapeHelper.java
new file mode 100644
index 000000000000..1bcc7a02438a
--- /dev/null
+++ b/core/java/com/android/internal/util/ScreenShapeHelper.java
@@ -0,0 +1,48 @@
+package com.android.internal.util;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.ViewRootImpl;
+
+import com.android.internal.R;
+
+/**
+ * @hide
+ */
+public class ScreenShapeHelper {
+ private static final boolean IS_EMULATOR = Build.HARDWARE.contains("goldfish");
+
+ /**
+ * Return the bottom pixel window outset of a window given its style attributes.
+ * @param displayMetrics Display metrics of the current device
+ * @param windowStyle Window style attributes for the window.
+ * @return An outset dimension in pixels or 0 if no outset should be applied.
+ */
+ public static int getWindowOutsetBottomPx(DisplayMetrics displayMetrics,
+ TypedArray windowStyle) {
+ if (IS_EMULATOR) {
+ return SystemProperties.getInt(ViewRootImpl.PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX, 0);
+ } else if (windowStyle.hasValue(R.styleable.Window_windowOutsetBottom)) {
+ TypedValue outsetBottom = new TypedValue();
+ windowStyle.getValue(R.styleable.Window_windowOutsetBottom, outsetBottom);
+ return (int) outsetBottom.getDimension(displayMetrics);
+ }
+ return 0;
+ }
+
+ /**
+ * Get whether a device has has a round screen.
+ */
+ public static boolean getWindowIsRound(Resources resources) {
+ if (IS_EMULATOR) {
+ return SystemProperties.getBoolean(ViewRootImpl.PROPERTY_EMULATOR_CIRCULAR, false);
+ } else {
+ return resources.getBoolean(
+ com.android.internal.R.bool.config_windowIsRound);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/AccessibleDateAnimator.java b/core/java/com/android/internal/widget/AccessibleDateAnimator.java
deleted file mode 100644
index f97a5d1214b3..000000000000
--- a/core/java/com/android/internal/widget/AccessibleDateAnimator.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import android.content.Context;
-import android.text.format.DateUtils;
-import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.ViewAnimator;
-
-/**
- * @hide
- */
-public class AccessibleDateAnimator extends ViewAnimator {
- private long mDateMillis;
-
- public AccessibleDateAnimator(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public void setDateMillis(long dateMillis) {
- mDateMillis = dateMillis;
- }
-
- /**
- * Announce the currently-selected date when launched.
- */
- @Override
- public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
- if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
- // Clear the event's current text so that only the current date will be spoken.
- event.getText().clear();
- int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR |
- DateUtils.FORMAT_SHOW_WEEKDAY;
-
- String dateString = DateUtils.formatDateTime(getContext(), mDateMillis, flags);
- event.getText().add(dateString);
- return true;
- }
- return super.dispatchPopulateAccessibilityEventInternal(event);
- }
-}
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
new file mode 100644
index 000000000000..be9945d35fbc
--- /dev/null
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.PopupWindow;
+
+import com.android.internal.R;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A floating toolbar for showing contextual menu items.
+ * This view shows as many menu item buttons as can fit in the horizontal toolbar and the
+ * the remaining menu items in a vertical overflow view when the overflow button is clicked.
+ * The horizontal toolbar morphs into the vertical overflow view.
+ */
+public final class FloatingToolbar {
+
+ private static final MenuItem.OnMenuItemClickListener NO_OP_MENUITEM_CLICK_LISTENER =
+ new MenuItem.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ return false;
+ }
+ };
+
+ private final Context mContext;
+ private final FloatingToolbarPopup mPopup;
+ private final ViewGroup mMenuItemButtonsContainer;
+ private final View.OnClickListener mMenuItemButtonOnClickListener =
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (v.getTag() instanceof MenuItem) {
+ mMenuItemClickListener.onMenuItemClick((MenuItem) v.getTag());
+ mPopup.dismiss();
+ }
+ }
+ };
+
+ private final Rect mContentRect = new Rect();
+ private final Point mCoordinates = new Point();
+
+ private Menu mMenu;
+ private List<CharSequence> mShowingTitles = new ArrayList<CharSequence>();
+ private MenuItem.OnMenuItemClickListener mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER;
+ private View mOpenOverflowButton;
+
+ private int mSuggestedWidth;
+
+ /**
+ * Initializes a floating toolbar.
+ */
+ public FloatingToolbar(Context context, Window window) {
+ mContext = Preconditions.checkNotNull(context);
+ mPopup = new FloatingToolbarPopup(Preconditions.checkNotNull(window.getDecorView()));
+ mMenuItemButtonsContainer = createMenuButtonsContainer(context);
+ }
+
+ /**
+ * Sets the menu to be shown in this floating toolbar.
+ * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the
+ * toolbar.
+ */
+ public FloatingToolbar setMenu(Menu menu) {
+ mMenu = Preconditions.checkNotNull(menu);
+ return this;
+ }
+
+ /**
+ * Sets the custom listener for invocation of menu items in this floating
+ * toolbar.
+ */
+ public FloatingToolbar setOnMenuItemClickListener(
+ MenuItem.OnMenuItemClickListener menuItemClickListener) {
+ if (menuItemClickListener != null) {
+ mMenuItemClickListener = menuItemClickListener;
+ } else {
+ mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER;
+ }
+ return this;
+ }
+
+ /**
+ * Sets the content rectangle. This is the area of the interesting content that this toolbar
+ * should avoid obstructing.
+ * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the
+ * toolbar.
+ */
+ public FloatingToolbar setContentRect(Rect rect) {
+ mContentRect.set(Preconditions.checkNotNull(rect));
+ return this;
+ }
+
+ /**
+ * Sets the suggested width of this floating toolbar.
+ * The actual width will be about this size but there are no guarantees that it will be exactly
+ * the suggested width.
+ * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the
+ * toolbar.
+ */
+ public FloatingToolbar setSuggestedWidth(int suggestedWidth) {
+ mSuggestedWidth = suggestedWidth;
+ return this;
+ }
+
+ /**
+ * Shows this floating toolbar.
+ */
+ public FloatingToolbar show() {
+ List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu);
+ if (hasContentChanged(menuItems) || hasWidthChanged()) {
+ mPopup.dismiss();
+ layoutMenuItemButtons(menuItems);
+ mShowingTitles = getMenuItemTitles(menuItems);
+ }
+ refreshCoordinates();
+ mPopup.updateCoordinates(mCoordinates.x, mCoordinates.y);
+ if (!mPopup.isShowing()) {
+ mPopup.show(mCoordinates.x, mCoordinates.y);
+ }
+ return this;
+ }
+
+ /**
+ * Updates this floating toolbar to reflect recent position and view updates.
+ * NOTE: This method is a no-op if the toolbar isn't showing.
+ */
+ public FloatingToolbar updateLayout() {
+ if (mPopup.isShowing()) {
+ // show() performs all the logic we need here.
+ show();
+ }
+ return this;
+ }
+
+ /**
+ * Dismisses this floating toolbar.
+ */
+ public void dismiss() {
+ mPopup.dismiss();
+ }
+
+ /**
+ * Returns {@code true} if this popup is currently showing. {@code false} otherwise.
+ */
+ public boolean isShowing() {
+ return mPopup.isShowing();
+ }
+
+ /**
+ * Refreshes {@link #mCoordinates} with values based on {@link #mContentRect}.
+ */
+ private void refreshCoordinates() {
+ int popupWidth = mPopup.getWidth();
+ int popupHeight = mPopup.getHeight();
+ if (!mPopup.isShowing()) {
+ // Popup isn't yet shown, get estimated size from the menu item buttons container.
+ mMenuItemButtonsContainer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ popupWidth = mMenuItemButtonsContainer.getMeasuredWidth();
+ popupHeight = mMenuItemButtonsContainer.getMeasuredHeight();
+ }
+ int x = mContentRect.centerX() - popupWidth / 2;
+ int y;
+ if (shouldDisplayAtTopOfContent()) {
+ y = mContentRect.top - popupHeight;
+ } else {
+ y = mContentRect.bottom;
+ }
+ mCoordinates.set(x, y);
+ }
+
+ /**
+ * Returns true if this floating toolbar's menu items have been reordered or changed.
+ */
+ private boolean hasContentChanged(List<MenuItem> menuItems) {
+ return !mShowingTitles.equals(getMenuItemTitles(menuItems));
+ }
+
+ /**
+ * Returns true if there is a significant change in width of the toolbar.
+ */
+ private boolean hasWidthChanged() {
+ int actualWidth = mPopup.getWidth();
+ int difference = Math.abs(actualWidth - mSuggestedWidth);
+ return difference > (actualWidth * 0.2);
+ }
+
+ /**
+ * Returns true if the preferred positioning of the toolbar is above the content rect.
+ */
+ private boolean shouldDisplayAtTopOfContent() {
+ return mContentRect.top - getMinimumOverflowHeight(mContext) > 0;
+ }
+
+ /**
+ * Returns the visible and enabled menu items in the specified menu.
+ * This method is recursive.
+ */
+ private List<MenuItem> getVisibleAndEnabledMenuItems(Menu menu) {
+ List<MenuItem> menuItems = new ArrayList<MenuItem>();
+ for (int i = 0; (menu != null) && (i < menu.size()); i++) {
+ MenuItem menuItem = menu.getItem(i);
+ if (menuItem.isVisible() && menuItem.isEnabled()) {
+ Menu subMenu = menuItem.getSubMenu();
+ if (subMenu != null) {
+ menuItems.addAll(getVisibleAndEnabledMenuItems(subMenu));
+ } else {
+ menuItems.add(menuItem);
+ }
+ }
+ }
+ return menuItems;
+ }
+
+ private List<CharSequence> getMenuItemTitles(List<MenuItem> menuItems) {
+ List<CharSequence> titles = new ArrayList<CharSequence>();
+ for (MenuItem menuItem : menuItems) {
+ titles.add(menuItem.getTitle());
+ }
+ return titles;
+ }
+
+ private void layoutMenuItemButtons(List<MenuItem> menuItems) {
+ final int toolbarWidth = getAdjustedToolbarWidth(mContext, mSuggestedWidth)
+ // Reserve space for the "open overflow" button.
+ - getEstimatedOpenOverflowButtonWidth(mContext);
+
+ int availableWidth = toolbarWidth;
+ LinkedList<MenuItem> remainingMenuItems = new LinkedList<MenuItem>(menuItems);
+
+ mMenuItemButtonsContainer.removeAllViews();
+
+ boolean isFirstItem = true;
+ while (!remainingMenuItems.isEmpty()) {
+ final MenuItem menuItem = remainingMenuItems.peek();
+ Button menuItemButton = createMenuItemButton(mContext, menuItem);
+
+ // Adding additional left padding for the first button to even out button spacing.
+ if (isFirstItem) {
+ menuItemButton.setPadding(
+ 2 * menuItemButton.getPaddingLeft(),
+ menuItemButton.getPaddingTop(),
+ menuItemButton.getPaddingRight(),
+ menuItemButton.getPaddingBottom());
+ isFirstItem = false;
+ }
+
+ // Adding additional right padding for the last button to even out button spacing.
+ if (remainingMenuItems.size() == 1) {
+ menuItemButton.setPadding(
+ menuItemButton.getPaddingLeft(),
+ menuItemButton.getPaddingTop(),
+ 2 * menuItemButton.getPaddingRight(),
+ menuItemButton.getPaddingBottom());
+ }
+
+ menuItemButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ int menuItemButtonWidth = Math.min(menuItemButton.getMeasuredWidth(), toolbarWidth);
+ if (menuItemButtonWidth <= availableWidth) {
+ menuItemButton.setTag(menuItem);
+ menuItemButton.setOnClickListener(mMenuItemButtonOnClickListener);
+ mMenuItemButtonsContainer.addView(menuItemButton);
+ menuItemButton.getLayoutParams().width = menuItemButtonWidth;
+ availableWidth -= menuItemButtonWidth;
+ remainingMenuItems.pop();
+ } else {
+ // The "open overflow" button launches the vertical overflow from the
+ // floating toolbar.
+ createOpenOverflowButtonIfNotExists();
+ mMenuItemButtonsContainer.addView(mOpenOverflowButton);
+ break;
+ }
+ }
+ mPopup.setContentView(mMenuItemButtonsContainer);
+ }
+
+ /**
+ * Creates and returns the button that opens the vertical overflow.
+ */
+ private void createOpenOverflowButtonIfNotExists() {
+ mOpenOverflowButton = (ImageButton) LayoutInflater.from(mContext)
+ .inflate(R.layout.floating_popup_open_overflow_button, null);
+ mOpenOverflowButton.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Open the overflow.
+ }
+ });
+ }
+
+ /**
+ * Creates and returns a floating toolbar menu buttons container.
+ */
+ private static ViewGroup createMenuButtonsContainer(Context context) {
+ return (ViewGroup) LayoutInflater.from(context)
+ .inflate(R.layout.floating_popup_container, null);
+ }
+
+ /**
+ * Creates and returns a menu button for the specified menu item.
+ */
+ private static Button createMenuItemButton(Context context, MenuItem menuItem) {
+ Button menuItemButton = (Button) LayoutInflater.from(context)
+ .inflate(R.layout.floating_popup_menu_button, null);
+ menuItemButton.setText(menuItem.getTitle());
+ menuItemButton.setContentDescription(menuItem.getTitle());
+ return menuItemButton;
+ }
+
+ private static int getMinimumOverflowHeight(Context context) {
+ return context.getResources().
+ getDimensionPixelSize(R.dimen.floating_toolbar_minimum_overflow_height);
+ }
+
+ private static int getEstimatedOpenOverflowButtonWidth(Context context) {
+ return context.getResources()
+ .getDimensionPixelSize(R.dimen.floating_toolbar_menu_button_minimum_width);
+ }
+
+ private static int getAdjustedToolbarWidth(Context context, int width) {
+ if (width <= 0 || width > getScreenWidth(context)) {
+ width = context.getResources()
+ .getDimensionPixelSize(R.dimen.floating_toolbar_default_width);
+ }
+ return width;
+ }
+
+ /**
+ * Returns the device's screen width.
+ */
+ public static int getScreenWidth(Context context) {
+ return context.getResources().getDisplayMetrics().widthPixels;
+ }
+
+ /**
+ * Returns the device's screen height.
+ */
+ public static int getScreenHeight(Context context) {
+ return context.getResources().getDisplayMetrics().heightPixels;
+ }
+
+
+ /**
+ * A popup window used by the floating toolbar.
+ */
+ private static final class FloatingToolbarPopup {
+
+ private final View mParent;
+ private final PopupWindow mPopupWindow;
+ private final ViewGroup mContentContainer;
+ private final Animator.AnimatorListener mOnDismissEnd =
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mPopupWindow.dismiss();
+ mDismissAnimating = false;
+ }
+ };
+ private final AnimatorSet mGrowFadeInFromBottomAnimation;
+ private final AnimatorSet mShrinkFadeOutFromBottomAnimation;
+
+ private boolean mDismissAnimating;
+
+ /**
+ * Initializes a new floating bar popup.
+ *
+ * @param parent A parent view to get the {@link View#getWindowToken()} token from.
+ */
+ public FloatingToolbarPopup(View parent) {
+ mParent = Preconditions.checkNotNull(parent);
+ mContentContainer = createContentContainer(parent.getContext());
+ mPopupWindow = createPopupWindow(mContentContainer);
+ mGrowFadeInFromBottomAnimation = createGrowFadeInFromBottom(mContentContainer);
+ mShrinkFadeOutFromBottomAnimation =
+ createShrinkFadeOutFromBottomAnimation(mContentContainer, mOnDismissEnd);
+ }
+
+ /**
+ * Shows this popup at the specified coordinates.
+ * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
+ * If this popup is already showing, this will be a no-op.
+ */
+ public void show(int x, int y) {
+ if (isShowing()) {
+ updateCoordinates(x, y);
+ return;
+ }
+
+ mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, 0, 0);
+ positionOnScreen(x, y);
+ growFadeInFromBottom();
+
+ mDismissAnimating = false;
+ }
+
+ /**
+ * Gets rid of this popup. If the popup isn't currently showing, this will be a no-op.
+ */
+ public void dismiss() {
+ if (!isShowing()) {
+ return;
+ }
+
+ if (mDismissAnimating) {
+ // This window is already dismissing. Don't restart the animation.
+ return;
+ }
+ mDismissAnimating = true;
+ shrinkFadeOutFromBottom();
+ }
+
+ /**
+ * Returns {@code true} if this popup is currently showing. {@code false} otherwise.
+ */
+ public boolean isShowing() {
+ return mPopupWindow.isShowing() && !mDismissAnimating;
+ }
+
+ /**
+ * Updates the coordinates of this popup.
+ * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
+ */
+ public void updateCoordinates(int x, int y) {
+ if (isShowing()) {
+ positionOnScreen(x, y);
+ }
+ }
+
+ /**
+ * Sets the content of this popup.
+ */
+ public void setContentView(View view) {
+ Preconditions.checkNotNull(view);
+ mContentContainer.removeAllViews();
+ mContentContainer.addView(view);
+ }
+
+ /**
+ * Returns the width of this popup.
+ */
+ public int getWidth() {
+ return mContentContainer.getWidth();
+ }
+
+ /**
+ * Returns the height of this popup.
+ */
+ public int getHeight() {
+ return mContentContainer.getHeight();
+ }
+
+ /**
+ * Returns the context this popup is running in.
+ */
+ public Context getContext() {
+ return mContentContainer.getContext();
+ }
+
+ private void positionOnScreen(int x, int y) {
+ if (getWidth() == 0) {
+ // content size is yet to be measured.
+ mContentContainer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ }
+ x = clamp(x, 0, getScreenWidth(getContext()) - getWidth());
+ y = clamp(y, 0, getScreenHeight(getContext()) - getHeight());
+
+ // Position the view w.r.t. the window.
+ mContentContainer.setX(x);
+ mContentContainer.setY(y);
+ }
+
+ /**
+ * Performs the "grow and fade in from the bottom" animation on the floating popup.
+ */
+ private void growFadeInFromBottom() {
+ setPivot();
+ mGrowFadeInFromBottomAnimation.start();
+ }
+
+ /**
+ * Performs the "shrink and fade out from bottom" animation on the floating popup.
+ */
+ private void shrinkFadeOutFromBottom() {
+ setPivot();
+ mShrinkFadeOutFromBottomAnimation.start();
+ }
+
+ /**
+ * Sets the popup content container's pivot.
+ */
+ private void setPivot() {
+ mContentContainer.setPivotX(mContentContainer.getMeasuredWidth() / 2);
+ mContentContainer.setPivotY(mContentContainer.getMeasuredHeight());
+ }
+
+ private static ViewGroup createContentContainer(Context context) {
+ return (ViewGroup) LayoutInflater.from(context)
+ .inflate(R.layout.floating_popup_container, null);
+ }
+
+ private static PopupWindow createPopupWindow(View content) {
+ ViewGroup popupContentHolder = new LinearLayout(content.getContext());
+ PopupWindow popupWindow = new PopupWindow(popupContentHolder);
+ popupWindow.setAnimationStyle(0);
+ popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+ popupWindow.setWidth(getScreenWidth(content.getContext()));
+ popupWindow.setHeight(getScreenHeight(content.getContext()));
+ content.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+ popupContentHolder.addView(content);
+ return popupWindow;
+ }
+
+ /**
+ * Creates a "grow and fade in from the bottom" animation for the specified view.
+ *
+ * @param view The view to animate
+ */
+ private static AnimatorSet createGrowFadeInFromBottom(View view) {
+ AnimatorSet growFadeInFromBottomAnimation = new AnimatorSet();
+ growFadeInFromBottomAnimation.playTogether(
+ ObjectAnimator.ofFloat(view, View.SCALE_X, 0.5f, 1).setDuration(125),
+ ObjectAnimator.ofFloat(view, View.SCALE_Y, 0.5f, 1).setDuration(125),
+ ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(75));
+ return growFadeInFromBottomAnimation;
+ }
+
+ /**
+ * Creates a "shrink and fade out from bottom" animation for the specified view.
+ *
+ * @param view The view to animate
+ * @param listener The animation listener
+ */
+ private static AnimatorSet createShrinkFadeOutFromBottomAnimation(
+ View view, Animator.AnimatorListener listener) {
+ AnimatorSet shrinkFadeOutFromBottomAnimation = new AnimatorSet();
+ shrinkFadeOutFromBottomAnimation.playTogether(
+ ObjectAnimator.ofFloat(view, View.SCALE_Y, 1, 0.5f).setDuration(125),
+ ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(75));
+ shrinkFadeOutFromBottomAnimation.setStartDelay(150);
+ shrinkFadeOutFromBottomAnimation.addListener(listener);
+ return shrinkFadeOutFromBottomAnimation;
+ }
+
+ /**
+ * Returns value, restricted to the range min->max (inclusive).
+ * If maximum is less than minimum, the result is undefined.
+ *
+ * @param value The value to clamp.
+ * @param minimum The minimum value in the range.
+ * @param maximum The maximum value in the range. Must not be less than minimum.
+ */
+ private static int clamp(int value, int minimum, int maximum) {
+ return Math.max(minimum, Math.min(value, maximum));
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java
index f916e6f784e7..80189428e54f 100644
--- a/core/java/com/android/internal/widget/ViewPager.java
+++ b/core/java/com/android/internal/widget/ViewPager.java
@@ -137,7 +137,7 @@ public class ViewPager extends ViewGroup {
private int mRestoredCurItem = -1;
private Parcelable mRestoredAdapterState = null;
private ClassLoader mRestoredClassLoader = null;
- private Scroller mScroller;
+ private final Scroller mScroller;
private PagerObserver mObserver;
private int mPageMargin;
@@ -162,9 +162,9 @@ public class ViewPager extends ViewGroup {
private boolean mIsBeingDragged;
private boolean mIsUnableToDrag;
- private int mDefaultGutterSize;
+ private final int mDefaultGutterSize;
private int mGutterSize;
- private int mTouchSlop;
+ private final int mTouchSlop;
/**
* Position of the last motion event.
*/
@@ -187,10 +187,10 @@ public class ViewPager extends ViewGroup {
* Determines speed during touch scrolling
*/
private VelocityTracker mVelocityTracker;
- private int mMinimumVelocity;
- private int mMaximumVelocity;
- private int mFlingDistance;
- private int mCloseEnough;
+ private final int mMinimumVelocity;
+ private final int mMaximumVelocity;
+ private final int mFlingDistance;
+ private final int mCloseEnough;
// If the pager is at least this close to its final position, complete the scroll
// on touch down and let the user interact with the content inside instead of
@@ -200,8 +200,8 @@ public class ViewPager extends ViewGroup {
private boolean mFakeDragging;
private long mFakeDragBeginTime;
- private EdgeEffect mLeftEdge;
- private EdgeEffect mRightEdge;
+ private final EdgeEffect mLeftEdge;
+ private final EdgeEffect mRightEdge;
private boolean mFirstLayout = true;
private boolean mNeedCalculatePageOffsets = false;
@@ -339,20 +339,24 @@ public class ViewPager extends ViewGroup {
interface Decor {}
public ViewPager(Context context) {
- super(context);
- initViewPager();
+ this(context, null);
}
public ViewPager(Context context, AttributeSet attrs) {
- super(context, attrs);
- initViewPager();
+ this(context, attrs, 0);
}
- void initViewPager() {
+ public ViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public ViewPager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
setWillNotDraw(false);
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setFocusable(true);
- final Context context = getContext();
+
mScroller = new Scroller(context, sInterpolator);
final ViewConfiguration configuration = ViewConfiguration.get(context);
final float density = context.getResources().getDisplayMetrics().density;
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 441af153b1bd..34de6c5ed7be 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -537,7 +537,6 @@ bool AndroidRuntime::parseCompilerRuntimeOption(const char* property,
*/
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
{
- int result = -1;
JavaVMInitArgs initArgs;
char propBuf[PROPERTY_VALUE_MAX];
char stackTraceFileBuf[sizeof("-Xstacktracefile:")-1 + PROPERTY_VALUE_MAX];
@@ -581,6 +580,7 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
char localeOption[sizeof("-Duser.locale=") + PROPERTY_VALUE_MAX];
char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX];
char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX];
+ char cpuAbiListBuf[sizeof("--cpu-abilist=") + PROPERTY_VALUE_MAX];
bool checkJni = false;
property_get("dalvik.vm.checkjni", propBuf, "");
@@ -699,7 +699,7 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
if (!hasFile("/system/etc/preloaded-classes")) {
ALOGE("Missing preloaded-classes file, /system/etc/preloaded-classes not found: %s\n",
strerror(errno));
- goto bail;
+ return -1;
}
addOption("-Ximage-compiler-option");
addOption("--image-classes=/system/etc/preloaded-classes");
@@ -811,6 +811,19 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
addOption(nativeBridgeLibrary);
}
+#if defined(__LP64__)
+ const char* cpu_abilist_property_name = "ro.product.cpu.abilist64";
+#else
+ const char* cpu_abilist_property_name = "ro.product.cpu.abilist32";
+#endif // defined(__LP64__)
+ property_get(cpu_abilist_property_name, propBuf, "");
+ if (propBuf[0] == '\0') {
+ ALOGE("%s is not expected to be empty", cpu_abilist_property_name);
+ return -1;
+ }
+ snprintf(cpuAbiListBuf, sizeof(cpuAbiListBuf), "--cpu-abilist=%s", propBuf);
+ addOption(cpuAbiListBuf);
+
initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray();
initArgs.nOptions = mOptions.size();
@@ -825,13 +838,10 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
*/
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
- goto bail;
+ return -1;
}
- result = 0;
-
-bail:
- return result;
+ return 0;
}
char* AndroidRuntime::toSlashClassName(const char* className)
diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp
index 8139c24cd88a..8bdbff43d379 100644
--- a/core/jni/android/graphics/MinikinUtils.cpp
+++ b/core/jni/android/graphics/MinikinUtils.cpp
@@ -26,10 +26,10 @@
namespace android {
-void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags, TypefaceImpl* typeface,
- const uint16_t* buf, size_t start, size_t count, size_t bufSize) {
- TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
- layout->setFontCollection(resolvedFace->fFontCollection);
+FontStyle MinikinUtils::prepareMinikinPaint(MinikinPaint* minikinPaint, FontCollection** pFont,
+ const Paint* paint, TypefaceImpl* typeface) {
+ const TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
+ *pFont = resolvedFace->fFontCollection;
FontStyle resolved = resolvedFace->fStyle;
/* Prepare minikin FontStyle */
@@ -40,15 +40,26 @@ void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags, T
FontStyle minikinStyle(minikinLang, minikinVariant, resolved.getWeight(), resolved.getItalic());
/* Prepare minikin Paint */
- MinikinPaint minikinPaint;
- minikinPaint.size = (int)/*WHY?!*/paint->getTextSize();
- minikinPaint.scaleX = paint->getTextScaleX();
- minikinPaint.skewX = paint->getTextSkewX();
- minikinPaint.letterSpacing = paint->getLetterSpacing();
- minikinPaint.paintFlags = MinikinFontSkia::packPaintFlags(paint);
- minikinPaint.fontFeatureSettings = paint->getFontFeatureSettings();
- minikinPaint.hyphenEdit = HyphenEdit(paint->getHyphenEdit());
+ // Note: it would be nice to handle fractional size values (it would improve smooth zoom
+ // behavior), but historically size has been treated as an int.
+ // TODO: explore whether to enable fractional sizes, possibly when linear text flag is set.
+ minikinPaint->size = (int)paint->getTextSize();
+ minikinPaint->scaleX = paint->getTextScaleX();
+ minikinPaint->skewX = paint->getTextSkewX();
+ minikinPaint->letterSpacing = paint->getLetterSpacing();
+ minikinPaint->paintFlags = MinikinFontSkia::packPaintFlags(paint);
+ minikinPaint->fontFeatureSettings = paint->getFontFeatureSettings();
+ minikinPaint->hyphenEdit = HyphenEdit(paint->getHyphenEdit());
+ return minikinStyle;
+}
+void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags,
+ TypefaceImpl* typeface, const uint16_t* buf, size_t start, size_t count,
+ size_t bufSize) {
+ FontCollection *font;
+ MinikinPaint minikinPaint;
+ FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, &font, paint, typeface);
+ layout->setFontCollection(font);
layout->doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint);
}
diff --git a/core/jni/android/graphics/MinikinUtils.h b/core/jni/android/graphics/MinikinUtils.h
index 236f1fd8000e..1ee6245f6ad7 100644
--- a/core/jni/android/graphics/MinikinUtils.h
+++ b/core/jni/android/graphics/MinikinUtils.h
@@ -31,22 +31,14 @@
namespace android {
-// TODO: these should be defined in Minikin's Layout.h
-enum {
- kBidi_LTR = 0,
- kBidi_RTL = 1,
- kBidi_Default_LTR = 2,
- kBidi_Default_RTL = 3,
- kBidi_Force_LTR = 4,
- kBidi_Force_RTL = 5,
-
- kBidi_Mask = 0x7
-};
-
class MinikinUtils {
public:
- static void doLayout(Layout* layout, const Paint* paint, int bidiFlags, TypefaceImpl* typeface,
- const uint16_t* buf, size_t start, size_t count, size_t bufSize);
+ static FontStyle prepareMinikinPaint(MinikinPaint* minikinPaint, FontCollection** pFont,
+ const Paint* paint, TypefaceImpl* typeface);
+
+ static void doLayout(Layout* layout, const Paint* paint, int bidiFlags,
+ TypefaceImpl* typeface, const uint16_t* buf, size_t start, size_t count,
+ size_t bufSize);
static float xOffsetForTextAlign(Paint* paint, const Layout& layout);
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index f0131b4c74ad..4b43de3e6d3f 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -101,6 +101,16 @@ public:
}
static jlong init(JNIEnv* env, jobject clazz) {
+ SK_COMPILE_ASSERT(1 << 0 == SkPaint::kAntiAlias_Flag, paint_flags_mismatch);
+ SK_COMPILE_ASSERT(1 << 2 == SkPaint::kDither_Flag, paint_flags_mismatch);
+ SK_COMPILE_ASSERT(1 << 3 == SkPaint::kUnderlineText_Flag, paint_flags_mismatch);
+ SK_COMPILE_ASSERT(1 << 4 == SkPaint::kStrikeThruText_Flag, paint_flags_mismatch);
+ SK_COMPILE_ASSERT(1 << 5 == SkPaint::kFakeBoldText_Flag, paint_flags_mismatch);
+ SK_COMPILE_ASSERT(1 << 6 == SkPaint::kLinearText_Flag, paint_flags_mismatch);
+ SK_COMPILE_ASSERT(1 << 7 == SkPaint::kSubpixelText_Flag, paint_flags_mismatch);
+ SK_COMPILE_ASSERT(1 << 8 == SkPaint::kDevKernText_Flag, paint_flags_mismatch);
+ SK_COMPILE_ASSERT(1 << 10 == SkPaint::kEmbeddedBitmapText_Flag, paint_flags_mismatch);
+
Paint* obj = new Paint();
defaultSettingsForAndroid(obj);
return reinterpret_cast<jlong>(obj);
diff --git a/core/jni/android/graphics/TypefaceImpl.h b/core/jni/android/graphics/TypefaceImpl.h
index d36f83a1636d..4b14917eaaf2 100644
--- a/core/jni/android/graphics/TypefaceImpl.h
+++ b/core/jni/android/graphics/TypefaceImpl.h
@@ -62,4 +62,4 @@ void TypefaceImpl_setDefault(TypefaceImpl* face);
}
-#endif // _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_ \ No newline at end of file
+#endif // _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 0b737a7795a7..7d122303e1fa 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -18,6 +18,8 @@
#include <map>
+#include <ScopedUtfChars.h>
+
#include <utils/Log.h>
#include <utils/Looper.h>
@@ -99,6 +101,9 @@ public:
if (string1 == NULL) {
return string2 != NULL;
}
+ if (string2 == NULL) {
+ return false;
+ }
return string1->compare(*string2) < 0;
}
};
@@ -264,9 +269,12 @@ private:
}
};
-static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQ, jobject msgQ, jfloatArray scratch) {
+static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQ, jobject msgQ,
+ jfloatArray scratch, jstring packageName) {
SensorManager& mgr(SensorManager::getInstance());
- sp<SensorEventQueue> queue(mgr.createEventQueue());
+ ScopedUtfChars packageUtf(env, packageName);
+ String8 clientName(packageUtf.c_str());
+ sp<SensorEventQueue> queue(mgr.createEventQueue(clientName));
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
if (messageQueue == NULL) {
@@ -280,10 +288,11 @@ static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject event
}
static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us,
- jint maxBatchReportLatency, jint reservedFlags) {
+ jint maxBatchReportLatency) {
sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
+
return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency,
- reservedFlags);
+ 0);
}
static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
@@ -316,11 +325,11 @@ static JNINativeMethod gSystemSensorManagerMethods[] = {
static JNINativeMethod gBaseEventQueueMethods[] = {
{"nativeInitBaseEventQueue",
- "(Landroid/hardware/SystemSensorManager$BaseEventQueue;Landroid/os/MessageQueue;[F)J",
- (void*)nativeInitSensorEventQueue },
+ "(Landroid/hardware/SystemSensorManager$BaseEventQueue;Landroid/os/MessageQueue;[FLjava/lang/String;)J",
+ (void*)nativeInitSensorEventQueue },
{"nativeEnableSensor",
- "(JIIII)I",
+ "(JIII)I",
(void*)nativeEnableSensor },
{"nativeDisableSensor",
diff --git a/core/jni/android_server_FingerprintManager.cpp b/core/jni/android_server_FingerprintManager.cpp
index 853425c78ecf..5d59234c507e 100644
--- a/core/jni/android_server_FingerprintManager.cpp
+++ b/core/jni/android_server_FingerprintManager.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "Fingerprint-JNI"
#include "JNIHelp.h"
+#include <inttypes.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
@@ -47,14 +48,15 @@ static jobject gCallback;
class CallbackHandler : public MessageHandler {
int type;
- int arg1, arg2;
+ int arg1, arg2, arg3;
public:
- CallbackHandler(int type, int arg1, int arg2) : type(type), arg1(arg1), arg2(arg2) { }
+ CallbackHandler(int type, int arg1, int arg2, int arg3)
+ : type(type), arg1(arg1), arg2(arg2), arg3(arg3) { }
virtual void handleMessage(const Message& message) {
//ALOG(LOG_VERBOSE, LOG_TAG, "hal_notify(msg=%d, arg1=%d, arg2=%d)\n", msg.type, arg1, arg2);
JNIEnv* env = AndroidRuntime::getJNIEnv();
- env->CallVoidMethod(gCallback, gFingerprintServiceClassInfo.notify, type, arg1, arg2);
+ env->CallVoidMethod(gCallback, gFingerprintServiceClassInfo.notify, type, arg1, arg2, arg3);
}
};
@@ -62,6 +64,7 @@ public:
static void hal_notify_callback(fingerprint_msg_t msg) {
uint32_t arg1 = 0;
uint32_t arg2 = 0;
+ uint32_t arg3 = 0;
switch (msg.type) {
case FINGERPRINT_ERROR:
arg1 = msg.data.error;
@@ -71,13 +74,16 @@ static void hal_notify_callback(fingerprint_msg_t msg) {
break;
case FINGERPRINT_PROCESSED:
arg1 = msg.data.processed.finger.fid;
+ arg2 = msg.data.processed.finger.gid;
break;
case FINGERPRINT_TEMPLATE_ENROLLING:
arg1 = msg.data.enroll.finger.fid;
- arg2 = msg.data.enroll.samples_remaining;
+ arg2 = msg.data.enroll.finger.gid;
+ arg3 = msg.data.enroll.samples_remaining;
break;
case FINGERPRINT_TEMPLATE_REMOVED:
arg1 = msg.data.removed.finger.fid;
+ arg2 = msg.data.removed.finger.gid;
break;
default:
ALOGE("fingerprint: invalid msg: %d", msg.type);
@@ -86,7 +92,7 @@ static void hal_notify_callback(fingerprint_msg_t msg) {
// This call potentially comes in on a thread not owned by us. Hand it off to our
// looper so it runs on our thread when calling back to FingerprintService.
// CallbackHandler object is reference-counted, so no cleanup necessary.
- gLooper->sendMessage(new CallbackHandler(msg.type, arg1, arg2), Message());
+ gLooper->sendMessage(new CallbackHandler(msg.type, arg1, arg2, arg3), Message());
}
static void nativeInit(JNIEnv *env, jobject clazz, jobject mQueue, jobject callbackObj) {
@@ -95,9 +101,15 @@ static void nativeInit(JNIEnv *env, jobject clazz, jobject mQueue, jobject callb
gLooper = android_os_MessageQueue_getMessageQueue(env, mQueue)->getLooper();
}
-static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
- ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll()\n");
- int ret = gContext.device->enroll(gContext.device, 0, timeout);
+static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout, jint groupId) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll(gid=%d, timeout=%d)\n", groupId, timeout);
+ int ret = gContext.device->enroll(gContext.device, groupId, timeout);
+ return reinterpret_cast<jint>(ret);
+}
+
+static jint nativeAuthenticate(JNIEnv* env, jobject clazz, jlong sessionId, jint groupId) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeAuthenticate(sid=%" PRId64 ", gid=%d)\n", sessionId, groupId);
+ int ret = gContext.device->authenticate(gContext.device, sessionId, groupId);
return reinterpret_cast<jint>(ret);
}
@@ -107,11 +119,11 @@ static jint nativeEnrollCancel(JNIEnv* env, jobject clazz) {
return reinterpret_cast<jint>(ret);
}
-static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
- ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(%d)\n", fingerprintId);
+static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerId, jint groupId) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(fid=%d, gid=%d)\n", fingerId, groupId);
fingerprint_finger_id_t finger;
- finger.gid = 0;
- finger.fid = fingerprintId;
+ finger.fid = fingerId;
+ finger.gid = groupId;
int ret = gContext.device->remove(gContext.device, finger);
return reinterpret_cast<jint>(ret);
}
@@ -172,9 +184,10 @@ static jint nativeCloseHal(JNIEnv* env, jobject clazz) {
// TODO: clean up void methods
static const JNINativeMethod g_methods[] = {
- { "nativeEnroll", "(I)I", (void*)nativeEnroll },
+ { "nativeAuthenticate", "(JI)I", (void*)nativeAuthenticate },
+ { "nativeEnroll", "(II)I", (void*)nativeEnroll },
{ "nativeEnrollCancel", "()I", (void*)nativeEnrollCancel },
- { "nativeRemove", "(I)I", (void*)nativeRemove },
+ { "nativeRemove", "(II)I", (void*)nativeRemove },
{ "nativeOpenHal", "()I", (void*)nativeOpenHal },
{ "nativeCloseHal", "()I", (void*)nativeCloseHal },
{ "nativeInit","(Landroid/os/MessageQueue;"
@@ -185,7 +198,7 @@ int register_android_server_fingerprint_FingerprintService(JNIEnv* env) {
jclass clazz = FindClassOrDie(env, FINGERPRINT_SERVICE);
gFingerprintServiceClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
gFingerprintServiceClassInfo.notify =
- GetMethodIDOrDie(env, gFingerprintServiceClassInfo.clazz,"notify", "(III)V");
+ GetMethodIDOrDie(env, gFingerprintServiceClassInfo.clazz,"notify", "(IIII)V");
int result = RegisterMethodsOrDie(env, FINGERPRINT_SERVICE, g_methods, NELEM(g_methods));
ALOG(LOG_VERBOSE, LOG_TAG, "FingerprintManager JNI ready.\n");
return result;
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 8800f0bc3184..6cc1f68ec656 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -34,6 +34,7 @@
#include "MinikinSkia.h"
#include "MinikinUtils.h"
#include "Paint.h"
+#include "minikin/LineBreaker.h"
namespace android {
@@ -46,636 +47,116 @@ struct JLineBreaksID {
static jclass gLineBreaks_class;
static JLineBreaksID gLineBreaks_fieldID;
-class Builder {
- public:
- ~Builder() {
- utext_close(&mUText);
- delete mBreakIterator;
- }
-
- void setLocale(const icu::Locale& locale) {
- delete mBreakIterator;
- UErrorCode status = U_ZERO_ERROR;
- mBreakIterator = icu::BreakIterator::createLineInstance(locale, status);
- // TODO: check status
- }
-
- void resize(size_t size) {
- mTextBuf.resize(size);
- mWidthBuf.resize(size);
- }
-
- size_t size() const {
- return mTextBuf.size();
- }
-
- uint16_t* buffer() {
- return mTextBuf.data();
- }
-
- float* widths() {
- return mWidthBuf.data();
- }
-
- // set text to current contents of buffer
- void setText() {
- UErrorCode status = U_ZERO_ERROR;
- utext_openUChars(&mUText, mTextBuf.data(), mTextBuf.size(), &status);
- mBreakIterator->setText(&mUText, status);
- }
-
- void finish() {
- if (mTextBuf.size() > MAX_TEXT_BUF_RETAIN) {
- mTextBuf.clear();
- mTextBuf.shrink_to_fit();
- mWidthBuf.clear();
- mWidthBuf.shrink_to_fit();
- }
- }
-
- icu::BreakIterator* breakIterator() const {
- return mBreakIterator;
- }
-
- float measureStyleRun(Paint* paint, TypefaceImpl* typeface, size_t start, size_t end,
- bool isRtl);
-
- void addReplacement(size_t start, size_t end, float width);
-
- private:
- const size_t MAX_TEXT_BUF_RETAIN = 32678;
- icu::BreakIterator* mBreakIterator = nullptr;
- UText mUText = UTEXT_INITIALIZER;
- std::vector<uint16_t>mTextBuf;
- std::vector<float>mWidthBuf;
-};
-
static const int CHAR_SPACE = 0x20;
static const int CHAR_TAB = 0x09;
static const int CHAR_NEWLINE = 0x0a;
static const int CHAR_ZWSP = 0x200b;
-class TabStops {
- public:
- // specified stops must be a sorted array (allowed to be null)
- TabStops(JNIEnv* env, jintArray stops, jint defaultTabWidth) :
- mStops(env), mTabWidth(defaultTabWidth) {
- if (stops != nullptr) {
- mStops.reset(stops);
- mNumStops = mStops.size();
- } else {
- mNumStops = 0;
- }
- }
- float width(float widthSoFar) const {
- const jint* mStopsArray = mStops.get();
- for (int i = 0; i < mNumStops; i++) {
- if (mStopsArray[i] > widthSoFar) {
- return mStopsArray[i];
- }
- }
- // find the next tabstop after widthSoFar
- return static_cast<int>((widthSoFar + mTabWidth) / mTabWidth) * mTabWidth;
- }
- private:
- ScopedIntArrayRO mStops;
- const int mTabWidth;
- int mNumStops;
-
- // disable copying and assignment
- TabStops(const TabStops&);
- void operator=(const TabStops&);
-};
-
-enum PrimitiveType {
- kPrimitiveType_Box,
- kPrimitiveType_Glue,
- kPrimitiveType_Penalty,
- kPrimitiveType_Variable,
- kPrimitiveType_Wordbreak
-};
-
-static const float PENALTY_INFINITY = 1e7; // forced non-break, negative infinity is forced break
-
-struct Primitive {
- PrimitiveType type;
- int location;
- // 'Box' has width
- // 'Glue' has width
- // 'Penalty' has width and penalty
- // 'Variable' has tabStop
- // 'Wordbreak' has penalty
- union {
- struct {
- float width;
- float penalty;
- };
- const TabStops* tabStop;
- };
-};
-
-class LineWidth {
- public:
- LineWidth(float firstWidth, int firstWidthLineCount, float restWidth) :
- mFirstWidth(firstWidth), mFirstWidthLineCount(firstWidthLineCount),
- mRestWidth(restWidth) {}
- float getLineWidth(int line) const {
- return (line < mFirstWidthLineCount) ? mFirstWidth : mRestWidth;
- }
- private:
- const float mFirstWidth;
- const int mFirstWidthLineCount;
- const float mRestWidth;
-};
-
-class LineBreaker {
- public:
- LineBreaker(const std::vector<Primitive>& primitives,
- const LineWidth& lineWidth) :
- mPrimitives(primitives), mLineWidth(lineWidth) {}
- virtual ~LineBreaker() {}
- virtual void computeBreaks(std::vector<int>* breaks, std::vector<float>* widths,
- std::vector<unsigned char>* flags) const = 0;
- protected:
- const std::vector<Primitive>& mPrimitives;
- const LineWidth& mLineWidth;
-};
-
-class OptimizingLineBreaker : public LineBreaker {
- public:
- OptimizingLineBreaker(const std::vector<Primitive>& primitives, const LineWidth& lineWidth) :
- LineBreaker(primitives, lineWidth) {}
- void computeBreaks(std::vector<int>* breaks, std::vector<float>* widths,
- std::vector<unsigned char>* flags) const {
- int numBreaks = mPrimitives.size();
- Node* opt = new Node[numBreaks];
- opt[0].prev = -1;
- opt[0].prevCount = 0;
- opt[0].width = 0;
- opt[0].demerits = 0;
- opt[0].flags = false;
- opt[numBreaks - 1].prev = -1;
- opt[numBreaks - 1].prevCount = 0;
-
- std::list<int> active;
- active.push_back(0);
- int lastBreak = 0;
- for (int i = 0; i < numBreaks; i++) {
- const Primitive& p = mPrimitives[i];
- if (p.type == kPrimitiveType_Penalty) {
- const bool finalBreak = (i + 1 == numBreaks);
- bool breakFound = false;
- Node bestBreak;
- for (std::list<int>::iterator it = active.begin(); it != active.end(); /* incrementing done in loop */) {
- const int pos = *it;
- bool flags;
- float width, printedWidth;
- const int lines = opt[pos].prevCount;
- const float maxWidth = mLineWidth.getLineWidth(lines);
- // we have to compute metrics every time --
- // we can't really precompute this stuff and just deal with breaks
- // because of the way tab characters work, this makes it computationally
- // harder, but this way, we can still optimize while treating tab characters
- // correctly
- computeMetrics(pos, i, &width, &printedWidth, &flags);
- if (printedWidth <= maxWidth) {
- float demerits = computeDemerits(maxWidth, printedWidth,
- finalBreak, p.penalty) + opt[pos].demerits;
- if (!breakFound || demerits < bestBreak.demerits) {
- bestBreak.prev = pos;
- bestBreak.prevCount = opt[pos].prevCount + 1;
- bestBreak.demerits = demerits;
- bestBreak.width = printedWidth;
- bestBreak.flags = flags;
- breakFound = true;
- }
- ++it;
- } else {
- active.erase(it++); // safe to delete like this
- }
- }
- if (p.penalty == -PENALTY_INFINITY) {
- active.clear();
- }
- if (breakFound) {
- opt[i] = bestBreak;
- active.push_back(i);
- lastBreak = i;
- }
- if (active.empty()) {
- // we can't give up!
- float width, printedWidth;
- bool flags;
- const int lines = opt[lastBreak].prevCount;
- const float maxWidth = mLineWidth.getLineWidth(lines);
- const int breakIndex = desperateBreak(lastBreak, numBreaks, maxWidth, &width, &printedWidth, &flags);
-
- opt[breakIndex].prev = lastBreak;
- opt[breakIndex].prevCount = lines + 1;
- opt[breakIndex].demerits = 0; // doesn't matter, it's the only one
- opt[breakIndex].width = width;
- opt[breakIndex].flags = flags;
-
- active.push_back(breakIndex);
- lastBreak = breakIndex;
- i = breakIndex; // incremented by i++
- }
- }
- }
-
- int idx = numBreaks - 1;
- int count = opt[idx].prevCount;
- breaks->resize(count);
- widths->resize(count);
- flags->resize(count);
- while (opt[idx].prev != -1) {
- --count;
-
- (*breaks)[count] = mPrimitives[idx].location;
- (*widths)[count] = opt[idx].width;
- (*flags)[count] = opt[idx].flags;
-
- idx = opt[idx].prev;
- }
- delete[] opt;
- }
- private:
- inline void computeMetrics(int start, int end, float* width, float* printedWidth, bool* flags) const {
- bool f = false;
- float w = 0, pw = 0;
- for (int i = start; i < end; i++) {
- const Primitive& p = mPrimitives[i];
- if (p.type == kPrimitiveType_Box || p.type == kPrimitiveType_Glue) {
- w += p.width;
- if (p.type == kPrimitiveType_Box) {
- pw = w;
- }
- } else if (p.type == kPrimitiveType_Variable) {
- w = p.tabStop->width(w);
- f = true;
- }
- }
- *width = w;
- *printedWidth = pw;
- *flags = f;
- }
-
- inline float computeDemerits(float maxWidth, float width, bool finalBreak, float penalty) const {
- float deviation = finalBreak ? 0 : maxWidth - width;
- return (deviation * deviation) + penalty;
- }
-
- // returns end pos (chosen break), -1 if fail
- inline int desperateBreak(int start, int limit, float maxWidth, float* width, float* printedWidth, bool* flags) const {
- float w = 0, pw = 0;
- bool breakFound = false;
- int breakIndex = 0, firstTabIndex = INT_MAX;
- for (int i = start; i < limit; i++) {
- const Primitive& p = mPrimitives[i];
-
- if (p.type == kPrimitiveType_Box || p.type == kPrimitiveType_Glue) {
- w += p.width;
- if (p.type == kPrimitiveType_Box) {
- pw = w;
- }
- } else if (p.type == kPrimitiveType_Variable) {
- w = p.tabStop->width(w);
- firstTabIndex = std::min(firstTabIndex, i);
- }
-
- if (pw > maxWidth) {
- if (breakFound) {
- break;
- } else {
- // no choice, keep going
- }
- }
-
- // must make progress
- if (i > start && (p.type == kPrimitiveType_Penalty || p.type == kPrimitiveType_Wordbreak)) {
- breakFound = true;
- breakIndex = i;
- }
- }
-
- if (breakFound) {
- *width = w;
- *printedWidth = pw;
- *flags = (start <= firstTabIndex && firstTabIndex < breakIndex);
- return breakIndex;
- } else {
- return -1;
- }
- }
-
- struct Node {
- int prev; // set to sentinel value (-1) for initial node
- int prevCount; // number of breaks so far
- float demerits;
- float width;
- bool flags;
- };
-};
-
-class GreedyLineBreaker : public LineBreaker {
- public:
- GreedyLineBreaker(const std::vector<Primitive>& primitives, const LineWidth& lineWidth) :
- LineBreaker(primitives, lineWidth) {}
- void computeBreaks(std::vector<int>* breaks, std::vector<float>* widths,
- std::vector<unsigned char>* flags) const {
- int lineNum = 0;
- float width = 0, printedWidth = 0;
- bool breakFound = false, goodBreakFound = false;
- int breakIndex = 0, goodBreakIndex = 0;
- float breakWidth = 0, goodBreakWidth = 0;
- int firstTabIndex = INT_MAX;
-
- float maxWidth = mLineWidth.getLineWidth(lineNum);
-
- const int numPrimitives = mPrimitives.size();
- // greedily fit as many characters as possible on each line
- // loop over all primitives, and choose the best break point
- // (if possible, a break point without splitting a word)
- // after going over the maximum length
- for (int i = 0; i < numPrimitives; i++) {
- const Primitive& p = mPrimitives[i];
-
- // update the current line width
- if (p.type == kPrimitiveType_Box || p.type == kPrimitiveType_Glue) {
- width += p.width;
- if (p.type == kPrimitiveType_Box) {
- printedWidth = width;
- }
- } else if (p.type == kPrimitiveType_Variable) {
- width = p.tabStop->width(width);
- // keep track of first tab character in the region we are examining
- // so we can determine whether or not a line contains a tab
- firstTabIndex = std::min(firstTabIndex, i);
- }
-
- // find the best break point for the characters examined so far
- if (printedWidth > maxWidth) {
- if (breakFound || goodBreakFound) {
- if (goodBreakFound) {
- // a true line break opportunity existed in the characters examined so far,
- // so there is no need to split a word
- i = goodBreakIndex; // no +1 because of i++
- lineNum++;
- maxWidth = mLineWidth.getLineWidth(lineNum);
- breaks->push_back(mPrimitives[goodBreakIndex].location);
- widths->push_back(goodBreakWidth);
- flags->push_back(firstTabIndex < goodBreakIndex);
- firstTabIndex = INT_MAX;
- } else {
- // must split a word because there is no other option
- i = breakIndex; // no +1 because of i++
- lineNum++;
- maxWidth = mLineWidth.getLineWidth(lineNum);
- breaks->push_back(mPrimitives[breakIndex].location);
- widths->push_back(breakWidth);
- flags->push_back(firstTabIndex < breakIndex);
- firstTabIndex = INT_MAX;
- }
- printedWidth = width = 0;
- goodBreakFound = breakFound = false;
- goodBreakWidth = breakWidth = 0;
- continue;
- } else {
- // no choice, keep going... must make progress by putting at least one
- // character on a line, even if part of that character is cut off --
- // there is no other option
- }
- }
-
- // update possible break points
- if (p.type == kPrimitiveType_Penalty && p.penalty < PENALTY_INFINITY) {
- // this does not handle penalties with width
-
- // handle forced line break
- if (p.penalty == -PENALTY_INFINITY) {
- lineNum++;
- maxWidth = mLineWidth.getLineWidth(lineNum);
- breaks->push_back(p.location);
- widths->push_back(printedWidth);
- flags->push_back(firstTabIndex < i);
- firstTabIndex = INT_MAX;
- printedWidth = width = 0;
- goodBreakFound = breakFound = false;
- goodBreakWidth = breakWidth = 0;
- continue;
- }
- if (i > breakIndex && (printedWidth <= maxWidth || breakFound == false)) {
- breakFound = true;
- breakIndex = i;
- breakWidth = printedWidth;
- }
- if (i > goodBreakIndex && printedWidth <= maxWidth) {
- goodBreakFound = true;
- goodBreakIndex = i;
- goodBreakWidth = printedWidth;
- }
- } else if (p.type == kPrimitiveType_Wordbreak) {
- // only do this if necessary -- we don't want to break words
- // when possible, but sometimes it is unavoidable
- if (i > breakIndex && (printedWidth <= maxWidth || breakFound == false)) {
- breakFound = true;
- breakIndex = i;
- breakWidth = printedWidth;
- }
- }
- }
-
- if (breakFound || goodBreakFound) {
- // output last break if there are more characters to output
- if (goodBreakFound) {
- breaks->push_back(mPrimitives[goodBreakIndex].location);
- widths->push_back(goodBreakWidth);
- flags->push_back(firstTabIndex < goodBreakIndex);
- } else {
- breaks->push_back(mPrimitives[breakIndex].location);
- widths->push_back(breakWidth);
- flags->push_back(firstTabIndex < breakIndex);
- }
- }
- }
-};
+// set text and set a number of parameters for creating a layout (width, tabstops, strategy)
+static void nSetupParagraph(JNIEnv* env, jclass, jlong nativePtr, jcharArray text, jint length,
+ jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth,
+ jintArray variableTabStops, jint defaultTabStop, jint strategy) {
+ LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
+ b->resize(length);
+ env->GetCharArrayRegion(text, 0, length, b->buffer());
+ b->setText();
+ b->setLineWidths(firstWidth, firstWidthLineLimit, restWidth);
+ if (variableTabStops == nullptr) {
+ b->setTabStops(nullptr, 0, defaultTabStop);
+ } else {
+ ScopedIntArrayRO stops(env, variableTabStops);
+ b->setTabStops(stops.get(), stops.size(), defaultTabStop);
+ }
+ b->setStrategy(static_cast<BreakStrategy>(strategy));
+}
-static jint recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
+static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
jfloatArray recycleWidths, jbooleanArray recycleFlags,
- jint recycleLength, const std::vector<jint>& breaks,
- const std::vector<jfloat>& widths, const std::vector<jboolean>& flags) {
- int bufferLength = breaks.size();
- if (recycleLength < bufferLength) {
+ jint recycleLength, size_t nBreaks, const jint* breaks,
+ const jfloat* widths, const jboolean* flags) {
+ if ((size_t)recycleLength < nBreaks) {
// have to reallocate buffers
- recycleBreaks = env->NewIntArray(bufferLength);
- recycleWidths = env->NewFloatArray(bufferLength);
- recycleFlags = env->NewBooleanArray(bufferLength);
+ recycleBreaks = env->NewIntArray(nBreaks);
+ recycleWidths = env->NewFloatArray(nBreaks);
+ recycleFlags = env->NewBooleanArray(nBreaks);
env->SetObjectField(recycle, gLineBreaks_fieldID.breaks, recycleBreaks);
env->SetObjectField(recycle, gLineBreaks_fieldID.widths, recycleWidths);
env->SetObjectField(recycle, gLineBreaks_fieldID.flags, recycleFlags);
}
// copy data
- env->SetIntArrayRegion(recycleBreaks, 0, breaks.size(), &breaks.front());
- env->SetFloatArrayRegion(recycleWidths, 0, widths.size(), &widths.front());
- env->SetBooleanArrayRegion(recycleFlags, 0, flags.size(), &flags.front());
-
- return bufferLength;
-}
-
-void computePrimitives(const jchar* textArr, const jfloat* widthsArr, jint length, const std::vector<int>& breaks,
- const TabStops& tabStopCalculator, std::vector<Primitive>* primitives) {
- int breaksSize = breaks.size();
- int breakIndex = 0;
- Primitive p;
- for (int i = 0; i < length; i++) {
- p.location = i;
- jchar c = textArr[i];
- if (c == CHAR_SPACE || c == CHAR_ZWSP) {
- p.type = kPrimitiveType_Glue;
- p.width = widthsArr[i];
- primitives->push_back(p);
- } else if (c == CHAR_TAB) {
- p.type = kPrimitiveType_Variable;
- p.tabStop = &tabStopCalculator; // shared between all variable primitives
- primitives->push_back(p);
- } else if (c != CHAR_NEWLINE) {
- while (breakIndex < breaksSize && breaks[breakIndex] < i) breakIndex++;
- p.width = 0;
- if (breakIndex < breaksSize && breaks[breakIndex] == i) {
- p.type = kPrimitiveType_Penalty;
- p.penalty = 0;
- } else {
- p.type = kPrimitiveType_Wordbreak;
- }
- if (widthsArr[i] != 0) {
- primitives->push_back(p);
- }
-
- p.type = kPrimitiveType_Box;
- p.width = widthsArr[i];
- primitives->push_back(p);
- }
- }
- // final break at end of everything
- p.location = length;
- p.type = kPrimitiveType_Penalty;
- p.width = 0;
- p.penalty = -PENALTY_INFINITY;
- primitives->push_back(p);
-}
-
-// sets the text on the builder
-static void nSetText(JNIEnv* env, jclass, jlong nativePtr, jcharArray text, int length) {
- Builder* b = reinterpret_cast<Builder*>(nativePtr);
- b->resize(length);
- env->GetCharArrayRegion(text, 0, length, b->buffer());
- b->setText();
+ env->SetIntArrayRegion(recycleBreaks, 0, nBreaks, breaks);
+ env->SetFloatArrayRegion(recycleWidths, 0, nBreaks, widths);
+ env->SetBooleanArrayRegion(recycleFlags, 0, nBreaks, flags);
}
static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
- jint length,
- jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth,
- jintArray variableTabStops, jint defaultTabStop, jboolean optimize,
jobject recycle, jintArray recycleBreaks,
jfloatArray recycleWidths, jbooleanArray recycleFlags,
jint recycleLength) {
- Builder* b = reinterpret_cast<Builder*>(nativePtr);
+ LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
- std::vector<int> breaks;
+ size_t nBreaks = b->computeBreaks();
- icu::BreakIterator* breakIterator = b->breakIterator();
- int loc = breakIterator->first();
- while ((loc = breakIterator->next()) != icu::BreakIterator::DONE) {
- breaks.push_back(loc);
- }
-
- // TODO: all these allocations can be moved into the builder
- std::vector<Primitive> primitives;
- TabStops tabStops(env, variableTabStops, defaultTabStop);
- computePrimitives(b->buffer(), b->widths(), length, breaks, tabStops, &primitives);
-
- LineWidth lineWidth(firstWidth, firstWidthLineLimit, restWidth);
- std::vector<int> computedBreaks;
- std::vector<float> computedWidths;
- std::vector<unsigned char> computedFlags;
+ recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleFlags, recycleLength,
+ nBreaks, b->getBreaks(), b->getWidths(), b->getFlags());
- if (optimize) {
- OptimizingLineBreaker breaker(primitives, lineWidth);
- breaker.computeBreaks(&computedBreaks, &computedWidths, &computedFlags);
- } else {
- GreedyLineBreaker breaker(primitives, lineWidth);
- breaker.computeBreaks(&computedBreaks, &computedWidths, &computedFlags);
- }
b->finish();
- return recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleFlags, recycleLength,
- computedBreaks, computedWidths, computedFlags);
+ return static_cast<jint>(nBreaks);
}
static jlong nNewBuilder(JNIEnv*, jclass) {
- return reinterpret_cast<jlong>(new Builder);
+ return reinterpret_cast<jlong>(new LineBreaker);
}
static void nFreeBuilder(JNIEnv*, jclass, jlong nativePtr) {
- delete reinterpret_cast<Builder*>(nativePtr);
+ delete reinterpret_cast<LineBreaker*>(nativePtr);
}
static void nFinishBuilder(JNIEnv*, jclass, jlong nativePtr) {
- Builder* b = reinterpret_cast<Builder*>(nativePtr);
+ LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
b->finish();
}
static void nSetLocale(JNIEnv* env, jclass, jlong nativePtr, jstring javaLocaleName) {
ScopedIcuLocale icuLocale(env, javaLocaleName);
- Builder* b = reinterpret_cast<Builder*>(nativePtr);
+ LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
if (icuLocale.valid()) {
b->setLocale(icuLocale.locale());
}
}
-float Builder::measureStyleRun(Paint* paint, TypefaceImpl* typeface, size_t start, size_t end,
- bool isRtl) {
- Layout layout;
- int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
- // TODO: should we provide more context?
- MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, mTextBuf.data() + start, 0,
- end - start, end - start);
- layout.getAdvances(mWidthBuf.data() + start);
- return layout.getAdvance();
-}
-
-void Builder::addReplacement(size_t start, size_t end, float width) {
- mWidthBuf[start] = width;
- std::fill(&mWidthBuf[start + 1], &mWidthBuf[end], 0.0f);
-}
-
// Basically similar to Paint.getTextRunAdvances but with C++ interface
static jfloat nAddStyleRun(JNIEnv* env, jclass, jlong nativePtr,
jlong nativePaint, jlong nativeTypeface, jint start, jint end, jboolean isRtl) {
- Builder* b = reinterpret_cast<Builder*>(nativePtr);
+ LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
Paint* paint = reinterpret_cast<Paint*>(nativePaint);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(nativeTypeface);
- return b->measureStyleRun(paint, typeface, start, end, isRtl);
+ FontCollection *font;
+ MinikinPaint minikinPaint;
+ FontStyle style = MinikinUtils::prepareMinikinPaint(&minikinPaint, &font, paint, typeface);
+ return b->addStyleRun(&minikinPaint, font, style, start, end, isRtl);
}
// Accept width measurements for the run, passed in from Java
static void nAddMeasuredRun(JNIEnv* env, jclass, jlong nativePtr,
jint start, jint end, jfloatArray widths) {
- Builder* b = reinterpret_cast<Builder*>(nativePtr);
- env->GetFloatArrayRegion(widths, start, end - start, b->widths() + start);
+ LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
+ env->GetFloatArrayRegion(widths, start, end - start, b->charWidths() + start);
+ b->addStyleRun(nullptr, nullptr, FontStyle{}, start, end, false);
}
static void nAddReplacementRun(JNIEnv* env, jclass, jlong nativePtr,
jint start, jint end, jfloat width) {
- Builder* b = reinterpret_cast<Builder*>(nativePtr);
+ LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
b->addReplacement(start, end, width);
}
static void nGetWidths(JNIEnv* env, jclass, jlong nativePtr, jfloatArray widths) {
- Builder* b = reinterpret_cast<Builder*>(nativePtr);
- env->SetFloatArrayRegion(widths, 0, b->size(), b->widths());
+ LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
+ env->SetFloatArrayRegion(widths, 0, b->size(), b->charWidths());
}
static JNINativeMethod gMethods[] = {
@@ -684,12 +165,12 @@ static JNINativeMethod gMethods[] = {
{"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
{"nFinishBuilder", "(J)V", (void*) nFinishBuilder},
{"nSetLocale", "(JLjava/lang/String;)V", (void*) nSetLocale},
- {"nSetText", "(J[CI)V", (void*) nSetText},
+ {"nSetupParagraph", "(J[CIFIF[III)V", (void*) nSetupParagraph},
{"nAddStyleRun", "(JJJIIZ)F", (void*) nAddStyleRun},
{"nAddMeasuredRun", "(JII[F)V", (void*) nAddMeasuredRun},
{"nAddReplacementRun", "(JIIF)V", (void*) nAddReplacementRun},
{"nGetWidths", "(J[F)V", (void*) nGetWidths},
- {"nComputeLineBreaks", "(JIFIF[IIZLandroid/text/StaticLayout$LineBreaks;[I[F[ZI)I",
+ {"nComputeLineBreaks", "(JLandroid/text/StaticLayout$LineBreaks;[I[F[ZI)I",
(void*) nComputeLineBreaks}
};
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 3c1993e8650b..9307ff9081ab 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -33,6 +33,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
+#include <inttypes.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -173,7 +174,11 @@ sumFiles(JNIEnv*, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char
static install_status_t
copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName)
{
- jstring* javaNativeLibPath = (jstring*) arg;
+ void** args = reinterpret_cast<void**>(arg);
+ jstring* javaNativeLibPath = (jstring*) args[0];
+ jboolean extractNativeLibs = *(jboolean*) args[1];
+ jboolean hasNativeBridge = *(jboolean*) args[2];
+
ScopedUtfChars nativeLibPath(env, *javaNativeLibPath);
size_t uncompLen;
@@ -181,13 +186,31 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr
long crc;
time_t modTime;
- if (!zipFile->getEntryInfo(zipEntry, NULL, &uncompLen, NULL, NULL, &when, &crc)) {
+ int method;
+ off64_t offset;
+
+ if (!zipFile->getEntryInfo(zipEntry, &method, &uncompLen, NULL, &offset, &when, &crc)) {
ALOGD("Couldn't read zip entry info\n");
return INSTALL_FAILED_INVALID_APK;
- } else {
- struct tm t;
- ZipUtils::zipTimeToTimespec(when, &t);
- modTime = mktime(&t);
+ }
+
+ if (!extractNativeLibs) {
+ // check if library is uncompressed and page-aligned
+ if (method != ZipFileRO::kCompressStored) {
+ ALOGD("Library '%s' is compressed - will not be able to open it directly from apk.\n",
+ fileName);
+ return INSTALL_FAILED_INVALID_APK;
+ }
+
+ if (offset % PAGE_SIZE != 0) {
+ ALOGD("Library '%s' is not page-aligned - will not be able to open it directly from"
+ " apk.\n", fileName);
+ return INSTALL_FAILED_INVALID_APK;
+ }
+
+ if (!hasNativeBridge) {
+ return INSTALL_SUCCEEDED;
+ }
}
// Build local file path
@@ -208,6 +231,9 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr
}
// Only copy out the native file if it's different.
+ struct tm t;
+ ZipUtils::zipTimeToTimespec(when, &t);
+ modTime = mktime(&t);
struct stat64 st;
if (!isFileDifferent(localFileName, uncompLen, modTime, crc, &st)) {
return INSTALL_SUCCEEDED;
@@ -465,10 +491,12 @@ static int findSupportedAbi(JNIEnv *env, jlong apkHandle, jobjectArray supported
static jint
com_android_internal_content_NativeLibraryHelper_copyNativeBinaries(JNIEnv *env, jclass clazz,
- jlong apkHandle, jstring javaNativeLibPath, jstring javaCpuAbi)
+ jlong apkHandle, jstring javaNativeLibPath, jstring javaCpuAbi,
+ jboolean extractNativeLibs, jboolean hasNativeBridge)
{
+ void* args[] = { &javaNativeLibPath, &extractNativeLibs, &hasNativeBridge };
return (jint) iterateOverNativeFiles(env, apkHandle, javaCpuAbi,
- copyFileIfChanged, &javaNativeLibPath);
+ copyFileIfChanged, reinterpret_cast<void*>(args));
}
static jlong
@@ -548,7 +576,7 @@ static JNINativeMethod gMethods[] = {
"(J)V",
(void *)com_android_internal_content_NativeLibraryHelper_close},
{"nativeCopyNativeBinaries",
- "(JLjava/lang/String;Ljava/lang/String;)I",
+ "(JLjava/lang/String;Ljava/lang/String;ZZ)I",
(void *)com_android_internal_content_NativeLibraryHelper_copyNativeBinaries},
{"nativeSumNativeBinaries",
"(JLjava/lang/String;)J",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4d6b5f68aa77..851c4bf17f80 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -77,6 +77,8 @@
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGING" />
+ <protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
+
<protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
<protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
<protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" />
@@ -2607,7 +2609,8 @@
android:protectionLevel="signature|system" />
<!-- @SystemApi Allows an application to collect component usage
- statistics @hide -->
+ statistics
+ <p>Not for use by third-party applications. -->
<permission android:name="android.permission.PACKAGE_USAGE_STATS"
android:label="@string/permlab_pkgUsageStats"
android:description="@string/permdesc_pkgUsageStats"
diff --git a/core/res/res/anim/ic_checkbox_checked_box_inner_merged_animation.xml b/core/res/res/anim/ic_checkbox_checked_box_inner_merged_animation.xml
new file mode 100644
index 000000000000..7be32afd424c
--- /dev/null
+++ b/core/res/res/anim/ic_checkbox_checked_box_inner_merged_animation.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="166"
+ android:propertyName="pathData"
+ android:valueFrom="M 0.0,-1.0 l 0.0,0.0 c 0.5522847498,0.0 1.0,0.4477152502 1.0,1.0 l 0.0,0.0 c 0.0,0.5522847498 -0.4477152502,1.0 -1.0,1.0 l 0.0,0.0 c -0.5522847498,0.0 -1.0,-0.4477152502 -1.0,-1.0 l 0.0,0.0 c 0.0,-0.5522847498 0.4477152502,-1.0 1.0,-1.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M 0.0,-1.0 l 0.0,0.0 c 0.5522847498,0.0 1.0,0.4477152502 1.0,1.0 l 0.0,0.0 c 0.0,0.5522847498 -0.4477152502,1.0 -1.0,1.0 l 0.0,0.0 c -0.5522847498,0.0 -1.0,-0.4477152502 -1.0,-1.0 l 0.0,0.0 c 0.0,-0.5522847498 0.4477152502,-1.0 1.0,-1.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="pathData"
+ android:valueFrom="M 0.0,-1.0 l 0.0,0.0 c 0.5522847498,0.0 1.0,0.4477152502 1.0,1.0 l 0.0,0.0 c 0.0,0.5522847498 -0.4477152502,1.0 -1.0,1.0 l 0.0,0.0 c -0.5522847498,0.0 -1.0,-0.4477152502 -1.0,-1.0 l 0.0,0.0 c 0.0,-0.5522847498 0.4477152502,-1.0 1.0,-1.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M -7.0,-7.0 l 14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,14.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-14.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@interpolator/ic_checkbox_checked_animation_interpolator_1" />
+ </set>
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="133"
+ android:propertyName="fillAlpha"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="fillAlpha"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:interpolator="@interpolator/ic_checkbox_checked_animation_interpolator_0" />
+ </set>
+</set>
diff --git a/core/res/res/anim/ic_checkbox_checked_check_path_merged_animation.xml b/core/res/res/anim/ic_checkbox_checked_check_path_merged_animation.xml
new file mode 100644
index 000000000000..fcba2c83f0e3
--- /dev/null
+++ b/core/res/res/anim/ic_checkbox_checked_check_path_merged_animation.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="166"
+ android:propertyName="pathData"
+ android:valueFrom="M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M -2.0,5.00001525879 c 0.0,0.0 -5.0,-5.00001525879 -5.0,-5.00001525879 c 0.0,0.0 1.41409301758,-1.41409301758 1.41409301758,-1.41409301758 c 0.0,0.0 3.58590698242,3.58601379395 3.58590698242,3.58601379395 c 0.0,0.0 7.58590698242,-7.58601379395 7.58590698242,-7.58601379395 c 0.0,0.0 1.41409301758,1.41409301758 1.41409301758,1.41409301758 c 0.0,0.0 -9.0,9.00001525879 -9.0,9.00001525879 Z"
+ android:valueTo="M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M 0.0,1.42500305176 c 0.0,0.0 -1.4234161377,-1.40159606934 -1.4234161377,-1.40159606934 c 0.0,0.0 1.41409301758,-1.41409301758 1.41409301758,-1.41409301758 c 0.0,0.0 0.00932312011719,-0.0124053955078 0.00932312011719,-0.0124053955078 c 0.0,0.0 0.0234069824219,-0.0235137939453 0.0234069824219,-0.0235137939453 c 0.0,0.0 1.41409301758,1.41409301758 1.41409301758,1.41409301758 c 0.0,0.0 -1.4375,1.43751525879 -1.4375,1.43751525879 Z"
+ android:valueType="pathType"
+ android:interpolator="@interpolator/ic_checkbox_checked_animation_interpolator_1" />
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="133"
+ android:propertyName="fillAlpha"
+ android:valueFrom="1.0"
+ android:valueTo="1.0"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="fillAlpha"
+ android:valueFrom="1.0"
+ android:valueTo="0.0"
+ android:interpolator="@interpolator/ic_checkbox_checked_animation_interpolator_0" />
+ </set>
+</set>
diff --git a/core/res/res/anim/ic_checkbox_checked_icon_null_animation.xml b/core/res/res/anim/ic_checkbox_checked_icon_null_animation.xml
new file mode 100644
index 000000000000..312003f1002b
--- /dev/null
+++ b/core/res/res/anim/ic_checkbox_checked_icon_null_animation.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="166"
+ android:propertyName="scaleX"
+ android:valueFrom="0.2"
+ android:valueTo="0.18"
+ android:interpolator="@interpolator/ic_checkbox_checked_animation_interpolator_1" />
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="scaleX"
+ android:valueFrom="0.18"
+ android:valueTo="0.2"
+ android:interpolator="@interpolator/ic_checkbox_checked_animation_interpolator_1" />
+ </set>
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="166"
+ android:propertyName="scaleY"
+ android:valueFrom="0.2"
+ android:valueTo="0.18"
+ android:interpolator="@interpolator/ic_checkbox_checked_animation_interpolator_1" />
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="scaleY"
+ android:valueFrom="0.18"
+ android:valueTo="0.2"
+ android:interpolator="@interpolator/ic_checkbox_checked_animation_interpolator_1" />
+ </set>
+</set>
diff --git a/core/res/res/anim/ic_checkbox_unchecked_box_inner_merged_animation.xml b/core/res/res/anim/ic_checkbox_unchecked_box_inner_merged_animation.xml
new file mode 100644
index 000000000000..b5ad5e9d444c
--- /dev/null
+++ b/core/res/res/anim/ic_checkbox_unchecked_box_inner_merged_animation.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <objectAnimator
+ android:duration="166"
+ android:propertyName="pathData"
+ android:valueFrom="M -7.0,-7.0 l 14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,14.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-14.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueTo="M 0.0,-0.05 l 0.0,0.0 c 0.02761423749,0.0 0.05,0.02238576251 0.05,0.05 l 0.0,0.0 c 0.0,0.02761423749 -0.02238576251,0.05 -0.05,0.05 l 0.0,0.0 c -0.02761423749,0.0 -0.05,-0.02238576251 -0.05,-0.05 l 0.0,0.0 c 0.0,-0.02761423749 0.02238576251,-0.05 0.05,-0.05 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:valueType="pathType"
+ android:interpolator="@interpolator/ic_checkbox_unchecked_animation_interpolator_1" />
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="166"
+ android:propertyName="fillAlpha"
+ android:valueFrom="1.0"
+ android:valueTo="1.0"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="fillAlpha"
+ android:valueFrom="1.0"
+ android:valueTo="0.0"
+ android:interpolator="@interpolator/ic_checkbox_unchecked_animation_interpolator_0" />
+ </set>
+</set>
diff --git a/core/res/res/anim/ic_checkbox_unchecked_box_outer_merged_animation.xml b/core/res/res/anim/ic_checkbox_unchecked_box_outer_merged_animation.xml
new file mode 100644
index 000000000000..066971a146a4
--- /dev/null
+++ b/core/res/res/anim/ic_checkbox_unchecked_box_outer_merged_animation.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="pathData"
+ android:valueFrom="M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M -2.0,5.00001525879 c 0.0,0.0 -1.4234161377,-1.40159606934 -1.4234161377,-1.40159606934 c 0.0,0.0 1.41409301758,-1.41409301758 1.41409301758,-1.41409301758 c 0.0,0.0 0.00932312011719,-0.0124053955078 0.00932312011719,-0.0124053955078 c 0.0,0.0 0.0234069824219,-0.0235137939453 0.0234069824219,-0.0235137939453 c 0.0,0.0 1.41409301758,1.41409301758 1.41409301758,1.41409301758 c 0.0,0.0 -1.4375,1.43751525879 -1.4375,1.43751525879 Z"
+ android:valueTo="M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M -2.0,5.00001525879 c 0.0,0.0 -1.4234161377,-1.40159606934 -1.4234161377,-1.40159606934 c 0.0,0.0 1.41409301758,-1.41409301758 1.41409301758,-1.41409301758 c 0.0,0.0 0.00932312011719,-0.0124053955078 0.00932312011719,-0.0124053955078 c 0.0,0.0 0.0234069824219,-0.0235137939453 0.0234069824219,-0.0235137939453 c 0.0,0.0 1.41409301758,1.41409301758 1.41409301758,1.41409301758 c 0.0,0.0 -1.4375,1.43751525879 -1.4375,1.43751525879 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="300"
+ android:propertyName="pathData"
+ android:valueFrom="M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M -2.0,5.00001525879 c 0.0,0.0 -1.4234161377,-1.40159606934 -1.4234161377,-1.40159606934 c 0.0,0.0 1.41409301758,-1.41409301758 1.41409301758,-1.41409301758 c 0.0,0.0 0.00932312011719,-0.0124053955078 0.00932312011719,-0.0124053955078 c 0.0,0.0 0.0234069824219,-0.0235137939453 0.0234069824219,-0.0235137939453 c 0.0,0.0 1.41409301758,1.41409301758 1.41409301758,1.41409301758 c 0.0,0.0 -1.4375,1.43751525879 -1.4375,1.43751525879 Z"
+ android:valueTo="M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M -2.0,5.00001525879 c 0.0,0.0 -5.0,-5.00001525879 -5.0,-5.00001525879 c 0.0,0.0 1.41409301758,-1.41409301758 1.41409301758,-1.41409301758 c 0.0,0.0 3.58590698242,3.58601379395 3.58590698242,3.58601379395 c 0.0,0.0 7.58590698242,-7.58601379395 7.58590698242,-7.58601379395 c 0.0,0.0 1.41409301758,1.41409301758 1.41409301758,1.41409301758 c 0.0,0.0 -9.0,9.00001525879 -9.0,9.00001525879 Z"
+ android:valueType="pathType"
+ android:interpolator="@interpolator/ic_checkbox_unchecked_animation_interpolator_1" />
+ </set>
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="166"
+ android:propertyName="fillAlpha"
+ android:valueFrom="0.0"
+ android:valueTo="0.0"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="fillAlpha"
+ android:valueFrom="0.0"
+ android:valueTo="1.0"
+ android:interpolator="@interpolator/ic_checkbox_unchecked_animation_interpolator_0" />
+ </set>
+</set>
diff --git a/core/res/res/anim/ic_checkbox_unchecked_icon_null_animation.xml b/core/res/res/anim/ic_checkbox_unchecked_icon_null_animation.xml
new file mode 100644
index 000000000000..fc40d476c8b4
--- /dev/null
+++ b/core/res/res/anim/ic_checkbox_unchecked_icon_null_animation.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleX"
+ android:valueFrom="0.2"
+ android:valueTo="0.18"
+ android:interpolator="@interpolator/ic_checkbox_unchecked_animation_interpolator_1" />
+ <objectAnimator
+ android:duration="300"
+ android:propertyName="scaleX"
+ android:valueFrom="0.18"
+ android:valueTo="0.2"
+ android:interpolator="@interpolator/ic_checkbox_unchecked_animation_interpolator_1" />
+ </set>
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleY"
+ android:valueFrom="0.2"
+ android:valueTo="0.18"
+ android:interpolator="@interpolator/ic_checkbox_unchecked_animation_interpolator_1" />
+ <objectAnimator
+ android:duration="300"
+ android:propertyName="scaleY"
+ android:valueFrom="0.18"
+ android:valueTo="0.2"
+ android:interpolator="@interpolator/ic_checkbox_unchecked_animation_interpolator_1" />
+ </set>
+</set>
diff --git a/core/res/res/color/date_picker_header_text_material.xml b/core/res/res/color/date_picker_header_text_material.xml
index cda894bc2252..baa8958ef3ce 100644
--- a/core/res/res/color/date_picker_header_text_material.xml
+++ b/core/res/res/color/date_picker_header_text_material.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
- android:state_selected="true"
+ android:state_activated="true"
android:color="?attr/textColorPrimaryInverse" />
<item
android:color="?attr/textColorSecondaryInverse" />
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_000.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_000.png
deleted file mode 100644
index 3cb407320801..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_001.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_001.png
deleted file mode 100644
index 8fd148052c14..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_002.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_002.png
deleted file mode 100644
index d35b579006ac..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_003.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_003.png
deleted file mode 100644
index 543c6bcf55cd..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_004.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_004.png
deleted file mode 100644
index 4fc3c4098496..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_005.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_005.png
deleted file mode 100644
index c184535b39cb..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_006.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_006.png
deleted file mode 100644
index 9f9dd4345355..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_007.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_007.png
deleted file mode 100644
index 8c629cea8c6e..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_008.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_008.png
deleted file mode 100644
index 81134b574fd1..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_009.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_009.png
deleted file mode 100644
index baa586091822..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_010.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_010.png
deleted file mode 100644
index d7e283667025..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_011.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_011.png
deleted file mode 100644
index 6f247952a6f8..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_012.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_012.png
deleted file mode 100644
index 22f997d83527..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_013.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_013.png
deleted file mode 100644
index 85f4471fdb0a..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_014.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_014.png
deleted file mode 100644
index ad483c9d171e..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_015.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_015.png
deleted file mode 100644
index f24c2fb4be79..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_000.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_000.png
deleted file mode 100644
index 7a9e9bd2b96b..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_001.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_001.png
deleted file mode 100644
index af0490253e38..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_002.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_002.png
deleted file mode 100644
index 32a6e943566c..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_003.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_003.png
deleted file mode 100644
index c1b4b3743e00..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_004.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_004.png
deleted file mode 100644
index 34d3adeb3ff4..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_005.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_005.png
deleted file mode 100644
index 3d5db5378210..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_006.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_006.png
deleted file mode 100644
index ea354372d277..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_007.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_007.png
deleted file mode 100644
index 48744f82cc0f..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_008.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_008.png
deleted file mode 100644
index f65451740c6e..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_009.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_009.png
deleted file mode 100644
index 16f959ae9a9d..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_010.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_010.png
deleted file mode 100644
index 98c754b77302..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_011.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_011.png
deleted file mode 100644
index 5827dc2141f7..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_012.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_012.png
deleted file mode 100644
index 9850d74bb495..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_013.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_013.png
deleted file mode 100644
index 03ab06b401f7..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_014.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_014.png
deleted file mode 100644
index 11cdd88906f6..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_015.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_015.png
deleted file mode 100644
index 874edbff6221..000000000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_000.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_000.png
deleted file mode 100644
index 97598180770e..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_001.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_001.png
deleted file mode 100644
index 4eb2c4f975c3..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_002.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_002.png
deleted file mode 100644
index e6d6b426b376..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_003.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_003.png
deleted file mode 100644
index 03cb23aee156..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_004.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_004.png
deleted file mode 100644
index bfe3c3df7ae4..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_005.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_005.png
deleted file mode 100644
index 65bdf42f21f9..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_006.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_006.png
deleted file mode 100644
index 44f9614b103f..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_007.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_007.png
deleted file mode 100644
index cf8ec3828932..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_008.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_008.png
deleted file mode 100644
index 4d624b34982b..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_009.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_009.png
deleted file mode 100644
index 7c4eb7f047ea..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_010.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_010.png
deleted file mode 100644
index e90dd310e623..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_011.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_011.png
deleted file mode 100644
index 831c0e86fbb1..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_012.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_012.png
deleted file mode 100644
index 7355dfd6296a..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_013.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_013.png
deleted file mode 100644
index be71a69795bd..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_014.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_014.png
deleted file mode 100644
index a4a185bc85b7..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_015.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_015.png
deleted file mode 100644
index 8d0386f575cb..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_000.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_000.png
deleted file mode 100644
index 70793c474816..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_001.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_001.png
deleted file mode 100644
index 632082b8ad3a..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_002.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_002.png
deleted file mode 100644
index e7fc5fbb402f..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_003.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_003.png
deleted file mode 100644
index 91a0a33935e0..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_004.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_004.png
deleted file mode 100644
index 3bd90d6d5a49..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_005.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_005.png
deleted file mode 100644
index 5ac39ecac6d4..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_006.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_006.png
deleted file mode 100644
index 418198348f89..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_007.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_007.png
deleted file mode 100644
index c8b04df5938b..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_008.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_008.png
deleted file mode 100644
index b7b3a9f2f857..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_009.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_009.png
deleted file mode 100644
index 62bc4eda6299..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_010.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_010.png
deleted file mode 100644
index ac463ad1405c..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_011.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_011.png
deleted file mode 100644
index 12b605dcc27b..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_012.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_012.png
deleted file mode 100644
index 63a3c6ae0315..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_013.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_013.png
deleted file mode 100644
index 17660c49a366..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_014.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_014.png
deleted file mode 100644
index 7d9de3d1161a..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_015.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_015.png
deleted file mode 100644
index 8aa1be2b6d84..000000000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_000.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_000.png
deleted file mode 100644
index 2347643c5a02..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_001.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_001.png
deleted file mode 100644
index 70aaa01b3b6c..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_002.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_002.png
deleted file mode 100644
index 01e498a166f7..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_003.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_003.png
deleted file mode 100644
index 71d1cf72d3f1..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_004.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_004.png
deleted file mode 100644
index d1e7b1de597b..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_005.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_005.png
deleted file mode 100644
index 7db7d06fda50..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_006.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_006.png
deleted file mode 100644
index dadb62edb139..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_007.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_007.png
deleted file mode 100644
index f87f74457f57..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_008.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_008.png
deleted file mode 100644
index be99d87fc7a1..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_009.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_009.png
deleted file mode 100644
index f83bc0533728..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_010.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_010.png
deleted file mode 100644
index 870071d858e6..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_011.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_011.png
deleted file mode 100644
index 3a18414e8d05..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_012.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_012.png
deleted file mode 100644
index f3d1187184d6..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_013.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_013.png
deleted file mode 100644
index 4078cca97719..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_014.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_014.png
deleted file mode 100644
index d4849b51abcf..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_015.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_015.png
deleted file mode 100644
index 6e2af72dd59e..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_000.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_000.png
deleted file mode 100644
index 9244174b9105..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_001.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_001.png
deleted file mode 100644
index 8c7fe9563f74..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_002.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_002.png
deleted file mode 100644
index 71eb1d0c1304..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_003.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_003.png
deleted file mode 100644
index 613f38af1104..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_004.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_004.png
deleted file mode 100644
index 2d20ccca93a9..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_005.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_005.png
deleted file mode 100644
index 407f78db8bc9..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_006.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_006.png
deleted file mode 100644
index 1bf24b01b9ef..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_007.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_007.png
deleted file mode 100644
index a450bd02d16f..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_008.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_008.png
deleted file mode 100644
index 63ba593f26f9..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_009.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_009.png
deleted file mode 100644
index 6d05e5aed625..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_010.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_010.png
deleted file mode 100644
index 1c8cd8f8df8b..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_011.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_011.png
deleted file mode 100644
index b8bc56432396..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_012.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_012.png
deleted file mode 100644
index 3d801282ec6c..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_013.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_013.png
deleted file mode 100644
index c21dfbaa8734..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_014.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_014.png
deleted file mode 100644
index 2dfe90d1df03..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_015.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_015.png
deleted file mode 100644
index 5f40d737d7f0..000000000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_000.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_000.png
deleted file mode 100644
index b75438101a22..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_001.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_001.png
deleted file mode 100644
index 517d7a7cf3f2..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_002.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_002.png
deleted file mode 100644
index 2c1d5b608985..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_003.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_003.png
deleted file mode 100644
index 0c6ff7ef9e2a..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_004.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_004.png
deleted file mode 100644
index 07966019a1f7..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_005.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_005.png
deleted file mode 100644
index 9b4e0f8f748a..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_006.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_006.png
deleted file mode 100644
index 25767eb5b3fd..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_007.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_007.png
deleted file mode 100644
index cd0951f593dc..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_008.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_008.png
deleted file mode 100644
index 9ae8165f0369..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_009.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_009.png
deleted file mode 100644
index efd9bc6f9faf..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_010.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_010.png
deleted file mode 100644
index fccbc9dce08f..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_011.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_011.png
deleted file mode 100644
index dddafca50ca3..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_012.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_012.png
deleted file mode 100644
index 7e37433dd1de..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_013.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_013.png
deleted file mode 100644
index 9bc22def39b2..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_014.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_014.png
deleted file mode 100644
index 507ed108b9fc..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_015.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_015.png
deleted file mode 100644
index 6a21c7fca1ca..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_000.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_000.png
deleted file mode 100644
index 0d544d90b068..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_001.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_001.png
deleted file mode 100644
index 39da0ac74f9d..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_002.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_002.png
deleted file mode 100644
index d5ada1242e34..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_003.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_003.png
deleted file mode 100644
index d4e096c9b47d..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_004.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_004.png
deleted file mode 100644
index 468a9b479d22..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_005.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_005.png
deleted file mode 100644
index ea3cd2edf313..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_006.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_006.png
deleted file mode 100644
index 0652cb098f83..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_007.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_007.png
deleted file mode 100644
index 768d2b06a5f3..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_008.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_008.png
deleted file mode 100644
index 1d06a905774c..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_009.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_009.png
deleted file mode 100644
index 8a70a80f529a..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_010.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_010.png
deleted file mode 100644
index bf9ec7fcd8b7..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_011.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_011.png
deleted file mode 100644
index cff07b9e21e3..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_012.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_012.png
deleted file mode 100644
index 40f997e21b81..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_013.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_013.png
deleted file mode 100644
index 6ba84ec58bb9..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_014.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_014.png
deleted file mode 100644
index 766610e543f1..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_015.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_015.png
deleted file mode 100644
index 810a02942f66..000000000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_000.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_000.png
deleted file mode 100644
index f0ff1a70f3a1..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_001.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_001.png
deleted file mode 100644
index b382df365d01..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_002.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_002.png
deleted file mode 100644
index 8cb4ce2e4129..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_003.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_003.png
deleted file mode 100644
index 4db2b0104275..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_004.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_004.png
deleted file mode 100644
index 8c4709b74e24..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_005.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_005.png
deleted file mode 100644
index 1ad960ab330f..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_006.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_006.png
deleted file mode 100644
index e47cc20b3cee..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_007.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_007.png
deleted file mode 100644
index c4d0d51cf2cc..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_008.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_008.png
deleted file mode 100644
index 915d56afe323..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_009.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_009.png
deleted file mode 100644
index 85795cbad9e7..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_010.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_010.png
deleted file mode 100644
index 157fd9102cac..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_011.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_011.png
deleted file mode 100644
index 9d446de2dcab..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_012.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_012.png
deleted file mode 100644
index dfac1f030f0c..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_013.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_013.png
deleted file mode 100644
index aed6c08d832c..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_014.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_014.png
deleted file mode 100644
index 1b8bd6b312e3..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_015.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_015.png
deleted file mode 100644
index 5dd0e5ba60a6..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_000.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_000.png
deleted file mode 100644
index 5dd0e5ba60a6..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_001.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_001.png
deleted file mode 100644
index 1a31ad9a9a9a..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_002.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_002.png
deleted file mode 100644
index 63c7f1290461..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_003.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_003.png
deleted file mode 100644
index 847dd0899730..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_004.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_004.png
deleted file mode 100644
index b93f3cc18c1a..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_005.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_005.png
deleted file mode 100644
index 1e3dea77a588..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_006.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_006.png
deleted file mode 100644
index 5a85238b2b79..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_007.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_007.png
deleted file mode 100644
index 35960cace82a..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_008.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_008.png
deleted file mode 100644
index 6db55553c110..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_009.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_009.png
deleted file mode 100644
index a9c5851c7bf7..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_010.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_010.png
deleted file mode 100644
index 38465bda1274..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_011.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_011.png
deleted file mode 100644
index 15942dc1fd85..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_012.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_012.png
deleted file mode 100644
index 67d0d649e5d9..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_013.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_013.png
deleted file mode 100644
index 69b5c1b9b95e..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_014.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_014.png
deleted file mode 100644
index 0e5d3315523e..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_015.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_015.png
deleted file mode 100644
index f0ff1a70f3a1..000000000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/btn_check_material_anim.xml b/core/res/res/drawable/btn_check_material_anim.xml
index 24df879ce393..41caa4ece032 100644
--- a/core/res/res/drawable/btn_check_material_anim.xml
+++ b/core/res/res/drawable/btn_check_material_anim.xml
@@ -15,159 +15,15 @@
-->
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:state_checked="true">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_015"
- android:tint="?attr/colorControlNormal"
- android:alpha="?attr/disabledAlpha" />
- </item>
- <item android:state_enabled="false">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_000"
- android:tint="?attr/colorControlNormal"
- android:alpha="?attr/disabledAlpha" />
- </item>
- <item android:state_checked="true" android:id="@+id/on">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_015"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:id="@+id/off">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_000"
- android:tint="?attr/colorControlNormal" />
- </item>
- <transition android:fromId="@+id/off" android:toId="@+id/on">
- <animation-list>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_000"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_001"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_002"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_003"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_004"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_005"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_006"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_007"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_008"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_009"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_010"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_011"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_012"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_013"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_014"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_mtrl_015"
- android:tint="?attr/colorControlActivated" />
- </item>
- </animation-list>
- </transition>
- <transition android:fromId="@+id/on" android:toId="@+id/off">
- <animation-list>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_000"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_001"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_002"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_003"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_004"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_005"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_006"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_007"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_008"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_009"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_010"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_011"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_012"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_013"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_014"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_mtrl_015"
- android:tint="?attr/colorControlNormal" />
- </item>
- </animation-list>
- </transition>
+ <item android:state_checked="true" android:id="@+id/on"
+ android:drawable="@drawable/ic_checkbox_checked" />
+ <item android:id="@+id/off"
+ android:drawable="@drawable/ic_checkbox_unchecked" />
+
+ <transition android:fromId="@+id/off" android:toId="@+id/on"
+ android:drawable="@drawable/ic_checkbox_unchecked_animation" />
+
+ <transition android:fromId="@+id/on" android:toId="@+id/off"
+ android:drawable="@drawable/ic_checkbox_checked_animation" />
</animated-selector>
diff --git a/core/res/res/drawable/ic_checkbox_checked.xml b/core/res/res/drawable/ic_checkbox_checked.xml
new file mode 100644
index 000000000000..476411516dad
--- /dev/null
+++ b/core/res/res/drawable/ic_checkbox_checked.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="ic_checkbox_checked"
+ android:width="32dp"
+ android:viewportWidth="48"
+ android:height="32dp"
+ android:viewportHeight="48"
+ android:tint="?attr/colorControlNormal" >
+ <group
+ android:name="icon_null"
+ android:translateX="24"
+ android:translateY="24"
+ android:scaleX="0.2"
+ android:scaleY="0.2" >
+ <group
+ android:name="check"
+ android:scaleX="7.5"
+ android:scaleY="7.5" >
+ <path
+ android:name="check_path_merged"
+ android:pathData="M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M -2.0,5.00001525879 c 0.0,0.0 -5.0,-5.00001525879 -5.0,-5.00001525879 c 0.0,0.0 1.41409301758,-1.41409301758 1.41409301758,-1.41409301758 c 0.0,0.0 3.58590698242,3.58601379395 3.58590698242,3.58601379395 c 0.0,0.0 7.58590698242,-7.58601379395 7.58590698242,-7.58601379395 c 0.0,0.0 1.41409301758,1.41409301758 1.41409301758,1.41409301758 c 0.0,0.0 -9.0,9.00001525879 -9.0,9.00001525879 Z"
+ android:fillColor="#FF000000" />
+ </group>
+ <group
+ android:name="box_dilate"
+ android:scaleX="7.5"
+ android:scaleY="7.5" >
+ <path
+ android:name="box_inner_merged"
+ android:pathData="M 0.0,-1.0 l 0.0,0.0 c 0.5522847498,0.0 1.0,0.4477152502 1.0,1.0 l 0.0,0.0 c 0.0,0.5522847498 -0.4477152502,1.0 -1.0,1.0 l 0.0,0.0 c -0.5522847498,0.0 -1.0,-0.4477152502 -1.0,-1.0 l 0.0,0.0 c 0.0,-0.5522847498 0.4477152502,-1.0 1.0,-1.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:fillColor="#FF000000"
+ android:fillAlpha="0" />
+ </group>
+ </group>
+</vector>
diff --git a/core/res/res/drawable/ic_checkbox_checked_animation.xml b/core/res/res/drawable/ic_checkbox_checked_animation.xml
new file mode 100644
index 000000000000..af5eeeea0968
--- /dev/null
+++ b/core/res/res/drawable/ic_checkbox_checked_animation.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/ic_checkbox_checked" >
+ <target
+ android:name="icon_null"
+ android:animation="@anim/ic_checkbox_checked_icon_null_animation" />
+ <target
+ android:name="check_path_merged"
+ android:animation="@anim/ic_checkbox_checked_check_path_merged_animation" />
+ <target
+ android:name="box_inner_merged"
+ android:animation="@anim/ic_checkbox_checked_box_inner_merged_animation" />
+</animated-vector>
diff --git a/core/res/res/drawable/ic_checkbox_unchecked.xml b/core/res/res/drawable/ic_checkbox_unchecked.xml
new file mode 100644
index 000000000000..410f0bcc901e
--- /dev/null
+++ b/core/res/res/drawable/ic_checkbox_unchecked.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:name="ic_checkbox_unchecked"
+ android:width="32dp"
+ android:viewportWidth="48"
+ android:height="32dp"
+ android:viewportHeight="48"
+ android:tint="?attr/colorControlNormal" >
+ <group
+ android:name="icon_null"
+ android:translateX="24"
+ android:translateY="24"
+ android:scaleX="0.2"
+ android:scaleY="0.2" >
+ <group
+ android:name="check"
+ android:scaleX="7.5"
+ android:scaleY="7.5" >
+ <path
+ android:name="box_outer_merged"
+ android:pathData="M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M -2.0,5.00001525879 c 0.0,0.0 -1.4234161377,-1.40159606934 -1.4234161377,-1.40159606934 c 0.0,0.0 1.41409301758,-1.41409301758 1.41409301758,-1.41409301758 c 0.0,0.0 0.00932312011719,-0.0124053955078 0.00932312011719,-0.0124053955078 c 0.0,0.0 0.0234069824219,-0.0235137939453 0.0234069824219,-0.0235137939453 c 0.0,0.0 1.41409301758,1.41409301758 1.41409301758,1.41409301758 c 0.0,0.0 -1.4375,1.43751525879 -1.4375,1.43751525879 Z"
+ android:fillColor="#FF000000"
+ android:fillAlpha="0" />
+ </group>
+ <group
+ android:name="box_dilate"
+ android:scaleX="7.5"
+ android:scaleY="7.5" >
+ <path
+ android:name="box_inner_merged"
+ android:pathData="M -7.0,-7.0 l 14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,14.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-14.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+ android:fillColor="#FF000000" />
+ </group>
+ </group>
+</vector>
diff --git a/core/res/res/drawable/ic_checkbox_unchecked_animation.xml b/core/res/res/drawable/ic_checkbox_unchecked_animation.xml
new file mode 100644
index 000000000000..605fce117523
--- /dev/null
+++ b/core/res/res/drawable/ic_checkbox_unchecked_animation.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<animated-vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/ic_checkbox_unchecked" >
+ <target
+ android:name="icon_null"
+ android:animation="@anim/ic_checkbox_unchecked_icon_null_animation" />
+ <target
+ android:name="box_outer_merged"
+ android:animation="@anim/ic_checkbox_unchecked_box_outer_merged_animation" />
+ <target
+ android:name="box_inner_merged"
+ android:animation="@anim/ic_checkbox_unchecked_box_inner_merged_animation" />
+</animated-vector>
diff --git a/core/res/res/drawable/pointer_arrow_icon.xml b/core/res/res/drawable/pointer_arrow_icon.xml
index 8f7d658c9f3a..72af0c11f50c 100644
--- a/core/res/res/drawable/pointer_arrow_icon.xml
+++ b/core/res/res/drawable/pointer_arrow_icon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
android:bitmap="@drawable/pointer_arrow"
- android:hotSpotX="6dp"
- android:hotSpotY="6dp" />
+ android:hotSpotX="5dp"
+ android:hotSpotY="5dp" />
diff --git a/core/res/res/drawable/time_picker_header_material.xml b/core/res/res/interpolator/ic_checkbox_checked_animation_interpolator_0.xml
index ef2068a2f626..ceac6636c3b2 100644
--- a/core/res/res/drawable/time_picker_header_material.xml
+++ b/core/res/res/interpolator/ic_checkbox_checked_animation_interpolator_0.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,7 +15,6 @@
limitations under the License.
-->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?attr/colorControlHighlight">
- <item android:drawable="?attr/colorAccent" />
-</ripple>
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 l 1.0,0.0 l 0.0,1.0" />
diff --git a/core/res/res/layout/date_picker_view_animator.xml b/core/res/res/interpolator/ic_checkbox_checked_animation_interpolator_1.xml
index 9085ed5907e3..26bc8ad609df 100644
--- a/core/res/res/layout/date_picker_view_animator.xml
+++ b/core/res/res/interpolator/ic_checkbox_checked_animation_interpolator_1.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,9 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.internal.widget.AccessibleDateAnimator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/animator"
- android:layout_width="@dimen/datepicker_component_width"
- android:layout_height="@dimen/datepicker_view_animator_height"
- android:gravity="center" /> \ No newline at end of file
+
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 c 0.33333333,0.0 0.0,1.0 1.0,1.0" />
diff --git a/core/res/res/interpolator/ic_checkbox_unchecked_animation_interpolator_0.xml b/core/res/res/interpolator/ic_checkbox_unchecked_animation_interpolator_0.xml
new file mode 100644
index 000000000000..ceac6636c3b2
--- /dev/null
+++ b/core/res/res/interpolator/ic_checkbox_unchecked_animation_interpolator_0.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 l 1.0,0.0 l 0.0,1.0" />
diff --git a/core/res/res/interpolator/ic_checkbox_unchecked_animation_interpolator_1.xml b/core/res/res/interpolator/ic_checkbox_unchecked_animation_interpolator_1.xml
new file mode 100644
index 000000000000..26bc8ad609df
--- /dev/null
+++ b/core/res/res/interpolator/ic_checkbox_unchecked_animation_interpolator_1.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<pathInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0.0,0.0 c 0.33333333,0.0 0.0,1.0 1.0,1.0" />
diff --git a/core/res/res/layout-land/date_picker_holo.xml b/core/res/res/layout-land/date_picker_holo.xml
deleted file mode 100644
index 991888c2daf5..000000000000
--- a/core/res/res/layout-land/date_picker_holo.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT 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="@dimen/datepicker_view_animator_height"
- android:gravity="center"
- android:orientation="horizontal"
- android:minWidth="@dimen/datepicker_dialog_width" >
-
- <include
- layout="@layout/date_picker_selected_date"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_weight="1" />
-
- <include layout="@layout/date_picker_view_animator" />
-
-</LinearLayout>
diff --git a/core/res/res/layout-land/date_picker_material.xml b/core/res/res/layout-land/date_picker_material.xml
new file mode 100644
index 000000000000..1e711c57fa04
--- /dev/null
+++ b/core/res/res/layout-land/date_picker_material.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <include
+ layout="@layout/date_picker_header_material"
+ android:layout_width="168dp"
+ android:layout_height="match_parent" />
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <include
+ layout="@layout/date_picker_view_animator_material"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <ViewStub
+ android:id="@id/buttonPanel"
+ android:layout="@layout/alert_dialog_button_bar_material"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/day_picker_button_margin_top" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/core/res/res/layout-watch/progress_dialog_material.xml b/core/res/res/layout-watch/progress_dialog_material.xml
new file mode 100644
index 000000000000..228f72454c0a
--- /dev/null
+++ b/core/res/res/layout-watch/progress_dialog_material.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:id="@+id/body"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:baselineAligned="false"
+ android:paddingStart="?attr/dialogPreferredPadding"
+ android:paddingTop="@dimen/dialog_padding_top_material"
+ android:paddingEnd="?attr/dialogPreferredPadding"
+ android:paddingBottom="@dimen/dialog_padding_top_material">
+
+ <ProgressBar
+ android:id="@id/progress"
+ style="?android:attr/progressBarStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:max="10000"
+ android:layout_marginEnd="?attr/dialogPreferredPadding" />
+
+ <TextView
+ android:id="@+id/message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical" />
+ </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/alert_dialog_button_bar_material.xml b/core/res/res/layout/alert_dialog_button_bar_material.xml
index 891bcd5e4354..1eea4e124af3 100644
--- a/core/res/res/layout/alert_dialog_button_bar_material.xml
+++ b/core/res/res/layout/alert_dialog_button_bar_material.xml
@@ -18,16 +18,16 @@
<com.android.internal.widget.ButtonBarLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/buttonPanel"
- style="?attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutDirection="locale"
android:orientation="horizontal"
android:paddingStart="12dp"
android:paddingEnd="12dp"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:gravity="bottom">
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
+ android:gravity="bottom"
+ style="?attr/buttonBarStyle">
<Button
android:id="@+id/button3"
diff --git a/core/res/res/layout/date_picker_header_material.xml b/core/res/res/layout/date_picker_header_material.xml
new file mode 100644
index 000000000000..bda7de93001c
--- /dev/null
+++ b/core/res/res/layout/date_picker_header_material.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/date_picker_header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="18dp"
+ android:paddingStart="?attr/dialogPreferredPadding"
+ android:paddingEnd="?attr/dialogPreferredPadding"
+ android:orientation="vertical"
+ tools:background="@color/accent_material_light"
+ tools:paddingStart="24dp"
+ tools:paddingEnd="24dp">
+
+ <!-- Top padding should stay on this view so that
+ the touch target is a bit larger. -->
+ <TextView
+ android:id="@+id/date_picker_header_year"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="16dp"
+ android:textAppearance="@style/TextAppearance.Material.DatePicker.YearLabel"
+ tools:text="2015"
+ tools:textSize="@dimen/date_picker_year_label_size"
+ tools:textColor="@color/white" />
+
+ <TextView
+ android:id="@+id/date_picker_header_date"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.Material.DatePicker.DateLabel"
+ android:maxLines="2"
+ android:ellipsize="none"
+ tools:text="Thu, Sep 30"
+ tools:textSize="@dimen/date_picker_date_label_size"
+ tools:textColor="@color/white" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/date_picker_holo.xml b/core/res/res/layout/date_picker_material.xml
index 72030ea209a5..a1c97ff79dbc 100644
--- a/core/res/res/layout/date_picker_holo.xml
+++ b/core/res/res/layout/date_picker_material.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2011 The Android Open Source Project
+ Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,17 +14,21 @@
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="@dimen/datepicker_component_width"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
- android:gravity="center"
android:orientation="vertical">
<include
- layout="@layout/date_picker_selected_date"
+ layout="@layout/date_picker_header_material"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
- <include layout="@layout/date_picker_view_animator" />
+ <include
+ layout="@layout/date_picker_view_animator_material"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
</LinearLayout>
diff --git a/core/res/res/layout/date_picker_selected_date.xml b/core/res/res/layout/date_picker_selected_date.xml
deleted file mode 100644
index 9becb817c12a..000000000000
--- a/core/res/res/layout/date_picker_selected_date.xml
+++ /dev/null
@@ -1,73 +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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/day_picker_selector_layout"
- android:layout_width="@dimen/datepicker_component_width"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/date_picker_header"
- android:layout_width="match_parent"
- android:layout_height="@dimen/datepicker_header_height"
- android:gravity="center"
- android:importantForAccessibility="no" />
-
- <LinearLayout
- android:id="@+id/date_picker_month_day_year_layout"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:paddingTop="4dp"
- android:paddingBottom="4dp"
- android:orientation="vertical"
- android:gravity="center">
-
- <LinearLayout
- android:id="@+id/date_picker_month_and_day_layout"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clickable="true"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/date_picker_month"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:duplicateParentState="true"
- android:gravity="center" />
-
- <TextView
- android:id="@+id/date_picker_day"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="-23dp"
- android:layout_marginBottom="-20dp"
- android:duplicateParentState="true"
- android:gravity="center" />
- </LinearLayout>
-
- <TextView
- android:id="@+id/date_picker_year"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center" />
- </LinearLayout>
-
-</LinearLayout>
diff --git a/core/res/res/layout/date_picker_view_animator_material.xml b/core/res/res/layout/date_picker_view_animator_material.xml
new file mode 100644
index 000000000000..98ef1dd47cc7
--- /dev/null
+++ b/core/res/res/layout/date_picker_view_animator_material.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<ViewAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/animator"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:gravity="center">
+
+ <android.widget.DayPickerView
+ android:id="@+id/date_picker_day_picker"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingStart="@dimen/day_picker_padding_horizontal"
+ android:paddingEnd="@dimen/day_picker_padding_horizontal"
+ android:paddingTop="@dimen/day_picker_padding_top" />
+
+ <android.widget.YearPickerView
+ android:id="@+id/date_picker_year_picker"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</ViewAnimator>
diff --git a/core/res/res/layout/floating_popup_container.xml b/core/res/res/layout/floating_popup_container.xml
new file mode 100644
index 000000000000..f24791973182
--- /dev/null
+++ b/core/res/res/layout/floating_popup_container.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/floating_toolbar_height"
+ android:elevation="2dp"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:background="@android:color/background_light" />
diff --git a/core/res/res/layout/floating_popup_menu_button.xml b/core/res/res/layout/floating_popup_menu_button.xml
new file mode 100644
index 000000000000..9fa13bdeb94e
--- /dev/null
+++ b/core/res/res/layout/floating_popup_menu_button.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:minWidth="@dimen/floating_toolbar_menu_button_side_padding"
+ android:paddingLeft="@dimen/floating_toolbar_menu_button_side_padding"
+ android:paddingRight="@dimen/floating_toolbar_menu_button_side_padding"
+ android:paddingTop="0dp"
+ android:paddingBottom="0dp"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:fontFamily="sans-serif"
+ android:textSize="@dimen/floating_toolbar_text_size"
+ android:textAllCaps="true"
+ android:background="?attr/selectableItemBackground" /> \ No newline at end of file
diff --git a/core/res/res/layout/floating_popup_open_overflow_button.xml b/core/res/res/layout/floating_popup_open_overflow_button.xml
new file mode 100644
index 000000000000..4c1176c2a4c9
--- /dev/null
+++ b/core/res/res/layout/floating_popup_open_overflow_button.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/floating_toolbar_menu_button_minimum_width"
+ android:layout_height="match_parent"
+ android:minWidth="@dimen/floating_toolbar_menu_button_minimum_width"
+ android:minHeight="@dimen/floating_toolbar_height"
+ android:src="@drawable/ic_menu_moreoverflow_material"
+ android:contentDescription="@string/action_menu_overflow_description"
+ android:background="?attr/selectableItemBackgroundBorderless" />
diff --git a/core/res/res/layout/year_label_text_view.xml b/core/res/res/layout/year_label_text_view.xml
index e5bd06810dc3..6240c4b9273c 100644
--- a/core/res/res/layout/year_label_text_view.xml
+++ b/core/res/res/layout/year_label_text_view.xml
@@ -13,10 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<android.widget.TextViewWithCircularIndicator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/month_text_view"
- android:layout_width="match_parent"
- android:layout_height="@dimen/datepicker_year_label_height"
- android:layout_gravity="center"
- android:gravity="center" />
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/month_text_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?attr/listPreferredItemHeightSmall"
+ android:paddingTop="12dp"
+ android:paddingBottom="12dp"
+ android:gravity="center" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 0c615915df0b..aed69ba56d54 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Minute se sirkelglyer"</string>
<string name="select_hours" msgid="6043079511766008245">"Kies ure"</string>
<string name="select_minutes" msgid="3974345615920336087">"Kies minute"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Maandrooster van dae"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Jaarlys"</string>
<string name="select_day" msgid="7774759604701773332">"Kies maand en dag"</string>
<string name="select_year" msgid="7952052866994196170">"Kies jaar"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> gekies"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index b639b4fba788..f6b38ad7df07 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"የደቂቃዎች ክብ ተንሸራታች"</string>
<string name="select_hours" msgid="6043079511766008245">"ሰዓታትን ይምረጡ"</string>
<string name="select_minutes" msgid="3974345615920336087">"ደቂቃዎችን ይምረጡ"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"የቀናት የወር ፍርግርግ"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"የዓመት ዝርዝር"</string>
<string name="select_day" msgid="7774759604701773332">"ወር እና ቀን ይምረጡ"</string>
<string name="select_year" msgid="7952052866994196170">"ዓመት ይምረጡ"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ተመርጧል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 42bf57d710c3..ddb0e4dc46a9 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1830,8 +1830,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"شريط التمرير الدائري للدقائق"</string>
<string name="select_hours" msgid="6043079511766008245">"تحديد الساعات"</string>
<string name="select_minutes" msgid="3974345615920336087">"تحديد الدقائق"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"شبكة الشهر مكونة من الأيام"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"قائمة الأعوام"</string>
<string name="select_day" msgid="7774759604701773332">"تحديد الشهر واليوم"</string>
<string name="select_year" msgid="7952052866994196170">"تحديد العام"</string>
<string name="item_is_selected" msgid="949687401682476608">"تم تحديد <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index ecfa7bd94180..efae80e4bd29 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Кръгов плъзгач за минутите"</string>
<string name="select_hours" msgid="6043079511766008245">"Избиране на часове"</string>
<string name="select_minutes" msgid="3974345615920336087">"Избиране на минути"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Месечна таблица на дните"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Списък с години"</string>
<string name="select_day" msgid="7774759604701773332">"Избиране на месец и ден"</string>
<string name="select_year" msgid="7952052866994196170">"Избиране на година"</string>
<string name="item_is_selected" msgid="949687401682476608">"Избрахте <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index f20e21f08622..c47a5028c0ce 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"বৃত্তাকার মিনিট নির্বাচকের স্লাইডার"</string>
<string name="select_hours" msgid="6043079511766008245">"ঘন্টা নির্বাচন করুন"</string>
<string name="select_minutes" msgid="3974345615920336087">"মিনিট নির্বাচন করুন"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"দিন দিয়ে সংগঠিত মাসের গ্রিড"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"বছরের তালিকা"</string>
<string name="select_day" msgid="7774759604701773332">"মাস এবং দিন নির্বাচন করুন"</string>
<string name="select_year" msgid="7952052866994196170">"বছর নির্বাচন করুন"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> নির্বাচন করা হয়েছে"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index aebebf284e80..ed964e9c238a 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Control circular dels minuts"</string>
<string name="select_hours" msgid="6043079511766008245">"Selecciona les hores"</string>
<string name="select_minutes" msgid="3974345615920336087">"Selecciona els minuts"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Graella mensual de dies"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Llista anual"</string>
<string name="select_day" msgid="7774759604701773332">"Selecciona un mes i un dia"</string>
<string name="select_year" msgid="7952052866994196170">"Selecciona un any"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> seleccionat"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 988818b4f8f0..d7e86a59a15c 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1812,8 +1812,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Kruhový posuvník minut"</string>
<string name="select_hours" msgid="6043079511766008245">"Zvolte hodiny"</string>
<string name="select_minutes" msgid="3974345615920336087">"Zvolte minuty"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Dny uspořádané po měsících"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Seznam roků"</string>
<string name="select_day" msgid="7774759604701773332">"Vyberte měsíc a den"</string>
<string name="select_year" msgid="7952052866994196170">"Vyberte rok"</string>
<string name="item_is_selected" msgid="949687401682476608">"Vybrána položka <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 20b7ad26d082..b97720d25b3f 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Cirkulær minutvælger"</string>
<string name="select_hours" msgid="6043079511766008245">"Vælg timer"</string>
<string name="select_minutes" msgid="3974345615920336087">"Vælg minutter"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Månedsgitter med dage"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Liste over år"</string>
<string name="select_day" msgid="7774759604701773332">"Vælg måned og dag"</string>
<string name="select_year" msgid="7952052866994196170">"Vælg år"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> er valgt"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 07153fea2475..227e20c722ed 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -203,7 +203,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flugmodus ist AN."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flugmodus ist AUS."</string>
<string name="global_action_settings" msgid="1756531602592545966">"Einstellungen"</string>
- <string name="global_action_assist" msgid="3892832961594295030">"Geräteassistent"</string>
+ <string name="global_action_assist" msgid="3892832961594295030">"Assistent"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Sprachassistent"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Jetzt sperren"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Kreisförmiger Schieberegler für Minuten"</string>
<string name="select_hours" msgid="6043079511766008245">"Stunden auswählen"</string>
<string name="select_minutes" msgid="3974345615920336087">"Minuten auswählen"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Monatsraster mit einzelnen Tagen"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Jahresliste"</string>
<string name="select_day" msgid="7774759604701773332">"Monat und Tag auswählen"</string>
<string name="select_year" msgid="7952052866994196170">"Jahr auswählen"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ausgewählt"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index e0a6f88d3a96..c3e1bb7400b8 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Κυκλικό ρυθμιστικό λεπτών"</string>
<string name="select_hours" msgid="6043079511766008245">"Επιλογή ωρών"</string>
<string name="select_minutes" msgid="3974345615920336087">"Επιλογή λεπτών"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Πλέγμα ημερών του μήνα"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Λίστα ετών"</string>
<string name="select_day" msgid="7774759604701773332">"Επιλογή μήνα και ημέρας"</string>
<string name="select_year" msgid="7952052866994196170">"Επιλογή έτους"</string>
<string name="item_is_selected" msgid="949687401682476608">"Επιλέχτηκε το στοιχείο <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index f52daf6dea76..bfcb90c92914 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Minutes circular slider"</string>
<string name="select_hours" msgid="6043079511766008245">"Select hours"</string>
<string name="select_minutes" msgid="3974345615920336087">"Select minutes"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Month grid of days"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Year list"</string>
<string name="select_day" msgid="7774759604701773332">"Select month and day"</string>
<string name="select_year" msgid="7952052866994196170">"Select year"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selected"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index f52daf6dea76..bfcb90c92914 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Minutes circular slider"</string>
<string name="select_hours" msgid="6043079511766008245">"Select hours"</string>
<string name="select_minutes" msgid="3974345615920336087">"Select minutes"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Month grid of days"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Year list"</string>
<string name="select_day" msgid="7774759604701773332">"Select month and day"</string>
<string name="select_year" msgid="7952052866994196170">"Select year"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selected"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index f52daf6dea76..bfcb90c92914 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Minutes circular slider"</string>
<string name="select_hours" msgid="6043079511766008245">"Select hours"</string>
<string name="select_minutes" msgid="3974345615920336087">"Select minutes"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Month grid of days"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Year list"</string>
<string name="select_day" msgid="7774759604701773332">"Select month and day"</string>
<string name="select_year" msgid="7952052866994196170">"Select year"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selected"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index ce419dc32b5f..78cc2274b09f 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Control deslizante circular de minutos"</string>
<string name="select_hours" msgid="6043079511766008245">"Seleccionar horas"</string>
<string name="select_minutes" msgid="3974345615920336087">"Seleccionar minutos"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Cuadrícula mensual de días"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Lista de años"</string>
<string name="select_day" msgid="7774759604701773332">"Seleccionar mes y día"</string>
<string name="select_year" msgid="7952052866994196170">"Seleccionar año"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> seleccionado"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index e22ea2121063..969881cf363d 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Control deslizante circular de minutos"</string>
<string name="select_hours" msgid="6043079511766008245">"Seleccionar horas"</string>
<string name="select_minutes" msgid="3974345615920336087">"Seleccionar minutos"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Cuadrícula mensual de días"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Lista de años"</string>
<string name="select_day" msgid="7774759604701773332">"Seleccionar mes y día"</string>
<string name="select_year" msgid="7952052866994196170">"Seleccionar año"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> seleccionado"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 85b5c3c04765..72b13dad7e8b 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Ringikujuline minutiliugur"</string>
<string name="select_hours" msgid="6043079511766008245">"Tundide valimine"</string>
<string name="select_minutes" msgid="3974345615920336087">"Minutite valimine"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Päevad kuu ruudustikus"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Aastate loend"</string>
<string name="select_day" msgid="7774759604701773332">"Kuu ja päeva valimine"</string>
<string name="select_year" msgid="7952052866994196170">"Aasta valimine"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> on valitud"</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 02d8dd3a62b6..da96ec3c564b 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Minutuak aukeratzeko ikuspegi zirkularra"</string>
<string name="select_hours" msgid="6043079511766008245">"Hautatu orduak"</string>
<string name="select_minutes" msgid="3974345615920336087">"Hautatu minutuak"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Hilabete-ikuspegiko eguna aukeratzeko sareta"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Urteen zerrenda"</string>
<string name="select_day" msgid="7774759604701773332">"Hautatu hilabetea eta eguna"</string>
<string name="select_year" msgid="7952052866994196170">"Hautatu urtea"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> hautatu da"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 2073b5e65a33..1aa1cc87276b 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"لغزنده دایره‌ای دقیقه"</string>
<string name="select_hours" msgid="6043079511766008245">"انتخاب ساعت"</string>
<string name="select_minutes" msgid="3974345615920336087">"انتخاب دقیقه"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"جدول روزها براساس ماه"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"لیست سال‌ها"</string>
<string name="select_day" msgid="7774759604701773332">"انتخاب ماه و روز"</string>
<string name="select_year" msgid="7952052866994196170">"انتخاب سال"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> انتخاب شد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index a2f1ccf72328..39860e3d8805 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Minuuttien ympyränmuotoinen liukusäädin"</string>
<string name="select_hours" msgid="6043079511766008245">"Valitse tunnit"</string>
<string name="select_minutes" msgid="3974345615920336087">"Valitse minuutit"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Päiväruudukko kuukausittain"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Vuosiluettelo"</string>
<string name="select_day" msgid="7774759604701773332">"Valitse kuukausi ja päivä"</string>
<string name="select_year" msgid="7952052866994196170">"Valitse vuosi"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> on valittu"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 837b58ace996..4a3e4a1a1c81 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Curseur circulaire des minutes"</string>
<string name="select_hours" msgid="6043079511766008245">"Sélectionnez les heures"</string>
<string name="select_minutes" msgid="3974345615920336087">"Sélectionnez les minutes"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Calendrier mensuel sous forme de grille"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Liste des années"</string>
<string name="select_day" msgid="7774759604701773332">"Sélectionnez un mois et un jour"</string>
<string name="select_year" msgid="7952052866994196170">"Sélectionnez une année"</string>
<string name="item_is_selected" msgid="949687401682476608">"« <xliff:g id="ITEM">%1$s</xliff:g> » a été sélectionné"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index c6e1387f684c..1713dd8de54d 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Curseur circulaire des minutes"</string>
<string name="select_hours" msgid="6043079511766008245">"Sélectionner une heure"</string>
<string name="select_minutes" msgid="3974345615920336087">"Sélectionner des minutes"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Calendrier mensuel sous forme de grille"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Liste des années"</string>
<string name="select_day" msgid="7774759604701773332">"Sélectionner un mois et un jour"</string>
<string name="select_year" msgid="7952052866994196170">"Sélectionner une année"</string>
<string name="item_is_selected" msgid="949687401682476608">"\"<xliff:g id="ITEM">%1$s</xliff:g>\" sélectionné"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 5218ed517750..e35d654f72bd 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Control de desprazamento circular dos minutos"</string>
<string name="select_hours" msgid="6043079511766008245">"Seleccionar horas"</string>
<string name="select_minutes" msgid="3974345615920336087">"Seleccionar minutos"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Grade mensual de días"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Lista de anos"</string>
<string name="select_day" msgid="7774759604701773332">"Seleccionar mes e día"</string>
<string name="select_year" msgid="7952052866994196170">"Seleccionar ano"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> seleccionado"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 6463cc53006f..53c395de238c 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1211,9 +1211,9 @@
<string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> चल रहा है"</string>
<string name="app_running_notification_text" msgid="4653586947747330058">"अधिक जानकारी के लिए या ऐप्स रोकने के लिए स्पर्श करें."</string>
<string name="ok" msgid="5970060430562524910">"ठीक है"</string>
- <string name="cancel" msgid="6442560571259935130">"रहने दें"</string>
+ <string name="cancel" msgid="6442560571259935130">"अभी नहीं"</string>
<string name="yes" msgid="5362982303337969312">"ठीक है"</string>
- <string name="no" msgid="5141531044935541497">"रहने दें"</string>
+ <string name="no" msgid="5141531044935541497">"अभी नहीं"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ध्यान दें"</string>
<string name="loading" msgid="7933681260296021180">"लोड हो रहे हैं..."</string>
<string name="capital_on" msgid="1544682755514494298">"चालू"</string>
@@ -1335,7 +1335,7 @@
<string name="sms_short_code_details" msgid="5873295990846059400">"इससे आपके मोबाइल खाते पर "<b>"शुल्क लग सकता है"</b>"."</string>
<string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"इससे आपके मोबाइल खाते पर शुल्क लगेगा."</b></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"भेजें"</string>
- <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"रहने दें"</string>
+ <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"अभी नहीं"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"मेरी पसंद को याद रखें"</string>
<string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"आप इसे बाद में सेटिंग &gt; ऐप्स में बदल सकते हैं"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"हमेशा अनुमति दें"</string>
@@ -1545,7 +1545,7 @@
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"वर्ष बढ़ाएं"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"वर्ष कम करें"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
- <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"रहने दें"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"अभी नहीं"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"हटाएं"</string>
<string name="keyboardview_keycode_done" msgid="1992571118466679775">"पूर्ण"</string>
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Mode change"</string>
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"मिनटों का चक्राकार स्लाइडर"</string>
<string name="select_hours" msgid="6043079511766008245">"घंटे चुनें"</string>
<string name="select_minutes" msgid="3974345615920336087">"मिनट चुनें"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"दिनों की माह ग्रिड"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"वर्ष की सूची"</string>
<string name="select_day" msgid="7774759604701773332">"माह और दिन चुनें"</string>
<string name="select_year" msgid="7952052866994196170">"वर्ष चुनें"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> चयनित"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 0f39d7c8977d..7d39eb80d943 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1803,8 +1803,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Kružni klizač minuta"</string>
<string name="select_hours" msgid="6043079511766008245">"Odaberite sate"</string>
<string name="select_minutes" msgid="3974345615920336087">"Odaberite minute"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Mreža dana u mjesecu"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Popis godina"</string>
<string name="select_day" msgid="7774759604701773332">"Odaberite mjesec i dan"</string>
<string name="select_year" msgid="7952052866994196170">"Odaberite godinu"</string>
<string name="item_is_selected" msgid="949687401682476608">"Odabrana je stavka <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index adada446a792..9a9bfb3a9d7c 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Perc kör alakú csúszkája"</string>
<string name="select_hours" msgid="6043079511766008245">"Óra kiválasztása"</string>
<string name="select_minutes" msgid="3974345615920336087">"Perc kiválasztása"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Napok havi leosztásban"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Évek listája"</string>
<string name="select_day" msgid="7774759604701773332">"Válassza ki a hónapot és a napot"</string>
<string name="select_year" msgid="7952052866994196170">"Válassza ki az évet"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> kiválasztva"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 65bacf7cac7b..1b5dfaa5d8ff 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Րոպեների ընտրություն թվատախտակից"</string>
<string name="select_hours" msgid="6043079511766008245">"Ընտրեք ժամը"</string>
<string name="select_minutes" msgid="3974345615920336087">"Ընտրեք րոպեն"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Ամսաթվի ընտրության պատուհան"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Տարիների ցանկ"</string>
<string name="select_day" msgid="7774759604701773332">"Ընտրեք ամիսն ու օրը"</string>
<string name="select_year" msgid="7952052866994196170">"Ընտրեք տարին"</string>
<string name="item_is_selected" msgid="949687401682476608">"Ընտրված է <xliff:g id="ITEM">%1$s</xliff:g> տարրը"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 2f7cb253beda..b0deed2acc94 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Penggeser putar menit"</string>
<string name="select_hours" msgid="6043079511766008245">"Pilih jam"</string>
<string name="select_minutes" msgid="3974345615920336087">"Pilih menit"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Kisi hari pada bulan"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Daftar tahun"</string>
<string name="select_day" msgid="7774759604701773332">"Pilih bulan dan hari"</string>
<string name="select_year" msgid="7952052866994196170">"Pilih tahun"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> dipilih"</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index a926d3d044d9..5538c00df22e 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Valskífa fyrir mínútur"</string>
<string name="select_hours" msgid="6043079511766008245">"Veldu klukkustundir"</string>
<string name="select_minutes" msgid="3974345615920336087">"Veldu mínútur"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Mánaðartafla með dögum"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Áralisti"</string>
<string name="select_day" msgid="7774759604701773332">"Veldu mánuð og dag"</string>
<string name="select_year" msgid="7952052866994196170">"Veldu ár"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> valið"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 74ad5f7fcec8..d8dd2ea70b9a 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Dispositivo di scorrimento circolare per i minuti"</string>
<string name="select_hours" msgid="6043079511766008245">"Seleziona le ore"</string>
<string name="select_minutes" msgid="3974345615920336087">"Seleziona i minuti"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Griglia di giorni per mese"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Elenco degli anni"</string>
<string name="select_day" msgid="7774759604701773332">"Seleziona mese e giorno"</string>
<string name="select_year" msgid="7952052866994196170">"Seleziona anno"</string>
<string name="item_is_selected" msgid="949687401682476608">"Elemento selezionato: <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 1e8d680cb2c5..1839b45155b4 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1812,8 +1812,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"מחוון דקות מעגלי"</string>
<string name="select_hours" msgid="6043079511766008245">"בחר שעות"</string>
<string name="select_minutes" msgid="3974345615920336087">"בחר דקות"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"בחירת ימים בחודש בתצוגת רשת"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"רשימת שנים"</string>
<string name="select_day" msgid="7774759604701773332">"בחר חודש ויום"</string>
<string name="select_year" msgid="7952052866994196170">"בחר שנה"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> נבחר"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 559801807f83..613a2f1a0668 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"円形スライダー(分)"</string>
<string name="select_hours" msgid="6043079511766008245">"時間を選択"</string>
<string name="select_minutes" msgid="3974345615920336087">"分を選択"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"日グリッド(月別)"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"年リスト"</string>
<string name="select_day" msgid="7774759604701773332">"月と日を選択"</string>
<string name="select_year" msgid="7952052866994196170">"年を選択"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g>を選択しました"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index d179c28039ae..befe9e771d4a 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"წუთების წრიული სლაიდერი"</string>
<string name="select_hours" msgid="6043079511766008245">"აირჩიეთ საათები"</string>
<string name="select_minutes" msgid="3974345615920336087">"აირჩიეთ წუთები"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"დღეების ბადე თვეზე"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"წლის სია"</string>
<string name="select_day" msgid="7774759604701773332">"აირჩიეთ თვე და რიცხვი"</string>
<string name="select_year" msgid="7952052866994196170">"აირჩიეთ წელი"</string>
<string name="item_is_selected" msgid="949687401682476608">"არჩეულია <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index caa12d29d761..8b191271089a 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Минут айналымын қозғалтқыш"</string>
<string name="select_hours" msgid="6043079511766008245">"Сағат таңдау"</string>
<string name="select_minutes" msgid="3974345615920336087">"Минут таңдау"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Күндердің айлық торлары"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Жыл тізімі"</string>
<string name="select_day" msgid="7774759604701773332">"Ай мен күнді таңдау"</string>
<string name="select_year" msgid="7952052866994196170">"Жыл таңдау"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> таңдалды"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 3326462055ee..12c9661fa254 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -1796,8 +1796,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"គ្រាប់​រំកិល​រង្វង់​នាទី"</string>
<string name="select_hours" msgid="6043079511766008245">"ជ្រើស​ម៉ោង"</string>
<string name="select_minutes" msgid="3974345615920336087">"ជ្រើស​នាទី"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"ក្រឡា​​​ខែ​នៃ​ថ្ងៃ"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"បញ្ជី​ឆ្នាំ"</string>
<string name="select_day" msgid="7774759604701773332">"ជ្រើស​ខែ និង​ថ្ងៃ"</string>
<string name="select_year" msgid="7952052866994196170">"ជ្រើស​ឆ្នាំ"</string>
<string name="item_is_selected" msgid="949687401682476608">"បាន​ជ្រើស <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index 2bd45d4366d2..2f967ea54a1a 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"ನಿಮಿಷಗಳ ವೃತ್ತಾಕಾರ ಸ್ಲೈಡರ್"</string>
<string name="select_hours" msgid="6043079511766008245">"ಗಂಟೆಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="select_minutes" msgid="3974345615920336087">"ನಿಮಿಷಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"ದಿನಗಳ ತಿಂಗಳಿನ ಗ್ರಿಡ್"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"ವರ್ಷದ ಪಟ್ಟಿ"</string>
<string name="select_day" msgid="7774759604701773332">"ತಿಂಗಳು ಮತ್ತು ದಿನವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="select_year" msgid="7952052866994196170">"ವರ್ಷವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 463f84d5c986..654fffb55f6e 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"분 원형 슬라이더"</string>
<string name="select_hours" msgid="6043079511766008245">"시간 선택"</string>
<string name="select_minutes" msgid="3974345615920336087">"분 선택"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"월별 바둑판식 날짜 표시"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"년"</string>
<string name="select_day" msgid="7774759604701773332">"월/일 선택"</string>
<string name="select_year" msgid="7952052866994196170">"연도 선택"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g>이(가) 선택됨"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index fdfc44231d8b..590524051c02 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -2309,8 +2309,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Мүнөт жебеси"</string>
<string name="select_hours" msgid="6043079511766008245">"Саатты тандаңыз"</string>
<string name="select_minutes" msgid="3974345615920336087">"Мүнөттөрдү тандаңыз"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Айдын күндөрү"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Жыл тизмеги"</string>
<string name="select_day" msgid="7774759604701773332">"Ай жана күндү тандаңыз"</string>
<string name="select_year" msgid="7952052866994196170">"Жылды тандаңыз"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> тандалды"</string>
diff --git a/core/res/res/values-land/dimens_material.xml b/core/res/res/values-land/dimens_material.xml
index 379ccf6a0ed5..202f4a4b73b6 100644
--- a/core/res/res/values-land/dimens_material.xml
+++ b/core/res/res/values-land/dimens_material.xml
@@ -48,4 +48,14 @@
<dimen name="timepicker_text_inset_inner">46dp</dimen>
<dimen name="timepicker_text_size_normal">14sp</dimen>
<dimen name="timepicker_text_size_inner">12sp</dimen>
+
+ <!-- Used by Material-style SimpleMonthView -->
+ <dimen name="date_picker_month_height">40dp</dimen>
+ <dimen name="date_picker_day_of_week_height">14dp</dimen>
+ <dimen name="date_picker_day_height">32dp</dimen>
+ <dimen name="date_picker_day_width">46dp</dimen>
+ <dimen name="date_picker_day_selector_radius">16dp</dimen>
+ <dimen name="day_picker_padding_horizontal">18dp</dimen>
+ <dimen name="day_picker_padding_top">0dp</dimen>
+ <dimen name="day_picker_button_margin_top">-8dp</dimen>
</resources>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index e565c00c7286..c932d2dcf5b1 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"ໂຕໝຸນປັບນາທີ"</string>
<string name="select_hours" msgid="6043079511766008245">"ເລືອກ​ຊົ່ວ​ໂມງ"</string>
<string name="select_minutes" msgid="3974345615920336087">"ເລືອກນາ​ທີ"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"ຕາຕາລາງວັນທີເດືອນປີ"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"ລາຍການປີ"</string>
<string name="select_day" msgid="7774759604701773332">"ເລືອກເດືອນ ແລະ ວັນ"</string>
<string name="select_year" msgid="7952052866994196170">"ເລືອກ​ປີ"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ຖືກເລືອກແລ້ວ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 099593cbb0e2..42b77709282f 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1812,8 +1812,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Apskritas minučių slankiklis"</string>
<string name="select_hours" msgid="6043079511766008245">"Pasirinkite valandas"</string>
<string name="select_minutes" msgid="3974345615920336087">"Pasirinkite minutes"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Mėnesio dienų tinklelis"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Metų sąrašas"</string>
<string name="select_day" msgid="7774759604701773332">"Pasirinkite mėnesį ir dieną"</string>
<string name="select_year" msgid="7952052866994196170">"Pasirinkite metus"</string>
<string name="item_is_selected" msgid="949687401682476608">"Pasirinkta: <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 9ab277296c32..1be0eebb74f2 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1803,8 +1803,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Minūšu apļveida slīdnis"</string>
<string name="select_hours" msgid="6043079511766008245">"Atlasiet stundas."</string>
<string name="select_minutes" msgid="3974345615920336087">"Atlasiet minūtes."</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Režģis ar mēneša dienām"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Gadu saraksts"</string>
<string name="select_day" msgid="7774759604701773332">"Atlasiet mēnesi un dienu."</string>
<string name="select_year" msgid="7952052866994196170">"Atlasiet gadu."</string>
<string name="item_is_selected" msgid="949687401682476608">"Atlasīts: <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-mcc310-mnc260/strings.xml b/core/res/res/values-mcc310-mnc260/strings.xml
index 5cadc2ae0df6..75b1b5376184 100644
--- a/core/res/res/values-mcc310-mnc260/strings.xml
+++ b/core/res/res/values-mcc310-mnc260/strings.xml
@@ -29,4 +29,6 @@
<string-array name="wfcOperatorErrorMessages">
<item>Wi-Fi Calling isn\&apos;t available. Contact your carrier to enable Wi-Fi Calling.</item>
</string-array>
+ <!-- Template for showing cellular network operator name while WFC is active -->
+ <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
</resources>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 2080d50eb16d..387238ee78ab 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -1796,8 +1796,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Приказ на минути во кружно движење"</string>
<string name="select_hours" msgid="6043079511766008245">"Избери часови"</string>
<string name="select_minutes" msgid="3974345615920336087">"Избери минути"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Рамка на месец со денови"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Список по години"</string>
<string name="select_day" msgid="7774759604701773332">"Избери месец и ден"</string>
<string name="select_year" msgid="7952052866994196170">"Избери година"</string>
<string name="item_is_selected" msgid="949687401682476608">"Избрано <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 2ae1177a07b9..68fd8690ef0a 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"ചാക്രികമായി മിനിറ്റുകൾ ദൃശ്യമാകുന്ന സ്ലൈഡർ"</string>
<string name="select_hours" msgid="6043079511766008245">"മണിക്കൂർ തിരഞ്ഞെടുക്കുക"</string>
<string name="select_minutes" msgid="3974345615920336087">"മിനിറ്റ് തിരഞ്ഞെടുക്കുക"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"മാസപ്രകാരമുള്ള ദിവസ ഗ്രിഡ്"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"വർഷങ്ങളുടെ ലിസ്റ്റ്"</string>
<string name="select_day" msgid="7774759604701773332">"മാസവും ദിവസവും തിരഞ്ഞെടുക്കുക"</string>
<string name="select_year" msgid="7952052866994196170">"വർഷം തിരഞ്ഞെടുക്കുക"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> തിരഞ്ഞെടുത്തു"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 4a8b5b99413d..07fb9a937815 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Минут гүйлгэгч"</string>
<string name="select_hours" msgid="6043079511766008245">"Цаг сонгоно уу"</string>
<string name="select_minutes" msgid="3974345615920336087">"Минут сонгоно уу"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Өдрүүдийг сараар"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Жилийн жагсаалт"</string>
<string name="select_day" msgid="7774759604701773332">"Сар болон өдрийг сонгоно уу"</string>
<string name="select_year" msgid="7952052866994196170">"Жилийг сонгоно уу"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> сонгогдсон"</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 3fc5663eed0f..737154e0c744 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"मिनिटे परिपत्रक स्लायडर"</string>
<string name="select_hours" msgid="6043079511766008245">"तास निवडा"</string>
<string name="select_minutes" msgid="3974345615920336087">"मिनिटे निवडा"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"दिवसांची महिना ग्रिड"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"वर्ष सूची"</string>
<string name="select_day" msgid="7774759604701773332">"महिना आणि दिवस निवडा"</string>
<string name="select_year" msgid="7952052866994196170">"वर्ष निवडा"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> निवडले"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index d849680669c6..10d5d5fa86cc 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Penggelangsar bulatan minit"</string>
<string name="select_hours" msgid="6043079511766008245">"Pilih jam"</string>
<string name="select_minutes" msgid="3974345615920336087">"Pilih minit"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Grid hari bulanan"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Senarai tahun"</string>
<string name="select_day" msgid="7774759604701773332">"Pilih bulan dan hari"</string>
<string name="select_year" msgid="7952052866994196170">"Pilih tahun"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> dipilih"</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 36a6cdefc43d..f97c576dbc0c 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"မိနစ်လှည့်သော ရွေ့လျားတန်"</string>
<string name="select_hours" msgid="6043079511766008245">"နာရီများ ရွေးပါ"</string>
<string name="select_minutes" msgid="3974345615920336087">"မိနစ်များ ရွေးပါ"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"လအလိုက် ရွေးနိုင်သော ရက်များ"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"ခုနှစ် အစဉ်"</string>
<string name="select_day" msgid="7774759604701773332">"လ နှင့် ရက် ရွေးပါ"</string>
<string name="select_year" msgid="7952052866994196170">"ခုနှစ်ကို ရွေးပါ"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ခုရွေးချယ်ထားပြီး"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 022bb160933e..3b4594078e7c 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Sirkulær glidebryter for minutter"</string>
<string name="select_hours" msgid="6043079511766008245">"Angi timer"</string>
<string name="select_minutes" msgid="3974345615920336087">"Angi minutter"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Månedsrutenett med dager"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Årsliste"</string>
<string name="select_day" msgid="7774759604701773332">"Velg måneden og dagen"</string>
<string name="select_year" msgid="7952052866994196170">"Velg året"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> er valgt"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 54fe0e50df89..907047f174b7 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -1800,8 +1800,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"मिनेट गोलाकार स्लाइडर"</string>
<string name="select_hours" msgid="6043079511766008245">"घण्टा चयन गर्नुहोस्"</string>
<string name="select_minutes" msgid="3974345615920336087">"मिनेट चयन गर्नुहोस्"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"दिनहरुको महिना ग्रिड"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"वर्ष सूची"</string>
<string name="select_day" msgid="7774759604701773332">"महिना र दिन चयन गर्नुहोस्"</string>
<string name="select_year" msgid="7952052866994196170">"वर्ष चयन गर्नुहोस्"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> चयन गरियो"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 3318bff373ca..d6c02f57ac29 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Ronde schuifregelaar voor minuten"</string>
<string name="select_hours" msgid="6043079511766008245">"Uren selecteren"</string>
<string name="select_minutes" msgid="3974345615920336087">"Minuten selecteren"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Maandraster van dagen"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Jaarlijst"</string>
<string name="select_day" msgid="7774759604701773332">"Maand en dag selecteren"</string>
<string name="select_year" msgid="7952052866994196170">"Jaar selecteren"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> geselecteerd"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 4e56e90a0b92..8e310536c10d 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1812,8 +1812,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Kołowy suwak minut"</string>
<string name="select_hours" msgid="6043079511766008245">"Wybierz godziny"</string>
<string name="select_minutes" msgid="3974345615920336087">"Wybierz minuty"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Siatka miesięczna z dniami"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Lista lat"</string>
<string name="select_day" msgid="7774759604701773332">"Wybierz miesiąc i dzień"</string>
<string name="select_year" msgid="7952052866994196170">"Wybierz rok"</string>
<string name="item_is_selected" msgid="949687401682476608">"Wybrałeś <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 1ddef71df9a9..7a0985c809f7 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Controlo de deslize circular dos minutos"</string>
<string name="select_hours" msgid="6043079511766008245">"Selecionar horas"</string>
<string name="select_minutes" msgid="3974345615920336087">"Selecionar minutos"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Grelha de dias do mês"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Lista de anos"</string>
<string name="select_day" msgid="7774759604701773332">"Selecionar mês e dia"</string>
<string name="select_year" msgid="7952052866994196170">"Selecionar ano"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selecionado"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 35ae34520783..8f86b40b2e36 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Controle deslizante circular dos minutos"</string>
<string name="select_hours" msgid="6043079511766008245">"Selecione as horas"</string>
<string name="select_minutes" msgid="3974345615920336087">"Selecione os minutos"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Grade mensal de dias"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Lista de anos"</string>
<string name="select_day" msgid="7774759604701773332">"Selecione o mês e o dia"</string>
<string name="select_year" msgid="7952052866994196170">"Selecione o ano"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selecionado"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 360b966b4663..624694164af4 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1803,8 +1803,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Selector circular pentru minute"</string>
<string name="select_hours" msgid="6043079511766008245">"Selectați orele"</string>
<string name="select_minutes" msgid="3974345615920336087">"Selectați minutele"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Afișare pe luni"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Listă de ani"</string>
<string name="select_day" msgid="7774759604701773332">"Selectați luna și ziua"</string>
<string name="select_year" msgid="7952052866994196170">"Selectați anul"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selectat"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 5aa3b39107e0..21cc5b72602e 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1812,8 +1812,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Выбор минут на циферблате"</string>
<string name="select_hours" msgid="6043079511766008245">"Выберите часы"</string>
<string name="select_minutes" msgid="3974345615920336087">"Выберите минуты"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Окно выбора даты"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Меню выбора года"</string>
<string name="select_day" msgid="7774759604701773332">"Выберите месяц и число"</string>
<string name="select_year" msgid="7952052866994196170">"Выберите год"</string>
<string name="item_is_selected" msgid="949687401682476608">"Выбран элемент <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 8a83db95471c..1b9b3178280d 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -1796,8 +1796,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"මිනිත්තු කවාකාර සර්පනය"</string>
<string name="select_hours" msgid="6043079511766008245">"පැය තෝරන්න"</string>
<string name="select_minutes" msgid="3974345615920336087">"මිනිත්තු තෝරන්න"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"දින ජාලයකින් මාසය"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"වසර ලැයිස්තුව"</string>
<string name="select_day" msgid="7774759604701773332">"මාසය සහ දිනය තෝරන්න"</string>
<string name="select_year" msgid="7952052866994196170">"වසර තෝරන්න"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> තෝරාගෙන ඇත"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 676ffe24b0dd..c46fc9321c29 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1812,8 +1812,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Kruhový posúvač minút"</string>
<string name="select_hours" msgid="6043079511766008245">"Vyberte hodiny"</string>
<string name="select_minutes" msgid="3974345615920336087">"Vyberte minúty"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Tabuľka dní v mesiaci"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Zoznam rokov"</string>
<string name="select_day" msgid="7774759604701773332">"Vyberte mesiac a deň"</string>
<string name="select_year" msgid="7952052866994196170">"Vyberte rok"</string>
<string name="item_is_selected" msgid="949687401682476608">"Bola vybratá položka <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 07d4bb735880..a42b022f414a 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1812,8 +1812,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Okrogli drsnik za minute"</string>
<string name="select_hours" msgid="6043079511766008245">"Izberite ure"</string>
<string name="select_minutes" msgid="3974345615920336087">"Izberite minute"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Mesečna mreža dni"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Seznam let"</string>
<string name="select_day" msgid="7774759604701773332">"Izberite mesec in dan"</string>
<string name="select_year" msgid="7952052866994196170">"Izberite leto"</string>
<string name="item_is_selected" msgid="949687401682476608">"Izbrano: <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 54da9a4cf8d0..7e2f18e21b00 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1803,8 +1803,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Кружни клизач за минуте"</string>
<string name="select_hours" msgid="6043079511766008245">"Изаберите сате"</string>
<string name="select_minutes" msgid="3974345615920336087">"Изаберите минуте"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Приказ дана у месецу у виду мреже"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Листа година"</string>
<string name="select_day" msgid="7774759604701773332">"Изаберите месец и дан"</string>
<string name="select_year" msgid="7952052866994196170">"Изаберите годину"</string>
<string name="item_is_selected" msgid="949687401682476608">"Изабрали сте <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index dd8a8839af1b..326842ce1164 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Cirkelreglage för minuter"</string>
<string name="select_hours" msgid="6043079511766008245">"Välj timmar"</string>
<string name="select_minutes" msgid="3974345615920336087">"Välj minuter"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Rutnät för månad"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Lista över år"</string>
<string name="select_day" msgid="7774759604701773332">"Välj månad och dag"</string>
<string name="select_year" msgid="7952052866994196170">"Välj år"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> har markerats"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index cfa56def1a01..d681855af35a 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Kitelezi cha mviringo wa dakika"</string>
<string name="select_hours" msgid="6043079511766008245">"Chagua saa"</string>
<string name="select_minutes" msgid="3974345615920336087">"Chagua dakika"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Gridi ya mwezi ya siku"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Orodha ya miaka"</string>
<string name="select_day" msgid="7774759604701773332">"Chagua mwezi na siku"</string>
<string name="select_year" msgid="7952052866994196170">"Chagua mwaka"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> kimechaguliwa"</string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 0e5bf3c43e9b..086fe6aa7ed1 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"நிமிடங்களுக்கான வட்டவடிவ ஸ்லைடர்"</string>
<string name="select_hours" msgid="6043079511766008245">"மணிநேரத்தைத் தேர்ந்தெடுக்கவும்"</string>
<string name="select_minutes" msgid="3974345615920336087">"நிமிடத்தைத் தேர்ந்தெடுக்கவும்"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"நாட்களின் மாதக் கட்டம்"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"ஆண்டு பட்டியல்"</string>
<string name="select_day" msgid="7774759604701773332">"மாதம் மற்றும் தேதியைத் தேர்ந்தெடுக்கவும்"</string>
<string name="select_year" msgid="7952052866994196170">"ஆண்டைத் தேர்ந்தெடுக்கவும்"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> தேர்ந்தெடுக்கப்பட்டது"</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 4684adf37371..5f59597c9a91 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"నిమిషాల వృత్తాకార స్లయిడర్"</string>
<string name="select_hours" msgid="6043079511766008245">"గంటలను ఎంచుకోండి"</string>
<string name="select_minutes" msgid="3974345615920336087">"నిమిషాలను ఎంచుకోండి"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"రోజుల యొక్క నెల గ్రిడ్"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"సంవత్సర జాబితా"</string>
<string name="select_day" msgid="7774759604701773332">"నెల మరియు రోజును ఎంచుకోండి"</string>
<string name="select_year" msgid="7952052866994196170">"సంవత్సరాన్ని ఎంచుకోండి"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ఎంచుకోబడింది"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 39be8c750879..df4ff52bd52c 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"ตัวเลื่อนหมุนระบุนาที"</string>
<string name="select_hours" msgid="6043079511766008245">"เลือกชั่วโมง"</string>
<string name="select_minutes" msgid="3974345615920336087">"เลือกนาที"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"ตารางเดือนของวัน"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"รายการปี"</string>
<string name="select_day" msgid="7774759604701773332">"เลือกเดือนและวัน"</string>
<string name="select_year" msgid="7952052866994196170">"เลือกปี"</string>
<string name="item_is_selected" msgid="949687401682476608">"เลือก <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 95a148065ab7..41480ed7f355 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Pabilog na slider ng mga minuto"</string>
<string name="select_hours" msgid="6043079511766008245">"Pumili ng mga oras"</string>
<string name="select_minutes" msgid="3974345615920336087">"Pumili ng mga minuto"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Grid ng mga araw ayon sa buwan"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Listahan ng taon"</string>
<string name="select_day" msgid="7774759604701773332">"Pumili ng buwan at araw"</string>
<string name="select_year" msgid="7952052866994196170">"Pumili ng taon"</string>
<string name="item_is_selected" msgid="949687401682476608">"Napili ang <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 373ef667f391..f254b5c1354f 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Dakika kaydırma çemberi"</string>
<string name="select_hours" msgid="6043079511766008245">"Saati seçin"</string>
<string name="select_minutes" msgid="3974345615920336087">"Dakikayı seçin"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Ayın günleri tablosu"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Yıl listesi"</string>
<string name="select_day" msgid="7774759604701773332">"Ayı ve günü seçin"</string>
<string name="select_year" msgid="7952052866994196170">"Yılı seçin"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> seçildi"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index c3cfe6dfed51..78beaf554c67 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1812,8 +1812,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Вибір хвилин на циферблаті"</string>
<string name="select_hours" msgid="6043079511766008245">"Виберіть години"</string>
<string name="select_minutes" msgid="3974345615920336087">"Виберіть хвилини"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Вікно вибору дати"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Меню вибору року"</string>
<string name="select_day" msgid="7774759604701773332">"Виберіть місяць і день"</string>
<string name="select_year" msgid="7952052866994196170">"Виберіть рік"</string>
<string name="item_is_selected" msgid="949687401682476608">"Вибрано: <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index f315112ed7d3..4f604aae1e9a 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"منٹس سرکلر سلائیڈر"</string>
<string name="select_hours" msgid="6043079511766008245">"گھنٹے منتخب کریں"</string>
<string name="select_minutes" msgid="3974345615920336087">"منٹ منتخب کریں"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"دنوں کا ماہ کا گرڈ"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"سال کی فہرست"</string>
<string name="select_day" msgid="7774759604701773332">"ماہ اور دن منتخب کریں"</string>
<string name="select_year" msgid="7952052866994196170">"سال منتخب کریں"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> کو منتخب کیا گیا"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 78bad617f486..dc90c2508ca9 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Doiradan daqiqani tanlang"</string>
<string name="select_hours" msgid="6043079511766008245">"Soatlarni tanlash"</string>
<string name="select_minutes" msgid="3974345615920336087">"Daqiqalarni tanlash"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Oy kunlari (jadval ko‘rinishida)"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Yil ro‘yxati"</string>
<string name="select_day" msgid="7774759604701773332">"Oy va kunni tanlash"</string>
<string name="select_year" msgid="7952052866994196170">"Yilni tanlash"</string>
<string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> tanlandi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index a2ebfd479cfa..5031e85fa04f 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Thanh trượt phút hình tròn"</string>
<string name="select_hours" msgid="6043079511766008245">"Chọn giờ"</string>
<string name="select_minutes" msgid="3974345615920336087">"Chọn phút"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Lưới ngày theo tháng"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Danh sách năm"</string>
<string name="select_day" msgid="7774759604701773332">"Chọn tháng và ngày"</string>
<string name="select_year" msgid="7952052866994196170">"Chọn năm"</string>
<string name="item_is_selected" msgid="949687401682476608">"Đã chọn <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 269afba2d463..d8631a6ac716 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -203,8 +203,7 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"已开启飞行模式"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"未开启飞行模式"</string>
<string name="global_action_settings" msgid="1756531602592545966">"设置"</string>
- <!-- no translation found for global_action_assist (3892832961594295030) -->
- <skip />
+ <string name="global_action_assist" msgid="3892832961594295030">"助理"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"语音助理"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"立即锁定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
@@ -1795,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"分钟转盘"</string>
<string name="select_hours" msgid="6043079511766008245">"选择小时"</string>
<string name="select_minutes" msgid="3974345615920336087">"选择分钟"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"按月份划分的日期网格"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"年份列表"</string>
<string name="select_day" msgid="7774759604701773332">"选择月份和日期"</string>
<string name="select_year" msgid="7952052866994196170">"选择年份"</string>
<string name="item_is_selected" msgid="949687401682476608">"已选择<xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index a62cf117f3e1..9b9e945e3f92 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"分鐘環形滑桿"</string>
<string name="select_hours" msgid="6043079511766008245">"選取小時"</string>
<string name="select_minutes" msgid="3974345615920336087">"選取分鐘"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"顯示每日的月曆方格"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"年份清單"</string>
<string name="select_day" msgid="7774759604701773332">"選取月份和日期"</string>
<string name="select_year" msgid="7952052866994196170">"選取年份"</string>
<string name="item_is_selected" msgid="949687401682476608">"已選取<xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 5d1821a46b36..323ccc390e8c 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"分鐘數環狀滑桿"</string>
<string name="select_hours" msgid="6043079511766008245">"選取小時數"</string>
<string name="select_minutes" msgid="3974345615920336087">"選取分鐘數"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"日期網格 (按月顯示)"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"年份清單"</string>
<string name="select_day" msgid="7774759604701773332">"選取月份和日期"</string>
<string name="select_year" msgid="7952052866994196170">"選取年份"</string>
<string name="item_is_selected" msgid="949687401682476608">"已選取 <xliff:g id="ITEM">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 4c3a40095a2a..ec68b1708716 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1794,8 +1794,6 @@
<string name="minute_picker_description" msgid="8606010966873791190">"Amaminithi weslayidi esiyindingilizi"</string>
<string name="select_hours" msgid="6043079511766008245">"Khetha amahora"</string>
<string name="select_minutes" msgid="3974345615920336087">"Khetha amaminithi"</string>
- <string name="day_picker_description" msgid="8990847925961297968">"Igridi yenyanga yezinsuku"</string>
- <string name="year_picker_description" msgid="5524331207436052403">"Uhlu lonyaka"</string>
<string name="select_day" msgid="7774759604701773332">"Khetha inyanga nosuku"</string>
<string name="select_year" msgid="7952052866994196170">"Khetha unyaka"</string>
<string name="item_is_selected" msgid="949687401682476608">"I-<xliff:g id="ITEM">%1$s</xliff:g> ekhethiwe"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 15797ddb81f9..79a6bde84468 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1036,7 +1036,7 @@
<attr name="colorSwitchThumbNormal" format="color" />
<!-- @hide The background used by framework controls. -->
- <attr name="controlBackground" format="color" />
+ <attr name="controlBackground" format="reference" />
<!-- The color applied to the edge effect on scrolling containers. -->
<attr name="colorEdgeEffect" format="color" />
@@ -2633,6 +2633,70 @@
<enum name="paddedBounds" value="3" />
</attr>
+ <!-- Defines the drawable to draw over the content. This can be used as an overlay.
+ The foreground drawable participates in the padding of the content if the gravity
+ is set to fill. -->
+ <attr name="foreground" format="reference|color" />
+ <!-- Defines the gravity to apply to the foreground drawable. The gravity defaults
+ to fill. -->
+ <attr name="foregroundGravity">
+ <!-- Push object to the top of its container, not changing its size. -->
+ <flag name="top" value="0x30" />
+ <!-- Push object to the bottom of its container, not changing its size. -->
+ <flag name="bottom" value="0x50" />
+ <!-- Push object to the left of its container, not changing its size. -->
+ <flag name="left" value="0x03" />
+ <!-- Push object to the right of its container, not changing its size. -->
+ <flag name="right" value="0x05" />
+ <!-- Place object in the vertical center of its container, not changing its size. -->
+ <flag name="center_vertical" value="0x10" />
+ <!-- Grow the vertical size of the object if needed so it completely fills its container. -->
+ <flag name="fill_vertical" value="0x70" />
+ <!-- Place object in the horizontal center of its container, not changing its size. -->
+ <flag name="center_horizontal" value="0x01" />
+ <!-- Grow the horizontal size of the object if needed so it completely fills its container. -->
+ <flag name="fill_horizontal" value="0x07" />
+ <!-- Place the object in the center of its container in both the vertical and horizontal axis, not changing its size. -->
+ <flag name="center" value="0x11" />
+ <!-- Grow the horizontal and vertical size of the object if needed so it completely fills its container. -->
+ <flag name="fill" value="0x77" />
+ <!-- Additional option that can be set to have the top and/or bottom edges of
+ the child clipped to its container's bounds.
+ The clip will be based on the vertical gravity: a top gravity will clip the bottom
+ edge, a bottom gravity will clip the top edge, and neither will clip both edges. -->
+ <flag name="clip_vertical" value="0x80" />
+ <!-- Additional option that can be set to have the left and/or right edges of
+ the child clipped to its container's bounds.
+ The clip will be based on the horizontal gravity: a left gravity will clip the right
+ edge, a right gravity will clip the left edge, and neither will clip both edges. -->
+ <flag name="clip_horizontal" value="0x08" />
+ </attr>
+ <!-- Defines whether the foreground drawable should be drawn inside the padding.
+ This property is turned on by default. -->
+ <attr name="foregroundInsidePadding" format="boolean" />
+ <!-- Tint to apply to the foreground. -->
+ <attr name="foregroundTint" format="color" />
+ <!-- Blending mode used to apply the foreground tint. -->
+ <attr name="foregroundTintMode">
+ <!-- The tint is drawn on top of the drawable.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the drawable with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="15" />
+ <!-- Combines the tint and drawable color and alpha channels, clamping the
+ result to valid color values. Saturate(S + D) -->
+ <enum name="add" value="16" />
+ </attr>
+
</declare-styleable>
<!-- Attributes that can be assigned to a tag for a particular View. -->
@@ -3366,72 +3430,9 @@
<attr name="padding" />
</declare-styleable>
<declare-styleable name="FrameLayout">
- <!-- Defines the drawable to draw over the content. This can be used as an overlay.
- The foreground drawable participates in the padding of the content if the gravity
- is set to fill. -->
- <attr name="foreground" format="reference|color" />
- <!-- Defines the gravity to apply to the foreground drawable. The gravity defaults
- to fill. -->
- <attr name="foregroundGravity">
- <!-- Push object to the top of its container, not changing its size. -->
- <flag name="top" value="0x30" />
- <!-- Push object to the bottom of its container, not changing its size. -->
- <flag name="bottom" value="0x50" />
- <!-- Push object to the left of its container, not changing its size. -->
- <flag name="left" value="0x03" />
- <!-- Push object to the right of its container, not changing its size. -->
- <flag name="right" value="0x05" />
- <!-- Place object in the vertical center of its container, not changing its size. -->
- <flag name="center_vertical" value="0x10" />
- <!-- Grow the vertical size of the object if needed so it completely fills its container. -->
- <flag name="fill_vertical" value="0x70" />
- <!-- Place object in the horizontal center of its container, not changing its size. -->
- <flag name="center_horizontal" value="0x01" />
- <!-- Grow the horizontal size of the object if needed so it completely fills its container. -->
- <flag name="fill_horizontal" value="0x07" />
- <!-- Place the object in the center of its container in both the vertical and horizontal axis, not changing its size. -->
- <flag name="center" value="0x11" />
- <!-- Grow the horizontal and vertical size of the object if needed so it completely fills its container. -->
- <flag name="fill" value="0x77" />
- <!-- Additional option that can be set to have the top and/or bottom edges of
- the child clipped to its container's bounds.
- The clip will be based on the vertical gravity: a top gravity will clip the bottom
- edge, a bottom gravity will clip the top edge, and neither will clip both edges. -->
- <flag name="clip_vertical" value="0x80" />
- <!-- Additional option that can be set to have the left and/or right edges of
- the child clipped to its container's bounds.
- The clip will be based on the horizontal gravity: a left gravity will clip the right
- edge, a right gravity will clip the left edge, and neither will clip both edges. -->
- <flag name="clip_horizontal" value="0x08" />
- </attr>
- <!-- Defines whether the foreground drawable should be drawn inside the padding.
- This property is turned on by default. -->
- <attr name="foregroundInsidePadding" format="boolean" />
<!-- Determines whether to measure all children or just those in
the VISIBLE or INVISIBLE state when measuring. Defaults to false. -->
<attr name="measureAllChildren" format="boolean" />
- <!-- Tint to apply to the foreground. -->
- <attr name="foregroundTint" format="color" />
- <!-- Blending mode used to apply the foreground tint. -->
- <attr name="foregroundTintMode">
- <!-- The tint is drawn on top of the drawable.
- [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
- <enum name="src_over" value="3" />
- <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
- color channels are thrown out. [Sa * Da, Sc * Da] -->
- <enum name="src_in" value="5" />
- <!-- The tint is drawn above the drawable, but with the drawable’s alpha
- channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
- <enum name="src_atop" value="9" />
- <!-- Multiplies the color and alpha channels of the drawable with those of
- the tint. [Sa * Da, Sc * Dc] -->
- <enum name="multiply" value="14" />
- <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
- <enum name="screen" value="15" />
- <!-- Combines the tint and drawable color and alpha channels, clamping the
- result to valid color values. Saturate(S + D) -->
- <enum name="add" value="16" />
- </attr>
</declare-styleable>
<declare-styleable name="ExpandableListView">
<!-- Indicator shown beside the group View. This can be a stateful Drawable. -->
@@ -4443,46 +4444,42 @@
</declare-styleable>
<declare-styleable name="DatePicker">
- <!-- The first year (inclusive), for example "1940".
- {@deprecated Use minDate instead.} -->
+ <!-- The first year (inclusive), for example "1940". {@deprecated Use minDate instead.} -->
<attr name="startYear" format="integer" />
- <!-- The last year (inclusive), for example "2010".
- {@deprecated Use maxDate instead.} -->
+ <!-- The last year (inclusive), for example "2010". {@deprecated Use maxDate instead.} -->
<attr name="endYear" format="integer" />
- <!-- Whether the spinners are shown. -->
- <attr name="spinnersShown" format="boolean" />
- <!-- Whether the calendar view is shown. -->
- <attr name="calendarViewShown" format="boolean" />
+
+ <!-- The first day of week according to {@link java.util.Calendar}. -->
+ <attr name="firstDayOfWeek" />
<!-- The minimal date shown by this calendar view in mm/dd/yyyy format. -->
<attr name="minDate" format="string" />
<!-- The maximal date shown by this calendar view in mm/dd/yyyy format. -->
<attr name="maxDate" format="string" />
- <!-- The first day of week according to {@link java.util.Calendar}. -->
- <attr name="firstDayOfWeek" />
+
+ <!-- Whether the spinners are shown. Only valid for "spinner" mode. -->
+ <attr name="spinnersShown" format="boolean" />
+ <!-- Whether the calendar view is shown. Only valid for "spinner" mode. -->
+ <attr name="calendarViewShown" format="boolean" />
+
<!-- @hide The layout of the date picker. -->
<attr name="internalLayout" format="reference" />
<!-- @hide The layout of the legacy DatePicker. -->
<attr name="legacyLayout" />
- <!-- The background color for the date selector 's day of week. -->
- <attr name="dayOfWeekBackground" format="color|reference" />
- <!-- The text color for the date selector's day of week. -->
- <attr name="dayOfWeekTextAppearance" format="reference" />
- <!-- The month's text appearance in the date selector. -->
- <attr name="headerMonthTextAppearance" format="reference" />
- <!-- The day of month's text appearance in the date selector. -->
- <attr name="headerDayOfMonthTextAppearance" format="reference" />
- <!-- The year's text appearance in the date selector. -->
- <attr name="headerYearTextAppearance" format="reference" />
- <!-- The background for the date selector. -->
+
+ <!-- The text color for the selected date header text, ex. "2014" or
+ "Tue, Mar 18". This should be a color state list where the
+ activated state will be used when the year picker or day picker is
+ active.-->
+ <attr name="headerTextColor" format="color" />
+ <!-- The background for the selected date header. -->
<attr name="headerBackground" />
+
<!-- The list year's text appearance in the list. -->
<attr name="yearListItemTextAppearance" format="reference" />
- <!-- The list year's selected circle color in the list. -->
- <attr name="yearListSelectorColor" format="color" />
+ <!-- @hide The list year's text appearance in the list when activated. -->
+ <attr name="yearListItemActivatedTextAppearance" format="reference" />
<!-- The text color list of the calendar. -->
<attr name="calendarTextColor" format="color" />
- <!-- @hide The activated background color for the calendar. -->
- <attr name="calendarDayBackgroundColor" format="color" />
<!-- Defines the look of the widget. Prior to the L release, the only choice was
spinner. As of L, with the Material theme selected, the default layout is calendar,
but this attribute can be used to force spinner to be used instead. -->
@@ -4492,6 +4489,19 @@
<!-- Date picker with calendar to select the date. -->
<enum name="calendar" value="2" />
</attr>
+
+ <!-- @deprecated The text appearance for the month (ex. May) in the selected date header. -->
+ <attr name="headerMonthTextAppearance" format="reference" />
+ <!-- @deprecated The text appearance for the day of month (ex. 28) in the selected date header. -->
+ <attr name="headerDayOfMonthTextAppearance" format="reference" />
+ <!-- The text appearance for the year (ex. 2014) in the selected date header. -->
+ <attr name="headerYearTextAppearance" format="reference" />
+ <!-- @deprecated The background color for the header's day of week. -->
+ <attr name="dayOfWeekBackground" format="color" />
+ <!-- @deprecated The text color for the header's day of week. -->
+ <attr name="dayOfWeekTextAppearance" format="reference" />
+ <!-- @deprecated The list year's selected circle color in the list. -->
+ <attr name="yearListSelectorColor" format="color" />
</declare-styleable>
<declare-styleable name="TwoLineListItem">
@@ -4709,35 +4719,42 @@
<declare-styleable name="CalendarView">
<!-- The first day of week according to {@link java.util.Calendar}. -->
<attr name="firstDayOfWeek" format="integer" />
- <!-- Whether do show week numbers. -->
- <attr name="showWeekNumber" format="boolean" />
<!-- The minimal date shown by this calendar view in mm/dd/yyyy format. -->
<attr name="minDate" />
<!-- The minimal date shown by this calendar view in mm/dd/yyyy format. -->
<attr name="maxDate" />
- <!-- The number of weeks to be shown. -->
+ <!-- The text appearance for the month and year in the calendar header. -->
+ <attr name="monthTextAppearance" format="reference" />
+ <!-- The text appearance for the week day abbreviation in the calendar header. -->
+ <attr name="weekDayTextAppearance" format="reference" />
+ <!-- The text appearance for the day numbers in the calendar grid. -->
+ <attr name="dateTextAppearance" format="reference" />
+ <!-- @hide The background color used for the day selection indicator. -->
+ <attr name="daySelectorColor" format="color" />
+ <!-- @hide The background color used for the day highlight indicator. -->
+ <attr name="dayHighlightColor" format="color" />
+ <!-- @hide Which style of calendar delegate to use. -->
+ <attr name="calendarViewMode">
+ <enum name="holo" value="0" />
+ <enum name="material" value="1" />
+ </attr>
+
+ <!-- @deprecated Whether do show week numbers. -->
+ <attr name="showWeekNumber" format="boolean" />
+ <!-- @deprecated The number of weeks to be shown. -->
<attr name="shownWeekCount" format="integer"/>
- <!-- The background color for the selected week. -->
+ <!-- @deprecated The background color for the selected week. -->
<attr name="selectedWeekBackgroundColor" format="color|reference" />
- <!-- The color for the dates of the focused month. -->
+ <!-- @deprecated The color for the dates of the focused month. -->
<attr name="focusedMonthDateColor" format="color|reference" />
- <!-- The color for the dates of an unfocused month. -->
+ <!-- @deprecated The color for the dates of an unfocused month. -->
<attr name="unfocusedMonthDateColor" format="color|reference" />
- <!-- The color for the week numbers. -->
+ <!-- @deprecated The color for the week numbers. -->
<attr name="weekNumberColor" format="color|reference" />
- <!-- The color for the separator line between weeks. -->
+ <!-- @deprecated The color for the separator line between weeks. -->
<attr name="weekSeparatorLineColor" format="color|reference" />
- <!-- Drawable for the vertical bar shown at the beginning and at the end of the selected date. -->
+ <!-- @deprecated Drawable for the vertical bar shown at the beginning and at the end of the selected date. -->
<attr name="selectedDateVerticalBar" format="reference" />
- <!-- The text appearance for the week day abbreviation of the calendar header. -->
- <attr name="weekDayTextAppearance" format="reference" />
- <!-- The text appearance for the calendar dates. -->
- <attr name="dateTextAppearance" format="reference" />
- <!-- The number of weeks to be shown. -->
- <attr name="calendarViewMode">
- <enum name="holo" value="0" />
- <enum name="material" value="1" />
- </attr>
</declare-styleable>
<declare-styleable name="NumberPicker">
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index c0b2cbef282f..283c23738073 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -389,13 +389,12 @@
with the same {@link android.R.attr#taskAffinity} as it has. -->
<attr name="allowTaskReparenting" format="boolean" />
- <!-- Declare that this application may use cleartext traffic (e.g., HTTP rather than HTTPS;
- WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP without STARTTLS or TLS).
- Defaults to true. If set to false {@code false}, the app declares that it does not
- intend to use cleartext network traffic, in which case platform components (e.g.,
- HTTP stacks, {@code WebView}, {@code MediaPlayer}) will refuse app's requests to use
- cleartext traffic. Third-party libraries are encouraged to honor this flag as well.
- @hide -->
+ <!-- Declare that this application may use cleartext traffic, such as HTTP rather than HTTPS;
+ WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP without STARTTLS or TLS.
+ Defaults to true. If set to false {@code false}, the application declares that it does not
+ intend to use cleartext network traffic, in which case platform components (e.g. HTTP
+ stacks, {@code WebView}, {@code MediaPlayer}) will refuse applications's requests to use
+ cleartext traffic. Third-party libraries are encouraged to honor this flag as well. -->
<attr name="usesCleartextTraffic" format="boolean" />
<!-- Declare that code from this application will need to be loaded into other
@@ -1039,6 +1038,10 @@
activity. -->
<attr name="resizeableActivity" format="boolean" />
+ <!-- When set installer will extract native libraries. If set to false
+ libraries in the apk must be stored and page-aligned. -->
+ <attr name="extractNativeLibs" format="boolean"/>
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -1160,17 +1163,17 @@
"com.google". -->
<attr name="requiredAccountType" format="string"/>
<attr name="isGame" />
- <!-- Declare that this application may use cleartext traffic (e.g., HTTP rather than HTTPS;
- WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP without STARTTLS or TLS).
- Defaults to true. If set to false {@code false}, the app declares that it does not
- intend to use cleartext network traffic, in which case platform components (e.g.,
- HTTP stacks, {@code WebView}, {@code MediaPlayer}) will refuse app's requests to use
- cleartext traffic. Third-party libraries are encouraged to honor this flag as well.
- @hide -->
+ <!-- Declare that this application may use cleartext traffic, such as HTTP rather than
+ HTTPS; WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP without STARTTLS or
+ TLS). Defaults to true. If set to false {@code false}, the application declares that it
+ does not intend to use cleartext network traffic, in which case platform components
+ (e.g. HTTP stacks, {@code WebView}, {@code MediaPlayer}) will refuse applications's
+ requests to use cleartext traffic. Third-party libraries are encouraged to honor this
+ flag as well. -->
<attr name="usesCleartextTraffic" />
<attr name="multiArch" />
+ <attr name="extractNativeLibs" />
</declare-styleable>
-
<!-- The <code>permission</code> tag declares a security permission that can be
used to control access from other packages to specific components or
features in your package (or other packages). See the
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index da68c920ea50..1cb39f0de592 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -16,16 +16,19 @@
<!-- Colors specific to Material themes. -->
<resources>
- <color name="background_material_dark">#ff303030</color>
- <color name="background_material_light">#fffafafa</color>
- <color name="background_floating_material_dark">#ff424242</color>
- <color name="background_floating_material_light">#ffffffff</color>
+ <color name="foreground_material_dark">@color/white</color>
+ <color name="foreground_material_light">@color/black</color>
+
+ <color name="background_material_dark">@color/material_grey_850</color>
+ <color name="background_material_light">@color/material_grey_50</color>
+ <color name="background_floating_material_dark">@color/material_grey_800</color>
+ <color name="background_floating_material_light">@color/white</color>
- <color name="primary_material_dark">#ff212121</color>
- <color name="primary_material_light">#fff5f5f5</color>
- <color name="primary_dark_material_dark">#ff000000</color>
- <color name="primary_dark_material_light">#ff757575</color>
- <color name="primary_dark_material_light_light_status_bar">#ffe0e0e0</color>
+ <color name="primary_material_dark">@color/material_grey_900</color>
+ <color name="primary_material_light">@color/material_grey_100</color>
+ <color name="primary_dark_material_dark">@color/black</color>
+ <color name="primary_dark_material_light">@color/material_grey_600</color>
+ <color name="primary_dark_material_light_light_status_bar">@color/material_grey_300</color>
<color name="accent_material_light">@color/material_deep_teal_500</color>
<color name="accent_material_dark">@color/material_deep_teal_200</color>
@@ -38,19 +41,20 @@
<color name="switch_thumb_disabled_material_dark">#ff616161</color>
<color name="switch_thumb_disabled_material_light">#ffbdbdbd</color>
- <color name="foreground_material_dark">@color/white</color>
- <color name="foreground_material_light">@color/black</color>
-
- <color name="link_text_material_dark">@color/material_deep_teal_200</color>
<color name="link_text_material_light">@color/material_deep_teal_500</color>
+ <color name="link_text_material_dark">@color/material_deep_teal_200</color>
<!-- Text & foreground colors -->
<eat-comment />
+ <!-- 87% black -->
<color name="primary_text_default_material_light">#de000000</color>
+ <!-- 54% black -->
<color name="secondary_text_default_material_light">#8a000000</color>
+ <!-- 100% white -->
<color name="primary_text_default_material_dark">#ffffffff</color>
+ <!-- 70% white -->
<color name="secondary_text_default_material_dark">#b3ffffff</color>
<item name="hint_alpha_material_dark" format="float" type="dimen">0.50</item>
@@ -66,6 +70,14 @@
<!-- Primary & accent colors -->
<eat-comment />
+ <color name="material_grey_900">#ff212121</color>
+ <color name="material_grey_850">#ff303030</color>
+ <color name="material_grey_800">#ff424242</color>
+ <color name="material_grey_600">#ff757575</color>
+ <color name="material_grey_300">#ffe0e0e0</color>
+ <color name="material_grey_100">#fff5f5f5</color>
+ <color name="material_grey_50">#fffafafa</color>
+
<color name="material_deep_teal_200">#ff80cbc4</color>
<color name="material_deep_teal_500">#ff009688</color>
@@ -98,16 +110,16 @@
<color name="datepicker_default_disabled_text_color_material_light">#80999999</color>
<color name="datepicker_default_disabled_text_color_material_dark">#80999999</color>
- <color name="datepicker_default_selected_text_color_material_light">#33b5e5</color>
- <color name="datepicker_default_selected_text_color_material_dark">#33b5e5</color>
+ <color name="datepicker_default_selected_text_color_material_light">#ff33b5e5</color>
+ <color name="datepicker_default_selected_text_color_material_dark">#ff33b5e5</color>
- <color name="datepicker_default_pressed_text_color_material_light">#0099cc</color>
- <color name="datepicker_default_pressed_text_color_material_dark">#0099cc</color>
+ <color name="datepicker_default_pressed_text_color_material_light">#ff0099cc</color>
+ <color name="datepicker_default_pressed_text_color_material_dark">#ff0099cc</color>
<color name="datepicker_default_circle_background_color_material_light">@color/material_deep_teal_500</color>
<color name="datepicker_default_circle_background_color_material_dark">@color/material_deep_teal_200</color>
- <color name="datepicker_default_view_animator_color_material_light">#f2f2f2</color>
+ <color name="datepicker_default_view_animator_color_material_light">#fff2f2f2</color>
<color name="datepicker_default_view_animator_color_material_dark">#ff303030</color>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 37c95987ba8d..1b2e952d7562 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1112,6 +1112,18 @@
device does not support multiple advertisement-->
<integer translatable="false" name="config_bluetooth_max_advertisers">0</integer>
+ <!-- Idle current for bluetooth controller. 0 by default-->
+ <integer translatable="false" name="config_bluetooth_idle_cur_ma">1</integer>
+
+ <!-- Rx current for bluetooth controller. 0 by default-->
+ <integer translatable="false" name="config_bluetooth_rx_cur_ma">2</integer>
+
+ <!-- Tx current for bluetooth controller. 0 by default-->
+ <integer translatable="false" name="config_bluetooth_tx_cur_ma">3</integer>
+
+ <!-- Operating volatage for bluetooth controller. 0 by default-->
+ <integer translatable="false" name="config_bluetooth_operating_voltage_mv">4</integer>
+
<!-- The default data-use polling period. -->
<integer name="config_datause_polling_period_sec">600</integer>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6c6d2ccaa6f2..3431f35d7dda 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -386,4 +386,11 @@
<item type="dimen" format="float" name="ambient_shadow_alpha">0.075</item>
<item type="dimen" format="float" name="spot_shadow_alpha">0.15</item>
+ <!-- Floating toolbar dimensions -->
+ <dimen name="floating_toolbar_height">48dp</dimen>
+ <dimen name="floating_toolbar_menu_button_side_padding">8dp</dimen>
+ <dimen name="floating_toolbar_text_size">14sp</dimen>
+ <dimen name="floating_toolbar_menu_button_minimum_width">48dp</dimen>
+ <dimen name="floating_toolbar_default_width">250dp</dimen>
+ <dimen name="floating_toolbar_minimum_overflow_height">192dp</dimen>
</resources>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 8d2afde07fa6..6fd39f6c540e 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -143,9 +143,7 @@
<dimen name="timepicker_text_size_inner">12sp</dimen>
<!-- Material date picker dimensions. -->
- <dimen name="datepicker_year_picker_padding_top">8dp</dimen>
<dimen name="datepicker_year_label_height">64dp</dimen>
- <dimen name="datepicker_year_label_text_size">22dp</dimen>
<dimen name="datepicker_component_width">260dp</dimen>
<dimen name="datepicker_dialog_width">520dp</dimen>
<dimen name="datepicker_selected_date_day_size">88dp</dimen>
@@ -154,10 +152,24 @@
<dimen name="datepicker_header_height">30dp</dimen>
<dimen name="datepicker_header_text_size">14dp</dimen>
+ <dimen name="datepicker_list_year_label_size">16sp</dimen>
+ <dimen name="datepicker_list_year_activated_label_size">26sp</dimen>
+
+ <dimen name="date_picker_year_label_size">16sp</dimen>
+ <dimen name="date_picker_date_label_size">34dp</dimen>
+
<!-- Used by Material-style SimpleMonthView -->
- <dimen name="datepicker_day_number_size">12sp</dimen>
- <dimen name="datepicker_month_label_size">14sp</dimen>
- <dimen name="datepicker_month_day_label_text_size">12sp</dimen>
- <dimen name="datepicker_month_list_item_header_height">48dp</dimen>
+ <dimen name="date_picker_month_text_size">14sp</dimen>
+ <dimen name="date_picker_day_of_week_text_size">12sp</dimen>
+ <dimen name="date_picker_day_text_size">12sp</dimen>
+ <dimen name="date_picker_month_height">56dp</dimen>
+ <dimen name="date_picker_day_of_week_height">36dp</dimen>
+ <dimen name="date_picker_day_height">40dp</dimen>
+ <dimen name="date_picker_day_width">44dp</dimen>
+ <dimen name="date_picker_day_selector_radius">20dp</dimen>
+ <dimen name="day_picker_padding_horizontal">20dp</dimen>
+ <dimen name="day_picker_padding_top">6dp</dimen>
+ <dimen name="day_picker_button_margin_top">0dp</dimen>
+
<dimen name="datepicker_view_animator_height">226dp</dimen>
</resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 6108b27f13b5..7e963954de5d 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -93,4 +93,5 @@
<item type="id" name="undo" />
<item type="id" name="redo" />
<item type="id" name="replaceText" />
+ <item type="id" name="accessibility_action_show_on_screen" />
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e507b3d0e64f..ef7bfaff4246 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2651,4 +2651,6 @@
<public type="attr" name="colorBackgroundFloating" />
+ <public type="attr" name="extractNativeLibs" />
+ <public type="attr" name="usesCleartextTraffic" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 19cae037951c..88225bd4586a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -251,6 +251,8 @@
<string-array name="wfcOperatorErrorCodes" translatable="false" />
<!-- WFC Operator Error Messages -->
<string-array name="wfcOperatorErrorMessages" />
+ <!-- Template for showing cellular network operator name while WFC is active -->
+ <string name="wfcSpnFormat">%s</string>
<!--
{0} is one of "bearerServiceCode*"
@@ -2226,6 +2228,36 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_useFingerprint">Allows the app to use fingerprint hardware for authentication</string>
+ <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
+ <string name="fingerprint_acquired_partial">Partial fingerprint detected. Please try again.</string>
+ <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
+ <string name="fingerprint_acquired_insufficient">Couldn\'t process fingerprint. Please try again.</string>
+ <!-- Message shown during fingerprint acquisision when the fingerprint sensor needs cleaning -->
+ <string name="fingerprint_acquired_imager_dirty">Fingerprint sensor is dirty. Please clean and try again.</string>
+ <!-- Message shown during fingerprint acquisision when the user removes their finger from the sensor too quickly -->
+ <string name="fingerprint_acquired_too_fast">Finger moved to fast. Please try again.</string>
+ <!-- Message shown during fingerprint acquisision when the user moves their finger too slowly -->
+ <string name="fingerprint_acquired_too_slow">Finger moved to slow. Please try again.</string>
+ <!-- Array containing custom messages shown during fingerprint acquisision from vendor. Vendor is expected to add and translate these strings -->
+ <string-array name="fingerprint_acquired_vendor">
+ <item>Vendor-specific acquisition error message 0</item>
+ </string-array>
+
+ <!-- Generic error message shown when the fingerprint hardware can't recognize the fingerprint -->
+ <string name="fingerprint_error_unable_to_process">Unable to process. Try again.</string>
+ <!-- Error message shown when the fingerprint hardware can't be accessed -->
+ <string name="fingerprint_error_hw_not_available">Hardware not available.</string>
+ <!-- Error message shown when the fingerprint hardware has run out of room for storing fingerprints -->
+ <string name="fingerprint_error_no_space">Fingerprint can\'t be stored. Please remove an existing fingerprint.</string>
+ <!-- Error message shown when the fingerprint hardware timer has expired and the user needs to restart the operation. -->
+ <string name="fingerprint_error_timeout">Fingerprint time out reached. Try again.</string>
+ <!-- Error message shown when the fingerprint hardware timer has expired and the user needs to restart the operation. -->
+ <string name="fingerprint_error_vendor">Fingerprint time out reached. Try again.</string>
+ <!-- Array containing custom error messages from vendor. Vendor is expected to add and translate these strings -->
+ <string-array name="fingerprint_error_vendor">
+ <item>Vendor-specifc error message.</item>
+ </string-array>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readSyncSettings">read sync settings</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -5042,18 +5074,6 @@
<!-- Accessibility announcement for minute circular picker [CHAR LIMIT=NONE] -->
<string name="select_minutes">Select minutes</string>
- <!--
- Content description for the month and day selector in the date picker, which displays
- a selectable grid of days laid out by month.
- [CHAR LIMIT=50]
- -->
- <string name="day_picker_description">Month grid of days</string>
- <!--
- Content description for the year selector in the date picker, which displays
- a scrolling, vertical list of years.
- [CHAR LIMIT=50]
- -->
- <string name="year_picker_description">Year list</string>
<!-- Accessibility announcement for the day picker [CHAR LIMIT=NONE] -->
<string name="select_day">Select month and day</string>
<!-- Accessibility announcement for the year picker [CHAR LIMIT=NONE] -->
@@ -5079,7 +5099,11 @@
<string name="sans_serif">sans-serif</string>
<!-- DO NOT TRANSLATE -->
- <string name="day_of_week_label_typeface">sans-serif</string>
+ <string name="date_picker_month_typeface">sans-serif-medium</string>
+ <!-- DO NOT TRANSLATE -->
+ <string name="date_picker_day_of_week_typeface">sans-serif-medium</string>
+ <!-- DO NOT TRANSLATE -->
+ <string name="date_picker_day_typeface">sans-serif-medium</string>
<!-- Notify use that they are in Lock-to-app -->
<string name="lock_to_app_toast">To unpin this screen, touch and hold Back and Overview at the same time.</string>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index a8ab18dbf7f4..f1f7462bed72 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -372,11 +372,13 @@ please see styles_device_defaults.xml.
<style name="TextAppearance.Material.WindowTitle" parent="TextAppearance.Material.Title" />
<style name="TextAppearance.Material.DialogWindowTitle" parent="TextAppearance.Material.Title" />
- <style name="TextAppearance.Material.CalendarViewWeekDayView" parent="TextAppearance.Material.Small">
- <item name="textStyle">bold</item>
- <item name="textColor">#505050</item>
+ <style name="TextAppearance.Material.Widget.Calendar.Day" parent="TextAppearance.Material.Caption">
+ <item name="textColor">?attr/textColorPrimaryActivated</item>
</style>
+ <style name="TextAppearance.Material.Widget.Calendar.DayOfWeek" parent="TextAppearance.Material.Caption" />
+ <style name="TextAppearance.Material.Widget.Calendar.Month" parent="TextAppearance.Material.Body2" />
+
<style name="TextAppearance.Material.TimePicker.TimeLabel" parent="TextAppearance.Material">
<item name="textSize">@dimen/timepicker_time_label_size</item>
<item name="textColor">@color/time_picker_header_text_material</item>
@@ -406,14 +408,27 @@ please see styles_device_defaults.xml.
</style>
<style name="TextAppearance.Material.DatePicker.YearLabel" parent="TextAppearance.Material">
- <item name="includeFontPadding">false</item>
<item name="textColor">@color/date_picker_header_text_material</item>
- <item name="textSize">@dimen/datepicker_selected_date_year_size</item>
+ <item name="textSize">@dimen/date_picker_year_label_size</item>
+ <item name="fontFamily">sans-serif-medium</item>
+ </style>
+
+ <style name="TextAppearance.Material.DatePicker.DateLabel" parent="TextAppearance.Material">
+ <item name="textColor">@color/date_picker_header_text_material</item>
+ <item name="textSize">@dimen/date_picker_date_label_size</item>
+ <item name="fontFamily">sans-serif-medium</item>
</style>
<style name="TextAppearance.Material.DatePicker.List.YearLabel" parent="TextAppearance.Material">
- <item name="textColor">?attr/textColorSecondaryActivated</item>
- <item name="textSize">@dimen/datepicker_year_label_text_size</item>
+ <item name="textColor">?attr/textColorPrimary</item>
+ <item name="textSize">@dimen/datepicker_list_year_label_size</item>
+ <item name="fontFamily">sans-serif</item>
+ </style>
+
+ <style name="TextAppearance.Material.DatePicker.List.YearLabel.Activated">
+ <item name="textColor">?attr/colorControlActivated</item>
+ <item name="textSize">@dimen/datepicker_list_year_activated_label_size</item>
+ <item name="fontFamily">sans-serif-medium</item>
</style>
<style name="TextAppearance.Material.Notification">
@@ -487,7 +502,8 @@ please see styles_device_defaults.xml.
<!-- Alert dialog button bar button -->
<style name="Widget.Material.Button.ButtonBar.AlertDialog" parent="Widget.Material.Button.Borderless.Colored">
<item name="minWidth">64dp</item>
- <item name="maxLines">2</item>
+ <item name="singleLine">true</item>
+ <item name="ellipsize">none</item>
<item name="minHeight">@dimen/alert_dialog_button_bar_height</item>
</style>
@@ -615,14 +631,13 @@ please see styles_device_defaults.xml.
</style>
<style name="Widget.Material.CalendarView" parent="Widget.CalendarView">
- <item name="selectedWeekBackgroundColor">#330099FF</item>
- <item name="focusedMonthDateColor">#FFFFFFFF</item>
- <item name="unfocusedMonthDateColor">#66FFFFFF</item>
- <item name="weekNumberColor">#33FFFFFF</item>
- <item name="weekSeparatorLineColor">#19FFFFFF</item>
- <item name="selectedDateVerticalBar">@drawable/day_picker_week_view_dayline_holo</item>
- <item name="weekDayTextAppearance">@style/TextAppearance.Material.CalendarViewWeekDayView</item>
<item name="calendarViewMode">material</item>
+
+ <item name="monthTextAppearance">@style/TextAppearance.Material.Widget.Calendar.Month</item>
+ <item name="weekDayTextAppearance">@style/TextAppearance.Material.Widget.Calendar.DayOfWeek</item>
+ <item name="dateTextAppearance">@style/TextAppearance.Material.Widget.Calendar.Day</item>
+ <item name="daySelectorColor">?attr/colorControlActivated</item>
+ <item name="dayHighlightColor">?attr/colorControlHighlight</item>
</style>
<style name="Widget.Material.ImageButton" parent="Widget.ImageButton">
@@ -647,11 +662,11 @@ please see styles_device_defaults.xml.
<item name="internalLayout">@layout/time_picker_material</item>
<item name="headerTimeTextAppearance">@style/TextAppearance.Material.TimePicker.TimeLabel</item>
<item name="headerAmPmTextAppearance">@style/TextAppearance.Material.TimePicker.AmPmLabel</item>
- <item name="headerBackground">@drawable/time_picker_header_material</item>
+ <item name="headerBackground">#ff555555</item>
<item name="numbersTextColor">?attr/textColorPrimaryActivated</item>
<item name="numbersInnerTextColor">?attr/textColorSecondaryActivated</item>
- <item name="numbersBackgroundColor">#10ffffff</item>
<item name="numbersSelectorColor">?attr/colorControlActivated</item>
+ <item name="numbersBackgroundColor">#ff555555</item>
<item name="amPmTextColor">?attr/textColorSecondary</item>
</style>
@@ -660,17 +675,10 @@ please see styles_device_defaults.xml.
<item name="legacyLayout">@layout/date_picker_legacy_holo</item>
<item name="calendarViewShown">true</item>
<!-- Attributes for new-style DatePicker. -->
- <item name="internalLayout">@layout/date_picker_holo</item>
- <item name="dayOfWeekBackground">#10000000</item>
- <item name="dayOfWeekTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfWeekLabel</item>
- <item name="headerMonthTextAppearance">@style/TextAppearance.Material.DatePicker.MonthLabel</item>
- <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfMonthLabel</item>
- <item name="headerYearTextAppearance">@style/TextAppearance.Material.DatePicker.YearLabel</item>
- <item name="headerBackground">?attr/colorAccent</item>
+ <item name="internalLayout">@layout/date_picker_material</item>
<item name="yearListItemTextAppearance">@style/TextAppearance.Material.DatePicker.List.YearLabel</item>
- <item name="yearListSelectorColor">?attr/colorControlActivated</item>
- <item name="calendarTextColor">?attr/textColorSecondaryActivated</item>
- <item name="calendarDayBackgroundColor">?attr/colorControlActivated</item>
+ <item name="yearListItemActivatedTextAppearance">@style/TextAppearance.Material.DatePicker.List.YearLabel.Activated</item>
+ <item name="headerBackground">#ff555555</item>
</style>
<style name="Widget.Material.ActivityChooserView" parent="Widget.ActivityChooserView">
@@ -1021,24 +1029,18 @@ please see styles_device_defaults.xml.
<style name="Widget.Material.Light.GestureOverlayView" parent="Widget.Material.GestureOverlayView"/>
<style name="Widget.Material.Light.GridView" parent="Widget.Material.GridView"/>
<style name="Widget.Material.Light.ImageButton" parent="Widget.Material.ImageButton"/>
-
- <style name="Widget.Material.Light.CalendarView" parent="Widget.CalendarView">
- <item name="selectedWeekBackgroundColor">#330066ff</item>
- <item name="focusedMonthDateColor">#FF000000</item>
- <item name="unfocusedMonthDateColor">#7F08002B</item>
- <item name="weekNumberColor">#7F080021</item>
- <item name="weekSeparatorLineColor">#7F08002A</item>
- <item name="weekDayTextAppearance">@style/TextAppearance.Material.CalendarViewWeekDayView</item>
- <item name="calendarViewMode">material</item>
- </style>
-
+ <style name="Widget.Material.Light.CalendarView" parent="Widget.Material.CalendarView" />
<style name="Widget.Material.Light.NumberPicker" parent="Widget.Material.NumberPicker"/>
<style name="Widget.Material.Light.TimePicker" parent="Widget.Material.TimePicker">
- <item name="numbersBackgroundColor">#10000000</item>
+ <item name="headerBackground">?attr/colorAccent</item>
+ <item name="numbersBackgroundColor">#ffeeeeee</item>
+ </style>
+
+ <style name="Widget.Material.Light.DatePicker" parent="Widget.Material.DatePicker">
+ <item name="headerBackground">?attr/colorAccent</item>
</style>
- <style name="Widget.Material.Light.DatePicker" parent="Widget.Material.DatePicker" />
<style name="Widget.Material.Light.ActivityChooserView" parent="Widget.Material.ActivityChooserView" />
<style name="Widget.Material.Light.ImageWell" parent="Widget.Material.ImageWell"/>
<style name="Widget.Material.Light.ListView" parent="Widget.Material.ListView"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 203b017391aa..67d547296c0b 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -349,6 +349,10 @@
<java-symbol type="integer" name="config_burnInProtectionMinVerticalOffset" />
<java-symbol type="integer" name="config_burnInProtectionMaxVerticalOffset" />
<java-symbol type="integer" name="config_burnInProtectionMaxRadius" />
+ <java-symbol type="integer" name="config_bluetooth_idle_cur_ma" />
+ <java-symbol type="integer" name="config_bluetooth_rx_cur_ma" />
+ <java-symbol type="integer" name="config_bluetooth_tx_cur_ma" />
+ <java-symbol type="integer" name="config_bluetooth_operating_voltage_mv" />
<java-symbol type="integer" name="config_cursorWindowSize" />
<java-symbol type="integer" name="config_drawLockTimeoutMillis" />
<java-symbol type="integer" name="config_doublePressOnPowerBehavior" />
@@ -756,6 +760,7 @@
<java-symbol type="string" name="wfcRegErrorTitle" />
<java-symbol type="array" name="wfcOperatorErrorCodes" />
<java-symbol type="array" name="wfcOperatorErrorMessages" />
+ <java-symbol type="string" name="wfcSpnFormat" />
<java-symbol type="string" name="policydesc_disableCamera" />
<java-symbol type="string" name="policydesc_encryptedStorage" />
<java-symbol type="string" name="policydesc_expirePassword" />
@@ -1988,7 +1993,7 @@
<java-symbol type="layout" name="time_picker_material" />
<java-symbol type="layout" name="time_picker_header_material" />
<java-symbol type="layout" name="year_label_text_view" />
- <java-symbol type="layout" name="date_picker_holo" />
+ <java-symbol type="layout" name="date_picker_material" />
<java-symbol type="id" name="time_header" />
<java-symbol type="id" name="hours" />
@@ -1999,11 +2004,8 @@
<java-symbol type="id" name="radial_picker" />
<java-symbol type="id" name="separator" />
<java-symbol type="id" name="date_picker_header" />
- <java-symbol type="id" name="date_picker_month_and_day_layout" />
- <java-symbol type="id" name="day_picker_selector_layout" />
- <java-symbol type="id" name="date_picker_month" />
- <java-symbol type="id" name="date_picker_day" />
- <java-symbol type="id" name="date_picker_year" />
+ <java-symbol type="id" name="date_picker_header_year" />
+ <java-symbol type="id" name="date_picker_header_date" />
<java-symbol type="id" name="animator" />
<java-symbol type="string" name="done_label" />
@@ -2039,19 +2041,24 @@
<java-symbol type="string" name="muted_by" />
<java-symbol type="string" name="item_is_selected" />
- <java-symbol type="string" name="day_of_week_label_typeface" />
<java-symbol type="string" name="select_day" />
- <java-symbol type="string" name="day_picker_description" />
<java-symbol type="string" name="select_year" />
- <java-symbol type="string" name="year_picker_description" />
- <java-symbol type="dimen" name="datepicker_day_number_size" />
- <java-symbol type="dimen" name="datepicker_month_label_size" />
- <java-symbol type="dimen" name="datepicker_month_day_label_text_size" />
- <java-symbol type="dimen" name="datepicker_month_list_item_header_height" />
+ <java-symbol type="string" name="date_picker_month_typeface" />
+ <java-symbol type="string" name="date_picker_day_of_week_typeface" />
+ <java-symbol type="string" name="date_picker_day_typeface" />
+ <java-symbol type="dimen" name="date_picker_month_text_size" />
+ <java-symbol type="dimen" name="date_picker_day_of_week_text_size" />
+ <java-symbol type="dimen" name="date_picker_day_text_size" />
+ <java-symbol type="dimen" name="date_picker_month_height" />
+ <java-symbol type="dimen" name="date_picker_day_height" />
+ <java-symbol type="dimen" name="date_picker_day_width" />
+ <java-symbol type="dimen" name="date_picker_day_selector_radius" />
+ <java-symbol type="id" name="date_picker_day_picker" />
+ <java-symbol type="id" name="date_picker_year_picker" />
+
<java-symbol type="dimen" name="datepicker_view_animator_height" />
<java-symbol type="dimen" name="datepicker_year_label_height" />
- <java-symbol type="dimen" name="datepicker_year_picker_padding_top" />
<java-symbol type="array" name="config_clockTickVibePattern" />
<java-symbol type="array" name="config_calendarDateVibePattern" />
@@ -2059,6 +2066,19 @@
<!-- From KeyguardServiceDelegate -->
<java-symbol type="string" name="config_keyguardComponent" />
+ <!-- Fingerprint messages -->
+ <java-symbol type="string" name="fingerprint_error_unable_to_process" />
+ <java-symbol type="string" name="fingerprint_error_hw_not_available" />
+ <java-symbol type="string" name="fingerprint_error_no_space" />
+ <java-symbol type="string" name="fingerprint_error_timeout" />
+ <java-symbol type="array" name="fingerprint_error_vendor" />
+ <java-symbol type="string" name="fingerprint_acquired_partial" />
+ <java-symbol type="string" name="fingerprint_acquired_insufficient" />
+ <java-symbol type="string" name="fingerprint_acquired_imager_dirty" />
+ <java-symbol type="string" name="fingerprint_acquired_too_slow" />
+ <java-symbol type="string" name="fingerprint_acquired_too_fast" />
+ <java-symbol type="array" name="fingerprint_acquired_vendor" />
+
<!-- From various Material changes -->
<java-symbol type="attr" name="titleTextAppearance" />
<java-symbol type="attr" name="subtitleTextAppearance" />
@@ -2115,7 +2135,6 @@
<java-symbol type="id" name="transitionTransform" />
<java-symbol type="id" name="parentMatrix" />
<java-symbol type="bool" name="config_auto_attach_data_on_creation" />
- <java-symbol type="id" name="date_picker_month_day_year_layout" />
<java-symbol type="attr" name="closeItemLayout" />
<java-symbol type="layout" name="resolver_different_item_header" />
<java-symbol type="array" name="config_default_vm_number" />
@@ -2167,4 +2186,23 @@
<java-symbol type="integer" name="config_screen_magnification_multi_tap_adjustment" />
<java-symbol type="dimen" name="config_screen_magnification_scaling_threshold" />
<java-symbol type="dimen" name="timepicker_selector_stroke"/>
+
+ <java-symbol type="style" name="TextAppearance.Material.Widget.Calendar.Month" />
+ <java-symbol type="style" name="TextAppearance.Material.Widget.Calendar.DayOfWeek" />
+ <java-symbol type="style" name="TextAppearance.Material.Widget.Calendar.Day" />
+ <java-symbol type="dimen" name="day_picker_padding_top"/>
+ <java-symbol type="dimen" name="date_picker_day_of_week_height"/>
+
+ <java-symbol type="id" name="accessibility_action_show_on_screen" />
+
+ <!-- Floating toolbar -->
+ <java-symbol type="layout" name="floating_popup_container" />
+ <java-symbol type="layout" name="floating_popup_menu_button" />
+ <java-symbol type="layout" name="floating_popup_open_overflow_button" />
+ <java-symbol type="dimen" name="floating_toolbar_height" />
+ <java-symbol type="dimen" name="floating_toolbar_menu_button_side_padding" />
+ <java-symbol type="dimen" name="floating_toolbar_text_size" />
+ <java-symbol type="dimen" name="floating_toolbar_menu_button_minimum_width" />
+ <java-symbol type="dimen" name="floating_toolbar_default_width" />
+ <java-symbol type="dimen" name="floating_toolbar_minimum_overflow_height" />
</resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 38cfecde00d7..9931d00ef90c 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -857,6 +857,7 @@ please see themes_device_defaults.xml.
<!-- Theme overlay that overrides window properties to display as a dialog. -->
<style name="ThemeOverlay.Material.Dialog">
<item name="colorBackgroundCacheHint">@null</item>
+ <item name="colorBackground">?attr/colorBackgroundFloating</item>
<item name="windowFrame">@null</item>
<item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
@@ -1271,7 +1272,6 @@ please see themes_device_defaults.xml.
<style name="Theme.Material.Settings" parent="Theme.Material.DayNight.DarkActionBar">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
- <item name="colorAccent">@color/material_deep_teal_500</item>
<item name="presentationTheme">@style/Theme.Material.Settings.Dialog.Presentation</item>
<item name="searchDialogTheme">@style/Theme.Material.Settings.SearchBar</item>
@@ -1281,7 +1281,6 @@ please see themes_device_defaults.xml.
<style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.DayNight.BaseDialog">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
- <item name="colorAccent">@color/material_deep_teal_500</item>
</style>
<style name="Theme.Material.Settings.Dialog" parent="Theme.Material.Settings.BaseDialog" />
@@ -1289,7 +1288,6 @@ please see themes_device_defaults.xml.
<style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.DayNight.Dialog.BaseAlert">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
- <item name="colorAccent">@color/material_deep_teal_500</item>
</style>
<style name="Theme.Material.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.BaseAlert" />
@@ -1297,7 +1295,6 @@ please see themes_device_defaults.xml.
<style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.DayNight.Dialog.Presentation">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
- <item name="colorAccent">@color/material_deep_teal_500</item>
</style>
<style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.DayNight.SearchBar">
@@ -1309,6 +1306,5 @@ please see themes_device_defaults.xml.
<style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.DayNight.CompactMenu">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
- <item name="colorAccent">@color/material_deep_teal_500</item>
</style>
</resources>
diff --git a/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java b/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java
new file mode 100644
index 000000000000..1a5043254e09
--- /dev/null
+++ b/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.net;
+
+import com.google.caliper.Param;
+import com.google.caliper.SimpleBenchmark;
+
+public class NetworkStatsBenchmark extends SimpleBenchmark {
+ private static final String UNDERLYING_IFACE = "wlan0";
+ private static final String TUN_IFACE = "tun0";
+ private static final int TUN_UID = 999999999;
+
+ @Param({"100", "1000"})
+ private int mSize;
+ private NetworkStats mNetworkStats;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mNetworkStats = new NetworkStats(0, mSize + 2);
+ int uid = 0;
+ NetworkStats.Entry recycle = new NetworkStats.Entry();
+ for (int i = 0; i < mSize; i++) {
+ recycle.iface = (i < mSize / 2) ? TUN_IFACE : UNDERLYING_IFACE;
+ recycle.uid = uid;
+ recycle.set = i % 2;
+ recycle.tag = NetworkStats.TAG_NONE;
+ recycle.rxBytes = 60000;
+ recycle.rxPackets = 60;
+ recycle.txBytes = 150000;
+ recycle.txPackets = 1500;
+ recycle.operations = 0;
+ mNetworkStats.addValues(recycle);
+ if (recycle.set == 1) {
+ uid++;
+ }
+ }
+ recycle.iface = UNDERLYING_IFACE;
+ recycle.uid = TUN_UID;
+ recycle.set = NetworkStats.SET_FOREGROUND;
+ recycle.tag = NetworkStats.TAG_NONE;
+ recycle.rxBytes = 90000 * mSize;
+ recycle.rxPackets = 40 * mSize;
+ recycle.txBytes = 180000 * mSize;
+ recycle.txPackets = 1200 * mSize;
+ recycle.operations = 0;
+ mNetworkStats.addValues(recycle);
+ }
+
+ public void timeMigrateTun(int reps) {
+ for (int i = 0; i < reps; i++) {
+ NetworkStats stats = mNetworkStats.clone();
+ stats.migrateTun(TUN_UID, TUN_IFACE, UNDERLYING_IFACE);
+ }
+ }
+
+ /**
+ * Since timeMigrateTun() includes a clone() call on the NetworkStats object,
+ * we need to measure the cost of the clone() call itself in order to get more
+ * accurate measurement on the migrateTun() method.
+ */
+ public void timeClone(int reps) {
+ for (int i = 0; i < reps; i++) {
+ NetworkStats stats = mNetworkStats.clone();
+ }
+ }
+}
diff --git a/core/tests/coretests/apks/install_jni_lib/Android.mk b/core/tests/coretests/apks/install_jni_lib/Android.mk
index b61ea8edda71..7322e8d6949b 100644
--- a/core/tests/coretests/apks/install_jni_lib/Android.mk
+++ b/core/tests/coretests/apks/install_jni_lib/Android.mk
@@ -23,6 +23,14 @@ LOCAL_SHARED_LIBRARIES := \
libnativehelper
LOCAL_MODULE := libframeworks_coretests_jni
+
+# this does not prevent build system
+# from installing library to /system/lib
LOCAL_MODULE_TAGS := tests
+# .. we want to avoid that... so we put it somewhere
+# bionic linker cant find it without outside help (nativetests):
+LOCAL_MODULE_PATH_32 := $($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+LOCAL_MODULE_PATH_64 := $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+
include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
index 957fc4a1f53e..e0b616c16184 100644
--- a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
+++ b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
@@ -27,8 +27,8 @@ static JNINativeMethod sMethods[] = {
{ "checkFunction", "()I", (void*) checkFunction },
};
-int register_com_android_framework_coretests_JNITests(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "com/android/framework/coretests/JNITests", sMethods,
+int register_com_android_frameworks_coretests_JNITests(JNIEnv* env) {
+ return jniRegisterNativeMethods(env, "com/android/frameworks/coretests/JNITests", sMethods,
NELEM(sMethods));
}
@@ -46,7 +46,7 @@ jint JNI_OnLoad(JavaVM *jvm, void *reserved) {
return JNI_ERR;
}
- if ((status = android::register_com_android_framework_coretests_JNITests(e)) < 0) {
+ if ((status = android::register_com_android_frameworks_coretests_JNITests(e)) < 0) {
return JNI_ERR;
}
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk b/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk
new file mode 100644
index 000000000000..5fa24055d9a8
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := install_jni_lib_open_from_apk
+
+LOCAL_JNI_SHARED_LIBRARIES_ZIP_OPTIONS := -0
+LOCAL_PAGE_ALIGN_JNI_SHARED_LIBRARIES := true
+
+include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/AndroidManifest.xml b/core/tests/coretests/apks/install_jni_lib_open_from_apk/AndroidManifest.xml
new file mode 100644
index 000000000000..190f89474405
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib_open_from_apk/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.install_jni_lib_open_from_apk">
+
+ <application android:hasCode="true" android:label="@string/app_name" android:extractNativeLibs="false">
+ <activity android:name="com.android.frameworks.coretests.OpenFromApkActivity"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/res/values/strings.xml b/core/tests/coretests/apks/install_jni_lib_open_from_apk/res/values/strings.xml
new file mode 100644
index 000000000000..8c2a0bfbee73
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib_open_from_apk/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name">Load From Apk Test</string>
+</resources>
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/src/com/android/frameworks/coretests/JNITests.java b/core/tests/coretests/apks/install_jni_lib_open_from_apk/src/com/android/frameworks/coretests/JNITests.java
new file mode 100644
index 000000000000..4f9176c8f7b8
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib_open_from_apk/src/com/android/frameworks/coretests/JNITests.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.frameworks.coretests;
+
+public class JNITests {
+ static {
+ System.loadLibrary("frameworks_coretests_jni");
+ }
+
+ public static native int checkFunction();
+}
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/src/com/android/frameworks/coretests/OpenFromApkActivity.java b/core/tests/coretests/apks/install_jni_lib_open_from_apk/src/com/android/frameworks/coretests/OpenFromApkActivity.java
new file mode 100644
index 000000000000..524cad7cfb69
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib_open_from_apk/src/com/android/frameworks/coretests/OpenFromApkActivity.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.frameworks.coretests;
+
+import android.app.Activity;
+import android.widget.TextView;
+import android.os.Bundle;
+
+public class OpenFromApkActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ TextView tv = new TextView(this);
+
+ int i = JNITests.checkFunction();
+
+ tv.setText("All is well: i=" + i);
+
+ setContentView(tv);
+ }
+
+}
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
index fd922a2c07fb..a470de1ed3c0 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
@@ -18,6 +18,8 @@ package android.net;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.SET_FOREGROUND;
+import static android.net.NetworkStats.SET_DBG_VPN_IN;
+import static android.net.NetworkStats.SET_DBG_VPN_OUT;
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.TAG_NONE;
@@ -346,7 +348,7 @@ public class NetworkStatsTest extends TestCase {
.addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface));
- assertEquals(17, delta.size());
+ assertEquals(21, delta.size());
// tunIface and TEST_IFACE entries are not changed.
assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE,
@@ -377,14 +379,33 @@ public class NetworkStatsTest extends TestCase {
0L, 0L, 0L, 0L, 0L);
// New entries are added for new application's underlying Iface traffic
- assertValues(delta, 13, underlyingIface, 10120, SET_DEFAULT, TAG_NONE,
+ assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE,
72667L, 197L, 41872l, 219L, 0L);
- assertValues(delta, 14, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE,
+ assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE,
9297L, 17L, 3936, 19L, 0L);
- assertValues(delta, 15, underlyingIface, 10120, SET_DEFAULT, testTag1,
+ assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1,
21691L, 41L, 13179L, 46L, 0L);
- assertValues(delta, 16, underlyingIface, 10120, SET_FOREGROUND, testTag1,
+ assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1,
1281L, 2L, 634L, 1L, 0L);
+
+ // New entries are added for debug purpose
+ assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE,
+ 39605L, 46L, 11690, 49, 0);
+ assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE,
+ 81964, 214, 45808, 238, 0);
+ assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_IN, TAG_NONE,
+ 4983, 10, 1717, 10, 0);
+ assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE,
+ 126552, 270, 59215, 297, 0);
+
+ }
+
+ private static void assertContains(NetworkStats stats, String iface, int uid, int set,
+ int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
+ int index = stats.findIndex(iface, uid, set, tag);
+ assertTrue(index != -1);
+ assertValues(stats, index, iface, uid, set, tag,
+ rxBytes, rxPackets, txBytes, txPackets, operations);
}
private static void assertValues(NetworkStats stats, int index, String iface, int uid, int set,
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 6659769b4204..c517201145b4 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -58,11 +58,11 @@
<group gid="log" />
</permission>
- <permission name="android.permission.READ_EXTERNAL_STORAGE" >
+ <permission name="android.permission.READ_EXTERNAL_STORAGE" perUser="true" >
<group gid="sdcard_r" />
</permission>
- <permission name="android.permission.WRITE_EXTERNAL_STORAGE" >
+ <permission name="android.permission.WRITE_EXTERNAL_STORAGE" perUser="true" >
<group gid="sdcard_r" />
<group gid="sdcard_rw" />
</permission>
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 38321a3d89d1..a0b26f3390b4 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -49,6 +49,8 @@ extra_font_files := \
################################
# Do not include Motoya on space-constrained devices
ifneq ($(SMALLER_FONT_FOOTPRINT),true)
+# Do not include Motoya if we are including full NotoSans
+ifneq ($(FONT_NOTOSANS_FULL),true)
include $(CLEAR_VARS)
LOCAL_MODULE := MTLmr3m.ttf
@@ -59,6 +61,7 @@ LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
include $(BUILD_PREBUILT)
extra_font_files += MTLmr3m.ttf
+endif # !FONT_NOTOSANS_FULL
endif # !SMALLER_FONT_FOOTPRINT
################################
diff --git a/docs/html/google/auth/http-auth.jd b/docs/html/google/auth/http-auth.jd
index 804ba1225e01..7d34d89d04bd 100644
--- a/docs/html/google/auth/http-auth.jd
+++ b/docs/html/google/auth/http-auth.jd
@@ -95,7 +95,7 @@ keytool -exportcert -alias &lt;keystore_alias> -keystore &lt;keystore_path> -lis
</pre>
<p>For example, you're using a debug-key with Eclipse, then the command looks like this:</p>
<pre class="no-pretty-print">
-keytool -exportcert -alias androiddebugkey-keystore ~/.android/debug.keystore -list -v
+keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v
</pre>
<p>Then the keystore password is "android".</p>
</li>
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 17e5b0b6bab1..a56e87ef9efd 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -16,6 +16,8 @@ package android.graphics.drawable;
import android.animation.Animator;
import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
+import android.animation.Animator.AnimatorListener;
import android.annotation.NonNull;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -37,6 +39,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.List;
/**
* This class uses {@link android.animation.ObjectAnimator} and
@@ -47,8 +50,8 @@ import java.util.ArrayList;
* </p>
* <p>
* First is the XML file for {@link android.graphics.drawable.VectorDrawable}.
- * Note that we allow the animation happen on the group's attributes and path's
- * attributes, which requires they are uniquely named in this xml file. Groups
+ * Note that we allow the animation to happen on the group's attributes and path's
+ * attributes, which requires they are uniquely named in this XML file. Groups
* and paths without animations do not need names.
* </p>
* <li>Here is a simple VectorDrawable in this vectordrawable.xml file.
@@ -71,7 +74,7 @@ import java.util.ArrayList;
* &lt;/vector&gt;
* </pre></li>
* <p>
- * Second is the AnimatedVectorDrawable's xml file, which defines the target
+ * Second is the AnimatedVectorDrawable's XML file, which defines the target
* VectorDrawable, the target paths and groups to animate, the properties of the
* path and group to animate and the animations defined as the ObjectAnimators
* or AnimatorSets.
@@ -90,7 +93,7 @@ import java.util.ArrayList;
* &lt;/animated-vector&gt;
* </pre></li>
* <p>
- * Last is the Animator xml file, which is the same as a normal ObjectAnimator
+ * Last is the Animator XML file, which is the same as a normal ObjectAnimator
* or AnimatorSet.
* To complete this example, here are the 2 animator files used in avd.xml:
* rotation.xml and path_morph.xml.
@@ -107,7 +110,7 @@ import java.util.ArrayList;
* the other. Note that the paths must be compatible for morphing.
* In more details, the paths should have exact same length of commands , and
* exact same length of parameters for each commands.
- * Note that the path string are better stored in strings.xml for reusing.
+ * Note that the path strings are better stored in strings.xml for reusing.
* <pre>
* &lt;set xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
* &lt;objectAnimator
@@ -312,6 +315,15 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
eventType = parser.next();
}
+ setupAnimatorSet();
+ }
+
+ private void setupAnimatorSet() {
+ if (mAnimatedVectorState.mTempAnimators != null) {
+ mAnimatedVectorState.mAnimatorSet.playTogether(mAnimatedVectorState.mTempAnimators);
+ mAnimatedVectorState.mTempAnimators.clear();
+ mAnimatedVectorState.mTempAnimators = null;
+ }
}
@Override
@@ -330,10 +342,44 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
}
}
+ /**
+ * Adds a listener to the set of listeners that are sent events through the life of an
+ * animation.
+ *
+ * @param listener the listener to be added to the current set of listeners for this animation.
+ */
+ public void addListener(AnimatorListener listener) {
+ mAnimatedVectorState.mAnimatorSet.addListener(listener);
+ }
+
+ /**
+ * Removes a listener from the set listening to this animation.
+ *
+ * @param listener the listener to be removed from the current set of listeners for this
+ * animation.
+ */
+ public void removeListener(AnimatorListener listener) {
+ mAnimatedVectorState.mAnimatorSet.removeListener(listener);
+ }
+
+ /**
+ * Gets the set of {@link android.animation.Animator.AnimatorListener} objects that are currently
+ * listening for events on this <code>AnimatedVectorDrawable</code> object.
+ *
+ * @return List<AnimatorListener> The set of listeners.
+ */
+ public List<AnimatorListener> getListeners() {
+ return mAnimatedVectorState.mAnimatorSet.getListeners();
+ }
+
private static class AnimatedVectorDrawableState extends ConstantState {
int mChangingConfigurations;
VectorDrawable mVectorDrawable;
- ArrayList<Animator> mAnimators;
+ // Always have a valid animatorSet to handle all the listeners call.
+ AnimatorSet mAnimatorSet = new AnimatorSet();
+ // When parsing the XML, we build individual animator and store in this array. At the end,
+ // we add this array into the mAnimatorSet.
+ private ArrayList<Animator> mTempAnimators;
ArrayMap<Animator, String> mTargetNameMap;
public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy,
@@ -353,18 +399,23 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
mVectorDrawable.setBounds(copy.mVectorDrawable.getBounds());
mVectorDrawable.setAllowCaching(false);
}
- if (copy.mAnimators != null) {
- final int numAnimators = copy.mAnimators.size();
- mAnimators = new ArrayList<Animator>(numAnimators);
+ if (copy.mAnimatorSet != null) {
+ final int numAnimators = copy.mTargetNameMap.size();
+ // Deep copy a animator set, and then setup the target map again.
+ mAnimatorSet = copy.mAnimatorSet.clone();
mTargetNameMap = new ArrayMap<Animator, String>(numAnimators);
+ // Since the new AnimatorSet is cloned from the old one, the order must be the
+ // same inside the array.
+ ArrayList<Animator> oldAnim = copy.mAnimatorSet.getChildAnimations();
+ ArrayList<Animator> newAnim = mAnimatorSet.getChildAnimations();
+
for (int i = 0; i < numAnimators; ++i) {
- Animator anim = copy.mAnimators.get(i);
- Animator animClone = anim.clone();
- String targetName = copy.mTargetNameMap.get(anim);
- Object targetObject = mVectorDrawable.getTargetByName(targetName);
- animClone.setTarget(targetObject);
- mAnimators.add(animClone);
- mTargetNameMap.put(animClone, targetName);
+ // Target name must be the same for new and old
+ String targetName = copy.mTargetNameMap.get(oldAnim.get(i));
+
+ Object newTargetObject = mVectorDrawable.getTargetByName(targetName);
+ newAnim.get(i).setTarget(newTargetObject);
+ mTargetNameMap.put(newAnim.get(i), targetName);
}
}
} else {
@@ -397,11 +448,11 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
private void setupAnimatorsForTarget(String name, Animator animator) {
Object target = mAnimatedVectorState.mVectorDrawable.getTargetByName(name);
animator.setTarget(target);
- if (mAnimatedVectorState.mAnimators == null) {
- mAnimatedVectorState.mAnimators = new ArrayList<Animator>();
+ if (mAnimatedVectorState.mTempAnimators == null) {
+ mAnimatedVectorState.mTempAnimators = new ArrayList<Animator>();
mAnimatedVectorState.mTargetNameMap = new ArrayMap<Animator, String>();
}
- mAnimatedVectorState.mAnimators.add(animator);
+ mAnimatedVectorState.mTempAnimators.add(animator);
mAnimatedVectorState.mTargetNameMap.put(animator, name);
if (DBG_ANIMATION_VECTOR_DRAWABLE) {
Log.v(LOGTAG, "add animator for target " + name + " " + animator);
@@ -410,27 +461,11 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
@Override
public boolean isRunning() {
- final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
- final int size = animators.size();
- for (int i = 0; i < size; i++) {
- final Animator animator = animators.get(i);
- if (animator.isRunning()) {
- return true;
- }
- }
- return false;
+ return mAnimatedVectorState.mAnimatorSet.isRunning();
}
private boolean isStarted() {
- final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
- final int size = animators.size();
- for (int i = 0; i < size; i++) {
- final Animator animator = animators.get(i);
- if (animator.isStarted()) {
- return true;
- }
- }
- return false;
+ return mAnimatedVectorState.mAnimatorSet.isStarted();
}
@Override
@@ -439,24 +474,13 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
if (isStarted()) {
return;
}
- // Otherwise, kick off every animator.
- final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
- final int size = animators.size();
- for (int i = 0; i < size; i++) {
- final Animator animator = animators.get(i);
- animator.start();
- }
+ mAnimatedVectorState.mAnimatorSet.start();
invalidateSelf();
}
@Override
public void stop() {
- final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
- final int size = animators.size();
- for (int i = 0; i < size; i++) {
- final Animator animator = animators.get(i);
- animator.end();
- }
+ mAnimatedVectorState.mAnimatorSet.end();
}
/**
@@ -473,27 +497,14 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
Log.w(LOGTAG, "AnimatedVectorDrawable can't reverse()");
return;
}
- final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
- final int size = animators.size();
- for (int i = 0; i < size; i++) {
- final Animator animator = animators.get(i);
- animator.reverse();
- }
+ mAnimatedVectorState.mAnimatorSet.reverse();
}
/**
* @hide
*/
public boolean canReverse() {
- final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
- final int size = animators.size();
- for (int i = 0; i < size; i++) {
- final Animator animator = animators.get(i);
- if (!animator.canReverse()) {
- return false;
- }
- }
- return true;
+ return mAnimatedVectorState.mAnimatorSet.canReverse();
}
private final Callback mCallback = new Callback() {
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 68ffed658553..dc10a813caa3 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -721,7 +721,7 @@ public class BitmapDrawable extends Drawable {
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.BitmapDrawable);
updateStateFromTypedArray(a);
- verifyState(a);
+ verifyRequiredAttributes(a);
a.recycle();
// Update local properties.
@@ -733,11 +733,13 @@ public class BitmapDrawable extends Drawable {
*
* @throws XmlPullParserException if any required attributes are missing
*/
- private void verifyState(TypedArray a) throws XmlPullParserException {
+ private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
+ // If we're not waiting on a theme, verify required attributes.
final BitmapState state = mBitmapState;
- if (state.mBitmap == null) {
+ if (state.mBitmap == null && (state.mThemeAttrs == null
+ || state.mThemeAttrs[R.styleable.BitmapDrawable_src] == 0)) {
throw new XmlPullParserException(a.getPositionDescription() +
- ": <bitmap> requires a valid src attribute");
+ ": <bitmap> requires a valid 'src' attribute");
}
}
@@ -759,7 +761,7 @@ public class BitmapDrawable extends Drawable {
final Bitmap bitmap = BitmapFactory.decodeResource(r, srcResId);
if (bitmap == null) {
throw new XmlPullParserException(a.getPositionDescription() +
- ": <bitmap> requires a valid src attribute");
+ ": <bitmap> requires a valid 'src' attribute");
}
state.mBitmap = bitmap;
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index c5e53daa09f2..b82768255ca0 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -56,21 +56,21 @@ import java.util.Stack;
* <p/>
* <dt><code>&lt;vector></code></dt>
* <dl>
- * <dd>Used to defined a vector drawable
+ * <dd>Used to define a vector drawable
* <dl>
* <dt><code>android:name</code></dt>
* <dd>Defines the name of this vector drawable.</dd>
* <dt><code>android:width</code></dt>
- * <dd>Used to defined the intrinsic width of the drawable.
+ * <dd>Used to define the intrinsic width of the drawable.
* This support all the dimension units, normally specified with dp.</dd>
* <dt><code>android:height</code></dt>
- * <dd>Used to defined the intrinsic height the drawable.
+ * <dd>Used to define the intrinsic height the drawable.
* This support all the dimension units, normally specified with dp.</dd>
* <dt><code>android:viewportWidth</code></dt>
- * <dd>Used to defined the width of the viewport space. Viewport is basically
+ * <dd>Used to define the width of the viewport space. Viewport is basically
* the virtual canvas where the paths are drawn on.</dd>
* <dt><code>android:viewportHeight</code></dt>
- * <dd>Used to defined the height of the viewport space. Viewport is basically
+ * <dd>Used to define the height of the viewport space. Viewport is basically
* the virtual canvas where the paths are drawn on.</dd>
* <dt><code>android:tint</code></dt>
* <dd>The color to apply to the drawable as a tint. By default, no tint is applied.</dd>
@@ -120,7 +120,7 @@ import java.util.Stack;
* <dt><code>android:name</code></dt>
* <dd>Defines the name of the path.</dd>
* <dt><code>android:pathData</code></dt>
- * <dd>Defines path string. This is using exactly same format as "d" attribute
+ * <dd>Defines path data using exactly same format as "d" attribute
* in the SVG's path data. This is defined in the viewport space.</dd>
* <dt><code>android:fillColor</code></dt>
* <dd>Defines the color to fill the path (none if not present).</dd>
@@ -156,7 +156,7 @@ import java.util.Stack;
* <dt><code>android:name</code></dt>
* <dd>Defines the name of the clip path.</dd>
* <dt><code>android:pathData</code></dt>
- * <dd>Defines clip path string. This is using exactly same format as "d" attribute
+ * <dd>Defines clip path using the same format as "d" attribute
* in the SVG's path data.</dd>
* </dl></dd>
* </dl>
@@ -249,8 +249,8 @@ public class VectorDrawable extends Drawable {
@Override
public void draw(Canvas canvas) {
final Rect bounds = getBounds();
- if (bounds.width() == 0 || bounds.height() == 0) {
- // too small to draw
+ if (bounds.width() <= 0 || bounds.height() <= 0) {
+ // Nothing to draw
return;
}
@@ -805,7 +805,6 @@ public class VectorDrawable extends Drawable {
// is no need for deep copying.
private final Path mPath;
private final Path mRenderPath;
- private static final Matrix IDENTITY_MATRIX = new Matrix();
private final Matrix mFinalPathMatrix = new Matrix();
private Paint mStrokePaint;
@@ -948,7 +947,7 @@ public class VectorDrawable extends Drawable {
public void draw(Canvas canvas, int w, int h, ColorFilter filter) {
// Travese the tree in pre-order to draw.
- drawGroupTree(mRootGroup, IDENTITY_MATRIX, canvas, w, h, filter);
+ drawGroupTree(mRootGroup, Matrix.IDENTITY_MATRIX, canvas, w, h, filter);
}
private void drawPath(VGroup vGroup, VPath vPath, Canvas canvas, int w, int h,
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index bfbf02884498..957e3c15ff47 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -25,6 +25,7 @@ import android.os.ServiceManager;
import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterBlob;
import android.security.keymaster.OperationResult;
import android.util.Log;
@@ -403,7 +404,7 @@ public class KeyStore {
return generateKey(alias, args, UID_SELF, flags, outCharacteristics);
}
- public int getKeyCharacteristics(String alias, byte[] clientId, byte[] appId,
+ public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
KeyCharacteristics outCharacteristics) {
try {
return mBinder.getKeyCharacteristics(alias, clientId, appId, outCharacteristics);
@@ -429,7 +430,8 @@ public class KeyStore {
return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
}
- public ExportResult exportKey(String alias, int format, byte[] clientId, byte[] appId) {
+ public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
+ KeymasterBlob appId) {
try {
return mBinder.exportKey(alias, format, clientId, appId);
} catch (RemoteException e) {
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index f935bb13f2d4..f755bb08a6e4 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -25,6 +25,7 @@ import android.security.KeyStore;
import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterBlob;
import android.security.keymaster.KeymasterDefs;
import android.security.keymaster.OperationResult;
import android.test.ActivityUnitTestCase;
@@ -36,6 +37,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
+import java.security.spec.RSAKeyGenParameterSpec;
import android.util.Log;
import android.util.Base64;
@@ -711,8 +713,8 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
+ args.addLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT,
+ RSAKeyGenParameterSpec.F4.longValue());
KeyCharacteristics outCharacteristics = new KeyCharacteristics();
int result = mKeyStore.generateKey(name, args, 0, outCharacteristics);
@@ -741,6 +743,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
public void testAppId() throws Exception {
String name = "test";
+ byte[] id = new byte[] {0x01, 0x02, 0x03};
KeymasterArguments args = new KeymasterArguments();
args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
@@ -748,8 +751,9 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, new byte[] {0x01, 0x02, 0x03});
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
+ args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, id);
+ args.addLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT,
+ RSAKeyGenParameterSpec.F4.longValue());
KeyCharacteristics outCharacteristics = new KeyCharacteristics();
int result = mKeyStore.generateKey(name, args, 0, outCharacteristics);
@@ -759,7 +763,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
mKeyStore.getKeyCharacteristics(name, null, null, outCharacteristics));
assertEquals("getKeyCharacteristics should succeed with application ID",
KeyStore.NO_ERROR,
- mKeyStore.getKeyCharacteristics(name, new byte[] {0x01, 0x02, 0x03}, null,
+ mKeyStore.getKeyCharacteristics(name, new KeymasterBlob(id), null,
outCharacteristics));
}
@@ -784,8 +788,6 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_OCB);
args.addInt(KeymasterDefs.KM_TAG_CHUNK_LENGTH, 4096);
args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, 16);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
KeyCharacteristics outCharacteristics = new KeyCharacteristics();
int rc = mKeyStore.generateKey(name, args, 0, outCharacteristics);
@@ -793,8 +795,6 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
KeymasterArguments out = new KeymasterArguments();
args = new KeymasterArguments();
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT,
true, args, out);
IBinder token = result.token;
@@ -883,8 +883,6 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_OCB);
args.addInt(KeymasterDefs.KM_TAG_CHUNK_LENGTH, 4096);
args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, 16);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
KeyCharacteristics outCharacteristics = new KeyCharacteristics();
int rc = mKeyStore.generateKey(name, args, 0, outCharacteristics);
@@ -892,8 +890,6 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
KeymasterArguments out = new KeymasterArguments();
args = new KeymasterArguments();
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
- args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT,
true, args, out);
assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 2a673f4bc6fc..8757e15006b7 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -484,7 +484,7 @@ void DisplayListRenderer::drawRects(const float* rects, int count, const SkPaint
}
void DisplayListRenderer::setDrawFilter(SkDrawFilter* filter) {
- mDrawFilter.reset(filter);
+ mDrawFilter.reset(SkSafeRef(filter));
}
void DisplayListRenderer::insertReorderBarrier(bool enableReorder) {
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 48ecd698bd91..53fd1adbeb14 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -296,8 +296,9 @@ private:
// so that we don't need to modify the paint every time we access it.
SkTLazy<SkPaint> filteredPaint;
if (mDrawFilter.get()) {
- paint = filteredPaint.init();
+ filteredPaint.set(*paint);
mDrawFilter->filter(filteredPaint.get(), SkDrawFilter::kPaint_Type);
+ paint = filteredPaint.get();
}
// compute the hash key for the paint and check the cache.
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index 9509c48038cf..30d3f41b0eed 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -197,6 +197,7 @@ bool ShadowTessellator::isClockwisePath(const SkPath& path) {
case SkPath::kLine_Verb:
arrayForDirection.add((Vector2){pts[1].x(), pts[1].y()});
break;
+ case SkPath::kConic_Verb:
case SkPath::kQuad_Verb:
arrayForDirection.add((Vector2){pts[1].x(), pts[1].y()});
arrayForDirection.add((Vector2){pts[2].x(), pts[2].y()});
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index 66de33380413..d9d06bf8560e 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -380,6 +380,7 @@ void TessellationCache::precacheShadows(const Matrix4* drawTransform, const Rect
const Vector3& lightCenter, float lightRadius) {
ShadowDescription key(casterPerimeter, drawTransform);
+ if (mShadowCache.get(key)) return;
sp<ShadowTask> task = new ShadowTask(drawTransform, localClip, opaque,
casterPerimeter, transformXY, transformZ, lightCenter, lightRadius);
if (mShadowProcessor == nullptr) {
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index ea4216c1c986..0091790c44bd 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -418,6 +418,7 @@ CREATE_BRIDGE2(dumpGraphicsMemory, int fd, RenderThread* thread) {
}
void RenderProxy::dumpGraphicsMemory(int fd) {
+ if (!RenderThread::hasInstance()) return;
SETUP_TASK(dumpGraphicsMemory);
args->fd = fd;
args->thread = &RenderThread::getInstance();
diff --git a/libs/hwui/thread/Signal.h b/libs/hwui/thread/Signal.h
index dcf54498b9f5..d4cfeeb29c17 100644
--- a/libs/hwui/thread/Signal.h
+++ b/libs/hwui/thread/Signal.h
@@ -30,8 +30,10 @@ public:
~Signal() { }
void signal() {
- Mutex::Autolock l(mLock);
- mSignaled = true;
+ {
+ Mutex::Autolock l(mLock);
+ mSignaled = true;
+ }
mCondition.signal(mType);
}
diff --git a/libs/hwui/thread/TaskManager.cpp b/libs/hwui/thread/TaskManager.cpp
index c69b2fd56383..f0ed0bbfedc1 100644
--- a/libs/hwui/thread/TaskManager.cpp
+++ b/libs/hwui/thread/TaskManager.cpp
@@ -109,8 +109,11 @@ bool TaskManager::WorkerThread::addTask(TaskWrapper task) {
return false;
}
- Mutex::Autolock l(mLock);
- ssize_t index = mTasks.add(task);
+ ssize_t index;
+ {
+ Mutex::Autolock l(mLock);
+ index = mTasks.add(task);
+ }
mSignal.signal();
return index >= 0;
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 28941b908cb3..cb70e8b722a9 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -134,6 +134,22 @@ public class AudioManager {
public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
/**
+ * @hide Broadcast intent when the devices for a particular stream type changes.
+ * Includes the stream, the new devices and previous devices.
+ * Notes:
+ * - for internal platform use only, do not make public,
+ * - never used for "remote" volume changes
+ *
+ * @see #EXTRA_VOLUME_STREAM_TYPE
+ * @see #EXTRA_VOLUME_STREAM_DEVICES
+ * @see #EXTRA_PREV_VOLUME_STREAM_DEVICES
+ * @see #getDevicesForStream
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String STREAM_DEVICES_CHANGED_ACTION =
+ "android.media.STREAM_DEVICES_CHANGED_ACTION";
+
+ /**
* @hide Broadcast intent when a stream mute state changes.
* Includes the stream that changed and the new mute state
*
@@ -196,6 +212,18 @@ public class AudioManager {
"android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
/**
+ * @hide The devices associated with the stream for the stream devices changed intent.
+ */
+ public static final String EXTRA_VOLUME_STREAM_DEVICES =
+ "android.media.EXTRA_VOLUME_STREAM_DEVICES";
+
+ /**
+ * @hide The previous devices associated with the stream for the stream devices changed intent.
+ */
+ public static final String EXTRA_PREV_VOLUME_STREAM_DEVICES =
+ "android.media.EXTRA_PREV_VOLUME_STREAM_DEVICES";
+
+ /**
* @hide The new master volume mute state for the master mute changed intent.
* Value is boolean
*/
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 259fe37884e6..99b7bee562a4 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -20,6 +20,7 @@ import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.util.Iterator;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Binder;
import android.os.Handler;
@@ -313,8 +314,14 @@ public class AudioRecord
audioParamCheck(attributes.getCapturePreset(), rate, encoding);
- mChannelCount = AudioFormat.channelCountFromInChannelMask(format.getChannelMask());
- mChannelMask = getChannelMaskFromLegacyConfig(format.getChannelMask(), false);
+ int channelMask = AudioFormat.CHANNEL_IN_DEFAULT;
+ if ((format.getPropertySetMask()
+ & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0)
+ {
+ channelMask = format.getChannelMask();
+ }
+ mChannelCount = AudioFormat.channelCountFromInChannelMask(channelMask);
+ mChannelMask = getChannelMaskFromLegacyConfig(channelMask, false);
audioBuffSizeCheck(bufferSizeInBytes);
@@ -335,6 +342,161 @@ public class AudioRecord
mState = STATE_INITIALIZED;
}
+ /**
+ * Builder class for {@link AudioRecord} objects.
+ * Use this class to configure and create an <code>AudioRecord</code> instance. By setting the
+ * recording preset (a.k.a. recording source) and audio format parameters, you indicate which of
+ * those vary from the default behavior on the device.
+ * <p> Here is an example where <code>Builder</code> is used to specify all {@link AudioFormat}
+ * parameters, to be used by a new <code>AudioRecord</code> instance:
+ *
+ * <pre class="prettyprint">
+ * AudioRecord recorder = new AudioRecord.Builder()
+ * .setCapturePreset(MediaRecorder.AudioSource.VOICE_COMMUNICATION)
+ * .setAudioFormat(new AudioFormat.Builder()
+ * .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
+ * .setSampleRate(32000)
+ * .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
+ * .build())
+ * .setBufferSize(2*minBuffSize)
+ * .build();
+ * </pre>
+ * <p>
+ * If the capture preset is not set with {@link #setCapturePreset(int)},
+ * {@link MediaRecorder.AudioSource#DEFAULT} is used.
+ * <br>If the audio format is not specified or is incomplete, its sample rate will be the
+ * default output sample rate of the device (see
+ * {@link AudioManager#PROPERTY_OUTPUT_SAMPLE_RATE}), its channel configuration will be
+ * {@link AudioFormat#CHANNEL_IN_DEFAULT}.
+ * <br>Failing to set an adequate buffer size with {@link #setBufferSizeInBytes(int)} will
+ * prevent the successful creation of an <code>AudioRecord</code> instance.
+ */
+ public static class Builder {
+ private AudioAttributes mAttributes;
+ private AudioFormat mFormat;
+ private int mBufferSizeInBytes;
+ private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
+
+ /**
+ * Constructs a new Builder with the default values as described above.
+ */
+ public Builder() {
+ }
+
+ /**
+ * @param preset the capture preset (also referred to as the recording source).
+ * See {@link MediaRecorder.AudioSource} for the supported capture preset definitions.
+ * @return the same Builder instance.
+ * @throws IllegalArgumentException
+ */
+ public Builder setCapturePreset(int preset) throws IllegalArgumentException {
+ if ( (preset < MediaRecorder.AudioSource.DEFAULT) ||
+ (preset > MediaRecorder.getAudioSourceMax()) ) {
+ throw new IllegalArgumentException("Invalid audio source " + preset);
+ }
+ mAttributes = new AudioAttributes.Builder()
+ .setInternalCapturePreset(preset)
+ .build();
+ return this;
+ }
+
+ /**
+ * @hide
+ * To be only used by system components. Allows specifying non-public capture presets
+ * @param attributes a non-null {@link AudioAttributes} instance that contains the capture
+ * preset to be used.
+ * @return the same Builder instance.
+ * @throws IllegalArgumentException
+ */
+ @SystemApi
+ public Builder setAudioAttributes(@NonNull AudioAttributes attributes)
+ throws IllegalArgumentException {
+ if (attributes == null) {
+ throw new IllegalArgumentException("Illegal null AudioAttributes argument");
+ }
+ if (attributes.getCapturePreset() == MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID) {
+ throw new IllegalArgumentException(
+ "No valid capture preset in AudioAttributes argument");
+ }
+ // keep reference, we only copy the data when building
+ mAttributes = attributes;
+ return this;
+ }
+
+ /**
+ * Sets the format of the audio data to be captured.
+ * @param format a non-null {@link AudioFormat} instance
+ * @return the same Builder instance.
+ * @throws IllegalArgumentException
+ */
+ public Builder setAudioFormat(@NonNull AudioFormat format) throws IllegalArgumentException {
+ if (format == null) {
+ throw new IllegalArgumentException("Illegal null AudioFormat argument");
+ }
+ // keep reference, we only copy the data when building
+ mFormat = format;
+ return this;
+ }
+
+ /**
+ * Sets the total size (in bytes) of the buffer where audio data is written
+ * during the recording. New audio data can be read from this buffer in smaller chunks
+ * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
+ * required buffer size for the successful creation of an AudioRecord instance.
+ * Using values smaller than getMinBufferSize() will result in an initialization failure.
+ * @param bufferSizeInBytes a value strictly greater than 0
+ * @return the same Builder instance.
+ * @throws IllegalArgumentException
+ */
+ public Builder setBufferSizeInBytes(int bufferSizeInBytes) throws IllegalArgumentException {
+ if (bufferSizeInBytes <= 0) {
+ throw new IllegalArgumentException("Invalid buffer size " + bufferSizeInBytes);
+ }
+ mBufferSizeInBytes = bufferSizeInBytes;
+ return this;
+ }
+
+ /**
+ * @hide
+ * To be only used by system components.
+ * @param sessionId ID of audio session the AudioRecord must be attached to, or
+ * {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at
+ * construction time.
+ * @return the same Builder instance.
+ * @throws IllegalArgumentException
+ */
+ @SystemApi
+ public Builder setSessionId(int sessionId) throws IllegalArgumentException {
+ if (sessionId < 0) {
+ throw new IllegalArgumentException("Invalid session ID " + sessionId);
+ }
+ mSessionId = sessionId;
+ return this;
+ }
+
+ /**
+ * @return a new {@link AudioRecord} instance initialized with all the parameters set
+ * on this <code>Builder</code>
+ * @throws UnsupportedOperationException if the parameters set on the <code>Builder</code>
+ * were incompatible, or if they are not supported by the device.
+ */
+ public AudioRecord build() throws UnsupportedOperationException {
+ if (mFormat == null) {
+ mFormat = new AudioFormat.Builder().build();
+ }
+ if (mAttributes == null) {
+ mAttributes = new AudioAttributes.Builder()
+ .setInternalCapturePreset(MediaRecorder.AudioSource.DEFAULT)
+ .build();
+ }
+ try {
+ return new AudioRecord(mAttributes, mFormat, mBufferSizeInBytes, mSessionId);
+ } catch (IllegalArgumentException e) {
+ throw new UnsupportedOperationException(e.getMessage());
+ }
+ }
+ }
+
// Convenience method for the constructor's parameter checks.
// This, getChannelMaskFromLegacyConfig and audioBuffSizeCheck are where constructor
// IllegalArgumentException-s are thrown
diff --git a/media/java/android/media/MediaDescription.java b/media/java/android/media/MediaDescription.java
index ddbffc2d7f0d..afc3ca7ef5f8 100644
--- a/media/java/android/media/MediaDescription.java
+++ b/media/java/android/media/MediaDescription.java
@@ -41,9 +41,13 @@ public class MediaDescription implements Parcelable {
* Extras for opaque use by apps/system.
*/
private final Bundle mExtras;
+ /**
+ * A Uri to identify this content.
+ */
+ private final Uri mMediaUri;
private MediaDescription(String mediaId, CharSequence title, CharSequence subtitle,
- CharSequence description, Bitmap icon, Uri iconUri, Bundle extras) {
+ CharSequence description, Bitmap icon, Uri iconUri, Bundle extras, Uri mediaUri) {
mMediaId = mediaId;
mTitle = title;
mSubtitle = subtitle;
@@ -51,6 +55,7 @@ public class MediaDescription implements Parcelable {
mIcon = icon;
mIconUri = iconUri;
mExtras = extras;
+ mMediaUri = mediaUri;
}
private MediaDescription(Parcel in) {
@@ -61,6 +66,7 @@ public class MediaDescription implements Parcelable {
mIcon = in.readParcelable(null);
mIconUri = in.readParcelable(null);
mExtras = in.readBundle();
+ mMediaUri = in.readParcelable(null);
}
/**
@@ -125,6 +131,15 @@ public class MediaDescription implements Parcelable {
return mExtras;
}
+ /**
+ * Returns a Uri representing this content or null.
+ *
+ * @return A media Uri or null.
+ */
+ public @Nullable Uri getMediaUri() {
+ return mMediaUri;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -139,6 +154,7 @@ public class MediaDescription implements Parcelable {
dest.writeParcelable(mIcon, flags);
dest.writeParcelable(mIconUri, flags);
dest.writeBundle(mExtras);
+ dest.writeParcelable(mMediaUri, flags);
}
@Override
@@ -170,6 +186,7 @@ public class MediaDescription implements Parcelable {
private Bitmap mIcon;
private Uri mIconUri;
private Bundle mExtras;
+ private Uri mMediaUri;
/**
* Creates an initially empty builder.
@@ -257,9 +274,20 @@ public class MediaDescription implements Parcelable {
return this;
}
+ /**
+ * Sets the media uri.
+ *
+ * @param mediaUri The content's {@link Uri} for the item or null.
+ * @return this
+ */
+ public Builder setMediaUri(@Nullable Uri mediaUri) {
+ mMediaUri = mediaUri;
+ return this;
+ }
+
public MediaDescription build() {
return new MediaDescription(mMediaId, mTitle, mSubtitle, mDescription, mIcon, mIconUri,
- mExtras);
+ mExtras, mMediaUri);
}
}
}
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 6b37a34c2895..069f7ff0d3a0 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -82,6 +82,10 @@ import android.util.Log;
* encrypted content, the samples returned from the extractor remain encrypted, they
* are only decrypted when the samples are delivered to the decoder.
* <p>
+ * MediaDrm methods throw {@link java.lang.IllegalStateException}
+ * when a method is called on a MediaDrm object that is in an invalid or inoperable
+ * state. This is typically due to incorrect application API usage, but may also
+ * be due to an unrecoverable failure in the DRM plugin or security hardware.
* <a name="Callbacks"></a>
* <h3>Callbacks</h3>
* <p>Applications should register for informational events in order
@@ -383,11 +387,27 @@ public final class MediaDrm {
public static final int KEY_TYPE_RELEASE = 3;
/**
+ * Key request type is initial license request
+ */
+ public static final int REQUEST_TYPE_INITIAL = 0;
+
+ /**
+ * Key request type is license renewal
+ */
+ public static final int REQUEST_TYPE_RENEWAL = 1;
+
+ /**
+ * Key request type is license release
+ */
+ public static final int REQUEST_TYPE_RELEASE = 2;
+
+ /**
* Contains the opaque data an app uses to request keys from a license server
*/
public final static class KeyRequest {
private byte[] mData;
private String mDefaultUrl;
+ private int mRequestType;
KeyRequest() {}
@@ -402,6 +422,11 @@ public final class MediaDrm {
* server URL from other sources.
*/
public String getDefaultUrl() { return mDefaultUrl; }
+
+ /**
+ * Get the type of the request
+ */
+ public int getRequestType() { return mRequestType; }
};
/**
@@ -460,7 +485,6 @@ public final class MediaDrm {
* reprovisioning is required
* @throws DeniedByServerException if the response indicates that the
* server rejected the request
- * @throws ResourceBusyException if required resources are in use
*/
public native byte[] provideKeyResponse(byte[] scope, byte[] response)
throws NotProvisionedException, DeniedByServerException;
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 58c86f20605a..058cfd263386 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -157,8 +157,11 @@ public class MediaRecorder
}
/**
- * Defines the audio source. These constants are used with
- * {@link MediaRecorder#setAudioSource(int)}.
+ * Defines the audio source.
+ * An audio source defines both a default physical source of audio signal, and a recording
+ * configuration; it's also known as a capture preset. These constants are for instance used
+ * in {@link MediaRecorder#setAudioSource(int)} or
+ * {@link AudioRecord.Builder#setCapturePreset(int)}.
*/
public final class AudioSource {
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index b4c612ae1ace..c227eb7fd276 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -1500,18 +1500,18 @@ public class MediaRouter {
/**
* The default playback type, "local", indicating the presentation of the media is happening
- * on the same device (e.g. a phone, a tablet) as where it is controlled from.
+ * on the same device (e&#46;g&#46; a phone, a tablet) as where it is controlled from.
* @see #getPlaybackType()
*/
public final static int PLAYBACK_TYPE_LOCAL = 0;
/**
* A playback type indicating the presentation of the media is happening on
- * a different device (i.e. the remote device) than where it is controlled from.
+ * a different device (i&#46;e&#46; the remote device) than where it is controlled from.
* @see #getPlaybackType()
*/
public final static int PLAYBACK_TYPE_REMOTE = 1;
/**
- * Playback information indicating the playback volume is fixed, i.e. it cannot be
+ * Playback information indicating the playback volume is fixed, i&#46;e&#46; it cannot be
* controlled from this object. An example of fixed playback volume is a remote player,
* playing over HDMI where the user prefers to control the volume on the HDMI sink, rather
* than attenuate at the source.
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index db6b38b3967e..88d979e06907 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -32,7 +32,6 @@ import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemProperties;
import android.util.AndroidRuntimeException;
import android.util.Log;
@@ -112,7 +111,24 @@ import com.android.internal.app.IAppOpsService;
* resumes.</p>
*/
public class SoundPool {
- private final SoundPoolDelegate mImpl;
+ static { System.loadLibrary("soundpool"); }
+
+ // SoundPool messages
+ //
+ // must match SoundPool.h
+ private static final int SAMPLE_LOADED = 1;
+
+ private final static String TAG = "SoundPool";
+ private final static boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private long mNativeContext; // accessed by native methods
+
+ private EventHandler mEventHandler;
+ private SoundPool.OnLoadCompleteListener mOnLoadCompleteListener;
+
+ private final Object mLock;
+ private final AudioAttributes mAttributes;
+ private final IAppOpsService mAppOps;
/**
* Constructor. Constructs a SoundPool object with the following
@@ -135,68 +151,26 @@ public class SoundPool {
}
private SoundPool(int maxStreams, AudioAttributes attributes) {
- if (SystemProperties.getBoolean("config.disable_media", false)) {
- mImpl = new SoundPoolStub();
- } else {
- mImpl = new SoundPoolImpl(this, maxStreams, attributes);
+ // do native setup
+ if (native_setup(new WeakReference<SoundPool>(this), maxStreams, attributes) != 0) {
+ throw new RuntimeException("Native setup failed");
}
+ mLock = new Object();
+ mAttributes = attributes;
+ IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
+ mAppOps = IAppOpsService.Stub.asInterface(b);
}
/**
- * Builder class for {@link SoundPool} objects.
+ * Release the SoundPool resources.
+ *
+ * Release all memory and native resources used by the SoundPool
+ * object. The SoundPool can no longer be used and the reference
+ * should be set to null.
*/
- public static class Builder {
- private int mMaxStreams = 1;
- private AudioAttributes mAudioAttributes;
+ public native final void release();
- /**
- * Constructs a new Builder with the defaults format values.
- * If not provided, the maximum number of streams is 1 (see {@link #setMaxStreams(int)} to
- * change it), and the audio attributes have a usage value of
- * {@link AudioAttributes#USAGE_MEDIA} (see {@link #setAudioAttributes(AudioAttributes)} to
- * change them).
- */
- public Builder() {
- }
-
- /**
- * Sets the maximum of number of simultaneous streams that can be played simultaneously.
- * @param maxStreams a value equal to 1 or greater.
- * @return the same Builder instance
- * @throws IllegalArgumentException
- */
- public Builder setMaxStreams(int maxStreams) throws IllegalArgumentException {
- if (maxStreams <= 0) {
- throw new IllegalArgumentException(
- "Strictly positive value required for the maximum number of streams");
- }
- mMaxStreams = maxStreams;
- return this;
- }
-
- /**
- * Sets the {@link AudioAttributes}. For examples, game applications will use attributes
- * built with usage information set to {@link AudioAttributes#USAGE_GAME}.
- * @param attributes a non-null
- * @return
- */
- public Builder setAudioAttributes(AudioAttributes attributes)
- throws IllegalArgumentException {
- if (attributes == null) {
- throw new IllegalArgumentException("Invalid null AudioAttributes");
- }
- mAudioAttributes = attributes;
- return this;
- }
-
- public SoundPool build() {
- if (mAudioAttributes == null) {
- mAudioAttributes = new AudioAttributes.Builder()
- .setUsage(AudioAttributes.USAGE_MEDIA).build();
- }
- return new SoundPool(mMaxStreams, mAudioAttributes);
- }
- }
+ protected void finalize() { release(); }
/**
* Load the sound from the specified path.
@@ -207,7 +181,19 @@ public class SoundPool {
* @return a sound ID. This value can be used to play or unload the sound.
*/
public int load(String path, int priority) {
- return mImpl.load(path, priority);
+ int id = 0;
+ try {
+ File f = new File(path);
+ ParcelFileDescriptor fd = ParcelFileDescriptor.open(f,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ if (fd != null) {
+ id = _load(fd.getFileDescriptor(), 0, f.length(), priority);
+ fd.close();
+ }
+ } catch (java.io.IOException e) {
+ Log.e(TAG, "error loading " + path);
+ }
+ return id;
}
/**
@@ -226,7 +212,17 @@ public class SoundPool {
* @return a sound ID. This value can be used to play or unload the sound.
*/
public int load(Context context, int resId, int priority) {
- return mImpl.load(context, resId, priority);
+ AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId);
+ int id = 0;
+ if (afd != null) {
+ id = _load(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength(), priority);
+ try {
+ afd.close();
+ } catch (java.io.IOException ex) {
+ //Log.d(TAG, "close failed:", ex);
+ }
+ }
+ return id;
}
/**
@@ -238,7 +234,15 @@ public class SoundPool {
* @return a sound ID. This value can be used to play or unload the sound.
*/
public int load(AssetFileDescriptor afd, int priority) {
- return mImpl.load(afd, priority);
+ if (afd != null) {
+ long len = afd.getLength();
+ if (len < 0) {
+ throw new AndroidRuntimeException("no length for fd");
+ }
+ return _load(afd.getFileDescriptor(), afd.getStartOffset(), len, priority);
+ } else {
+ return 0;
+ }
}
/**
@@ -256,7 +260,7 @@ public class SoundPool {
* @return a sound ID. This value can be used to play or unload the sound.
*/
public int load(FileDescriptor fd, long offset, long length, int priority) {
- return mImpl.load(fd, offset, length, priority);
+ return _load(fd, offset, length, priority);
}
/**
@@ -269,9 +273,7 @@ public class SoundPool {
* @param soundID a soundID returned by the load() function
* @return true if just unloaded, false if previously unloaded
*/
- public final boolean unload(int soundID) {
- return mImpl.unload(soundID);
- }
+ public native final boolean unload(int soundID);
/**
* Play a sound from a sound ID.
@@ -299,8 +301,10 @@ public class SoundPool {
*/
public final int play(int soundID, float leftVolume, float rightVolume,
int priority, int loop, float rate) {
- return mImpl.play(
- soundID, leftVolume, rightVolume, priority, loop, rate);
+ if (isRestricted()) {
+ leftVolume = rightVolume = 0;
+ }
+ return _play(soundID, leftVolume, rightVolume, priority, loop, rate);
}
/**
@@ -314,9 +318,7 @@ public class SoundPool {
*
* @param streamID a streamID returned by the play() function
*/
- public final void pause(int streamID) {
- mImpl.pause(streamID);
- }
+ public native final void pause(int streamID);
/**
* Resume a playback stream.
@@ -328,9 +330,7 @@ public class SoundPool {
*
* @param streamID a streamID returned by the play() function
*/
- public final void resume(int streamID) {
- mImpl.resume(streamID);
- }
+ public native final void resume(int streamID);
/**
* Pause all active streams.
@@ -340,9 +340,7 @@ public class SoundPool {
* are playing. It also sets a flag so that any streams that
* are playing can be resumed by calling autoResume().
*/
- public final void autoPause() {
- mImpl.autoPause();
- }
+ public native final void autoPause();
/**
* Resume all previously active streams.
@@ -350,9 +348,7 @@ public class SoundPool {
* Automatically resumes all streams that were paused in previous
* calls to autoPause().
*/
- public final void autoResume() {
- mImpl.autoResume();
- }
+ public native final void autoResume();
/**
* Stop a playback stream.
@@ -365,9 +361,7 @@ public class SoundPool {
*
* @param streamID a streamID returned by the play() function
*/
- public final void stop(int streamID) {
- mImpl.stop(streamID);
- }
+ public native final void stop(int streamID);
/**
* Set stream volume.
@@ -381,9 +375,11 @@ public class SoundPool {
* @param leftVolume left volume value (range = 0.0 to 1.0)
* @param rightVolume right volume value (range = 0.0 to 1.0)
*/
- public final void setVolume(int streamID,
- float leftVolume, float rightVolume) {
- mImpl.setVolume(streamID, leftVolume, rightVolume);
+ public final void setVolume(int streamID, float leftVolume, float rightVolume) {
+ if (isRestricted()) {
+ return;
+ }
+ _setVolume(streamID, leftVolume, rightVolume);
}
/**
@@ -404,9 +400,7 @@ public class SoundPool {
*
* @param streamID a streamID returned by the play() function
*/
- public final void setPriority(int streamID, int priority) {
- mImpl.setPriority(streamID, priority);
- }
+ public native final void setPriority(int streamID, int priority);
/**
* Set loop mode.
@@ -419,9 +413,7 @@ public class SoundPool {
* @param streamID a streamID returned by the play() function
* @param loop loop mode (0 = no loop, -1 = loop forever)
*/
- public final void setLoop(int streamID, int loop) {
- mImpl.setLoop(streamID, loop);
- }
+ public native final void setLoop(int streamID, int loop);
/**
* Change playback rate.
@@ -435,9 +427,7 @@ public class SoundPool {
* @param streamID a streamID returned by the play() function
* @param rate playback rate (1.0 = normal playback, range 0.5 to 2.0)
*/
- public final void setRate(int streamID, float rate) {
- mImpl.setRate(streamID, rate);
- }
+ public native final void setRate(int streamID, float rate);
public interface OnLoadCompleteListener {
/**
@@ -454,356 +444,137 @@ public class SoundPool {
* Sets the callback hook for the OnLoadCompleteListener.
*/
public void setOnLoadCompleteListener(OnLoadCompleteListener listener) {
- mImpl.setOnLoadCompleteListener(listener);
- }
-
- /**
- * Release the SoundPool resources.
- *
- * Release all memory and native resources used by the SoundPool
- * object. The SoundPool can no longer be used and the reference
- * should be set to null.
- */
- public final void release() {
- mImpl.release();
- }
-
- /**
- * Interface for SoundPool implementations.
- * SoundPool is statically referenced and unconditionally called from all
- * over the framework, so we can't simply omit the class or make it throw
- * runtime exceptions, as doing so would break the framework. Instead we
- * now select either a real or no-op impl object based on whether media is
- * enabled.
- *
- * @hide
- */
- /* package */ interface SoundPoolDelegate {
- public int load(String path, int priority);
- public int load(Context context, int resId, int priority);
- public int load(AssetFileDescriptor afd, int priority);
- public int load(
- FileDescriptor fd, long offset, long length, int priority);
- public boolean unload(int soundID);
- public int play(
- int soundID, float leftVolume, float rightVolume,
- int priority, int loop, float rate);
- public void pause(int streamID);
- public void resume(int streamID);
- public void autoPause();
- public void autoResume();
- public void stop(int streamID);
- public void setVolume(int streamID, float leftVolume, float rightVolume);
- public void setVolume(int streamID, float volume);
- public void setPriority(int streamID, int priority);
- public void setLoop(int streamID, int loop);
- public void setRate(int streamID, float rate);
- public void setOnLoadCompleteListener(OnLoadCompleteListener listener);
- public void release();
- }
-
-
- /**
- * Real implementation of the delegate interface. This was formerly the
- * body of SoundPool itself.
- */
- /* package */ static class SoundPoolImpl implements SoundPoolDelegate {
- static { System.loadLibrary("soundpool"); }
-
- private final static String TAG = "SoundPool";
- private final static boolean DEBUG = false;
-
- private long mNativeContext; // accessed by native methods
-
- private EventHandler mEventHandler;
- private SoundPool.OnLoadCompleteListener mOnLoadCompleteListener;
- private SoundPool mProxy;
-
- private final Object mLock;
- private final AudioAttributes mAttributes;
- private final IAppOpsService mAppOps;
-
- // SoundPool messages
- //
- // must match SoundPool.h
- private static final int SAMPLE_LOADED = 1;
-
- public SoundPoolImpl(SoundPool proxy, int maxStreams, AudioAttributes attr) {
-
- // do native setup
- if (native_setup(new WeakReference(this), maxStreams, attr) != 0) {
- throw new RuntimeException("Native setup failed");
- }
- mLock = new Object();
- mProxy = proxy;
- mAttributes = attr;
- IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
- mAppOps = IAppOpsService.Stub.asInterface(b);
- }
-
- public int load(String path, int priority)
- {
- int id = 0;
- try {
- File f = new File(path);
- ParcelFileDescriptor fd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
- if (fd != null) {
- id = _load(fd.getFileDescriptor(), 0, f.length(), priority);
- fd.close();
- }
- } catch (java.io.IOException e) {
- Log.e(TAG, "error loading " + path);
- }
- return id;
- }
-
- @Override
- public int load(Context context, int resId, int priority) {
- AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId);
- int id = 0;
- if (afd != null) {
- id = _load(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength(), priority);
- try {
- afd.close();
- } catch (java.io.IOException ex) {
- //Log.d(TAG, "close failed:", ex);
- }
- }
- return id;
- }
-
- @Override
- public int load(AssetFileDescriptor afd, int priority) {
- if (afd != null) {
- long len = afd.getLength();
- if (len < 0) {
- throw new AndroidRuntimeException("no length for fd");
+ synchronized(mLock) {
+ if (listener != null) {
+ // setup message handler
+ Looper looper;
+ if ((looper = Looper.myLooper()) != null) {
+ mEventHandler = new EventHandler(looper);
+ } else if ((looper = Looper.getMainLooper()) != null) {
+ mEventHandler = new EventHandler(looper);
+ } else {
+ mEventHandler = null;
}
- return _load(afd.getFileDescriptor(), afd.getStartOffset(), len, priority);
} else {
- return 0;
+ mEventHandler = null;
}
+ mOnLoadCompleteListener = listener;
}
+ }
- @Override
- public int load(FileDescriptor fd, long offset, long length, int priority) {
- return _load(fd, offset, length, priority);
- }
-
- private native final int _load(FileDescriptor fd, long offset, long length, int priority);
-
- @Override
- public native final boolean unload(int soundID);
-
- @Override
- public final int play(int soundID, float leftVolume, float rightVolume,
- int priority, int loop, float rate) {
- if (isRestricted()) {
- leftVolume = rightVolume = 0;
- }
- return _play(soundID, leftVolume, rightVolume, priority, loop, rate);
+ private boolean isRestricted() {
+ if ((mAttributes.getFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
+ return false;
}
-
- public native final int _play(int soundID, float leftVolume, float rightVolume,
- int priority, int loop, float rate);
-
- private boolean isRestricted() {
- if ((mAttributes.getFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
- return false;
- }
- try {
- final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO,
- mAttributes.getUsage(),
- Process.myUid(), ActivityThread.currentPackageName());
- return mode != AppOpsManager.MODE_ALLOWED;
- } catch (RemoteException e) {
- return false;
- }
+ try {
+ final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO,
+ mAttributes.getUsage(),
+ Process.myUid(), ActivityThread.currentPackageName());
+ return mode != AppOpsManager.MODE_ALLOWED;
+ } catch (RemoteException e) {
+ return false;
}
+ }
- @Override
- public native final void pause(int streamID);
+ private native final int _load(FileDescriptor fd, long offset, long length, int priority);
- @Override
- public native final void resume(int streamID);
+ private native final int native_setup(Object weakRef, int maxStreams,
+ Object/*AudioAttributes*/ attributes);
- @Override
- public native final void autoPause();
+ private native final int _play(int soundID, float leftVolume, float rightVolume,
+ int priority, int loop, float rate);
- @Override
- public native final void autoResume();
+ private native final void _setVolume(int streamID, float leftVolume, float rightVolume);
- @Override
- public native final void stop(int streamID);
+ // post event from native code to message handler
+ @SuppressWarnings("unchecked")
+ private static void postEventFromNative(Object ref, int msg, int arg1, int arg2, Object obj) {
+ SoundPool soundPool = ((WeakReference<SoundPool>) ref).get();
+ if (soundPool == null)
+ return;
- @Override
- public final void setVolume(int streamID, float leftVolume, float rightVolume) {
- if (isRestricted()) {
- return;
- }
- _setVolume(streamID, leftVolume, rightVolume);
+ if (soundPool.mEventHandler != null) {
+ Message m = soundPool.mEventHandler.obtainMessage(msg, arg1, arg2, obj);
+ soundPool.mEventHandler.sendMessage(m);
}
+ }
- private native final void _setVolume(int streamID, float leftVolume, float rightVolume);
-
- @Override
- public void setVolume(int streamID, float volume) {
- setVolume(streamID, volume, volume);
+ private final class EventHandler extends Handler {
+ public EventHandler(Looper looper) {
+ super(looper);
}
@Override
- public native final void setPriority(int streamID, int priority);
-
- @Override
- public native final void setLoop(int streamID, int loop);
-
- @Override
- public native final void setRate(int streamID, float rate);
-
- @Override
- public void setOnLoadCompleteListener(SoundPool.OnLoadCompleteListener listener)
- {
- synchronized(mLock) {
- if (listener != null) {
- // setup message handler
- Looper looper;
- if ((looper = Looper.myLooper()) != null) {
- mEventHandler = new EventHandler(mProxy, looper);
- } else if ((looper = Looper.getMainLooper()) != null) {
- mEventHandler = new EventHandler(mProxy, looper);
- } else {
- mEventHandler = null;
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ case SAMPLE_LOADED:
+ if (DEBUG) Log.d(TAG, "Sample " + msg.arg1 + " loaded");
+ synchronized(mLock) {
+ if (mOnLoadCompleteListener != null) {
+ mOnLoadCompleteListener.onLoadComplete(SoundPool.this, msg.arg1, msg.arg2);
}
- } else {
- mEventHandler = null;
}
- mOnLoadCompleteListener = listener;
- }
- }
-
- private class EventHandler extends Handler
- {
- private SoundPool mSoundPool;
-
- public EventHandler(SoundPool soundPool, Looper looper) {
- super(looper);
- mSoundPool = soundPool;
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch(msg.what) {
- case SAMPLE_LOADED:
- if (DEBUG) Log.d(TAG, "Sample " + msg.arg1 + " loaded");
- synchronized(mLock) {
- if (mOnLoadCompleteListener != null) {
- mOnLoadCompleteListener.onLoadComplete(mSoundPool, msg.arg1, msg.arg2);
- }
- }
- break;
- default:
- Log.e(TAG, "Unknown message type " + msg.what);
- return;
- }
- }
- }
-
- // post event from native code to message handler
- private static void postEventFromNative(Object weakRef, int msg, int arg1, int arg2, Object obj)
- {
- SoundPoolImpl soundPoolImpl = (SoundPoolImpl)((WeakReference)weakRef).get();
- if (soundPoolImpl == null)
+ break;
+ default:
+ Log.e(TAG, "Unknown message type " + msg.what);
return;
-
- if (soundPoolImpl.mEventHandler != null) {
- Message m = soundPoolImpl.mEventHandler.obtainMessage(msg, arg1, arg2, obj);
- soundPoolImpl.mEventHandler.sendMessage(m);
}
}
-
- public native final void release();
-
- private native final int native_setup(Object weakRef, int maxStreams,
- Object/*AudioAttributes*/ attributes);
-
- protected void finalize() { release(); }
}
/**
- * No-op implementation of SoundPool.
- * Used when media is disabled by the system.
- * @hide
+ * Builder class for {@link SoundPool} objects.
*/
- /* package */ static class SoundPoolStub implements SoundPoolDelegate {
- public SoundPoolStub() { }
-
- public int load(String path, int priority) {
- return 0;
- }
-
- @Override
- public int load(Context context, int resId, int priority) {
- return 0;
- }
-
- @Override
- public int load(AssetFileDescriptor afd, int priority) {
- return 0;
- }
-
- @Override
- public int load(FileDescriptor fd, long offset, long length, int priority) {
- return 0;
- }
+ public static class Builder {
+ private int mMaxStreams = 1;
+ private AudioAttributes mAudioAttributes;
- @Override
- public final boolean unload(int soundID) {
- return true;
+ /**
+ * Constructs a new Builder with the defaults format values.
+ * If not provided, the maximum number of streams is 1 (see {@link #setMaxStreams(int)} to
+ * change it), and the audio attributes have a usage value of
+ * {@link AudioAttributes#USAGE_MEDIA} (see {@link #setAudioAttributes(AudioAttributes)} to
+ * change them).
+ */
+ public Builder() {
}
- @Override
- public final int play(int soundID, float leftVolume, float rightVolume,
- int priority, int loop, float rate) {
- return 0;
+ /**
+ * Sets the maximum of number of simultaneous streams that can be played simultaneously.
+ * @param maxStreams a value equal to 1 or greater.
+ * @return the same Builder instance
+ * @throws IllegalArgumentException
+ */
+ public Builder setMaxStreams(int maxStreams) throws IllegalArgumentException {
+ if (maxStreams <= 0) {
+ throw new IllegalArgumentException(
+ "Strictly positive value required for the maximum number of streams");
+ }
+ mMaxStreams = maxStreams;
+ return this;
}
- @Override
- public final void pause(int streamID) { }
-
- @Override
- public final void resume(int streamID) { }
-
- @Override
- public final void autoPause() { }
-
- @Override
- public final void autoResume() { }
-
- @Override
- public final void stop(int streamID) { }
-
- @Override
- public final void setVolume(int streamID,
- float leftVolume, float rightVolume) { }
-
- @Override
- public void setVolume(int streamID, float volume) {
+ /**
+ * Sets the {@link AudioAttributes}. For examples, game applications will use attributes
+ * built with usage information set to {@link AudioAttributes#USAGE_GAME}.
+ * @param attributes a non-null
+ * @return
+ */
+ public Builder setAudioAttributes(AudioAttributes attributes)
+ throws IllegalArgumentException {
+ if (attributes == null) {
+ throw new IllegalArgumentException("Invalid null AudioAttributes");
+ }
+ mAudioAttributes = attributes;
+ return this;
}
- @Override
- public final void setPriority(int streamID, int priority) { }
-
- @Override
- public final void setLoop(int streamID, int loop) { }
-
- @Override
- public final void setRate(int streamID, float rate) { }
-
- @Override
- public void setOnLoadCompleteListener(SoundPool.OnLoadCompleteListener listener) {
+ public SoundPool build() {
+ if (mAudioAttributes == null) {
+ mAudioAttributes = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_MEDIA).build();
+ }
+ return new SoundPool(mMaxStreams, mAudioAttributes);
}
-
- @Override
- public final void release() { }
}
}
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index 49087b03f748..adb6b0600f97 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -15,8 +15,8 @@
package android.media.session;
-import android.media.Rating;
import android.content.Intent;
+import android.media.Rating;
import android.net.Uri;
import android.os.Bundle;
import android.os.ResultReceiver;
@@ -30,8 +30,9 @@ oneway interface ISessionCallback {
// These callbacks are for the TransportPerformer
void onPlay();
- void onPlayFromMediaId(String uri, in Bundle extras);
+ void onPlayFromMediaId(String mediaId, in Bundle extras);
void onPlayFromSearch(String query, in Bundle extras);
+ void onPlayFromUri(in Uri uri, in Bundle extras);
void onSkipToTrack(long id);
void onPause();
void onStop();
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index e2d06d37f0b2..8d58a607f39d 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -23,9 +23,9 @@ import android.media.Rating;
import android.media.routing.IMediaRouterDelegate;
import android.media.routing.IMediaRouterStateCallback;
import android.media.session.ISessionControllerCallback;
+import android.media.session.MediaSession;
import android.media.session.ParcelableVolumeInfo;
import android.media.session.PlaybackState;
-import android.media.session.MediaSession;
import android.net.Uri;
import android.os.Bundle;
import android.os.ResultReceiver;
@@ -55,8 +55,9 @@ interface ISessionController {
// These commands are for the TransportControls
void play();
- void playFromMediaId(String uri, in Bundle extras);
+ void playFromMediaId(String mediaId, in Bundle extras);
void playFromSearch(String string, in Bundle extras);
+ void playFromUri(in Uri uri, in Bundle extras);
void skipToQueueItem(long id);
void pause();
void stop();
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index c23a1391475f..dd81a228b51b 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -516,8 +516,8 @@ public final class MediaController {
}
/**
- * Callback for receiving updates on from the session. A Callback can be
- * registered using {@link #registerCallback}
+ * Callback for receiving updates from the session. A Callback can be
+ * registered using {@link #registerCallback}.
*/
public static abstract class Callback {
/**
@@ -615,9 +615,9 @@ public final class MediaController {
}
/**
- * Request that the player start playback for a specific {@link Uri}.
+ * Request that the player start playback for a specific media id.
*
- * @param mediaId The uri of the requested media.
+ * @param mediaId The id of the requested media.
* @param extras Optional extras that can include extra information about the media item
* to be played.
*/
@@ -656,6 +656,25 @@ public final class MediaController {
}
/**
+ * Request that the player start playback for a specific {@link Uri}.
+ *
+ * @param uri The URI of the requested media.
+ * @param extras Optional extras that can include extra information about the media item
+ * to be played.
+ */
+ public void playFromUri(Uri uri, Bundle extras) {
+ if (uri == null || Uri.EMPTY.equals(uri)) {
+ throw new IllegalArgumentException(
+ "You must specify a non-empty Uri for playFromUri.");
+ }
+ try {
+ mSessionBinder.playFromUri(uri, extras);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling play(" + uri + ").", e);
+ }
+ }
+
+ /**
* Play an item with a specific id in the play queue. If you specify an
* id that is not in the play queue, the behavior is undefined.
*/
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index cc602c96ccd4..cee82b4612d6 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -30,6 +30,7 @@ import android.media.MediaMetadata;
import android.media.Rating;
import android.media.VolumeProvider;
import android.media.routing.MediaRouter;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -541,6 +542,10 @@ public final class MediaSession {
postToCallback(CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
}
+ private void dispatchPlayFromUri(Uri uri, Bundle extras) {
+ postToCallback(CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
+ }
+
private void dispatchSkipToItem(long id) {
postToCallback(CallbackMessageHandler.MSG_SKIP_TO_ITEM, id);
}
@@ -833,6 +838,12 @@ public final class MediaSession {
}
/**
+ * Override to handle requests to play a specific media item represented by a URI.
+ */
+ public void onPlayFromUri(Uri uri, Bundle extras) {
+ }
+
+ /**
* Override to handle requests to play an item with a given id from the
* play queue.
*/
@@ -961,6 +972,14 @@ public final class MediaSession {
}
@Override
+ public void onPlayFromUri(Uri uri, Bundle extras) {
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchPlayFromUri(uri, extras);
+ }
+ }
+
+ @Override
public void onSkipToTrack(long id) {
MediaSession session = mMediaSession.get();
if (session != null) {
@@ -1171,6 +1190,7 @@ public final class MediaSession {
private static final int MSG_COMMAND = 15;
private static final int MSG_ADJUST_VOLUME = 16;
private static final int MSG_SET_VOLUME = 17;
+ private static final int MSG_PLAY_URI = 18;
private MediaSession.Callback mCallback;
@@ -1210,6 +1230,9 @@ public final class MediaSession {
case MSG_PLAY_SEARCH:
mCallback.onPlayFromSearch((String) msg.obj, msg.getData());
break;
+ case MSG_PLAY_URI:
+ mCallback.onPlayFromUri((Uri) msg.obj, msg.getData());
+ break;
case MSG_SKIP_TO_ITEM:
mCallback.onSkipToQueueItem((Long) msg.obj);
break;
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 6807e7f79422..bbe04b5875eb 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -126,6 +126,13 @@ public final class PlaybackState implements Parcelable {
public static final long ACTION_SKIP_TO_QUEUE_ITEM = 1 << 12;
/**
+ * Indicates this session supports the play from URI command.
+ *
+ * @see Builder#setActions(long)
+ */
+ public static final long ACTION_PLAY_FROM_URI = 1 << 13;
+
+ /**
* This is the default playback state and indicates that no media has been
* added yet, or the performer has been reset and has no content to play.
*
@@ -353,6 +360,11 @@ public final class PlaybackState implements Parcelable {
* <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
* <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
* <li> {@link PlaybackState#ACTION_SET_RATING}</li>
+ * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li>
+ * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li>
+ * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
+ * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
+ * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
* </ul>
*/
public long getActions() {
@@ -868,6 +880,11 @@ public final class PlaybackState implements Parcelable {
* <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
* <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
* <li> {@link PlaybackState#ACTION_SET_RATING}</li>
+ * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li>
+ * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li>
+ * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
+ * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
+ * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
* </ul>
*
* @param actions The set of actions allowed.
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 438e767a8a25..936762c1a28a 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -1054,6 +1054,50 @@ public final class TvContract {
public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
/**
+ * Internal integer flag used by individual TV input services.
+ * <p>
+ * This is internal to the provider that inserted it, and should not be decoded by other
+ * apps.
+ * </p><p>
+ * Type: INTEGER
+ * </p>
+ */
+ public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+
+ /**
+ * Internal integer flag used by individual TV input services.
+ * <p>
+ * This is internal to the provider that inserted it, and should not be decoded by other
+ * apps.
+ * </p><p>
+ * Type: INTEGER
+ * </p>
+ */
+ public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+
+ /**
+ * Internal integer flag used by individual TV input services.
+ * <p>
+ * This is internal to the provider that inserted it, and should not be decoded by other
+ * apps.
+ * </p><p>
+ * Type: INTEGER
+ * </p>
+ */
+ public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+
+ /**
+ * Internal integer flag used by individual TV input services.
+ * <p>
+ * This is internal to the provider that inserted it, and should not be decoded by other
+ * apps.
+ * </p><p>
+ * Type: INTEGER
+ * </p>
+ */
+ public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+
+ /**
* The version number of this row entry used by TV input services.
* <p>
* This is best used by sync adapters to identify the rows to update. The number can be
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index cf1b4414b094..8ed383a347b5 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -1077,12 +1077,19 @@ public abstract class TvInputService extends Service {
int dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
if (DEBUG) Log.d(TAG, "dispatchInputEvent(" + event + ")");
boolean isNavigationKey = false;
+ boolean skipDispatchToOverlayView = false;
if (event instanceof KeyEvent) {
KeyEvent keyEvent = (KeyEvent) event;
- isNavigationKey = isNavigationKey(keyEvent.getKeyCode());
if (keyEvent.dispatch(this, mDispatcherState, this)) {
return TvInputManager.Session.DISPATCH_HANDLED;
}
+ isNavigationKey = isNavigationKey(keyEvent.getKeyCode());
+ // When media keys and KEYCODE_MEDIA_AUDIO_TRACK are dispatched to ViewRootImpl,
+ // ViewRootImpl always consumes the keys. In this case, an application loses
+ // a chance to handle media keys. Therefore, media keys are not dispatched to
+ // ViewRootImpl.
+ skipDispatchToOverlayView = KeyEvent.isMediaKey(keyEvent.getKeyCode())
+ || keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK;
} else if (event instanceof MotionEvent) {
MotionEvent motionEvent = (MotionEvent) event;
final int source = motionEvent.getSource();
@@ -1100,7 +1107,8 @@ public abstract class TvInputService extends Service {
}
}
}
- if (mOverlayViewContainer == null || !mOverlayViewContainer.isAttachedToWindow()) {
+ if (mOverlayViewContainer == null || !mOverlayViewContainer.isAttachedToWindow()
+ || skipDispatchToOverlayView) {
return TvInputManager.Session.DISPATCH_NOT_HANDLED;
}
if (!mOverlayViewContainer.hasWindowFocus()) {
@@ -1223,6 +1231,8 @@ public abstract class TvInputService extends Service {
args.arg2 = mProxySession;
args.arg3 = mProxySessionCallback;
args.arg4 = session.getToken();
+ session.tune(TvContract.buildChannelUriForPassthroughInput(
+ getHardwareInputId()));
} else {
args.arg1 = null;
args.arg2 = null;
@@ -1232,7 +1242,6 @@ public abstract class TvInputService extends Service {
}
mServiceHandler.obtainMessage(ServiceHandler.DO_NOTIFY_SESSION_CREATED, args)
.sendToTarget();
- session.tune(TvContract.buildChannelUriForPassthroughInput(getHardwareInputId()));
}
@Override
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 1433c79f377f..d10df3e9c3e3 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -435,7 +435,7 @@ static void ImageWriter_queueImage(JNIEnv* env, jobject thiz, jlong nativeCtx, j
Image_unlockIfLocked(env, image);
// Set timestamp
- ALOGV("timestamp to be queued: %lld", timestampNs);
+ ALOGV("timestamp to be queued: %" PRId64, timestampNs);
res = native_window_set_buffers_timestamp(anw.get(), timestampNs);
if (res != OK) {
jniThrowRuntimeException(env, "Set timestamp failed");
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 8302a345dc41..96d71339cee9 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -59,6 +59,7 @@ namespace android {
struct RequestFields {
jfieldID data;
jfieldID defaultUrl;
+ jfieldID requestType;
};
struct ArrayListFields {
@@ -101,6 +102,12 @@ struct KeyTypes {
jint kKeyTypeRelease;
} gKeyTypes;
+struct KeyRequestTypes {
+ jint kKeyRequestTypeInitial;
+ jint kKeyRequestTypeRenewal;
+ jint kKeyRequestTypeRelease;
+} gKeyRequestTypes;
+
struct CertificateTypes {
jint kCertificateTypeNone;
jint kCertificateTypeX509;
@@ -182,7 +189,7 @@ void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
jint jeventType;
// translate DrmPlugin event types into their java equivalents
- switch(eventType) {
+ switch (eventType) {
case DrmPlugin::kDrmPluginEventProvisionRequired:
jeventType = gEventTypes.kEventProvisionRequired;
break;
@@ -236,7 +243,7 @@ static bool throwExceptionAsNecessary(
const char *drmMessage = NULL;
- switch(err) {
+ switch (err) {
case ERROR_DRM_UNKNOWN:
drmMessage = "General DRM error";
break;
@@ -587,6 +594,13 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) {
GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I");
+ gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I");
+ gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I");
+ gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field);
+
GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
@@ -595,6 +609,7 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) {
FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
+ GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I");
FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
@@ -786,9 +801,10 @@ static jobject android_media_MediaDrm_getKeyRequest(
Vector<uint8_t> request;
String8 defaultUrl;
+ DrmPlugin::KeyRequestType keyRequestType;
status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
- keyType, optParams, request, defaultUrl);
+ keyType, optParams, request, defaultUrl, &keyRequestType);
if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
return NULL;
@@ -807,6 +823,25 @@ static jobject android_media_MediaDrm_getKeyRequest(
jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
+
+ switch (keyRequestType) {
+ case DrmPlugin::kKeyRequestType_Initial:
+ env->SetIntField(keyObj, gFields.keyRequest.requestType,
+ gKeyRequestTypes.kKeyRequestTypeInitial);
+ break;
+ case DrmPlugin::kKeyRequestType_Renewal:
+ env->SetIntField(keyObj, gFields.keyRequest.requestType,
+ gKeyRequestTypes.kKeyRequestTypeRenewal);
+ break;
+ case DrmPlugin::kKeyRequestType_Release:
+ env->SetIntField(keyObj, gFields.keyRequest.requestType,
+ gKeyRequestTypes.kKeyRequestTypeRelease);
+ break;
+ case DrmPlugin::kKeyRequestType_Unknown:
+ throwStateException(env, "DRM plugin failure: unknown key request type",
+ ERROR_DRM_UNKNOWN);
+ break;
+ }
}
return keyObj;
diff --git a/media/jni/soundpool/Android.mk b/media/jni/soundpool/Android.mk
index 71ab01347d47..24760561e119 100644
--- a/media/jni/soundpool/Android.mk
+++ b/media/jni/soundpool/Android.mk
@@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- android_media_SoundPool_SoundPoolImpl.cpp \
+ android_media_SoundPool.cpp \
SoundPool.cpp \
SoundPoolThread.cpp
diff --git a/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
index b2333f863cdd..fc4cf0568968 100644
--- a/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp
+++ b/media/jni/soundpool/android_media_SoundPool.cpp
@@ -47,10 +47,10 @@ static audio_attributes_fields_t javaAudioAttrFields;
// ----------------------------------------------------------------------------
static jint
-android_media_SoundPool_SoundPoolImpl_load_FD(JNIEnv *env, jobject thiz, jobject fileDescriptor,
+android_media_SoundPool_load_FD(JNIEnv *env, jobject thiz, jobject fileDescriptor,
jlong offset, jlong length, jint priority)
{
- ALOGV("android_media_SoundPool_SoundPoolImpl_load_FD");
+ ALOGV("android_media_SoundPool_load_FD");
SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return 0;
return (jint) ap->load(jniGetFDFromFileDescriptor(env, fileDescriptor),
@@ -58,104 +58,104 @@ android_media_SoundPool_SoundPoolImpl_load_FD(JNIEnv *env, jobject thiz, jobject
}
static jboolean
-android_media_SoundPool_SoundPoolImpl_unload(JNIEnv *env, jobject thiz, jint sampleID) {
- ALOGV("android_media_SoundPool_SoundPoolImpl_unload\n");
+android_media_SoundPool_unload(JNIEnv *env, jobject thiz, jint sampleID) {
+ ALOGV("android_media_SoundPool_unload\n");
SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return JNI_FALSE;
return ap->unload(sampleID) ? JNI_TRUE : JNI_FALSE;
}
static jint
-android_media_SoundPool_SoundPoolImpl_play(JNIEnv *env, jobject thiz, jint sampleID,
+android_media_SoundPool_play(JNIEnv *env, jobject thiz, jint sampleID,
jfloat leftVolume, jfloat rightVolume, jint priority, jint loop,
jfloat rate)
{
- ALOGV("android_media_SoundPool_SoundPoolImpl_play\n");
+ ALOGV("android_media_SoundPool_play\n");
SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return 0;
return (jint) ap->play(sampleID, leftVolume, rightVolume, priority, loop, rate);
}
static void
-android_media_SoundPool_SoundPoolImpl_pause(JNIEnv *env, jobject thiz, jint channelID)
+android_media_SoundPool_pause(JNIEnv *env, jobject thiz, jint channelID)
{
- ALOGV("android_media_SoundPool_SoundPoolImpl_pause");
+ ALOGV("android_media_SoundPool_pause");
SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return;
ap->pause(channelID);
}
static void
-android_media_SoundPool_SoundPoolImpl_resume(JNIEnv *env, jobject thiz, jint channelID)
+android_media_SoundPool_resume(JNIEnv *env, jobject thiz, jint channelID)
{
- ALOGV("android_media_SoundPool_SoundPoolImpl_resume");
+ ALOGV("android_media_SoundPool_resume");
SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return;
ap->resume(channelID);
}
static void
-android_media_SoundPool_SoundPoolImpl_autoPause(JNIEnv *env, jobject thiz)
+android_media_SoundPool_autoPause(JNIEnv *env, jobject thiz)
{
- ALOGV("android_media_SoundPool_SoundPoolImpl_autoPause");
+ ALOGV("android_media_SoundPool_autoPause");
SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return;
ap->autoPause();
}
static void
-android_media_SoundPool_SoundPoolImpl_autoResume(JNIEnv *env, jobject thiz)
+android_media_SoundPool_autoResume(JNIEnv *env, jobject thiz)
{
- ALOGV("android_media_SoundPool_SoundPoolImpl_autoResume");
+ ALOGV("android_media_SoundPool_autoResume");
SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return;
ap->autoResume();
}
static void
-android_media_SoundPool_SoundPoolImpl_stop(JNIEnv *env, jobject thiz, jint channelID)
+android_media_SoundPool_stop(JNIEnv *env, jobject thiz, jint channelID)
{
- ALOGV("android_media_SoundPool_SoundPoolImpl_stop");
+ ALOGV("android_media_SoundPool_stop");
SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return;
ap->stop(channelID);
}
static void
-android_media_SoundPool_SoundPoolImpl_setVolume(JNIEnv *env, jobject thiz, jint channelID,
+android_media_SoundPool_setVolume(JNIEnv *env, jobject thiz, jint channelID,
jfloat leftVolume, jfloat rightVolume)
{
- ALOGV("android_media_SoundPool_SoundPoolImpl_setVolume");
+ ALOGV("android_media_SoundPool_setVolume");
SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return;
ap->setVolume(channelID, (float) leftVolume, (float) rightVolume);
}
static void
-android_media_SoundPool_SoundPoolImpl_setPriority(JNIEnv *env, jobject thiz, jint channelID,
+android_media_SoundPool_setPriority(JNIEnv *env, jobject thiz, jint channelID,
jint priority)
{
- ALOGV("android_media_SoundPool_SoundPoolImpl_setPriority");
+ ALOGV("android_media_SoundPool_setPriority");
SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return;
ap->setPriority(channelID, (int) priority);
}
static void
-android_media_SoundPool_SoundPoolImpl_setLoop(JNIEnv *env, jobject thiz, jint channelID,
+android_media_SoundPool_setLoop(JNIEnv *env, jobject thiz, jint channelID,
int loop)
{
- ALOGV("android_media_SoundPool_SoundPoolImpl_setLoop");
+ ALOGV("android_media_SoundPool_setLoop");
SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return;
ap->setLoop(channelID, loop);
}
static void
-android_media_SoundPool_SoundPoolImpl_setRate(JNIEnv *env, jobject thiz, jint channelID,
+android_media_SoundPool_setRate(JNIEnv *env, jobject thiz, jint channelID,
jfloat rate)
{
- ALOGV("android_media_SoundPool_SoundPoolImpl_setRate");
+ ALOGV("android_media_SoundPool_setRate");
SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return;
ap->setRate(channelID, (float) rate);
@@ -169,7 +169,7 @@ static void android_media_callback(SoundPoolEvent event, SoundPool* soundPool, v
}
static jint
-android_media_SoundPool_SoundPoolImpl_native_setup(JNIEnv *env, jobject thiz, jobject weakRef,
+android_media_SoundPool_native_setup(JNIEnv *env, jobject thiz, jobject weakRef,
jint maxChannels, jobject jaa)
{
if (jaa == 0) {
@@ -191,7 +191,7 @@ android_media_SoundPool_SoundPoolImpl_native_setup(JNIEnv *env, jobject thiz, jo
(audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType);
paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
- ALOGV("android_media_SoundPool_SoundPoolImpl_native_setup");
+ ALOGV("android_media_SoundPool_native_setup");
SoundPool *ap = new SoundPool(maxChannels, paa);
if (ap == NULL) {
return -1;
@@ -211,9 +211,9 @@ android_media_SoundPool_SoundPoolImpl_native_setup(JNIEnv *env, jobject thiz, jo
}
static void
-android_media_SoundPool_SoundPoolImpl_release(JNIEnv *env, jobject thiz)
+android_media_SoundPool_release(JNIEnv *env, jobject thiz)
{
- ALOGV("android_media_SoundPool_SoundPoolImpl_release");
+ ALOGV("android_media_SoundPool_release");
SoundPool *ap = MusterSoundPool(env, thiz);
if (ap != NULL) {
@@ -236,63 +236,63 @@ android_media_SoundPool_SoundPoolImpl_release(JNIEnv *env, jobject thiz)
static JNINativeMethod gMethods[] = {
{ "_load",
"(Ljava/io/FileDescriptor;JJI)I",
- (void *)android_media_SoundPool_SoundPoolImpl_load_FD
+ (void *)android_media_SoundPool_load_FD
},
{ "unload",
"(I)Z",
- (void *)android_media_SoundPool_SoundPoolImpl_unload
+ (void *)android_media_SoundPool_unload
},
{ "_play",
"(IFFIIF)I",
- (void *)android_media_SoundPool_SoundPoolImpl_play
+ (void *)android_media_SoundPool_play
},
{ "pause",
"(I)V",
- (void *)android_media_SoundPool_SoundPoolImpl_pause
+ (void *)android_media_SoundPool_pause
},
{ "resume",
"(I)V",
- (void *)android_media_SoundPool_SoundPoolImpl_resume
+ (void *)android_media_SoundPool_resume
},
{ "autoPause",
"()V",
- (void *)android_media_SoundPool_SoundPoolImpl_autoPause
+ (void *)android_media_SoundPool_autoPause
},
{ "autoResume",
"()V",
- (void *)android_media_SoundPool_SoundPoolImpl_autoResume
+ (void *)android_media_SoundPool_autoResume
},
{ "stop",
"(I)V",
- (void *)android_media_SoundPool_SoundPoolImpl_stop
+ (void *)android_media_SoundPool_stop
},
{ "_setVolume",
"(IFF)V",
- (void *)android_media_SoundPool_SoundPoolImpl_setVolume
+ (void *)android_media_SoundPool_setVolume
},
{ "setPriority",
"(II)V",
- (void *)android_media_SoundPool_SoundPoolImpl_setPriority
+ (void *)android_media_SoundPool_setPriority
},
{ "setLoop",
"(II)V",
- (void *)android_media_SoundPool_SoundPoolImpl_setLoop
+ (void *)android_media_SoundPool_setLoop
},
{ "setRate",
"(IF)V",
- (void *)android_media_SoundPool_SoundPoolImpl_setRate
+ (void *)android_media_SoundPool_setRate
},
{ "native_setup",
"(Ljava/lang/Object;ILjava/lang/Object;)I",
- (void*)android_media_SoundPool_SoundPoolImpl_native_setup
+ (void*)android_media_SoundPool_native_setup
},
{ "release",
"()V",
- (void*)android_media_SoundPool_SoundPoolImpl_release
+ (void*)android_media_SoundPool_release
}
};
-static const char* const kClassPathName = "android/media/SoundPool$SoundPoolImpl";
+static const char* const kClassPathName = "android/media/SoundPool";
jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
@@ -314,14 +314,14 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
fields.mNativeContext = env->GetFieldID(clazz, "mNativeContext", "J");
if (fields.mNativeContext == NULL) {
- ALOGE("Can't find SoundPoolImpl.mNativeContext");
+ ALOGE("Can't find SoundPool.mNativeContext");
return result;
}
fields.mPostEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
if (fields.mPostEvent == NULL) {
- ALOGE("Can't find android/media/SoundPoolImpl.postEventFromNative");
+ ALOGE("Can't find android/media/SoundPool.postEventFromNative");
return result;
}
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index e95e5ec322ef..165b11e2b5ea 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -42,10 +42,21 @@
</intent-filter>
</activity>
+ <activity
+ android:name=".StandaloneActivity"
+ android:theme="@style/StandaloneTheme"
+ android:icon="@drawable/ic_doc_text"
+ android:enabled="false">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
<provider
android:name=".RecentsProvider"
android:authorities="com.android.documentsui.recents"
- android:exported="false" />
+ android:exported="false"/>
<receiver android:name=".PackageReceiver">
<intent-filter>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index 04692f604a7f..bf01bf156d67 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -43,4 +43,22 @@
<item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
</style>
+ <style name="StandaloneTheme" parent="android:Theme.Light">
+ <item name="android:actionBarWidgetTheme">@null</item>
+ <item name="android:actionBarTheme">@*android:style/ThemeOverlay.Material.Dark.ActionBar</item>
+ <item name="android:actionBarPopupTheme">@*android:style/ThemeOverlay.Material.Light</item>
+
+ <item name="android:colorPrimaryDark">@*android:color/material_blue_grey_900</item>
+ <item name="android:colorPrimary">@*android:color/material_blue_grey_800</item>
+ <item name="android:colorAccent">@*android:color/material_deep_teal_500</item>
+
+ <item name="android:listDivider">@*android:drawable/list_divider_material</item>
+
+ <item name="android:windowActionBar">false</item>
+ <item name="android:windowActionModeOverlay">true</item>
+ <item name="android:windowNoTitle">true</item>
+
+ <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
+ </style>
+
</resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
new file mode 100644
index 000000000000..a8a0c1d4503a
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import java.util.HashMap;
+import java.util.List;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.pm.ResolveInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.SparseArray;
+
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.model.DurableUtils;
+import com.android.documentsui.model.RootInfo;
+import com.google.common.collect.Maps;
+
+abstract class BaseActivity extends Activity {
+
+ public abstract State getDisplayState();
+ public abstract RootInfo getCurrentRoot();
+ public abstract void onStateChanged();
+ public abstract void setRootsDrawerOpen(boolean open);
+ public abstract void onDocumentPicked(DocumentInfo doc);
+ public abstract void onDocumentsPicked(List<DocumentInfo> docs);
+ public abstract DocumentInfo getCurrentDirectory();
+ public abstract void setPending(boolean pending);
+ public abstract void onStackPicked(DocumentStack stack);
+ public abstract void onPickRequested(DocumentInfo pickTarget);
+ public abstract void onAppPicked(ResolveInfo info);
+ public abstract void onRootPicked(RootInfo root, boolean closeDrawer);
+ public abstract void onSaveRequested(DocumentInfo replaceTarget);
+ public abstract void onSaveRequested(String mimeType, String displayName);
+
+ public static BaseActivity get(Fragment fragment) {
+ return (BaseActivity) fragment.getActivity();
+ }
+
+ public static class State implements android.os.Parcelable {
+ public int action;
+ public String[] acceptMimes;
+
+ /** Explicit user choice */
+ public int userMode = MODE_UNKNOWN;
+ /** Derived after loader */
+ public int derivedMode = MODE_LIST;
+
+ /** Explicit user choice */
+ public int userSortOrder = SORT_ORDER_UNKNOWN;
+ /** Derived after loader */
+ public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
+
+ public boolean allowMultiple = false;
+ public boolean showSize = false;
+ public boolean localOnly = false;
+ public boolean forceAdvanced = false;
+ public boolean showAdvanced = false;
+ public boolean stackTouched = false;
+ public boolean restored = false;
+
+ /** Current user navigation stack; empty implies recents. */
+ public DocumentStack stack = new DocumentStack();
+ /** Currently active search, overriding any stack. */
+ public String currentSearch;
+
+ /** Instance state for every shown directory */
+ public HashMap<String, SparseArray<Parcelable>> dirState = Maps.newHashMap();
+
+ public static final int ACTION_OPEN = 1;
+ public static final int ACTION_CREATE = 2;
+ public static final int ACTION_GET_CONTENT = 3;
+ public static final int ACTION_OPEN_TREE = 4;
+ public static final int ACTION_MANAGE = 5;
+ public static final int ACTION_MANAGE_ALL = 6;
+
+ public static final int MODE_UNKNOWN = 0;
+ public static final int MODE_LIST = 1;
+ public static final int MODE_GRID = 2;
+
+ public static final int SORT_ORDER_UNKNOWN = 0;
+ public static final int SORT_ORDER_DISPLAY_NAME = 1;
+ public static final int SORT_ORDER_LAST_MODIFIED = 2;
+ public static final int SORT_ORDER_SIZE = 3;
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(action);
+ out.writeInt(userMode);
+ out.writeStringArray(acceptMimes);
+ out.writeInt(userSortOrder);
+ out.writeInt(allowMultiple ? 1 : 0);
+ out.writeInt(showSize ? 1 : 0);
+ out.writeInt(localOnly ? 1 : 0);
+ out.writeInt(forceAdvanced ? 1 : 0);
+ out.writeInt(showAdvanced ? 1 : 0);
+ out.writeInt(stackTouched ? 1 : 0);
+ out.writeInt(restored ? 1 : 0);
+ DurableUtils.writeToParcel(out, stack);
+ out.writeString(currentSearch);
+ out.writeMap(dirState);
+ }
+
+ public static final Creator<State> CREATOR = new Creator<State>() {
+ @Override
+ public State createFromParcel(Parcel in) {
+ final State state = new State();
+ state.action = in.readInt();
+ state.userMode = in.readInt();
+ state.acceptMimes = in.readStringArray();
+ state.userSortOrder = in.readInt();
+ state.allowMultiple = in.readInt() != 0;
+ state.showSize = in.readInt() != 0;
+ state.localOnly = in.readInt() != 0;
+ state.forceAdvanced = in.readInt() != 0;
+ state.showAdvanced = in.readInt() != 0;
+ state.stackTouched = in.readInt() != 0;
+ state.restored = in.readInt() != 0;
+ DurableUtils.readFromParcel(in, state.stack);
+ state.currentSearch = in.readString();
+ in.readMap(state.dirState, null);
+ return state;
+ }
+
+ @Override
+ public State[] newArray(int size) {
+ return new State[size];
+ }
+ };
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index ba8c35fc3664..1a17ee01230e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -70,7 +70,7 @@ public class CreateDirectoryFragment extends DialogFragment {
public void onClick(DialogInterface dialog, int which) {
final String displayName = text1.getText().toString();
- final DocumentsActivity activity = (DocumentsActivity) getActivity();
+ final BaseActivity activity = (BaseActivity) getActivity();
final DocumentInfo cwd = activity.getCurrentDirectory();
new CreateDirectoryTask(activity, cwd, displayName).executeOnExecutor(
@@ -83,12 +83,12 @@ public class CreateDirectoryFragment extends DialogFragment {
}
private class CreateDirectoryTask extends AsyncTask<Void, Void, DocumentInfo> {
- private final DocumentsActivity mActivity;
+ private final BaseActivity mActivity;
private final DocumentInfo mCwd;
private final String mDisplayName;
public CreateDirectoryTask(
- DocumentsActivity activity, DocumentInfo cwd, String displayName) {
+ BaseActivity activity, DocumentInfo cwd, String displayName) {
mActivity = activity;
mCwd = cwd;
mDisplayName = displayName;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 39c2252799d3..f55912c24b5c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -17,12 +17,12 @@
package com.android.documentsui;
import static com.android.documentsui.DocumentsActivity.TAG;
-import static com.android.documentsui.DocumentsActivity.State.ACTION_CREATE;
-import static com.android.documentsui.DocumentsActivity.State.ACTION_MANAGE;
-import static com.android.documentsui.DocumentsActivity.State.MODE_GRID;
-import static com.android.documentsui.DocumentsActivity.State.MODE_LIST;
-import static com.android.documentsui.DocumentsActivity.State.MODE_UNKNOWN;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_UNKNOWN;
+import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
+import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
+import static com.android.documentsui.BaseActivity.State.MODE_GRID;
+import static com.android.documentsui.BaseActivity.State.MODE_LIST;
+import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
@@ -76,7 +76,7 @@ import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
-import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.ProviderExecutor.Preemptable;
import com.android.documentsui.RecentsProvider.StateColumns;
import com.android.documentsui.model.DocumentInfo;
@@ -301,13 +301,13 @@ public class DirectoryFragment extends Fragment {
state.derivedMode = result.mode;
}
state.derivedSortOrder = result.sortOrder;
- ((DocumentsActivity) context).onStateChanged();
+ ((BaseActivity) context).onStateChanged();
updateDisplayState();
// When launched into empty recents, show drawer
if (mType == TYPE_RECENT_OPEN && mAdapter.isEmpty() && !state.stackTouched) {
- ((DocumentsActivity) context).setRootsDrawerOpen(true);
+ ((BaseActivity) context).setRootsDrawerOpen(true);
}
// Restore any previous instance state
@@ -386,7 +386,7 @@ public class DirectoryFragment extends Fragment {
// Mode change is just visual change; no need to kick loader, and
// deliver change event immediately.
state.derivedMode = state.userMode;
- ((DocumentsActivity) getActivity()).onStateChanged();
+ ((BaseActivity) getActivity()).onStateChanged();
updateDisplayState();
}
@@ -441,7 +441,7 @@ public class DirectoryFragment extends Fragment {
final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
if (isDocumentEnabled(docMimeType, docFlags)) {
final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
- ((DocumentsActivity) getActivity()).onDocumentPicked(doc);
+ ((BaseActivity) getActivity()).onDocumentPicked(doc);
}
}
}
@@ -487,7 +487,7 @@ public class DirectoryFragment extends Fragment {
final int id = item.getItemId();
if (id == R.id.menu_open) {
- DocumentsActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
+ BaseActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
mode.finish();
return true;
@@ -616,7 +616,7 @@ public class DirectoryFragment extends Fragment {
}
private static State getDisplayState(Fragment fragment) {
- return ((DocumentsActivity) fragment.getActivity()).getDisplayState();
+ return ((BaseActivity) fragment.getActivity()).getDisplayState();
}
private static abstract class Footer {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 163615d4b677..8e4ec8c3db2d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -17,11 +17,11 @@
package com.android.documentsui;
import static com.android.documentsui.DocumentsActivity.TAG;
-import static com.android.documentsui.DocumentsActivity.State.MODE_UNKNOWN;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_DISPLAY_NAME;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_SIZE;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_UNKNOWN;
+import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import android.content.AsyncTaskLoader;
@@ -36,7 +36,7 @@ import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.util.Log;
-import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.RecentsProvider.StateColumns;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 8778f116cc81..2245b16fb32f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -20,14 +20,13 @@ import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
import static com.android.documentsui.DirectoryFragment.ANIM_SIDE;
import static com.android.documentsui.DirectoryFragment.ANIM_UP;
-import static com.android.documentsui.DocumentsActivity.State.ACTION_CREATE;
-import static com.android.documentsui.DocumentsActivity.State.ACTION_GET_CONTENT;
-import static com.android.documentsui.DocumentsActivity.State.ACTION_MANAGE;
-import static com.android.documentsui.DocumentsActivity.State.ACTION_OPEN;
-import static com.android.documentsui.DocumentsActivity.State.ACTION_OPEN_TREE;
-import static com.android.documentsui.DocumentsActivity.State.MODE_GRID;
-import static com.android.documentsui.DocumentsActivity.State.MODE_LIST;
-
+import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
+import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT;
+import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
+import static com.android.documentsui.BaseActivity.State.ACTION_OPEN;
+import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE;
+import static com.android.documentsui.BaseActivity.State.MODE_GRID;
+import static com.android.documentsui.BaseActivity.State.MODE_LIST;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
@@ -46,15 +45,12 @@ import android.graphics.Point;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.DrawerLayout.DrawerListener;
import android.util.Log;
-import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -79,7 +75,6 @@ import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
import com.android.documentsui.model.RootInfo;
-import com.google.common.collect.Maps;
import libcore.io.IoUtils;
@@ -87,11 +82,10 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executor;
-public class DocumentsActivity extends Activity {
+public class DocumentsActivity extends BaseActivity {
public static final String TAG = "Documents";
private static final String EXTRA_STATE = "state";
@@ -203,8 +197,8 @@ public class DocumentsActivity extends Activity {
moreApps.setComponent(null);
moreApps.setPackage(null);
RootsFragment.show(getFragmentManager(), moreApps);
- } else if (mState.action == ACTION_OPEN || mState.action == ACTION_CREATE
- || mState.action == ACTION_OPEN_TREE) {
+ } else if (mState.action == ACTION_OPEN
+ || mState.action == ACTION_CREATE || mState.action == ACTION_OPEN_TREE) {
RootsFragment.show(getFragmentManager(), null);
}
@@ -389,6 +383,7 @@ public class DocumentsActivity extends Activity {
updateActionBar();
}
+ @Override
public void setRootsDrawerOpen(boolean open) {
if (!mShowAsDialog) {
if (open) {
@@ -667,9 +662,7 @@ public class DocumentsActivity extends Activity {
invalidateOptionsMenu();
}
- /**
- * Update UI to reflect internal state changes not from user.
- */
+ @Override
public void onStateChanged() {
invalidateOptionsMenu();
}
@@ -690,6 +683,7 @@ public class DocumentsActivity extends Activity {
DirectoryFragment.get(getFragmentManager()).onUserModeChanged();
}
+ @Override
public void setPending(boolean pending) {
final SaveFragment save = SaveFragment.get(getFragmentManager());
if (save != null) {
@@ -808,6 +802,7 @@ public class DocumentsActivity extends Activity {
}
};
+ @Override
public RootInfo getCurrentRoot() {
if (mState.stack.root != null) {
return mState.stack.root;
@@ -816,6 +811,7 @@ public class DocumentsActivity extends Activity {
}
}
+ @Override
public DocumentInfo getCurrentDirectory() {
return mState.stack.peek();
}
@@ -834,6 +830,7 @@ public class DocumentsActivity extends Activity {
}
}
+ @Override
public State getDisplayState() {
return mState;
}
@@ -895,6 +892,7 @@ public class DocumentsActivity extends Activity {
dumpStack();
}
+ @Override
public void onStackPicked(DocumentStack stack) {
try {
// Update the restored stack to ensure we have freshest data
@@ -909,6 +907,7 @@ public class DocumentsActivity extends Activity {
}
}
+ @Override
public void onRootPicked(RootInfo root, boolean closeDrawer) {
// Clear entire backstack and start in new root
mState.stack.root = root;
@@ -955,6 +954,7 @@ public class DocumentsActivity extends Activity {
}
}
+ @Override
public void onAppPicked(ResolveInfo info) {
final Intent intent = new Intent(getIntent());
intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_FORWARD_RESULT);
@@ -985,6 +985,7 @@ public class DocumentsActivity extends Activity {
}
}
+ @Override
public void onDocumentPicked(DocumentInfo doc) {
final FragmentManager fm = getFragmentManager();
if (doc.isDirectory()) {
@@ -1020,6 +1021,7 @@ public class DocumentsActivity extends Activity {
}
}
+ @Override
public void onDocumentsPicked(List<DocumentInfo> docs) {
if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
final int size = docs.size();
@@ -1031,14 +1033,17 @@ public class DocumentsActivity extends Activity {
}
}
+ @Override
public void onSaveRequested(DocumentInfo replaceTarget) {
new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getCurrentExecutor());
}
+ @Override
public void onSaveRequested(String mimeType, String displayName) {
new CreateFinishTask(mimeType, displayName).executeOnExecutor(getCurrentExecutor());
}
+ @Override
public void onPickRequested(DocumentInfo pickTarget) {
final Uri viaUri = DocumentsContract.buildTreeDocumentUri(pickTarget.authority,
pickTarget.documentId);
@@ -1188,102 +1193,6 @@ public class DocumentsActivity extends Activity {
}
}
- public static class State implements android.os.Parcelable {
- public int action;
- public String[] acceptMimes;
-
- /** Explicit user choice */
- public int userMode = MODE_UNKNOWN;
- /** Derived after loader */
- public int derivedMode = MODE_LIST;
-
- /** Explicit user choice */
- public int userSortOrder = SORT_ORDER_UNKNOWN;
- /** Derived after loader */
- public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
-
- public boolean allowMultiple = false;
- public boolean showSize = false;
- public boolean localOnly = false;
- public boolean forceAdvanced = false;
- public boolean showAdvanced = false;
- public boolean stackTouched = false;
- public boolean restored = false;
-
- /** Current user navigation stack; empty implies recents. */
- public DocumentStack stack = new DocumentStack();
- /** Currently active search, overriding any stack. */
- public String currentSearch;
-
- /** Instance state for every shown directory */
- public HashMap<String, SparseArray<Parcelable>> dirState = Maps.newHashMap();
-
- public static final int ACTION_OPEN = 1;
- public static final int ACTION_CREATE = 2;
- public static final int ACTION_GET_CONTENT = 3;
- public static final int ACTION_OPEN_TREE = 4;
- public static final int ACTION_MANAGE = 5;
-
- public static final int MODE_UNKNOWN = 0;
- public static final int MODE_LIST = 1;
- public static final int MODE_GRID = 2;
-
- public static final int SORT_ORDER_UNKNOWN = 0;
- public static final int SORT_ORDER_DISPLAY_NAME = 1;
- public static final int SORT_ORDER_LAST_MODIFIED = 2;
- public static final int SORT_ORDER_SIZE = 3;
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(action);
- out.writeInt(userMode);
- out.writeStringArray(acceptMimes);
- out.writeInt(userSortOrder);
- out.writeInt(allowMultiple ? 1 : 0);
- out.writeInt(showSize ? 1 : 0);
- out.writeInt(localOnly ? 1 : 0);
- out.writeInt(forceAdvanced ? 1 : 0);
- out.writeInt(showAdvanced ? 1 : 0);
- out.writeInt(stackTouched ? 1 : 0);
- out.writeInt(restored ? 1 : 0);
- DurableUtils.writeToParcel(out, stack);
- out.writeString(currentSearch);
- out.writeMap(dirState);
- }
-
- public static final Creator<State> CREATOR = new Creator<State>() {
- @Override
- public State createFromParcel(Parcel in) {
- final State state = new State();
- state.action = in.readInt();
- state.userMode = in.readInt();
- state.acceptMimes = in.readStringArray();
- state.userSortOrder = in.readInt();
- state.allowMultiple = in.readInt() != 0;
- state.showSize = in.readInt() != 0;
- state.localOnly = in.readInt() != 0;
- state.forceAdvanced = in.readInt() != 0;
- state.showAdvanced = in.readInt() != 0;
- state.stackTouched = in.readInt() != 0;
- state.restored = in.readInt() != 0;
- DurableUtils.readFromParcel(in, state.stack);
- state.currentSearch = in.readString();
- in.readMap(state.dirState, null);
- return state;
- }
-
- @Override
- public State[] newArray(int size) {
- return new State[size];
- }
- };
- }
-
private void dumpStack() {
Log.d(TAG, "Current stack: ");
Log.d(TAG, " * " + mState.stack.root);
@@ -1291,8 +1200,4 @@ public class DocumentsActivity extends Activity {
Log.d(TAG, " +-- " + doc);
}
}
-
- public static DocumentsActivity get(Fragment fragment) {
- return (DocumentsActivity) fragment.getActivity();
- }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
index 5112c92295c5..4b008ca3fac2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
@@ -69,7 +69,7 @@ public class PickFragment extends Fragment {
private View.OnClickListener mPickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
- final DocumentsActivity activity = DocumentsActivity.get(PickFragment.this);
+ final BaseActivity activity = BaseActivity.get(PickFragment.this);
activity.onPickRequested(mPickTarget);
}
};
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index 34ce42dc56f4..f5908c55cfa2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -17,7 +17,7 @@
package com.android.documentsui;
import static com.android.documentsui.DocumentsActivity.TAG;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
import android.app.ActivityManager;
import android.content.AsyncTaskLoader;
@@ -34,7 +34,7 @@ import android.provider.DocumentsContract.Root;
import android.text.format.DateUtils;
import android.util.Log;
-import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
import com.google.android.collect.Maps;
import com.google.common.collect.Lists;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index dd75dbdba635..26aecc5cb144 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -45,7 +45,7 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
-import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.RecentsProvider.RecentColumns;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
@@ -95,7 +95,7 @@ public class RecentsCreateFragment extends Fragment {
mListView.setAdapter(mAdapter);
final RootsCache roots = DocumentsApplication.getRootsCache(context);
- final State state = ((DocumentsActivity) getActivity()).getDisplayState();
+ final State state = ((BaseActivity) getActivity()).getDisplayState();
mCallbacks = new LoaderCallbacks<List<DocumentStack>>() {
@Override
@@ -110,7 +110,7 @@ public class RecentsCreateFragment extends Fragment {
// When launched into empty recents, show drawer
if (mAdapter.isEmpty() && !state.stackTouched) {
- ((DocumentsActivity) context).setRootsDrawerOpen(true);
+ ((BaseActivity) context).setRootsDrawerOpen(true);
}
}
@@ -139,7 +139,7 @@ public class RecentsCreateFragment extends Fragment {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final DocumentStack stack = mAdapter.getItem(position);
- ((DocumentsActivity) getActivity()).onStackPicked(stack);
+ ((BaseActivity) getActivity()).onStackPicked(stack);
}
};
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index d72db1dccfcf..ec71a045f7aa 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -36,7 +36,7 @@ import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
import android.util.Log;
-import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 884cf31d8c79..ed5e123fac34 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -16,8 +16,6 @@
package com.android.documentsui;
-import static com.android.documentsui.DocumentsActivity.State.ACTION_GET_CONTENT;
-
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
@@ -43,7 +41,7 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
-import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
import com.google.common.collect.Lists;
@@ -101,7 +99,7 @@ public class RootsFragment extends Fragment {
final Context context = getActivity();
final RootsCache roots = DocumentsApplication.getRootsCache(context);
- final State state = ((DocumentsActivity) context).getDisplayState();
+ final State state = ((BaseActivity) context).getDisplayState();
mCallbacks = new LoaderCallbacks<Collection<RootInfo>>() {
@Override
@@ -138,9 +136,9 @@ public class RootsFragment extends Fragment {
public void onDisplayStateChanged() {
final Context context = getActivity();
- final State state = ((DocumentsActivity) context).getDisplayState();
+ final State state = ((BaseActivity) context).getDisplayState();
- if (state.action == ACTION_GET_CONTENT) {
+ if (state.action == State.ACTION_GET_CONTENT) {
mList.setOnItemLongClickListener(mItemLongClickListener);
} else {
mList.setOnItemLongClickListener(null);
@@ -153,7 +151,7 @@ public class RootsFragment extends Fragment {
public void onCurrentRootChanged() {
if (mAdapter == null) return;
- final RootInfo root = ((DocumentsActivity) getActivity()).getCurrentRoot();
+ final RootInfo root = ((BaseActivity) getActivity()).getCurrentRoot();
for (int i = 0; i < mAdapter.getCount(); i++) {
final Object item = mAdapter.getItem(i);
if (item instanceof RootItem) {
@@ -176,7 +174,7 @@ public class RootsFragment extends Fragment {
private OnItemClickListener mItemListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- final DocumentsActivity activity = DocumentsActivity.get(RootsFragment.this);
+ final BaseActivity activity = BaseActivity.get(RootsFragment.this);
final Item item = mAdapter.getItem(position);
if (item instanceof RootItem) {
activity.onRootPicked(((RootItem) item).root, true);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
index 8d37cdf77adf..49651b4dc50b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
@@ -19,7 +19,7 @@ package com.android.documentsui;
import android.content.AsyncTaskLoader;
import android.content.Context;
-import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
import java.util.Collection;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
index ce98db244270..a13fccc2a3c6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
@@ -113,7 +113,7 @@ public class SaveFragment extends Fragment {
private View.OnClickListener mSaveListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
- final DocumentsActivity activity = DocumentsActivity.get(SaveFragment.this);
+ final BaseActivity activity = BaseActivity.get(SaveFragment.this);
if (mReplaceTarget != null) {
activity.onSaveRequested(mReplaceTarget);
} else {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
index 6c8ca2019b39..3ec3d1c01062 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
@@ -16,9 +16,9 @@
package com.android.documentsui;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_DISPLAY_NAME;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
-import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java b/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
new file mode 100644
index 000000000000..e01328d7ef5a
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
@@ -0,0 +1,952 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+
+import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
+import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
+import static com.android.documentsui.DirectoryFragment.ANIM_SIDE;
+import static com.android.documentsui.DirectoryFragment.ANIM_UP;
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.ActivityNotFoundException;
+import android.content.ClipData;
+import android.content.ComponentName;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.Point;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Debug;
+import android.provider.DocumentsContract;
+import android.support.v4.app.ActionBarDrawerToggle;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v4.widget.DrawerLayout.DrawerListener;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MenuItem.OnActionExpandListener;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.SearchView;
+import android.widget.SearchView.OnQueryTextListener;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.Toast;
+import android.widget.Toolbar;
+
+import com.android.documentsui.RecentsProvider.ResumeColumns;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.model.DurableUtils;
+import com.android.documentsui.model.RootInfo;
+
+import libcore.io.IoUtils;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+public class StandaloneActivity extends BaseActivity {
+ public static final String TAG = "StandaloneFileManagement";
+
+ private static final String EXTRA_STATE = "state";
+
+ private static final int CODE_FORWARD = 42;
+
+ private SearchView mSearchView;
+
+ private Toolbar mToolbar;
+ private Spinner mToolbarStack;
+
+ private Toolbar mRootsToolbar;
+
+ private ActionBarDrawerToggle mDrawerToggle;
+
+ private DirectoryContainerView mDirectoryContainer;
+
+ private boolean mIgnoreNextNavigation;
+ private boolean mIgnoreNextClose;
+ private boolean mIgnoreNextCollapse;
+
+ private boolean mSearchExpanded;
+
+ private RootsCache mRoots;
+ private State mState;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ // Debug.waitForDebugger();
+ super.onCreate(icicle);
+
+ mRoots = DocumentsApplication.getRootsCache(this);
+
+ setResult(Activity.RESULT_CANCELED);
+ setContentView(R.layout.activity);
+
+ final Context context = this;
+ final Resources res = getResources();
+
+ // Strongly define our horizontal dimension; we leave vertical as
+ final WindowManager.LayoutParams a = getWindow().getAttributes();
+
+ final Point size = new Point();
+ getWindowManager().getDefaultDisplay().getSize(size);
+ // a.width = (int) res.getFraction(R.dimen.dialog_width, size.x, size.x);
+
+ getWindow().setAttributes(a);
+
+ mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
+
+ if (icicle != null) {
+ mState = icicle.getParcelable(EXTRA_STATE);
+ } else {
+ buildDefaultState();
+ }
+
+ mToolbar = (Toolbar) findViewById(R.id.toolbar);
+ mToolbar.setTitleTextAppearance(context,
+ android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
+
+ mToolbarStack = (Spinner) findViewById(R.id.stack);
+ mToolbarStack.setOnItemSelectedListener(mStackListener);
+
+ mRootsToolbar = (Toolbar) findViewById(R.id.roots_toolbar);
+ if (mRootsToolbar != null) {
+ mRootsToolbar.setTitleTextAppearance(context,
+ android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
+ }
+
+ setActionBar(mToolbar);
+
+ RootsFragment.show(getFragmentManager(), null);
+ if (!mState.restored) {
+ new RestoreStackTask().execute();
+ } else {
+ onCurrentDirectoryChanged(ANIM_NONE);
+ }
+ }
+
+ private void buildDefaultState() {
+ mState = new State();
+
+ final Intent intent = getIntent();
+ mState.action = State.ACTION_MANAGE_ALL;
+ mState.acceptMimes = new String[] { "*/*" };
+ mState.allowMultiple = true;
+ mState.acceptMimes = new String[] { intent.getType() };
+ mState.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
+ mState.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
+ mState.showAdvanced = mState.forceAdvanced
+ | LocalPreferences.getDisplayAdvancedDevices(this);
+ mState.showSize = true;
+ }
+
+ private class RestoreRootTask extends AsyncTask<Void, Void, RootInfo> {
+ private Uri mRootUri;
+
+ public RestoreRootTask(Uri rootUri) {
+ mRootUri = rootUri;
+ }
+
+ @Override
+ protected RootInfo doInBackground(Void... params) {
+ final String rootId = DocumentsContract.getRootId(mRootUri);
+ return mRoots.getRootOneshot(mRootUri.getAuthority(), rootId);
+ }
+
+ @Override
+ protected void onPostExecute(RootInfo root) {
+ if (isDestroyed()) return;
+ mState.restored = true;
+
+ if (root != null) {
+ onRootPicked(root, true);
+ } else {
+ Log.w(TAG, "Failed to find root: " + mRootUri);
+ finish();
+ }
+ }
+ }
+
+ private class RestoreStackTask extends AsyncTask<Void, Void, Void> {
+ private volatile boolean mRestoredStack;
+ private volatile boolean mExternal;
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ // Restore last stack for calling package
+ final String packageName = getCallingPackageMaybeExtra();
+ final Cursor cursor = getContentResolver()
+ .query(RecentsProvider.buildResume(packageName), null, null, null, null);
+ try {
+ if (cursor.moveToFirst()) {
+ mExternal = cursor.getInt(cursor.getColumnIndex(ResumeColumns.EXTERNAL)) != 0;
+ final byte[] rawStack = cursor.getBlob(
+ cursor.getColumnIndex(ResumeColumns.STACK));
+ DurableUtils.readFromArray(rawStack, mState.stack);
+ mRestoredStack = true;
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to resume: " + e);
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+
+ if (mRestoredStack) {
+ // Update the restored stack to ensure we have freshest data
+ final Collection<RootInfo> matchingRoots = mRoots.getMatchingRootsBlocking(mState);
+ try {
+ mState.stack.updateRoot(matchingRoots);
+ mState.stack.updateDocuments(getContentResolver());
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Failed to restore stack: " + e);
+ mState.stack.reset();
+ mRestoredStack = false;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ if (isDestroyed()) return;
+ mState.restored = true;
+ onCurrentDirectoryChanged(ANIM_NONE);
+ }
+ }
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+ if (mDrawerToggle != null) {
+ mDrawerToggle.syncState();
+ }
+ updateActionBar();
+ }
+
+ @Override
+ public void setRootsDrawerOpen(boolean open) {
+ Log.w(TAG, "Trying to change state of roots drawer to > " + (open ? "open" : "closed"));
+ // throw new UnsupportedOperationException();
+ }
+
+ public void updateActionBar() {
+ final RootInfo root = getCurrentRoot();
+ mToolbar.setNavigationIcon(
+ root != null ? root.loadToolbarIcon(mToolbar.getContext()) : null);
+ mToolbar.setNavigationContentDescription(R.string.drawer_open);
+ mToolbar.setNavigationOnClickListener(null);
+
+ if (mSearchExpanded) {
+ mToolbar.setTitle(null);
+ mToolbarStack.setVisibility(View.GONE);
+ mToolbarStack.setAdapter(null);
+ } else {
+ if (mState.stack.size() <= 1) {
+ mToolbar.setTitle(root.title);
+ mToolbarStack.setVisibility(View.GONE);
+ mToolbarStack.setAdapter(null);
+ } else {
+ mToolbar.setTitle(null);
+ mToolbarStack.setVisibility(View.VISIBLE);
+ mToolbarStack.setAdapter(mStackAdapter);
+
+ mIgnoreNextNavigation = true;
+ mToolbarStack.setSelection(mStackAdapter.getCount() - 1);
+ }
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ getMenuInflater().inflate(R.menu.activity, menu);
+
+ for (int i = 0; i < menu.size(); i++) {
+ final MenuItem item = menu.getItem(i);
+ switch (item.getItemId()) {
+ case R.id.menu_advanced:
+ case R.id.menu_file_size:
+ break;
+ default:
+ item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ }
+ }
+
+ final MenuItem searchMenu = menu.findItem(R.id.menu_search);
+ mSearchView = (SearchView) searchMenu.getActionView();
+ mSearchView.setOnQueryTextListener(new OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String query) {
+ mSearchExpanded = true;
+ mState.currentSearch = query;
+ mSearchView.clearFocus();
+ onCurrentDirectoryChanged(ANIM_NONE);
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String newText) {
+ return false;
+ }
+ });
+
+ searchMenu.setOnActionExpandListener(new OnActionExpandListener() {
+ @Override
+ public boolean onMenuItemActionExpand(MenuItem item) {
+ mSearchExpanded = true;
+ updateActionBar();
+ return true;
+ }
+
+ @Override
+ public boolean onMenuItemActionCollapse(MenuItem item) {
+ mSearchExpanded = false;
+ if (mIgnoreNextCollapse) {
+ mIgnoreNextCollapse = false;
+ return true;
+ }
+
+ mState.currentSearch = null;
+ onCurrentDirectoryChanged(ANIM_NONE);
+ return true;
+ }
+ });
+
+ mSearchView.setOnCloseListener(new SearchView.OnCloseListener() {
+ @Override
+ public boolean onClose() {
+ mSearchExpanded = false;
+ if (mIgnoreNextClose) {
+ mIgnoreNextClose = false;
+ return false;
+ }
+
+ mState.currentSearch = null;
+ onCurrentDirectoryChanged(ANIM_NONE);
+ return false;
+ }
+ });
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ final FragmentManager fm = getFragmentManager();
+
+ final RootInfo root = getCurrentRoot();
+ final DocumentInfo cwd = getCurrentDirectory();
+
+ final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
+ final MenuItem search = menu.findItem(R.id.menu_search);
+ final MenuItem sort = menu.findItem(R.id.menu_sort);
+ final MenuItem sortSize = menu.findItem(R.id.menu_sort_size);
+ final MenuItem grid = menu.findItem(R.id.menu_grid);
+ final MenuItem list = menu.findItem(R.id.menu_list);
+ final MenuItem advanced = menu.findItem(R.id.menu_advanced);
+ final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
+
+ sort.setVisible(cwd != null);
+ grid.setVisible(mState.derivedMode != State.MODE_GRID);
+ list.setVisible(mState.derivedMode != State.MODE_LIST);
+
+ if (mState.currentSearch != null) {
+ // Search uses backend ranking; no sorting
+ sort.setVisible(false);
+
+ search.expandActionView();
+
+ mSearchView.setIconified(false);
+ mSearchView.clearFocus();
+ mSearchView.setQuery(mState.currentSearch, false);
+ } else {
+ mIgnoreNextClose = true;
+ mSearchView.setIconified(true);
+ mSearchView.clearFocus();
+
+ mIgnoreNextCollapse = true;
+ search.collapseActionView();
+ }
+
+ // Only sort by size when visible
+ sortSize.setVisible(mState.showSize);
+
+ fileSize.setVisible(true);
+ search.setVisible(true);
+ createDir.setVisible(true);
+ advanced.setVisible(true);
+
+ advanced.setTitle(LocalPreferences.getDisplayAdvancedDevices(this)
+ ? R.string.menu_advanced_hide : R.string.menu_advanced_show);
+ fileSize.setTitle(LocalPreferences.getDisplayFileSize(this)
+ ? R.string.menu_file_size_hide : R.string.menu_file_size_show);
+
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (mDrawerToggle != null && mDrawerToggle.onOptionsItemSelected(item)) {
+ return true;
+ }
+
+ final int id = item.getItemId();
+ if (id == android.R.id.home) {
+ onBackPressed();
+ return true;
+ } else if (id == R.id.menu_create_dir) {
+ CreateDirectoryFragment.show(getFragmentManager());
+ return true;
+ } else if (id == R.id.menu_search) {
+ return false;
+ } else if (id == R.id.menu_sort_name) {
+ setUserSortOrder(State.SORT_ORDER_DISPLAY_NAME);
+ return true;
+ } else if (id == R.id.menu_sort_date) {
+ setUserSortOrder(State.SORT_ORDER_LAST_MODIFIED);
+ return true;
+ } else if (id == R.id.menu_sort_size) {
+ setUserSortOrder(State.SORT_ORDER_SIZE);
+ return true;
+ } else if (id == R.id.menu_grid) {
+ setUserMode(State.MODE_GRID);
+ return true;
+ } else if (id == R.id.menu_list) {
+ setUserMode(State.MODE_LIST);
+ return true;
+ } else if (id == R.id.menu_advanced) {
+ setDisplayAdvancedDevices(!LocalPreferences.getDisplayAdvancedDevices(this));
+ return true;
+ } else if (id == R.id.menu_file_size) {
+ setDisplayFileSize(!LocalPreferences.getDisplayFileSize(this));
+ return true;
+ } else {
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ private void setDisplayAdvancedDevices(boolean display) {
+ LocalPreferences.setDisplayAdvancedDevices(this, display);
+ mState.showAdvanced = mState.forceAdvanced | display;
+ RootsFragment.get(getFragmentManager()).onDisplayStateChanged();
+ invalidateOptionsMenu();
+ }
+
+ private void setDisplayFileSize(boolean display) {
+ LocalPreferences.setDisplayFileSize(this, display);
+ mState.showSize = display;
+ DirectoryFragment.get(getFragmentManager()).onDisplayStateChanged();
+ invalidateOptionsMenu();
+ }
+
+ @Override
+ public void onStateChanged() {
+ invalidateOptionsMenu();
+ }
+
+ /**
+ * Set state sort order based on explicit user action.
+ */
+ private void setUserSortOrder(int sortOrder) {
+ mState.userSortOrder = sortOrder;
+ DirectoryFragment.get(getFragmentManager()).onUserSortOrderChanged();
+ }
+
+ /**
+ * Set state mode based on explicit user action.
+ */
+ private void setUserMode(int mode) {
+ mState.userMode = mode;
+ DirectoryFragment.get(getFragmentManager()).onUserModeChanged();
+ }
+
+ @Override
+ public void setPending(boolean pending) {
+ final SaveFragment save = SaveFragment.get(getFragmentManager());
+ if (save != null) {
+ save.setPending(pending);
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (!mState.stackTouched) {
+ super.onBackPressed();
+ return;
+ }
+
+ final int size = mState.stack.size();
+ if (size > 1) {
+ mState.stack.pop();
+ onCurrentDirectoryChanged(ANIM_UP);
+ } else {
+ super.onBackPressed();
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle state) {
+ super.onSaveInstanceState(state);
+ state.putParcelable(EXTRA_STATE, mState);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle state) {
+ super.onRestoreInstanceState(state);
+ }
+
+ private BaseAdapter mStackAdapter = new BaseAdapter() {
+ @Override
+ public int getCount() {
+ return mState.stack.size();
+ }
+
+ @Override
+ public DocumentInfo getItem(int position) {
+ return mState.stack.get(mState.stack.size() - position - 1);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.item_subdir_title, parent, false);
+ }
+
+ final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+ final DocumentInfo doc = getItem(position);
+
+ if (position == 0) {
+ final RootInfo root = getCurrentRoot();
+ title.setText(root.title);
+ } else {
+ title.setText(doc.displayName);
+ }
+
+ return convertView;
+ }
+
+ @Override
+ public View getDropDownView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.item_subdir, parent, false);
+ }
+
+ final ImageView subdir = (ImageView) convertView.findViewById(R.id.subdir);
+ final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+ final DocumentInfo doc = getItem(position);
+
+ if (position == 0) {
+ final RootInfo root = getCurrentRoot();
+ title.setText(root.title);
+ subdir.setVisibility(View.GONE);
+ } else {
+ title.setText(doc.displayName);
+ subdir.setVisibility(View.VISIBLE);
+ }
+
+ return convertView;
+ }
+ };
+
+ private OnItemSelectedListener mStackListener = new OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ if (mIgnoreNextNavigation) {
+ mIgnoreNextNavigation = false;
+ return;
+ }
+
+ while (mState.stack.size() > position + 1) {
+ mState.stackTouched = true;
+ mState.stack.pop();
+ }
+ onCurrentDirectoryChanged(ANIM_UP);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ // Ignored
+ }
+ };
+
+ @Override
+ public RootInfo getCurrentRoot() {
+ if (mState.stack.root != null) {
+ return mState.stack.root;
+ } else {
+ return mRoots.getRecentsRoot();
+ }
+ }
+
+ public DocumentInfo getCurrentDirectory() {
+ return mState.stack.peek();
+ }
+
+ private String getCallingPackageMaybeExtra() {
+ final String extra = getIntent().getStringExtra(DocumentsContract.EXTRA_PACKAGE_NAME);
+ return (extra != null) ? extra : getCallingPackage();
+ }
+
+ public Executor getCurrentExecutor() {
+ final DocumentInfo cwd = getCurrentDirectory();
+ if (cwd != null && cwd.authority != null) {
+ return ProviderExecutor.forAuthority(cwd.authority);
+ } else {
+ return AsyncTask.THREAD_POOL_EXECUTOR;
+ }
+ }
+
+ @Override
+ public State getDisplayState() {
+ return mState;
+ }
+
+ private void onCurrentDirectoryChanged(int anim) {
+ final FragmentManager fm = getFragmentManager();
+ final RootInfo root = getCurrentRoot();
+ final DocumentInfo cwd = getCurrentDirectory();
+
+ mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_DOWN);
+
+ if (cwd == null) {
+ DirectoryFragment.showRecentsOpen(fm, anim);
+
+ // Start recents in grid when requesting visual things
+ final boolean visualMimes = MimePredicate.mimeMatches(
+ MimePredicate.VISUAL_MIMES, mState.acceptMimes);
+ mState.userMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
+ mState.derivedMode = mState.userMode;
+ } else {
+ if (mState.currentSearch != null) {
+ // Ongoing search
+ DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
+ } else {
+ // Normal boring directory
+ DirectoryFragment.showNormal(fm, root, cwd, anim);
+ }
+ }
+
+ final RootsFragment roots = RootsFragment.get(fm);
+ if (roots != null) {
+ roots.onCurrentRootChanged();
+ }
+
+ updateActionBar();
+ invalidateOptionsMenu();
+ dumpStack();
+ }
+
+ @Override
+ public void onStackPicked(DocumentStack stack) {
+ try {
+ // Update the restored stack to ensure we have freshest data
+ stack.updateDocuments(getContentResolver());
+
+ mState.stack = stack;
+ mState.stackTouched = true;
+ onCurrentDirectoryChanged(ANIM_SIDE);
+
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Failed to restore stack: " + e);
+ }
+ }
+
+ @Override
+ public void onRootPicked(RootInfo root, boolean closeDrawer) {
+ // Clear entire backstack and start in new root
+ mState.stack.root = root;
+ mState.stack.clear();
+ mState.stackTouched = true;
+
+ if (!mRoots.isRecentsRoot(root)) {
+ new PickRootTask(root).executeOnExecutor(getCurrentExecutor());
+ } else {
+ onCurrentDirectoryChanged(ANIM_SIDE);
+ }
+ }
+
+ private class PickRootTask extends AsyncTask<Void, Void, DocumentInfo> {
+ private RootInfo mRoot;
+
+ public PickRootTask(RootInfo root) {
+ mRoot = root;
+ }
+
+ @Override
+ protected DocumentInfo doInBackground(Void... params) {
+ try {
+ final Uri uri = DocumentsContract.buildDocumentUri(
+ mRoot.authority, mRoot.documentId);
+ return DocumentInfo.fromUri(getContentResolver(), uri);
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Failed to find root", e);
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(DocumentInfo result) {
+ if (result != null) {
+ mState.stack.push(result);
+ mState.stackTouched = true;
+ onCurrentDirectoryChanged(ANIM_SIDE);
+ }
+ }
+ }
+
+ @Override
+ public void onAppPicked(ResolveInfo info) {
+ final Intent intent = new Intent(getIntent());
+ intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ intent.setComponent(new ComponentName(
+ info.activityInfo.applicationInfo.packageName, info.activityInfo.name));
+ startActivityForResult(intent, CODE_FORWARD);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ Log.d(TAG, "onActivityResult() code=" + resultCode);
+
+ // Only relay back results when not canceled; otherwise stick around to
+ // let the user pick another app/backend.
+ if (requestCode == CODE_FORWARD && resultCode != RESULT_CANCELED) {
+
+ // Remember that we last picked via external app
+ final String packageName = getCallingPackageMaybeExtra();
+ final ContentValues values = new ContentValues();
+ values.put(ResumeColumns.EXTERNAL, 1);
+ getContentResolver().insert(RecentsProvider.buildResume(packageName), values);
+
+ // Pass back result to original caller
+ setResult(resultCode, data);
+ finish();
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+
+ @Override
+ public void onDocumentPicked(DocumentInfo doc) {
+ final FragmentManager fm = getFragmentManager();
+ if (doc.isDirectory()) {
+ mState.stack.push(doc);
+ mState.stackTouched = true;
+ onCurrentDirectoryChanged(ANIM_DOWN);
+ } else {
+ // Fall back to viewing
+ final Intent view = new Intent(Intent.ACTION_VIEW);
+ view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ view.setData(doc.derivedUri);
+
+ try {
+ startActivity(view);
+ } catch (ActivityNotFoundException ex2) {
+ Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+
+ public void onDocumentsPicked(List<DocumentInfo> docs) {
+ // TODO
+ }
+
+ @Override
+ public void onSaveRequested(DocumentInfo replaceTarget) {
+ new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getCurrentExecutor());
+ }
+
+ @Override
+ public void onSaveRequested(String mimeType, String displayName) {
+ new CreateFinishTask(mimeType, displayName).executeOnExecutor(getCurrentExecutor());
+ }
+
+ @Override
+ public void onPickRequested(DocumentInfo pickTarget) {
+ final Uri viaUri = DocumentsContract.buildTreeDocumentUri(pickTarget.authority,
+ pickTarget.documentId);
+ new PickFinishTask(viaUri).executeOnExecutor(getCurrentExecutor());
+ }
+
+ private void saveStackBlocking() {
+ final ContentResolver resolver = getContentResolver();
+ final ContentValues values = new ContentValues();
+
+ final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack);
+
+ // Remember location for next app launch
+ final String packageName = getCallingPackageMaybeExtra();
+ values.clear();
+ values.put(ResumeColumns.STACK, rawStack);
+ values.put(ResumeColumns.EXTERNAL, 0);
+ resolver.insert(RecentsProvider.buildResume(packageName), values);
+ }
+
+ private void onFinished(Uri... uris) {
+ Log.d(TAG, "onFinished() " + Arrays.toString(uris));
+
+ final Intent intent = new Intent();
+ if (uris.length == 1) {
+ intent.setData(uris[0]);
+ } else if (uris.length > 1) {
+ final ClipData clipData = new ClipData(
+ null, mState.acceptMimes, new ClipData.Item(uris[0]));
+ for (int i = 1; i < uris.length; i++) {
+ clipData.addItem(new ClipData.Item(uris[i]));
+ }
+ intent.setClipData(clipData);
+ }
+
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
+
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ }
+
+ private class CreateFinishTask extends AsyncTask<Void, Void, Uri> {
+ private final String mMimeType;
+ private final String mDisplayName;
+
+ public CreateFinishTask(String mimeType, String displayName) {
+ mMimeType = mimeType;
+ mDisplayName = displayName;
+ }
+
+ @Override
+ protected void onPreExecute() {
+ setPending(true);
+ }
+
+ @Override
+ protected Uri doInBackground(Void... params) {
+ final ContentResolver resolver = getContentResolver();
+ final DocumentInfo cwd = getCurrentDirectory();
+
+ ContentProviderClient client = null;
+ Uri childUri = null;
+ try {
+ client = DocumentsApplication.acquireUnstableProviderOrThrow(
+ resolver, cwd.derivedUri.getAuthority());
+ childUri = DocumentsContract.createDocument(
+ client, cwd.derivedUri, mMimeType, mDisplayName);
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to create document", e);
+ } finally {
+ ContentProviderClient.releaseQuietly(client);
+ }
+
+ if (childUri != null) {
+ saveStackBlocking();
+ }
+
+ return childUri;
+ }
+
+ @Override
+ protected void onPostExecute(Uri result) {
+ if (result != null) {
+ onFinished(result);
+ } else {
+ Toast.makeText(StandaloneActivity.this, R.string.save_error, Toast.LENGTH_SHORT)
+ .show();
+ }
+
+ setPending(false);
+ }
+ }
+
+ private class ExistingFinishTask extends AsyncTask<Void, Void, Void> {
+ private final Uri[] mUris;
+
+ public ExistingFinishTask(Uri... uris) {
+ mUris = uris;
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ saveStackBlocking();
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ onFinished(mUris);
+ }
+ }
+
+ private class PickFinishTask extends AsyncTask<Void, Void, Void> {
+ private final Uri mUri;
+
+ public PickFinishTask(Uri uri) {
+ mUri = uri;
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ saveStackBlocking();
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ onFinished(mUri);
+ }
+ }
+
+ private void dumpStack() {
+ Log.d(TAG, "Current stack: ");
+ Log.d(TAG, " * " + mState.stack.root);
+ for (DocumentInfo doc : mState.stack) {
+ Log.d(TAG, " +-- " + doc);
+ }
+ }
+
+ public static BaseActivity get(Fragment fragment) {
+ return (BaseActivity) fragment.getActivity();
+ }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 396fe4f34f41..c9805aed3bbd 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -40,6 +40,7 @@ import static android.os.BatteryManager.EXTRA_HEALTH;
import android.media.AudioManager;
import android.os.BatteryManager;
+import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.Message;
@@ -51,9 +52,11 @@ import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
+
import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.FingerprintManagerReceiver;
+import android.service.fingerprint.FingerprintManager.AuthenticationCallback;
import android.service.fingerprint.FingerprintUtils;
+import android.service.fingerprint.FingerprintManager.AuthenticationResult;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
@@ -109,10 +112,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
private static final int MSG_SCREEN_TURNED_ON = 319;
private static final int MSG_SCREEN_TURNED_OFF = 320;
private static final int MSG_KEYGUARD_BOUNCER_CHANGED = 322;
- private static final int MSG_FINGERPRINT_PROCESSED = 323;
- private static final int MSG_FINGERPRINT_ACQUIRED = 324;
- private static final int MSG_FACE_UNLOCK_STATE_CHANGED = 325;
- private static final int MSG_SIM_SUBSCRIPTION_INFO_CHANGED = 326;
+ private static final int MSG_FINGERPRINT_AUTHENTICATED = 323;
+ private static final int MSG_FINGERPRINT_ERROR = 324;
+ private static final int MSG_FINGERPRINT_HELP = 325;
+ private static final int MSG_FACE_UNLOCK_STATE_CHANGED = 326;
+ private static final int MSG_SIM_SUBSCRIPTION_INFO_CHANGED = 327;
private static KeyguardUpdateMonitor sInstance;
@@ -201,11 +205,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
case MSG_SCREEN_TURNED_ON:
handleScreenTurnedOn();
break;
- case MSG_FINGERPRINT_ACQUIRED:
- handleFingerprintAcquired(msg.arg1);
+ case MSG_FINGERPRINT_AUTHENTICATED:
+ handleFingerprintAuthenticated(msg.arg1, msg.arg2);
+ break;
+ case MSG_FINGERPRINT_HELP:
+ handleFingerprintHelp(msg.arg1 /* msgId */, (String) msg.obj /* errString */);
break;
- case MSG_FINGERPRINT_PROCESSED:
- handleFingerprintProcessed(msg.arg1);
+ case MSG_FINGERPRINT_ERROR:
+ handleFingerprintError(msg.arg1 /* msgId */, (String) msg.obj /* errString */);
break;
case MSG_FACE_UNLOCK_STATE_CHANGED:
handleFaceUnlockStateChanged(msg.arg1 != 0, msg.arg2);
@@ -227,7 +234,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
private SparseBooleanArray mUserHasTrust = new SparseBooleanArray();
private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray();
- private SparseBooleanArray mUserFingerprintRecognized = new SparseBooleanArray();
+ private SparseBooleanArray mUserFingerprintAuthenticated = new SparseBooleanArray();
private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray();
@Override
@@ -314,18 +321,18 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
}
- private void onFingerprintRecognized(int userId) {
- mUserFingerprintRecognized.put(userId, true);
+ private void onFingerprintAuthenticated(int userId) {
+ mUserFingerprintAuthenticated.put(userId, true);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onFingerprintRecognized(userId);
+ cb.onFingerprintAuthenticated(userId);
}
}
}
- private void handleFingerprintProcessed(int fingerprintId) {
- if (fingerprintId == 0) return; // not a valid fingerprint
+ private void handleFingerprintAuthenticated(int fingerId, int groupId) {
+ if (fingerId == 0) return; // not a valid fingerprint
final int userId;
try {
@@ -341,17 +348,28 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
final ContentResolver res = mContext.getContentResolver();
final int ids[] = FingerprintUtils.getFingerprintIdsForUser(res, userId);
for (int i = 0; i < ids.length; i++) {
- if (ids[i] == fingerprintId) {
- onFingerprintRecognized(userId);
+ // TODO: fix once HAL supports storing group id
+ final boolean isCorrectUser = true || (groupId == userId);
+ if (ids[i] == fingerId && isCorrectUser) {
+ onFingerprintAuthenticated(userId);
}
}
}
- private void handleFingerprintAcquired(int info) {
+ private void handleFingerprintHelp(int msgId, String helpString) {
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onFingerprintAcquired(info);
+ cb.onFingerprintHelp(msgId, helpString);
+ }
+ }
+ }
+
+ private void handleFingerprintError(int msgId, String errString) {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onFingerprintError(msgId, errString);
}
}
}
@@ -387,7 +405,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
public boolean getUserHasTrust(int userId) {
return !isTrustDisabled(userId) && mUserHasTrust.get(userId)
- || mUserFingerprintRecognized.get(userId);
+ || mUserFingerprintAuthenticated.get(userId);
}
public boolean getUserTrustIsManaged(int userId) {
@@ -464,23 +482,29 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
}
};
- private FingerprintManagerReceiver mFingerprintManagerReceiver =
- new FingerprintManagerReceiver() {
+
+ private FingerprintManager.AuthenticationCallback mAuthenticationCallback
+ = new AuthenticationCallback() {
+
@Override
- public void onProcessed(int fingerprintId) {
- mHandler.obtainMessage(MSG_FINGERPRINT_PROCESSED, fingerprintId, 0).sendToTarget();
- };
+ public void onAuthenticationSucceeded(AuthenticationResult result) {
+ mHandler.obtainMessage(MSG_FINGERPRINT_AUTHENTICATED,
+ result.getFingerprint().getFingerId(),
+ result.getFingerprint().getGroupId()).sendToTarget();
+ }
@Override
- public void onAcquired(int info) {
- mHandler.obtainMessage(MSG_FINGERPRINT_ACQUIRED, info, 0).sendToTarget();
+ public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
+ mHandler.obtainMessage(MSG_FINGERPRINT_HELP, helpMsgId, 0, helpString).sendToTarget();
}
@Override
- public void onError(int error) {
- if (DEBUG) Log.w(TAG, "FingerprintManager reported error: " + error);
+ public void onAuthenticationError(int errMsgId, CharSequence errString) {
+ mHandler.obtainMessage(MSG_FINGERPRINT_ERROR, errMsgId, 0, errString);
}
};
+ private CancellationSignal mFingerprintCancelSignal;
+ private FingerprintManager mFpm;
/**
* When we receive a
@@ -606,6 +630,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
cb.onScreenTurnedOn();
}
}
+ startListeningForFingerprint(mContext);
}
protected void handleScreenTurnedOff(int arg1) {
@@ -617,6 +642,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
cb.onScreenTurnedOff(arg1);
}
}
+ stopListeningForFingerprint();
}
/**
@@ -705,9 +731,25 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
TrustManager trustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
trustManager.registerTrustListener(this);
- FingerprintManager fpm;
- fpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
- fpm.startListening(mFingerprintManagerReceiver);
+ mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
+ startListeningForFingerprint(context);
+ }
+
+ private void startListeningForFingerprint(Context context) {
+ if (mFpm != null && mFpm.isHardwareDetected()) {
+ if (mFingerprintCancelSignal == null) {
+ mFingerprintCancelSignal = new CancellationSignal();
+ } else {
+ mFingerprintCancelSignal.cancel();
+ }
+ mFpm.authenticate(null, mAuthenticationCallback, mFingerprintCancelSignal, 0);
+ }
+ }
+
+ private void stopListeningForFingerprint() {
+ if (mFingerprintCancelSignal != null) {
+ mFingerprintCancelSignal.cancel();
+ }
}
private boolean isDeviceProvisionedInSettingsDb() {
@@ -1152,7 +1194,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
public void clearFingerprintRecognized() {
- mUserFingerprintRecognized.clear();
+ mUserFingerprintAuthenticated.clear();
}
public void reportFailedUnlockAttempt() {
@@ -1239,7 +1281,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
mHandler.sendEmptyMessage(MSG_SCREEN_TURNED_ON);
}
- public void dispatchScreenTurndOff(int why) {
+ public void dispatchScreenTurnedOff(int why) {
synchronized(this) {
mScreenOn = false;
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index f0e2389a367e..c2462e01e637 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -19,6 +19,7 @@ import android.app.admin.DevicePolicyManager;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.os.SystemClock;
+import android.service.fingerprint.FingerprintManager;
import android.telephony.TelephonyManager;
import android.view.WindowManagerPolicy;
@@ -176,14 +177,24 @@ public class KeyguardUpdateMonitorCallback {
/**
* Called when a fingerprint is recognized.
- * @param userId
+ * @param userId the user id for which the fingerprint was authenticated
*/
- public void onFingerprintRecognized(int userId) { }
+ public void onFingerprintAuthenticated(int userId) { }
/**
- * Called when fingerprint is acquired but not yet recognized
+ * Called when fingerprint provides help string (e.g. "Try again")
+ * @param msgId
+ * @param helpString
*/
- public void onFingerprintAcquired(int info) { }
+ public void onFingerprintHelp(int msgId, String helpString) { }
+
+ /**
+ * Called when fingerprint provides an semi-permanent error message
+ * (e.g. "Hardware not available").
+ * @param msgId one of the error messages listed in {@link FingerprintManager}
+ * @param errString
+ */
+ public void onFingerprintError(int msgId, String errString) { }
/**
* Called when the state of face unlock changed.
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index 5d8c3c6a7c09..13d5543640f5 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -69,7 +69,7 @@
<item quantity="one"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> प्रिंट कार्य</item>
<item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> प्रिंट कार्य</item>
</plurals>
- <string name="cancel" msgid="4373674107267141885">"रहने दें"</string>
+ <string name="cancel" msgid="4373674107267141885">"अभी नहीं"</string>
<string name="restart" msgid="2472034227037808749">"पुन: आरंभ करें"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"प्रिंटर के लिए कोई कनेक्शन नहीं"</string>
<string name="reason_unknown" msgid="5507940196503246139">"अज्ञात"</string>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 30786f057fbf..952b22010889 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -62,9 +62,10 @@ public class SettingsHelper {
*/
private static final ArraySet<String> sBroadcastOnRestore;
static {
- sBroadcastOnRestore = new ArraySet<String>(2);
+ sBroadcastOnRestore = new ArraySet<String>(3);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+ sBroadcastOnRestore.add(Settings.Secure.ENABLED_INPUT_METHODS);
}
private interface SettingsLookup {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 3c4424505f04..9d165016e30f 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -105,6 +105,18 @@
android:resource="@xml/file_provider_paths" />
</provider>
+ <provider
+ android:name=".BugreportStorageProvider"
+ android:authorities="com.android.shell.documents"
+ android:grantUriPermissions="true"
+ android:exported="true"
+ android:permission="android.permission.MANAGE_DOCUMENTS"
+ android:enabled="false">
+ <intent-filter>
+ <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
+ </intent-filter>
+ </provider>
+
<activity
android:name=".BugreportWarningActivity"
android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
diff --git a/packages/Shell/res/values-af/strings.xml b/packages/Shell/res/values-af/strings.xml
index 8c4f75f4c212..56d7cc23b771 100644
--- a/packages/Shell/res/values-af/strings.xml
+++ b/packages/Shell/res/values-af/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Raak om jou foutverslag te deel"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Foutverslae bevat data van die stelsel se verskillende loglêers af, insluitend persoonlike en private inligting. Deel foutverslae net met programme en mense wat jy vertrou."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Wys hierdie boodskap volgende keer"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-am/strings.xml b/packages/Shell/res/values-am/strings.xml
index af84a09f4489..233c8514f420 100644
--- a/packages/Shell/res/values-am/strings.xml
+++ b/packages/Shell/res/values-am/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"የሳንካ ሪፖርትዎን ለማጋራት ይንክኩ"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"የሳንካ ሪፖርቶች የግል መረጃን ጨምሮ ከበርካታ የስርዓቱ ምዝግብ ማስታወሻዎች የመጣ ውሂብን ይዟል። የሳንካ ሪፖርቶች ለሚያምኗቸው መተግበሪያዎችን እና ሰዎችን ብቻ ያጋሩ።"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ይህን መልዕክት በሚቀጥለው ጊዜ አሳይ"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-ar/strings.xml b/packages/Shell/res/values-ar/strings.xml
index 69d7d3f1215c..385c51c2e162 100644
--- a/packages/Shell/res/values-ar/strings.xml
+++ b/packages/Shell/res/values-ar/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"المس لمشاركة تقرير الأخطاء"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"تحتوي تقارير الأخطاء على بيانات من ملفات سجلات النظام المتنوعة، بما في ذلك معلومات شخصية وخاصة. لا تشارك تقارير الأخطاء إلا مع التطبيقات والأشخاص الموثوق بهم."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"إظهار هذه الرسالة في المرة القادمة"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-bg/strings.xml b/packages/Shell/res/values-bg/strings.xml
index f7ae49c193c9..97e82bf9c5d9 100644
--- a/packages/Shell/res/values-bg/strings.xml
+++ b/packages/Shell/res/values-bg/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Докоснете, за да споделите отчета си за програмни грешки"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Отчетите за програмни грешки съдържат данни от различни регистрационни файлове на системата, включително лична и поверителна информация. Споделяйте ги само с приложения и хора, на които имате доверие."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Това съобщение да се показва следващия път"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-bn-rBD/strings.xml b/packages/Shell/res/values-bn-rBD/strings.xml
index 5e8cec498e0e..13f99522a5cb 100644
--- a/packages/Shell/res/values-bn-rBD/strings.xml
+++ b/packages/Shell/res/values-bn-rBD/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"আপনার ত্রুটির প্রতিবেদন ভাগ করতে স্পর্শ করুন"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"ত্রুটির প্রতিবেদনগুলিতে থাকা ডেটা, সিস্টেমের বিভিন্ন লগ ফাইলগুলি থেকে আসে, যাতে ব্যক্তিগত এবং গোপনীয় তথ্য অন্তর্ভুক্ত থাকে৷ আপনি বিশ্বাস করেন শুধুমাত্র এমন অ্যাপ্লিকেশান এবং ব্যক্তিদের সাথে ত্রুটির প্রতিবেদনগুলি ভাগ করুন৷"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"এই বার্তাটি পরের বার দেখান"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-ca/strings.xml b/packages/Shell/res/values-ca/strings.xml
index fa4d1f3b8bc8..7b5076a59ee4 100644
--- a/packages/Shell/res/values-ca/strings.xml
+++ b/packages/Shell/res/values-ca/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca aquí per compartir el teu informe d\'error."</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Els informes d\'error contenen dades dels diferents fitxers de registre del sistema, inclosa informació privada i personal. Comparteix els informes d\'error només amb les aplicacions i amb les persones en qui confies."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostra aquest missatge la propera vegada"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-cs/strings.xml b/packages/Shell/res/values-cs/strings.xml
index d321159ddb4d..1faf34172c1a 100644
--- a/packages/Shell/res/values-cs/strings.xml
+++ b/packages/Shell/res/values-cs/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Chybové hlášení můžete sdílet klepnutím."</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Chybová hlášení obsahují data z různých souborů protokolů systému včetně osobních a soukromých informací. Chybová hlášení sdílejte pouze s aplikacemi a uživateli, kterým důvěřujete."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Zobrazit tuto zprávu příště"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-da/strings.xml b/packages/Shell/res/values-da/strings.xml
index 3e58bc273aea..28507b3efe4c 100644
--- a/packages/Shell/res/values-da/strings.xml
+++ b/packages/Shell/res/values-da/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tryk for at dele din fejlrapport"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Fejlrapporter indeholder data fra systemets forskellige logfiler, f.eks. personlige og private oplysninger. Del kun fejlrapporter med apps og personer, du har tillid til."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Vis denne underretning næste gang"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-de/strings.xml b/packages/Shell/res/values-de/strings.xml
index f7387ffc1d72..a1738b8ad538 100644
--- a/packages/Shell/res/values-de/strings.xml
+++ b/packages/Shell/res/values-de/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tippen, um Fehlerbericht zu teilen"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Fehlerberichte enthalten Daten aus verschiedenen Protokolldateien des Systems, darunter auch personenbezogene und private Daten. Teilen Sie Fehlerberichte nur mit Apps und Personen, denen Sie vertrauen."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Diese Nachricht nächstes Mal zeigen"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-el/strings.xml b/packages/Shell/res/values-el/strings.xml
index 529b420c9c73..26f024eb51a2 100644
--- a/packages/Shell/res/values-el/strings.xml
+++ b/packages/Shell/res/values-el/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Αγγίξτε για να μοιραστείτε τη αναφορά σφαλμάτων"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Οι αναφορές σφαλμάτων περιέχουν δεδομένα από τα διάφορα αρχεία καταγραφής του συστήματος, συμπεριλαμβανομένων προσωπικών και ιδιωτικών πληροφοριών. Να μοιράζεστε αναφορές σφαλμάτων μόνο με εφαρμογές και άτομα που εμπιστεύεστε."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Εμφάνιση αυτού του μηνύματος την επόμενη φορά"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-en-rAU/strings.xml b/packages/Shell/res/values-en-rAU/strings.xml
index fab4223c37cf..22424736c6eb 100644
--- a/packages/Shell/res/values-en-rAU/strings.xml
+++ b/packages/Shell/res/values-en-rAU/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Touch to share your bug report"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people that you trust."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Show this message next time"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-en-rGB/strings.xml b/packages/Shell/res/values-en-rGB/strings.xml
index fab4223c37cf..22424736c6eb 100644
--- a/packages/Shell/res/values-en-rGB/strings.xml
+++ b/packages/Shell/res/values-en-rGB/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Touch to share your bug report"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people that you trust."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Show this message next time"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-en-rIN/strings.xml b/packages/Shell/res/values-en-rIN/strings.xml
index fab4223c37cf..22424736c6eb 100644
--- a/packages/Shell/res/values-en-rIN/strings.xml
+++ b/packages/Shell/res/values-en-rIN/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Touch to share your bug report"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people that you trust."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Show this message next time"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-es-rUS/strings.xml b/packages/Shell/res/values-es-rUS/strings.xml
index d01561ca876a..240332a56f75 100644
--- a/packages/Shell/res/values-es-rUS/strings.xml
+++ b/packages/Shell/res/values-es-rUS/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca para compartir tu informe de errores."</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Los informes de errores contienen datos de los distintos archivos de registro del sistema, incluida la información personal y privada. Comparte los informes de errores únicamente con aplicaciones y personas en las que confíes."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar este mensaje la próxima vez"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-es/strings.xml b/packages/Shell/res/values-es/strings.xml
index 19bfc2529626..ea75003b4d9d 100644
--- a/packages/Shell/res/values-es/strings.xml
+++ b/packages/Shell/res/values-es/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca para compartir tu informe de error"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Los informes de errores contienen datos de los distintos archivos de registro del sistema, incluida información personal y privada. Comparte los informes de errores únicamente con aplicaciones y usuarios en los que confíes."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar este mensaje la próxima vez"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-et-rEE/strings.xml b/packages/Shell/res/values-et-rEE/strings.xml
index 7de367d1553c..4fec4835c94f 100644
--- a/packages/Shell/res/values-et-rEE/strings.xml
+++ b/packages/Shell/res/values-et-rEE/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Veaaruande jagamiseks puudutage"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Veaaruanded sisaldavad andmeid erinevatest süsteemi logifailidest, sh isiklikku ja privaatset teavet. Jagage veaaruandeid ainult usaldusväärsete rakenduste ja inimestega."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Kuva see sõnum järgmisel korral"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-eu-rES/strings.xml b/packages/Shell/res/values-eu-rES/strings.xml
index 0c42cab00317..d689026ca420 100644
--- a/packages/Shell/res/values-eu-rES/strings.xml
+++ b/packages/Shell/res/values-eu-rES/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Akatsen txostena partekatzeko, ukitu"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Akatsen txostenek sistemaren erregistro-fitxategietako datuak dauzkate, informazio pertsonala eta pribatua barne. Akatsen txostenak partekatzen badituzu, partekatu soilik aplikazio eta pertsona fidagarriekin."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Erakutsi mezu hau hurrengoan"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-fa/strings.xml b/packages/Shell/res/values-fa/strings.xml
index a737a778c975..e0f0cf107c75 100644
--- a/packages/Shell/res/values-fa/strings.xml
+++ b/packages/Shell/res/values-fa/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"جهت اشتراک‌گذاری گزارش اشکال خود لمس کنید"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"گزارش‌های اشکال حاوی داده‌هایی از فایل‌های گزارش مختلف در سیستم هستند، شامل اطلاعات شخصی و خصوصی. گزارش‌های اشکال را فقط با افراد و برنامه‌های مورد اعتماد خود به اشتراک بگذارید."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"دفعه بعد این پیام نشان داده شود"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-fi/strings.xml b/packages/Shell/res/values-fi/strings.xml
index 247cb6fc8028..5a89fd9c4476 100644
--- a/packages/Shell/res/values-fi/strings.xml
+++ b/packages/Shell/res/values-fi/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Jaa virheraportti koskettamalla tätä"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Virheraportit sisältävät järjestelmän lokitietoja, ja niihin voi sisältyä henkilökohtaisia ja yksityisiä tietoja. Jaa virheraportteja vain luotettaville sovelluksille ja käyttäjille."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Näytä tämä viesti seuraavalla kerralla"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-fr-rCA/strings.xml b/packages/Shell/res/values-fr-rCA/strings.xml
index d82ec9531a46..56469b020a98 100644
--- a/packages/Shell/res/values-fr-rCA/strings.xml
+++ b/packages/Shell/res/values-fr-rCA/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Appuyer ici pour partager votre rapport de bogue"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Les rapports de bogue contiennent des données des fichiers journaux du système, y compris des informations personnelles et privées. Ne partagez les rapports de bogue qu\'avec les applications et les personnes que vous estimez fiables."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Afficher ce message la prochaine fois"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-fr/strings.xml b/packages/Shell/res/values-fr/strings.xml
index c52dd8d1d686..7a27d8c283e1 100644
--- a/packages/Shell/res/values-fr/strings.xml
+++ b/packages/Shell/res/values-fr/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Appuyez ici pour partager le rapport de bug"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Les rapports de bug contiennent des données des fichiers journaux du système, y compris des informations personnelles et privées. Ne partagez les rapports de bug qu\'avec les applications et les personnes que vous estimez fiables."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Afficher ce message la prochaine fois"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-gl-rES/strings.xml b/packages/Shell/res/values-gl-rES/strings.xml
index 8d01a8bd9de3..85090961c040 100644
--- a/packages/Shell/res/values-gl-rES/strings.xml
+++ b/packages/Shell/res/values-gl-rES/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toca aquí para compartir o teu informe de erros"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Os informes de erros conteñen datos dos distintos ficheiros de rexistro do sistema, incluída información persoal e privada. Comparte os informes de erros unicamente con aplicacións e persoas de confianza."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensaxe a próxima vez"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-hi/strings.xml b/packages/Shell/res/values-hi/strings.xml
index daf65537eafa..3402c3887837 100644
--- a/packages/Shell/res/values-hi/strings.xml
+++ b/packages/Shell/res/values-hi/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"अपनी बग रिपोर्ट साझा करने के लिए स्पर्श करें"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"बग रिपोर्ट में व्यक्तिगत और निजी जानकारी सहित, सिस्टम की विभिन्न लॉग फ़ाइलों का डेटा होता है. बग रिपोर्ट केवल विश्वसनीय ऐप्स और व्यक्तियों से ही साझा करें."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"यह संदेश अगली बार दिखाएं"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-hr/strings.xml b/packages/Shell/res/values-hr/strings.xml
index da01dd8da172..37f04470a7c6 100644
--- a/packages/Shell/res/values-hr/strings.xml
+++ b/packages/Shell/res/values-hr/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Dodirnite za dijeljenje prijave programske pogreške"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Prijave programskih pogrešaka sadržavaju podatke iz različitih datoteka zapisnika sustava, uključujući osobne i privatne informacije. Prijave programskih pogrešaka dijelite samo s aplikacijama i osobama koje smatrate pouzdanima."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Prikaži tu poruku sljedeći put"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-hu/strings.xml b/packages/Shell/res/values-hu/strings.xml
index 0ebdc3d1cf35..a9b15aed508a 100644
--- a/packages/Shell/res/values-hu/strings.xml
+++ b/packages/Shell/res/values-hu/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Érintse meg a programhiba-jelentés megosztásához"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"A programhiba-jelentések a rendszer különféle naplófájljaiból származó adatokat tartalmaznak, köztük személyes és magánjellegű információkat is. Csak olyan alkalmazásokkal és személyekkel osszon meg programhiba-jelentéseket, amelyekben vagy akikben megbízik."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Üzenet mutatása legközelebb"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-hy-rAM/strings.xml b/packages/Shell/res/values-hy-rAM/strings.xml
index 80b1ccb9073e..c89f68798ca6 100644
--- a/packages/Shell/res/values-hy-rAM/strings.xml
+++ b/packages/Shell/res/values-hy-rAM/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Հպեք` ձեր վրիպակի մասին զեկույցը տարածելու համար"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Վրիպակի զեկույցները պարունակում են տվյալներ համակարգի տարբեր մուտքի ֆայլերից, այդ թվում նաև անհատական ​​և գաղտնի տեղեկություններ: Վրիպակի զեկույցները կիսեք միայն այն հավելվածների և մարդկանց հետ, որոնց վստահում եք:"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Այս հաղորդագրությունը ցույց տալ հաջորդ անգամ"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-in/strings.xml b/packages/Shell/res/values-in/strings.xml
index b1c7293c7d91..5dd388a20533 100644
--- a/packages/Shell/res/values-in/strings.xml
+++ b/packages/Shell/res/values-in/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Sentuh untuk membagikan laporan bug Anda"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Laporan bug berisi data dari berbagai file log sistem, termasuk informasi pribadi dan rahasia. Hanya bagikan laporan bug dengan aplikasi dan orang yang Anda percaya."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Tampilkan pesan ini lain kali"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-is-rIS/strings.xml b/packages/Shell/res/values-is-rIS/strings.xml
index 3f4fd3b5ce74..22802d05bc77 100644
--- a/packages/Shell/res/values-is-rIS/strings.xml
+++ b/packages/Shell/res/values-is-rIS/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Snertu til að deila villutilkynningunni"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Villutilkynningar innihalda gögn úr hinum ýmsu annálsskrám kerfisins, þ. á m. persónuleg gögn og trúnaðarupplýsingar. Deildu villutilkynningum eingöngu með forritum og fólki sem þú treystir."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Sýna þessi skilaboð næst"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-it/strings.xml b/packages/Shell/res/values-it/strings.xml
index 9e86affe6aae..c2606a8e8fbf 100644
--- a/packages/Shell/res/values-it/strings.xml
+++ b/packages/Shell/res/values-it/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tocca per condividere la segnalazione di bug"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Le segnalazioni di bug contengono dati da vari file di log del sistema, incluse informazioni personali e private. Condividi le segnalazioni di bug solo con app e persone attendibili."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostra questo messaggio la prossima volta"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-iw/strings.xml b/packages/Shell/res/values-iw/strings.xml
index 4e06d03e5d27..f77f2599b8ac 100644
--- a/packages/Shell/res/values-iw/strings.xml
+++ b/packages/Shell/res/values-iw/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"גע כדי לשתף את דוח הבאגים שלך"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"דוחות על באגים כוללים נתונים מקובצי היומן השונים במערכת, כולל מידע אישי ופרטי. שתף דוחות באגים רק עם אפליקציות ואנשים שאתה סומך עליהם."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"הצג את ההודעה הזו בפעם הבאה"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-ja/strings.xml b/packages/Shell/res/values-ja/strings.xml
index 1b24f31c2d98..3891e544f590 100644
--- a/packages/Shell/res/values-ja/strings.xml
+++ b/packages/Shell/res/values-ja/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"バグレポートを共有するにはタップします"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"バグレポートには、個人の非公開情報など、システムのさまざまなログファイルのデータが含まれます。共有する場合は信頼するアプリとユーザーのみを選択してください。"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"このメッセージを次回も表示する"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-ka-rGE/strings.xml b/packages/Shell/res/values-ka-rGE/strings.xml
index 977e9aa66c1e..23bb21525531 100644
--- a/packages/Shell/res/values-ka-rGE/strings.xml
+++ b/packages/Shell/res/values-ka-rGE/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"შეეხეთ თქვენი ხარვეზების ანგარიშის გასაზიარებლად"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"ხარვეზის ანგარიშები მოიცავს მონაცემებს სხვადასხვა სისტემური ჟურნალის ფაილებიდან, მათ შორის პირად და კონფიდენციალურ ინფორმაციას."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"შემდგომში აჩვენე ეს შეტყობინება"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-kk-rKZ/strings.xml b/packages/Shell/res/values-kk-rKZ/strings.xml
index 9969eff5b803..48f8643fbf5b 100644
--- a/packages/Shell/res/values-kk-rKZ/strings.xml
+++ b/packages/Shell/res/values-kk-rKZ/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Бөліс үшін, вирус туралы баянатты түртіңіз."</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Вирус туралы баянатта жүйеде тіркелген әртүрлі файлдар туралы деректер болады, оған жеке және құпия ақпарат та кіреді. Вирус баянаттарын сенімді қолданбалар және сенімді адамдармен ғана бөлісіңіз."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Бұл хабарды келесі жолы көрсетіңіз"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-km-rKH/strings.xml b/packages/Shell/res/values-km-rKH/strings.xml
index 04e31708140e..88b9f5763b6f 100644
--- a/packages/Shell/res/values-km-rKH/strings.xml
+++ b/packages/Shell/res/values-km-rKH/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ប៉ះ​ ដើម្បី​ចែក​រំលែក​របាយការណ៍​កំហុស​របស់​អ្នក"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"របាយការណ៍​កំហុស​រួមមាន​ឯកសារ​កំណត់​ហេតុ​ផ្សេងៗ​របស់​ប្រព័ន្ធ រួមមាន​ព័ត៌មាន​ផ្ទាល់ខ្លួន និង​ឯកជន។ ចែករំលែក​របាយការណ៍​កំហុស​ជា​មួយ​កម្មវិធី និង​មនុស្ស​ដែល​អ្នក​ទុក​ចិត្ត។"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"បង្ហាញ​សារ​នេះ​ពេល​ក្រោយ"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-kn-rIN/strings.xml b/packages/Shell/res/values-kn-rIN/strings.xml
index 42e9eaa15ccf..29d8988a2b16 100644
--- a/packages/Shell/res/values-kn-rIN/strings.xml
+++ b/packages/Shell/res/values-kn-rIN/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ನಿಮ್ಮ ದೋಷದ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲು ಸ್ಪರ್ಶಿಸಿ"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"ವೈಯಕ್ತಿಕ ಮತ್ತು ಖಾಸಗಿ ಮಾಹಿತಿಯು ಸೇರಿದಂತೆ, ಸಿಸ್ಟಂನ ಹಲವಾರು ಲಾಗ್ ಫೈಲ್‌ಗಳಿಂದ ಡೇಟಾವನ್ನು ದೋಷದ ವರದಿಗಳು ಒಳಗೊಂಡಿವೆ. ನೀವು ನಂಬುವಂತಹ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಜನರೊಂದಿಗೆ ಮಾತ್ರ ದೋಷದ ವರದಿಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಿ."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ಈ ಸಂದೇಶವನ್ನು ಮುಂದಿನ ಬಾರಿ ತೋರಿಸಿ"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-ko/strings.xml b/packages/Shell/res/values-ko/strings.xml
index 3e0dd0be2d0f..ca4402f89c24 100644
--- a/packages/Shell/res/values-ko/strings.xml
+++ b/packages/Shell/res/values-ko/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"버그 신고서를 공유하려면 터치하세요."</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"버그 신고서는 시스템의 다양한 로그 파일 데이터(예: 개인 및 비공개 정보)를 포함합니다. 신뢰할 수 있는 앱과 사용자에게만 버그 신고서를 공유하세요."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"다음에 이 메시지 표시"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-ky-rKG/strings.xml b/packages/Shell/res/values-ky-rKG/strings.xml
index 6d9ace794dce..5243dee17d11 100644
--- a/packages/Shell/res/values-ky-rKG/strings.xml
+++ b/packages/Shell/res/values-ky-rKG/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Ката тууралуу билдирүүңүздү жөнөтүш үчүн, тийиңиз"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Ката тууралуу билдирүүлөр системанын ар кандай лог файлдарынын берилиштерин камтыйт, аларга өздүк жана купуя маалыматтар дагы кирет. Ката тууралуу билдирүүлөрдү сиз ишенген колдонмолор жана адамдар менен гана бөлүшүңүз."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Бул билдирүү кийин көрсөтүлсүн"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-lo-rLA/strings.xml b/packages/Shell/res/values-lo-rLA/strings.xml
index b2724ade1708..041129021080 100644
--- a/packages/Shell/res/values-lo-rLA/strings.xml
+++ b/packages/Shell/res/values-lo-rLA/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ແຕະເພື່ອສົ່ງການລາຍງານປັນຫາຂອງທ່ານ"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"ການລາຍງານຂໍ້ຜິດພາດປະກອບມີ ຂໍ້ມູນຈາກໄຟລ໌ບັນທຶກຂອງລະບົບຫຼາຍໄຟລ໌, ຮວມທັງຂໍ້ມູນສ່ວນໂຕນຳ. ທ່ານຕ້ອງແບ່ງປັນລາຍງານຂໍ້ຜິດພາດໃຫ້ແອັບຯ ແລະຄົນທີ່ທ່ານເຊື່ອຖືໄດ້ເທົ່ານັ້ນ."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ສະແດງຂໍ້ຄວາມນີ້ອີກໃນເທື່ອຕໍ່ໄປ"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-lt/strings.xml b/packages/Shell/res/values-lt/strings.xml
index a78b1db0d659..9d04d371ecfa 100644
--- a/packages/Shell/res/values-lt/strings.xml
+++ b/packages/Shell/res/values-lt/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Palieskite, kad bendrintumėte riktų ataskaitą"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Riktų ataskaitose pateikiami duomenys iš įvairių sistemos žurnalo failų, įskaitant asmeninę ir privačią informaciją. Riktų ataskaitas bendrinkite tik su patikimomis programomis ir žmonėmis."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Rodyti šį pranešimą kitą kartą"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-lv/strings.xml b/packages/Shell/res/values-lv/strings.xml
index 430cb8d158b5..62f569218e0c 100644
--- a/packages/Shell/res/values-lv/strings.xml
+++ b/packages/Shell/res/values-lv/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Pieskarieties, lai kopīgotu kļūdu pārskatu."</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Kļūdu pārskatā ir iekļauti dati no dažādiem sistēmas žurnālfailiem, tostarp personas dati un privāta informācija. Kļūdu pārskatus ieteicams kopīgot tikai ar uzticamām lietotnēm un lietotājiem."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Rādīt šo ziņojumu nākamajā reizē"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-mk-rMK/strings.xml b/packages/Shell/res/values-mk-rMK/strings.xml
index e6c2c92b615a..a0184df642bb 100644
--- a/packages/Shell/res/values-mk-rMK/strings.xml
+++ b/packages/Shell/res/values-mk-rMK/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Допри да се сподели твојот извештај за грешка"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Извештаите за грешка содржат податоци од разни датотеки за евиденција на системот, вклучувајќи лични и приватни информации. Извештаите за грешка споделувајте ги само со апликации и луѓе на коишто им верувате."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Прикажи ја поракава следниот пат"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-ml-rIN/strings.xml b/packages/Shell/res/values-ml-rIN/strings.xml
index 5f3e0b6aaf67..d3eae5a6bbac 100644
--- a/packages/Shell/res/values-ml-rIN/strings.xml
+++ b/packages/Shell/res/values-ml-rIN/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"നിങ്ങളുടെ ബഗ് റിപ്പോർട്ട് പങ്കിടാൻ സ്‌പർശിക്കുക"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"വ്യക്തിഗതവും സ്വകാര്യവുമായ വിവരങ്ങൾ ഉൾപ്പെടെ, സിസ്റ്റത്തിന്റെ നിരവധി ലോഗ് ഫയലുകളിൽ നിന്നുള്ള ഡാറ്റ, ബഗ് റിപ്പോർട്ടുകളിൽ അടങ്ങിയിരിക്കുന്നു. നിങ്ങൾ വിശ്വസിക്കുന്ന അപ്ലിക്കേഷനുകൾക്കും ആളുകൾക്കും മാത്രം ബഗ് റിപ്പോർട്ടുകൾ പങ്കിടുക."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ഈ സന്ദേശം അടുത്ത തവണ ദൃശ്യമാക്കുക"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-mn-rMN/strings.xml b/packages/Shell/res/values-mn-rMN/strings.xml
index 4637f2d914df..63e78aef121b 100644
--- a/packages/Shell/res/values-mn-rMN/strings.xml
+++ b/packages/Shell/res/values-mn-rMN/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Та алдааны мэдэгдлийг хуваалцах бол хүрнэ үү"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Алдааны репорт нь хувийн болон нууц мэдээлэл зэргийг агуулсан системийн төрөл бүрийн лог файлын датаг агуулна. Алдааны репортыг зөвхөн итгэлтэй апп болон хүмүүст хуваалцана уу."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Энэ мессежийг дараагийн удаа харуулах"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-mr-rIN/strings.xml b/packages/Shell/res/values-mr-rIN/strings.xml
index ca3c4b3f82f3..7e973952ba07 100644
--- a/packages/Shell/res/values-mr-rIN/strings.xml
+++ b/packages/Shell/res/values-mr-rIN/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"आपला दोष अहवाल सामायिक करण्‍यासाठी स्‍पर्श करा"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"दोष अहवालांमध्‍ये वैयक्तिक आणि खाजगी माहितीसह, सिस्‍टमच्‍या अनेक लॉग फायलींमधील डेटा असतो. केवळ आपला विश्वास असलेल्‍या अ‍ॅप्‍स आणि लोकांसह दोष अहवाल सामायिक करा."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"पुढील वेळी हा संदेश दर्शवा"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-ms-rMY/strings.xml b/packages/Shell/res/values-ms-rMY/strings.xml
index d7bdc78e91cd..60efb6bf6516 100644
--- a/packages/Shell/res/values-ms-rMY/strings.xml
+++ b/packages/Shell/res/values-ms-rMY/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Sentuh untuk berkongsi laporan pepijat anda"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Laporan pepijat mengandungi data dari pelbagai fail log sistem, termasuk maklumat peribadi dan sulit. Kongsikan laporan pepijat hanya dengan apl dan orang yang anda percayai."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Tunjukkan mesej ini pada masa akan datang"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-my-rMM/strings.xml b/packages/Shell/res/values-my-rMM/strings.xml
index 6cac6687afad..093b6c5e69ed 100644
--- a/packages/Shell/res/values-my-rMM/strings.xml
+++ b/packages/Shell/res/values-my-rMM/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"အမှားအယွင်း မှတ်တမ်းကို မျှဝေရန် ထိလိုက်ပါ"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"အမှားအယွင်း မှတ်တမ်းမှာ ပါရှိသော အချက်အလက်များမှာ ကိုယ်ရေးကိုယ်တာ နဲ့ လုံခြုံရေး အချက်အလက်များပါဝင်သော စနစ်မှ ပြုလုပ်မှု မှတ်တမ်းများ ဖြစ်ပါသည်၊ အမှားအယွင်း မှတ်တမ်းများကို ယုံကြည်ရသော အပလီကေးရှင်းများနဲ့ လူများကိုသာ ပေးဝေပြသမှု လုပ်ပါရန်။"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ဤစာတန်းကို နောက်တစ်ခါတွင် ပြရန်"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-nb/strings.xml b/packages/Shell/res/values-nb/strings.xml
index 657a2091cab6..891fddb52769 100644
--- a/packages/Shell/res/values-nb/strings.xml
+++ b/packages/Shell/res/values-nb/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Trykk for å dele feilrapporten din"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Feilrapporter inkluderer data fra systemets forskjellige loggfiler. Dette omfatter personlig og privat informasjon. Du bør bare dele feilrapporter med apper og folk du stoler på."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Vis denne meldingen neste gang"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-ne-rNP/strings.xml b/packages/Shell/res/values-ne-rNP/strings.xml
index a5514822ff10..71c393ff759d 100644
--- a/packages/Shell/res/values-ne-rNP/strings.xml
+++ b/packages/Shell/res/values-ne-rNP/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"तपाईंको बग रिपोर्ट साझेदारी गर्न छुनुहोस्"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"बग रिपोर्टहरूमा प्रणालीका विभिन्न लग फाइलहरूबाट व्यक्तिगत तथा नीजि सूचनासहितको डेटा रहन्छ। बग रिपोर्टहरू अनुप्रयोगहरू र तपाईँले विश्वास गरेका व्यक्तिहरूसँग मात्र साझेदारी गर्नुहोस्।"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"यो सन्देश अर्को पटक देखाउनुहोस्"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-nl/strings.xml b/packages/Shell/res/values-nl/strings.xml
index 51ae329c68d0..2f0951be2a56 100644
--- a/packages/Shell/res/values-nl/strings.xml
+++ b/packages/Shell/res/values-nl/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Raak aan om uw foutenrapport te delen"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Foutenrapporten bevatten gegevens uit de verschillende logbestanden van het systeem, waaronder persoonlijke en privégegevens. Deel foutenrapporten alleen met apps en mensen die u vertrouwt."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Dit bericht de volgende keer weergeven"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-pl/strings.xml b/packages/Shell/res/values-pl/strings.xml
index 2c810d6e7893..b97070d153ee 100644
--- a/packages/Shell/res/values-pl/strings.xml
+++ b/packages/Shell/res/values-pl/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Kliknij, by udostępnić raport o błędach"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Raporty o błędach zawierają dane z różnych plików dzienników systemu, w tym dane osobowe i prywatne. Udostępniaj je tylko aplikacjom i osobom, którym ufasz."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Pokaż ten komunikat następnym razem"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-pt-rPT/strings.xml b/packages/Shell/res/values-pt-rPT/strings.xml
index 7a833d69cfe6..24ebc64a6ba4 100644
--- a/packages/Shell/res/values-pt-rPT/strings.xml
+++ b/packages/Shell/res/values-pt-rPT/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toque para partilhar o relatório de erros"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Os relatórios de erros incluem dados de vários ficheiros de registo do sistema, nomeadamente informações pessoais e privadas. Partilhe relatórios de erros apenas com aplicações e pessoas fidedignas."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensagem da próxima vez"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-pt/strings.xml b/packages/Shell/res/values-pt/strings.xml
index c166bf37abae..c7c00b983cdc 100644
--- a/packages/Shell/res/values-pt/strings.xml
+++ b/packages/Shell/res/values-pt/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Toque para compartilhar seu relatório de bugs"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Os relatórios de bugs contêm dados de diversos arquivos de registro do sistema, inclusive informações pessoais e particulares. Compartilhe relatórios de bugs somente com apps e pessoas nos quais você confia."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Mostrar esta mensagem da próxima vez"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-ro/strings.xml b/packages/Shell/res/values-ro/strings.xml
index 537ba3d79cae..4b78a42a0d0f 100644
--- a/packages/Shell/res/values-ro/strings.xml
+++ b/packages/Shell/res/values-ro/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Atingeți pentru a permite accesul la raportul despre erori"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Rapoartele despre erori conțin date din diferite fișiere de jurnal ale sistemului, inclusiv informații private și personale. Permiteți accesul la rapoartele despre erori numai aplicațiilor și persoanelor în care aveți încredere."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Afișați acest mesaj data viitoare"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-ru/strings.xml b/packages/Shell/res/values-ru/strings.xml
index 77a8cd061f51..c3536541d553 100644
--- a/packages/Shell/res/values-ru/strings.xml
+++ b/packages/Shell/res/values-ru/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Нажмите, чтобы отправить отчет об ошибках"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Отчеты об ошибках содержат данные различных системных журналов и могут включать личную информацию. Рекомендуем открывать к ним доступ только лицам и приложениям, заслуживающим доверие."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Показать это сообщение в следующий раз"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-si-rLK/strings.xml b/packages/Shell/res/values-si-rLK/strings.xml
index 34d7f82a3d8c..f3fabedd3e1d 100644
--- a/packages/Shell/res/values-si-rLK/strings.xml
+++ b/packages/Shell/res/values-si-rLK/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"ඔබගේ දෝෂ වාර්තාව බෙදා ගැනීමට ස්පර්ශ කරන්න"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"පුද්ගලික සහ පෞද්ගලික තොරතුරු ඇතුළත්ව පද්ධතියේ විවිධ ලොග් ගොනු වල දත්ත දෝෂ වාර්තාවේ අඩංගු වේ. ඔබට විශ්වාසවන්ත යෙදුම් සහ පුද්ගලයින් සමඟ පමණක් දෝෂ වාර්තා බෙදා ගන්න."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"ඊළඟ වෙලාවේ මෙම පණිවිඩය පෙන්වන්න"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-sk/strings.xml b/packages/Shell/res/values-sk/strings.xml
index 0d6940d606ca..9a42dcef0caf 100644
--- a/packages/Shell/res/values-sk/strings.xml
+++ b/packages/Shell/res/values-sk/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Hlásenie o chybách môžete zdielať klepnutím"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Správy o chybách obsahujú údaje z rôznych súborov denníkov systému vrátane osobných a súkromných informácií. Zdieľajte ich iba s dôveryhodnými aplikáciami a ľuďmi."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Zobraziť túto správu nabudúce"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-sl/strings.xml b/packages/Shell/res/values-sl/strings.xml
index b2caa07c27e0..d736c914bd86 100644
--- a/packages/Shell/res/values-sl/strings.xml
+++ b/packages/Shell/res/values-sl/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Dotaknite se, če želite deliti sporočilo o napaki z drugimi"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Poročila o napakah vsebujejo podatke iz različnih dnevniških datotek sistema, vključno z osebnimi in zasebnimi podatki. Poročila o napakah delite samo z aplikacijami in ljudmi, ki jim zaupate."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Pokaži to sporočilo naslednjič"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-sr/strings.xml b/packages/Shell/res/values-sr/strings.xml
index 9e4e595ef1ed..bfd83e72b6e2 100644
--- a/packages/Shell/res/values-sr/strings.xml
+++ b/packages/Shell/res/values-sr/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Додирните да бисте делили извештај о грешци"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Извештаји о грешкама садрже податке из различитих системских датотека евиденције, укључујући личне и приватне податке. Делите извештаје о грешкама само са апликацијама и људима у које имате поверења."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Прикажи ову поруку следећи пут"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-sv/strings.xml b/packages/Shell/res/values-sv/strings.xml
index c26a7cecf329..93e48454b743 100644
--- a/packages/Shell/res/values-sv/strings.xml
+++ b/packages/Shell/res/values-sv/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tryck om du vill dela felrapporten"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Felrapporter innehåller data från systemets olika loggfiler, inklusive personliga och privata uppgifter. Dela bara felrapporter med personer du litar på."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Visa det här meddelandet nästa gång"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-sw/strings.xml b/packages/Shell/res/values-sw/strings.xml
index 4553328cdc30..620b0909f7a7 100644
--- a/packages/Shell/res/values-sw/strings.xml
+++ b/packages/Shell/res/values-sw/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Gusa ili ushiriki ripoti yako ya hitilafu"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Ripoti ya hitilafu ina data kutoka kwenye faili za kumbukumbu mbalimbali za mfumo, pamoja na maelezo ya kibinafsi na faragha. Shiriki ripoti ya hitilafu na programu na watu unaowaamini pekee."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Onyesha ujumbe huu wakati mwingine"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-ta-rIN/strings.xml b/packages/Shell/res/values-ta-rIN/strings.xml
index d94555d5f766..c0e3b282a1b1 100644
--- a/packages/Shell/res/values-ta-rIN/strings.xml
+++ b/packages/Shell/res/values-ta-rIN/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"உங்கள் பிழை அறிக்கையைப் பகிர, தொடவும்"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"பிழை அறிக்கைகளில், சொந்த வாழ்க்கை மற்றும் தனிப்பட்ட தகவல் உள்பட கணினியின் பல்வேறு பதிவுகளில் உள்ள தரவு இருக்கும். நீங்கள் நம்பும் பயன்பாடுகள் மற்றும் நபர்களுடன் மட்டும் பிழை அறிக்கைகளைப் பகிரவும்."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"இந்தச் செய்தியை அடுத்த முறைக் காட்டு"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-te-rIN/strings.xml b/packages/Shell/res/values-te-rIN/strings.xml
index 6b5710b95202..78ed6ee83547 100644
--- a/packages/Shell/res/values-te-rIN/strings.xml
+++ b/packages/Shell/res/values-te-rIN/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి తాకండి"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"బగ్ నివేదికలు వ్యక్తిగతమైన మరియు రహస్యమైన సమాచారంతో సహా సిస్టమ్ యొక్క విభిన్న లాగ్ ఫైల్‌ల్లోని డేటాను కలిగి ఉంటాయి. కనుక బగ్ నివేదికలను మీరు విశ్వసించే అనువర్తనాలు మరియు వ్యక్తులతో మాత్రమే భాగస్వామ్యం చేయండి."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"తదుపరిసారి ఈ సందేశాన్ని చూపు"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-th/strings.xml b/packages/Shell/res/values-th/strings.xml
index 07029520dd11..0c14f818019a 100644
--- a/packages/Shell/res/values-th/strings.xml
+++ b/packages/Shell/res/values-th/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"แตะเพื่อแชร์รายงานข้อบกพร่องของคุณ"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"รายงานข้อบกพร่องมีข้อมูลจากไฟล์บันทึกต่างๆ ของระบบ รวมถึงข้อมูลส่วนตัว แชร์รายงานข้อบกพร่องกับแอปและบุคคลที่คุณไว้ใจเท่านั้น"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"แสดงข้อความนี้ในครั้งต่อไป"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-tl/strings.xml b/packages/Shell/res/values-tl/strings.xml
index 8d42ecd951f2..63a3c4f5e341 100644
--- a/packages/Shell/res/values-tl/strings.xml
+++ b/packages/Shell/res/values-tl/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Pindutin upang ibahagi ang iyong ulat ng bug"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Naglalaman ang mga ulat ng bug ng data mula sa iba\'t ibang file ng log ng system, kabilang ang personal at pribadong impormasyon. Magbahagi lang ng mga ulat ng bug sa apps at mga tao na pinagkakatiwalaan mo."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Ipakita ang mensaheng ito sa susunod"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-tr/strings.xml b/packages/Shell/res/values-tr/strings.xml
index ed0697e9af8a..8dddb9fd0453 100644
--- a/packages/Shell/res/values-tr/strings.xml
+++ b/packages/Shell/res/values-tr/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Hata raporunuzu paylaşmak için dokunun"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Hata raporları, kişisel ve özel bilgiler dahil olmak üzere sistemin çeşitli günlük dosyalarından veriler içerir. Hata raporlarını sadece güvendiğiniz uygulamalar ve kişilerle paylaşın."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bir dahaki sefere bu iletiyi göster"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-uk/strings.xml b/packages/Shell/res/values-uk/strings.xml
index f9f5bb340b54..ca10a05707f2 100644
--- a/packages/Shell/res/values-uk/strings.xml
+++ b/packages/Shell/res/values-uk/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Торкніться, щоб надіслати звіт про помилки"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Звіти про помилки містять дані з різних файлів журналу системи, зокрема особисті та конфіденційні. Надсилайте звіт про помилки лише тим, кому довіряєте."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Показати це повідомлення наступного разу"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-ur-rPK/strings.xml b/packages/Shell/res/values-ur-rPK/strings.xml
index afdb24192c0e..948966ff6b3d 100644
--- a/packages/Shell/res/values-ur-rPK/strings.xml
+++ b/packages/Shell/res/values-ur-rPK/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"اپنی بَگ رپورٹ کا اشتراک کرنے کیلئے ٹچ کریں"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"بَگ رپورٹس میں سسٹم کی مختلف لاگ فائلوں سے ڈیٹا شامل ہوتا ہے، بشمول ذاتی اور نجی معلومات۔ بَگ رپورٹس کا اشتراک صرف اپنے بھروسے مند ایپس اور لوگوں کے ساتھ کریں۔"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"یہ پیغام اگلی بار دکھائیں"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-uz-rUZ/strings.xml b/packages/Shell/res/values-uz-rUZ/strings.xml
index e9c3900cd375..ff7670693c76 100644
--- a/packages/Shell/res/values-uz-rUZ/strings.xml
+++ b/packages/Shell/res/values-uz-rUZ/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Xatolik hisobotini bo‘lishish uchun barmog‘ingizni tegizing."</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Xatolik hisobotlari tizimdagi har xil jurnal fayllardagi ma’lumotlarni, shuningdek, shaxsiy hamda maxfiy ma’lumotlarni o‘z ichiga oladi. Xatolik hisobotlarini faqat ishonchli dasturlar va odamlar bilan bo‘lishing."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Ushbu xabar keyingi safar ko‘rsatilsin"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-vi/strings.xml b/packages/Shell/res/values-vi/strings.xml
index 49194112610e..61db64ed6691 100644
--- a/packages/Shell/res/values-vi/strings.xml
+++ b/packages/Shell/res/values-vi/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Chạm để chia sẻ báo cáo lỗi của bạn"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Các báo cáo lỗi chứa dữ liệu từ nhiều tệp nhật ký khác nhau của hệ thống, bao gồm cả thông tin cá nhân và riêng tư. Chỉ chia sẻ báo cáo lỗi với các ứng dụng và những người mà bạn tin tưởng."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Hiển thị thông báo này vào lần tới"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-zh-rCN/strings.xml b/packages/Shell/res/values-zh-rCN/strings.xml
index 409b5caffc9f..02ca707a78d1 100644
--- a/packages/Shell/res/values-zh-rCN/strings.xml
+++ b/packages/Shell/res/values-zh-rCN/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"触摸即可分享您的错误报告"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"错误报告包含的数据来自于系统的各个日志文件,其中包含个人信息和隐私信息。请务必只与您信任的应用和用户分享错误报告。"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"下次再显示这条讯息"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-zh-rHK/strings.xml b/packages/Shell/res/values-zh-rHK/strings.xml
index f2e034b66822..df86fdb71f23 100644
--- a/packages/Shell/res/values-zh-rHK/strings.xml
+++ b/packages/Shell/res/values-zh-rHK/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"輕觸即可分享您的錯誤報告"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"錯誤報告中有來自系統各個記錄檔案的資料,包括個人和私人資料。請只與您信任的應用程式和使用者分享錯誤報告。"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"下次再顯示這則訊息"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-zh-rTW/strings.xml b/packages/Shell/res/values-zh-rTW/strings.xml
index fe3bcff1cddb..fd16ab2f45ca 100644
--- a/packages/Shell/res/values-zh-rTW/strings.xml
+++ b/packages/Shell/res/values-zh-rTW/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"輕觸即可分享您的錯誤報告"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"錯誤報告的資料來自系統各個紀錄檔,包括個人和私密資訊。請務必只與您信任的應用程式和使用者分享錯誤報告。"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"下次仍顯示這則訊息"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values-zu/strings.xml b/packages/Shell/res/values-zu/strings.xml
index 38e95952a101..707cee969eaa 100644
--- a/packages/Shell/res/values-zu/strings.xml
+++ b/packages/Shell/res/values-zu/strings.xml
@@ -22,4 +22,6 @@
<string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Thinta ukuze wabelane ngombiko wakho wesiphazamisi"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Imibiko yeziphazamisi iqukethe idatha yamafayela wokungena ahlukile wesistimu, afaka ulwazi lomuntu siqu noma lobumfihlo. Yabelana kuphela ngemibiko yeziphazamisi nezinhlelo zokusebenza nabantu obathembayo."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Bonisa lo mlayezo ngesikhathi esilandelayo"</string>
+ <!-- no translation found for bugreport_storage_title (5332488144740527109) -->
+ <skip />
</resources>
diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml
index 51e2c951a2a5..3db0848ed632 100644
--- a/packages/Shell/res/values/strings.xml
+++ b/packages/Shell/res/values/strings.xml
@@ -30,4 +30,7 @@
<string name="bugreport_confirm">Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people you trust.</string>
<!-- Checkbox that indicates this dialog should be shown again when the next bugreport is taken. [CHAR LIMIT=50] -->
<string name="bugreport_confirm_repeat">Show this message next time</string>
+
+ <!-- Title for documents backend that offers bugreports. -->
+ <string name="bugreport_storage_title">Bug reports</string>
</resources>
diff --git a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
new file mode 100644
index 000000000000..814aa8cb8c06
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.shell;
+
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.database.MatrixCursor.RowBuilder;
+import android.os.CancellationSignal;
+import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsProvider;
+import android.webkit.MimeTypeMap;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+public class BugreportStorageProvider extends DocumentsProvider {
+ private static final String DOC_ID_ROOT = "bugreport";
+
+ private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
+ Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_ICON, Root.COLUMN_TITLE,
+ Root.COLUMN_DOCUMENT_ID,
+ };
+
+ private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
+ Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, Document.COLUMN_DISPLAY_NAME,
+ Document.COLUMN_LAST_MODIFIED, Document.COLUMN_FLAGS, Document.COLUMN_SIZE,
+ };
+
+ private File mRoot;
+
+ @Override
+ public boolean onCreate() {
+ mRoot = new File(getContext().getFilesDir(), "bugreports");
+ return true;
+ }
+
+ @Override
+ public Cursor queryRoots(String[] projection) throws FileNotFoundException {
+ final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
+ final RowBuilder row = result.newRow();
+ row.add(Root.COLUMN_ROOT_ID, DOC_ID_ROOT);
+ row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED);
+ row.add(Root.COLUMN_ICON, android.R.mipmap.sym_def_app_icon);
+ row.add(Root.COLUMN_TITLE, getContext().getString(R.string.bugreport_storage_title));
+ row.add(Root.COLUMN_DOCUMENT_ID, DOC_ID_ROOT);
+ return result;
+ }
+
+ @Override
+ public Cursor queryDocument(String documentId, String[] projection)
+ throws FileNotFoundException {
+ final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
+ if (DOC_ID_ROOT.equals(documentId)) {
+ final RowBuilder row = result.newRow();
+ row.add(Document.COLUMN_DOCUMENT_ID, documentId);
+ row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
+ row.add(Document.COLUMN_DISPLAY_NAME, mRoot.getName());
+ row.add(Document.COLUMN_LAST_MODIFIED, mRoot.lastModified());
+ row.add(Document.COLUMN_FLAGS, Document.FLAG_DIR_PREFERS_LAST_MODIFIED);
+ } else {
+ addFileRow(result, getFileForDocId(documentId));
+ }
+ return result;
+ }
+
+ @Override
+ public Cursor queryChildDocuments(
+ String parentDocumentId, String[] projection, String sortOrder)
+ throws FileNotFoundException {
+ final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
+ if (DOC_ID_ROOT.equals(parentDocumentId)) {
+ final File[] files = mRoot.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ addFileRow(result, file);
+ }
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public ParcelFileDescriptor openDocument(
+ String documentId, String mode, CancellationSignal signal)
+ throws FileNotFoundException {
+ if (ParcelFileDescriptor.parseMode(mode) != ParcelFileDescriptor.MODE_READ_ONLY) {
+ throw new FileNotFoundException("Failed to open: " + documentId + ", mode = " + mode);
+ }
+ return ParcelFileDescriptor.open(getFileForDocId(documentId),
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ }
+
+ @Override
+ public void deleteDocument(String documentId) throws FileNotFoundException {
+ if (!getFileForDocId(documentId).delete()) {
+ throw new FileNotFoundException("Failed to delete: " + documentId);
+ }
+ }
+
+ private static String[] resolveRootProjection(String[] projection) {
+ return projection != null ? projection : DEFAULT_ROOT_PROJECTION;
+ }
+
+ private static String[] resolveDocumentProjection(String[] projection) {
+ return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION;
+ }
+
+ private static String getTypeForName(String name) {
+ final int lastDot = name.lastIndexOf('.');
+ if (lastDot >= 0) {
+ final String extension = name.substring(lastDot + 1).toLowerCase();
+ final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+ if (mime != null) {
+ return mime;
+ }
+ }
+ return "application/octet-stream";
+ }
+
+ private String getDocIdForFile(File file) {
+ return DOC_ID_ROOT + ":" + file.getName();
+ }
+
+ private File getFileForDocId(String documentId) throws FileNotFoundException {
+ final int splitIndex = documentId.indexOf(':', 1);
+ final String name = documentId.substring(splitIndex + 1);
+ if (splitIndex == -1 || !DOC_ID_ROOT.equals(documentId.substring(0, splitIndex)) ||
+ !FileUtils.isValidExtFilename(name)) {
+ throw new FileNotFoundException("Invalid document ID: " + documentId);
+ }
+ final File file = new File(mRoot, name);
+ if (!file.exists()) {
+ throw new FileNotFoundException("File not found: " + documentId);
+ }
+ return file;
+ }
+
+ private void addFileRow(MatrixCursor result, File file) {
+ final RowBuilder row = result.newRow();
+ row.add(Document.COLUMN_DOCUMENT_ID, getDocIdForFile(file));
+ row.add(Document.COLUMN_MIME_TYPE, getTypeForName(file.getName()));
+ row.add(Document.COLUMN_DISPLAY_NAME, file.getName());
+ row.add(Document.COLUMN_LAST_MODIFIED, file.lastModified());
+ row.add(Document.COLUMN_FLAGS, Document.FLAG_SUPPORTS_DELETE);
+ row.add(Document.COLUMN_SIZE, file.length());
+ }
+}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 158e133aa436..7a58c8790c4e 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -106,6 +106,9 @@
<uses-permission android:name="android.permission.TRUST_LISTENER" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
+ <!-- Needed for WallpaperManager.clear in ImageWallpaper.updateWallpaperLocked -->
+ <uses-permission android:name="android.permission.SET_WALLPAPER"/>
+
<!-- Recents -->
<uses-permission android:name="android.permission.BIND_APPWIDGET" />
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_bottom.xml b/packages/SystemUI/res/drawable/vector_drawable_place_bottom.xml
new file mode 100644
index 000000000000..14f19819aa1c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_bottom.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0zM4.0,10.0l16.0,0.0l0.0,10.0L4.0,20.0L4.0,10.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_bottom_left.xml b/packages/SystemUI/res/drawable/vector_drawable_place_bottom_left.xml
new file mode 100644
index 000000000000..cea63248d767
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_bottom_left.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M24.0,24.0L24.0,0.0L0.0,0.0l0.0,24.0L24.0,24.0zM4.0,10.0l10.0,0.0l0.0,10.0L4.0,20.0L4.0,10.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_bottom_right.xml b/packages/SystemUI/res/drawable/vector_drawable_place_bottom_right.xml
new file mode 100644
index 000000000000..c2ae9c8b5842
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_bottom_right.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M24.0,24.0L24.0,0.0L0.0,0.0l0.0,24.0L24.0,24.0zM20.0,20.0L10.0,20.0L10.0,10.0l10.0,0.0L20.0,20.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_fullscreen.xml b/packages/SystemUI/res/drawable/vector_drawable_place_fullscreen.xml
new file mode 100644
index 000000000000..aee0b7fbba99
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_fullscreen.xml
@@ -0,0 +1,33 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M0.0,8.0l4.0,0.0 0.0,-4.0 4.0,0.0 0.0,-4.0 -8.0,0.0z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M4.0,16.0l-4.0,0.0 0.0,8.0 8.0,0.0 0.0,-4.0 -4.0,0.0z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M16.0,0.0l0.0,4.0 4.0,0.0 0.0,4.0 4.0,0.0 0.0,-8.0z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20.0,20.0l-4.0,0.0 0.0,4.0 8.0,0.0 0.0,-8.0 -4.0,0.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_left.xml b/packages/SystemUI/res/drawable/vector_drawable_place_left.xml
new file mode 100644
index 000000000000..078f83cf8926
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_left.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M24.0,0.0L0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0zM14.0,4.0l0.0,16.0L4.0,20.0L4.0,4.0L14.0,4.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_right.xml b/packages/SystemUI/res/drawable/vector_drawable_place_right.xml
new file mode 100644
index 000000000000..86730db141f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_right.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0L0.0,24.0zM10.0,20.0L10.0,4.0l10.0,0.0l0.0,16.0L10.0,20.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_top.xml b/packages/SystemUI/res/drawable/vector_drawable_place_top.xml
new file mode 100644
index 000000000000..92e01afd35e8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_top.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M24.0,24.0L24.0,0.0L0.0,0.0l0.0,24.0L24.0,24.0zM20.0,14.0L4.0,14.0L4.0,4.0l16.0,0.0L20.0,14.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_top_left.xml b/packages/SystemUI/res/drawable/vector_drawable_place_top_left.xml
new file mode 100644
index 000000000000..feb612c1bcc1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_top_left.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0zM4.0,4.0l10.0,0.0l0.0,10.0L4.0,14.0L4.0,4.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_top_right.xml b/packages/SystemUI/res/drawable/vector_drawable_place_top_right.xml
new file mode 100644
index 000000000000..9f4ee49c2b6e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_top_right.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0zM20.0,14.0L10.0,14.0L10.0,4.0l10.0,0.0L20.0,14.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml
new file mode 100644
index 000000000000..a718d4d57a56
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="16dp"
+ android:orientation="vertical"
+ android:descendantFocusability="beforeDescendants"
+ android:focusableInTouchMode="true">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <Button
+ android:id="@+id/place_left"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_left" />
+ <Button
+ android:id="@+id/place_right"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_right" />
+ <Button
+ android:id="@+id/place_full"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_fullscreen" />
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml
new file mode 100644
index 000000000000..250f53da1cea
--- /dev/null
+++ b/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="16dp"
+ android:orientation="vertical"
+ android:descendantFocusability="beforeDescendants"
+ android:focusableInTouchMode="true">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <Button
+ android:id="@+id/place_top"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_top" />
+ <Button
+ android:id="@+id/place_bottom"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_bottom" />
+ <Button
+ android:id="@+id/place_full"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_fullscreen" />
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout-sw600dp/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-sw600dp/recents_task_resize_dialog.xml
new file mode 100644
index 000000000000..29e4bce109f4
--- /dev/null
+++ b/packages/SystemUI/res/layout-sw600dp/recents_task_resize_dialog.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="16dp"
+ android:orientation="vertical"
+ android:descendantFocusability="beforeDescendants"
+ android:focusableInTouchMode="true">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <Button
+ android:id="@+id/place_left"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_left" />
+ <Button
+ android:id="@+id/place_right"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_right" />
+ <Button
+ android:id="@+id/place_top"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_top" />
+ <Button
+ android:id="@+id/place_bottom"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_bottom" />
+ <Button
+ android:id="@+id/place_top_left"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_top_left" />
+ <Button
+ android:id="@+id/place_top_right"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_top_right" />
+ <Button
+ android:id="@+id/place_bottom_left"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_bottom_left" />
+ <Button
+ android:id="@+id/place_bottom_right"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_bottom_right" />
+ <Button
+ android:id="@+id/place_full"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_weight="1"
+ android:layout_margin="10dp"
+ android:background="@drawable/vector_drawable_place_fullscreen" />
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_multistack_stack_size_dialog.xml b/packages/SystemUI/res/layout/recents_multistack_stack_size_dialog.xml
deleted file mode 100644
index 36e54a06fb2d..000000000000
--- a/packages/SystemUI/res/layout/recents_multistack_stack_size_dialog.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="16dp"
- android:orientation="vertical"
- android:descendantFocusability="beforeDescendants"
- android:focusableInTouchMode="true">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <EditText
- android:id="@+id/inset_left"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:hint="Left"
- android:singleLine="true"
- android:imeOptions="actionNext"
- android:inputType="number"
- android:selectAllOnFocus="true" />
- <EditText
- android:id="@+id/inset_top"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:hint="Top"
- android:singleLine="true"
- android:imeOptions="actionNext"
- android:inputType="number"
- android:selectAllOnFocus="true" />
- <EditText
- android:id="@+id/inset_right"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:hint="Right"
- android:singleLine="true"
- android:imeOptions="actionNext"
- android:inputType="number"
- android:selectAllOnFocus="true" />
- <EditText
- android:id="@+id/inset_bottom"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:hint="Bottom"
- android:singleLine="true"
- android:imeOptions="actionDone"
- android:inputType="number"
- android:selectAllOnFocus="true" />
- </LinearLayout>
-</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 34e4bebf015f..441318568f35 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"ontsluit"</string>
<string name="phone_label" msgid="2320074140205331708">"maak foon oop"</string>
<string name="camera_label" msgid="7261107956054836961">"maak kamera oop"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Kanselleer"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Versoenbaarheid-zoem se knoppie."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoem kleiner na groter skerm."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth gekoppel."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Geen netwerk nie"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi af"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Geen gestoorde netwerke beskikbaar nie"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Saai uit"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Saai tans uit"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Onbenoemde toestel"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Gereed om uit te saai"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 827a8a32379d..789df15eba66 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"ክፈት"</string>
<string name="phone_label" msgid="2320074140205331708">"ስልክ ክፈት"</string>
<string name="camera_label" msgid="7261107956054836961">"ካሜራ ክፈት"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"ይቅር"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"የተኳኋኝአጉላ አዝራር።"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"አነስተኛውን ማያ ወደ ትልቅ አጉላ።"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ብሉቱዝ ተያይዟል።"</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ምንም አውታረ መረብ የለም"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ጠፍቷል"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"ምንም የተቀመጡ አውታረ መረቦች አይገኙም"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"ውሰድ"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"በመውሰድ ላይ"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"ያልተሰየመ መሳሪያ"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"ለመውሰድ ዝግጁ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 104067aca1f2..081ce59282d7 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -92,6 +92,9 @@
<string name="unlock_label" msgid="8779712358041029439">"إلغاء القفل"</string>
<string name="phone_label" msgid="2320074140205331708">"فتح الهاتف"</string>
<string name="camera_label" msgid="7261107956054836961">"فتح الكاميرا"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"إلغاء"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"زر تكبير/تصغير للتوافق."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"استخدام التكبير/التصغير لتحويل شاشة صغيرة إلى شاشة أكبر"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"تم توصيل البلوتوث."</string>
@@ -261,8 +264,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"لا تتوفر شبكة"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"‏إيقاف Wi-Fi"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"لا تتوفر أية شبكة محفوظة"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"إرسال"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"جارٍ الإرسال"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"جهاز لا يحمل اسمًا"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"جاهز للإرسال"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index a4251beef753..5d57b45ee211 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"отключване"</string>
<string name="phone_label" msgid="2320074140205331708">"отваряне на телефона"</string>
<string name="camera_label" msgid="7261107956054836961">"отваряне на камерата"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Отказ"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Бутон за промяна на мащаба с цел съвместимост."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Промяна на мащаба на екрана от по-малък до по-голям."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth е включен."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Няма мрежа"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi е изключен"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Няма налични запазени мрежи"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Предаване"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Предава се"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Устройство без име"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Готово за предаване"</string>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index b085767ffb13..7edb583f31b4 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"আনলক করুন"</string>
<string name="phone_label" msgid="2320074140205331708">"ফোন খুলুন"</string>
<string name="camera_label" msgid="7261107956054836961">"ক্যামেরা খুলুন"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"বাতিল করুন"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"সামঞ্জস্যের জুম বোতাম৷"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ছোট থেকে বৃহৎ স্ক্রীণে জুম করুন৷"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth সংযুক্ত হয়েছে৷"</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"কোনো নেটওয়ার্ক নেই"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi বন্ধ"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"কোন সংরক্ষিত নেটওয়ার্ক উপলব্ধ নেই"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"কাস্ট করুন"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"কাস্ট করা হচ্ছে"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"নামবিহীন ডিভাইস"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"কাস্ট করার জন্য প্রস্তুত"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index b260e444f8c2..02c4adcb9dba 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"desbloqueja"</string>
<string name="phone_label" msgid="2320074140205331708">"obre el telèfon"</string>
<string name="camera_label" msgid="7261107956054836961">"obre la càmera"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Cancel·la"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botó de zoom de compatibilitat."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Amplia menys com més gran sigui la pantalla."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connectat."</string>
@@ -259,8 +262,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No hi ha cap xarxa"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desconnectada"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"No hi ha cap xarxa desada disponible."</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Emet"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"En emissió"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositiu sense nom"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"A punt per a l\'emissió"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index f1cbb7e1c824..4ba18f4cf74e 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -90,6 +90,9 @@
<string name="unlock_label" msgid="8779712358041029439">"odemknout"</string>
<string name="phone_label" msgid="2320074140205331708">"otevřít telefon"</string>
<string name="camera_label" msgid="7261107956054836961">"spustit fotoaparát"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Zrušit"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačítko úpravy velikosti z důvodu kompatibility"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zvětšit menší obrázek na větší obrazovku."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Rozhraní Bluetooth je připojeno."</string>
@@ -261,8 +264,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Žádná síť"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi vypnuta"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Nejsou dostupné žádné uložené sítě"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Odeslat"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Odesílání"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Nepojmenované zařízení"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Připraveno k vysílání"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 92efc8934934..1790319579b8 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"lås op"</string>
<string name="phone_label" msgid="2320074140205331708">"åbn telefon"</string>
<string name="camera_label" msgid="7261107956054836961">"åbn kamera"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Annuller"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knap for kompatibilitetszoom."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom mindre til større skærm."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth tilsluttet."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Intet netværk"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi slået fra"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Der er ingen tilgængelige gemte netværk"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Caster"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Enhed uden navn"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Klar til at caste"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 1119f1fe0bae..d73a77519b82 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"Entsperren"</string>
<string name="phone_label" msgid="2320074140205331708">"Telefon öffnen"</string>
<string name="camera_label" msgid="7261107956054836961">"Kamera öffnen"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Abbrechen"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Schaltfläche für Kompatibilitätszoom"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom auf einen größeren Bildschirm"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Mit Bluetooth verbunden"</string>
@@ -259,8 +262,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_detail_empty_text" msgid="2831702993995222755">"Keine gespeicherten Netzwerke verfügbar"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Übertragen"</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>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Startklar"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index bc1b7a29f482..5ccd6696237a 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -88,6 +88,8 @@
<string name="unlock_label" msgid="8779712358041029439">"ξεκλείδωμα"</string>
<string name="phone_label" msgid="2320074140205331708">"άνοιγμα τηλεφώνου"</string>
<string name="camera_label" msgid="7261107956054836961">"άνοιγμα φωτογραφικής μηχανής"</string>
+ <string name="recents_caption_resize" msgid="3517056471774958200">"Επιλέξτε τη νέα διάταξη εργασίας"</string>
+ <string name="cancel" msgid="6442560571259935130">"Ακύρωση"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Κουμπί εστίασης συμβατότητας."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Ζουμ από μικρότερη σε μεγαλύτερη οθόνη."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Το Bluetooth είναι συνδεδεμένο."</string>
@@ -259,8 +261,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Κανένα δίκτυο"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ανενεργό"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Δεν υπάρχουν διαθέσιμα αποθηκευμένα δίκτυα"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Μετάδοση"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Μετάδοση"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Ανώνυμη συσκευή"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Έτοιμο για μετάδοση"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 9ac2a641347a..e4f0edb09d42 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"unlock"</string>
<string name="phone_label" msgid="2320074140205331708">"open phone"</string>
<string name="camera_label" msgid="7261107956054836961">"open camera"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Cancel"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No Network"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Off"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"No saved networks available"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Casting"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Unnamed device"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Ready to cast"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 9ac2a641347a..e4f0edb09d42 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"unlock"</string>
<string name="phone_label" msgid="2320074140205331708">"open phone"</string>
<string name="camera_label" msgid="7261107956054836961">"open camera"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Cancel"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No Network"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Off"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"No saved networks available"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Casting"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Unnamed device"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Ready to cast"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 9ac2a641347a..e4f0edb09d42 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"unlock"</string>
<string name="phone_label" msgid="2320074140205331708">"open phone"</string>
<string name="camera_label" msgid="7261107956054836961">"open camera"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Cancel"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No Network"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Off"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"No saved networks available"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Casting"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Unnamed device"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Ready to cast"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index a605a03a2ea5..121004bae071 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"desbloquear"</string>
<string name="phone_label" msgid="2320074140205331708">"abrir teléfono"</string>
<string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado"</string>
@@ -259,8 +262,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Sin red"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desactivada"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"No hay redes guardadas disponibles"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Transmitir"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Transmitiendo"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo sin nombre"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Listo para transmitir"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index dcffc65be5e2..989691a22eec 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -88,6 +88,8 @@
<string name="unlock_label" msgid="8779712358041029439">"desbloquear"</string>
<string name="phone_label" msgid="2320074140205331708">"abrir teléfono"</string>
<string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>
+ <string name="recents_caption_resize" msgid="3517056471774958200">"Seleccionar diseño de tarea nueva"</string>
+ <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado"</string>
@@ -257,8 +259,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No hay red."</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desactivado"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"No hay redes guardadas disponibles"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Enviar"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Enviando"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo sin nombre"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Listo para enviar"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 1a74a8f96f5e..3ba9df901160 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"ava lukk"</string>
<string name="phone_label" msgid="2320074140205331708">"ava telefon"</string>
<string name="camera_label" msgid="7261107956054836961">"ava kaamera"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Tühista"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Sobivussuumi nupp."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Suumi suuremale ekraanile vähem."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth on ühendatud."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Võrku pole"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"WiFi-ühendus on väljas"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Ühtegi salvestatud võrku pole saadaval"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Ülekandmine"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Osatäitjad"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Nimeta seade"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Valmis ülekandmiseks"</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index c7019d9784b8..e69b79d08584 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"desblokeatu"</string>
<string name="phone_label" msgid="2320074140205331708">"ireki telefonoan"</string>
<string name="camera_label" msgid="7261107956054836961">"ireki kamera"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Utzi"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Zoom-bateragarritasunaren botoia."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Handiagotu pantaila txikia."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetootha konektatuta."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ez dago sarerik"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi konexioa desaktibatuta"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Ez dago gordetako sarerik erabilgarri"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Igorpena"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Igortzen"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Izenik gabeko gailua"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Igortzeko prest"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 398e0b0806e4..c97da7007b88 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"بازکردن قفل"</string>
<string name="phone_label" msgid="2320074140205331708">"باز کردن تلفن"</string>
<string name="camera_label" msgid="7261107956054836961">"باز کردن دوربین"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"لغو"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"دکمه بزرگنمایی سازگار."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"بزرگنمایی از صفحه‌های کوچک تا بزرگ."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"بلوتوث متصل است."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"شبکه‌ای موجود نیست"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"‏Wi-Fi خاموش است"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"شبکه ذخیره شده‌ای در دسترس نیست"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"فرستادن"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"در حال فرستادن"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"دستگاه بدون نام"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"آماده برای فرستادن"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 61e591acfc83..c39f57cca3c6 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"avaa lukitus"</string>
<string name="phone_label" msgid="2320074140205331708">"avaa puhelin"</string>
<string name="camera_label" msgid="7261107956054836961">"avaa kamera"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Peruuta"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Yhteensopivuuszoomaus-painike."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoomaa pienemmältä suuremmalle ruudulle."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth yhdistetty."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ei verkkoa"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi-yhteys pois käytöstä"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Tallennettuja verkkoja ei ole käytettävissä"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Suoratoisto"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Lähetetään"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Nimetön laite"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Valmis lähetystä varten"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 3427cfaada5c..37857e7b6b9b 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"déverrouiller"</string>
<string name="phone_label" msgid="2320074140205331708">"Ouvrir le téléphone"</string>
<string name="camera_label" msgid="7261107956054836961">"Ouvrir l\'appareil photo"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Annuler"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connecté"</string>
@@ -259,8 +262,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Aucun réseau"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi désactivé"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Aucun des réseaux enregistrés n\'est disponible"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Diffuser"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Diffusion"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Appareil sans nom"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Prêt à diffuser"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 393a0f80623b..f309545d2f70 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"déverrouiller"</string>
<string name="phone_label" msgid="2320074140205331708">"ouvrir le téléphone"</string>
<string name="camera_label" msgid="7261107956054836961">"ouvrir l\'appareil photo"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Annuler"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connecté"</string>
@@ -259,8 +262,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Aucun réseau"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi désactivé"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Aucun réseau enregistré disponible."</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Diffuser"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Diffusion"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Appareil sans nom"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Prêt à caster"</string>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index c47fc4e4a445..2d1b31a8e58c 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"desbloquear"</string>
<string name="phone_label" msgid="2320074140205331708">"abrir teléfono"</string>
<string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidade"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilidade co tamaño da pantalla."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado"</string>
@@ -259,8 +262,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Non hai rede"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wifi desactivada"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Non hai redes gardadas dispoñibles"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Emisión"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Emitindo"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo sen nome"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Listo para emitir"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 516ae5ecc999..390a8c5573a3 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"अनलॉक करें"</string>
<string name="phone_label" msgid="2320074140205331708">"फ़ोन खोलें"</string>
<string name="camera_label" msgid="7261107956054836961">"कैमरा खोलें"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"अभी नहीं"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"संगतता ज़ूम बटन."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"छोटी से बड़ी स्‍क्रीन पर ज़ूम करें."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब्लूटूथ कनेक्ट किया गया."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"कोई नेटवर्क नहीं"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"वाई-फ़ाई बंद"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"कोई भी सहेजा गया नेटवर्क उपलब्ध नहीं"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"कास्ट करें"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"कास्टिंग"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"अनाम डिवाइस"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"कास्ट करने के लिए तैयार"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index f63b1cdb1c64..d9ef59f2f378 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -89,6 +89,9 @@
<string name="unlock_label" msgid="8779712358041029439">"otključavanje"</string>
<string name="phone_label" msgid="2320074140205331708">"otvaranje telefona"</string>
<string name="camera_label" msgid="7261107956054836961">"otvaranje fotoaparata"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Odustani"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Gumb za kompatibilnost zumiranja."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zumiranje manjeg zaslona na veći."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth povezan."</string>
@@ -258,8 +261,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nema mreže"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi isključen"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Spremljene mreže nisu dostupne"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Emitiranje"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Emitiranje"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Uređaj bez naziva"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Spreman za emitiranje"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 621bdb89a3e9..34e63cdf0f2b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"feloldás"</string>
<string name="phone_label" msgid="2320074140205331708">"telefon megnyitása"</string>
<string name="camera_label" msgid="7261107956054836961">"kamera megnyitása"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Mégse"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kompatibilitási zoom gomb."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kicsinyítsen a nagyobb képernyőhöz."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth csatlakoztatva."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nincs hálózat"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi kikapcsolva"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Nem áll rendelkezésre mentett hálózat"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Tartalomátküldés"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Átküldés"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Név nélküli eszköz"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Küldésre kész"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 4529415ba35b..8241049c6ff4 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"ապակողպել"</string>
<string name="phone_label" msgid="2320074140205331708">"բացել հեռախոսը"</string>
<string name="camera_label" msgid="7261107956054836961">"բացել ֆոտոխցիկը"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Չեղարկել"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Համատեղելիության խոշորացման կոճակը:"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Դիտափոխել փոքրից ավելի մեծ էկրան:"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-ը միացված է:"</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ցանց չկա"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi-ը անջատված է"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Հասանելի պահված ցանցեր չկան"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Հեռարձակում"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Հեռարձակում"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Անանուն սարք"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Պատրաստ է հեռարձակման"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 66a7df0c9e0b..9c5b82b27c19 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"buka kunci"</string>
<string name="phone_label" msgid="2320074140205331708">"buka ponsel"</string>
<string name="camera_label" msgid="7261107956054836961">"buka kamera"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Batal"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tombol perbesar/perkecil kompatibilitas."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Perbesar dari layar kecil ke besar."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth tersambung."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tidak Ada Jaringan"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Mati"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Jaringan yang tersimpan tak tersedia"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Transmisi"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Melakukan transmisi"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Perangkat tanpa nama"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Siap melakukan transmisi"</string>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 1ae45661d8f7..db68c9626445 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"taka úr lás"</string>
<string name="phone_label" msgid="2320074140205331708">"opna síma"</string>
<string name="camera_label" msgid="7261107956054836961">"opna myndavél"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Hætta við"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Hnappur fyrir samhæfisaðdrátt."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aðlaga forrit fyrir lítinn skjá að stærri skjá."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth tengt."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ekkert net"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Slökkt á Wi-Fi"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Engin vistuð net til staðar"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Útsending"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Sendir út"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Ónefnt tæki"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Tilbúið í útsendingu"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index c9ccf051d8ac..37cf79c56b8d 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -88,6 +88,8 @@
<string name="unlock_label" msgid="8779712358041029439">"sblocca"</string>
<string name="phone_label" msgid="2320074140205331708">"apri telefono"</string>
<string name="camera_label" msgid="7261107956054836961">"apri fotocamera"</string>
+ <string name="recents_caption_resize" msgid="3517056471774958200">"Seleziona un nuovo layout per le attività"</string>
+ <string name="cancel" msgid="6442560571259935130">"Annulla"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Pulsante zoom compatibilità."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom inferiore per schermo più grande."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth collegato."</string>
@@ -259,8 +261,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nessuna rete"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi disattivato"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Nessuna rete salvata disponibile"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Trasmetti"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"In trasmissione"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo senza nome"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pronto a trasmettere"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index ff7fc57e7ae7..ba966d04128a 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -90,6 +90,9 @@
<string name="unlock_label" msgid="8779712358041029439">"בטל את הנעילה"</string>
<string name="phone_label" msgid="2320074140205331708">"פתח את הטלפון"</string>
<string name="camera_label" msgid="7261107956054836961">"פתח את המצלמה"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"ביטול"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"לחצן מרחק מתצוגה של תאימות."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"שנה מרחק מתצוגה של מסך קטן לגדול יותר."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"‏Bluetooth מחובר."</string>
@@ -259,8 +262,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"אין רשת"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"‏Wi-Fi כבוי"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"אין רשתות שמורות זמינות"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"מעביר"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"מכשיר ללא שם"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"מוכן להעביר"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index ca6aec9e5588..ce77d20b7849 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"ロック解除"</string>
<string name="phone_label" msgid="2320074140205331708">"電話を起動"</string>
<string name="camera_label" msgid="7261107956054836961">"カメラを起動"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"キャンセル"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"互換ズームボタン。"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"小さい画面から大きい画面に拡大。"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetoothに接続済み。"</string>
@@ -259,8 +262,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ネットワークなし"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi OFF"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"保存されているネットワークがありません"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"キャスト"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"キャストしています"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"名前のないデバイス"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"キャスト準備完了"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 100af704c16e..5ce23e9f4a15 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"განბლოკვა"</string>
<string name="phone_label" msgid="2320074140205331708">"ტელეფონის გახსნა"</string>
<string name="camera_label" msgid="7261107956054836961">"კამერის გახსნა"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"გაუქმება"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"თავსებადი მასშტაბირების ღილაკი."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"შეცვალეთ პატარა ეკრანი უფრო დიდით."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth დაკავშირებულია."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ქსელი არ არის"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi გამორთულია"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"შენახული ქსელები მიუწვდომელია"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"ტრანსლირება"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"გადაიცემა"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"უსახელო მოწყობილობა"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"მზად არის სამაუწყებლოდ"</string>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 9ed07ca48eb2..bf28e29a4682 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"бекітпесін ашу"</string>
<string name="phone_label" msgid="2320074140205331708">"телефонды ашу"</string>
<string name="camera_label" msgid="7261107956054836961">"камераны ашу"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Бас тарту"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Үйлесімділік ұлғайту түймесі."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Үлкендеу экранда кішірейту."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth қосылған."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Желі жоқ"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi өшірулі"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Сақталған желілер қол жетімді емес"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Трансляциялау"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Трансляциялануда"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Атаусыз құрылғы"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Трансляциялауға дайын"</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index de48a23e9e9b..c13c83592c3d 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"ដោះ​សោ"</string>
<string name="phone_label" msgid="2320074140205331708">"បើក​ទូរស័ព្ទ"</string>
<string name="camera_label" msgid="7261107956054836961">"បើក​ម៉ាស៊ីន​ថត"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"បោះ​បង់​"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ប៊ូតុង​ពង្រីក​ត្រូវ​គ្នា។"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ពង្រីក/បង្រួម​​អេក្រង់​ពី​​ទៅធំ"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"បាន​តភ្ជាប់​ប៊្លូធូស។"</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"គ្មាន​បណ្ដាញ"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"វ៉ាយហ្វាយ​បានបិទ"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"មិន​មាន​បណ្ដាញ​ដែល​បាន​រក្សាទុក"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"ខាស"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"ការ​ចាត់​ថ្នាក់"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"ឧបករណ៍​​ដែល​មិន​មាន​ឈ្មោះ"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"ត្រៀម​រួចរាល់​ដើម្បី​ចាត់​ថ្នាក់"</string>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 2687de189ff4..43d242e23143 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"ಅನ್‌ಲಾಕ್ ಮಾಡು"</string>
<string name="phone_label" msgid="2320074140205331708">"ಫೋನ್ ತೆರೆಯಿರಿ"</string>
<string name="camera_label" msgid="7261107956054836961">"ಕ್ಯಾಮರಾ ತೆರೆಯಿರಿ"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"ರದ್ದುಮಾಡು"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ಹೊಂದಾಣಿಕೆಯ ಝೂಮ್ ಬಟನ್."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ಚಿಕ್ಕ ಪರದೆಯಿಂದ ದೊಡ್ಡ ಪರದೆಗೆ ಝೂಮ್ ಮಾಡು."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ಬ್ಲೂಟೂತ್‌‌ ಸಂಪರ್ಕಗೊಂಡಿದೆ."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ನೆಟ್‌ವರ್ಕ್ ಇಲ್ಲ"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ಆಫ್"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"ಯಾವುದೇ ಉಳಿಸಲಾದ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"ಬಿತ್ತರಿಸುವಿಕೆ"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"ಬಿತ್ತರಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"ಹೆಸರಿಸದಿರುವ ಸಾಧನ"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"ಬಿತ್ತರಿಸಲು ಸಿದ್ದವಾಗಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 993bef48e60a..2abec1dd5218 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"잠금 해제"</string>
<string name="phone_label" msgid="2320074140205331708">"휴대전화 열기"</string>
<string name="camera_label" msgid="7261107956054836961">"카메라 열기"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"취소"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"호환성 확대/축소 버튼입니다."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"작은 화면을 큰 화면으로 확대합니다."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"블루투스가 연결되었습니다."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"네트워크가 연결되지 않음"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi 꺼짐"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"저장된 네트워크가 없습니다."</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"전송"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"전송 중"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"이름이 없는 기기"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"전송 준비 완료"</string>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 25471e5e64b1..e20a386a2cf2 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -113,6 +113,10 @@
<string name="unlock_label" msgid="8779712358041029439">"кулпуну ачуу"</string>
<string name="phone_label" msgid="2320074140205331708">"телефонду ачуу"</string>
<string name="camera_label" msgid="7261107956054836961">"камераны ачуу"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <!-- no translation found for cancel (6442560571259935130) -->
+ <skip />
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Масштабды сыйыштыруу баскычы."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Кичинекейди чоң экранга масштабдоо."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth байланышта"</string>
@@ -282,8 +286,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Желе жок"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi өчүк"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Сакталган тармактар жок"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Тышкы экранга чыгаруу"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Тышкы экранга чыгарылууда"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Аты жок түзмөк"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Тышкы экранга чыгарууга даяр"</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index b5e1bfe5781c..7aebf2c24f32 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"ປົດລັອກ"</string>
<string name="phone_label" msgid="2320074140205331708">"​ເປີດ​​ແປ້ນ​ໂທ​ລະ​ສັບ"</string>
<string name="camera_label" msgid="7261107956054836961">"ເປີດ​ກ້ອງ"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"ຍົກເລີກ"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ປຸ່ມຊູມທີ່ໃຊ້ຮ່ວມກັນໄດ້."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ຊູມຈໍນ້ອຍໄປເປັນຈໍຂະຫນາດໃຫຍ່."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ເຊື່ອມຕໍ່ Bluetooth ແລ້ວ."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ບໍ່ມີເຄືອຂ່າຍ"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi​-Fi ປິດ"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"ບໍ່​ມີ​ເຄືອ​ຂ່າຍ​ທີ່​ບັນ​ທຶກ​ໄວ້​ທີ່​ສາ​ມາດ​ໃຊ້​ໄດ້"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"ຄາສທ໌"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"​ກຳ​ລັງ​ສົ່ງ​ສັນ​ຍານ"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"​ອຸ​ປະ​ກອນບໍ່​ມີ​ຊື່"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"​ພ້ອ​ມ​ສົ່ງ​ສັນ​ຍານ​ແລ້ວ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 0fc6fbb42fdf..25539afd5fb6 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -90,6 +90,9 @@
<string name="unlock_label" msgid="8779712358041029439">"atrakinti"</string>
<string name="phone_label" msgid="2320074140205331708">"atidaryti telefoną"</string>
<string name="camera_label" msgid="7261107956054836961">"atidaryti fotoaparatą"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Atšaukti"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Suderinamumo priartinimo mygtukas."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Padidinti ekraną."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"„Bluetooth“ prijungtas."</string>
@@ -259,8 +262,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tinklo nėra"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"„Wi-Fi“ išjungta"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Nėra pasiekiamų išsaugotų tinklų"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Perdavimas"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Perduodama"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Įrenginys be pavadinimo"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Paruošta perduoti"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 54cc36af3424..223132b8d62f 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -89,6 +89,9 @@
<string name="unlock_label" msgid="8779712358041029439">"atbloķēt"</string>
<string name="phone_label" msgid="2320074140205331708">"atvērt tālruni"</string>
<string name="camera_label" msgid="7261107956054836961">"atvērt kameru"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Atcelt"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Saderības tālummaiņas poga."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Veikt tālummaiņu no mazāka ekrāna uz lielāku."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth savienojums ir izveidots."</string>
@@ -258,8 +261,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nav tīkla"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ir izslēgts"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Nav pieejams neviens saglabātais tīkls."</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Apraide"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Notiek apraide…"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Nenosaukta ierīce"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Gatavs apraidei"</string>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 2be9c4ccbccc..f29d25165648 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"отклучи"</string>
<string name="phone_label" msgid="2320074140205331708">"отвори телефон"</string>
<string name="camera_label" msgid="7261107956054836961">"отвори камера"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Откажи"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Копче за компатибилност на зум."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Зумот е помал на поголем екран."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth е поврзан."</string>
@@ -259,8 +262,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Нема мрежа"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi е исклучено"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Нема достапни зачувани мрежи"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Емитувај"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Емитување"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Неименуван уред"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Подготвено за емитување"</string>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index c446927eb0db..1413cd18736d 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"അൺലോക്കുചെയ്യുക"</string>
<string name="phone_label" msgid="2320074140205331708">"ഫോൺ തുറക്കുക"</string>
<string name="camera_label" msgid="7261107956054836961">"ക്യാമറ തുറക്കുക"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"റദ്ദാക്കുക"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"അനുയോജ്യതാ സൂം ബട്ടൺ."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ചെറുതിൽ നിന്ന് വലിയ സ്‌ക്രീനിലേക്ക് സൂം ചെയ്യുക."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ബ്ലൂടൂത്ത് കണക്‌റ്റുചെയ്തു."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"നെറ്റ്‌വർക്ക് ഒന്നുമില്ല"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ഓഫുചെയ്യുക"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"സംരംക്ഷിച്ച നെറ്റ്‌വർക്കുകളൊന്നും ലഭ്യമല്ല"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"കാസ്‌റ്റുചെയ്യുക"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"കാസ്റ്റുചെയ്യുന്നു"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"പേരിടാത്ത ഉപകരണം"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"കാസ്‌റ്റ് ചെയ്യാൻ തയ്യാറാണ്"</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index a767983137ac..15334e4a63b8 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -86,6 +86,9 @@
<string name="unlock_label" msgid="8779712358041029439">"тайлах"</string>
<string name="phone_label" msgid="2320074140205331708">"утас нээх"</string>
<string name="camera_label" msgid="7261107956054836961">"камер нээх"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Цуцлах"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Тохиромжтой өсгөх товч."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Жижгээс том дэлгэцрүү өсгөх."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Блютүүт холбогдсон."</string>
@@ -255,8 +258,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Сүлжээгүй"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi унтарсан"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Хадгалагдсан сүлжээ байхгүй"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Дамжуулах"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Дамжуулж байна"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Нэргүй төхөөрөмж"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Дамжуулахад бэлэн"</string>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 6023d49fb94d..f40429c1735b 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -88,6 +88,8 @@
<string name="unlock_label" msgid="8779712358041029439">"अनलॉक करा"</string>
<string name="phone_label" msgid="2320074140205331708">"फोन उघडा"</string>
<string name="camera_label" msgid="7261107956054836961">"कॅमेरा उघडा"</string>
+ <string name="recents_caption_resize" msgid="3517056471774958200">"नवीन कार्य लेआउट निवडा"</string>
+ <string name="cancel" msgid="6442560571259935130">"रद्द करा"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"सुसंगतता झूम बटण."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"लहानपासून मोठ्‍या स्‍क्रीनवर झूम करा."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब कनेक्‍ट केले."</string>
@@ -257,8 +259,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"नेटवर्क नाही"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"वाय-फाय बंद"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"कोणतीही जतन केलेली नेटवर्क उपलब्ध नाहीत"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"कास्‍ट करा"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"कास्ट करत आहे"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"निनावी डिव्हाइस"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"कास्ट करण्यास सज्ज"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 8579e07acd45..721084bfaa51 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"buka kunci"</string>
<string name="phone_label" msgid="2320074140205331708">"buka telefon"</string>
<string name="camera_label" msgid="7261107956054836961">"buka kamera"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Batal"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Butang zum keserasian."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Skrin zum lebih kecil kepada lebih besar."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth disambungkan."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tiada Rangkaian"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Dimatikan"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Tiada rangkaian disimpan tersedia"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Hantar"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Menghantar"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Peranti tidak bernama"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Bersedia untuk menghantar"</string>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index b6feaa2f9e2e..d84290a31fbe 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"သော့ဖွင့်ရန်"</string>
<string name="phone_label" msgid="2320074140205331708">"ဖုန်းကို ဖွင့်ရန်"</string>
<string name="camera_label" msgid="7261107956054836961">"ကင်မရာ ဖွင့်ရန်"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"ထားတော့"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"အံ့ဝင်သောချုံ့ချဲ့ခလုတ်"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ဖန်သားပြင်ပေါ်တွင် အသေးမှအကြီးသို့ချဲ့ခြင်း"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ဘလူးတုသ်ချိတ်ဆက်ထားမှု"</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ကွန်ရက်မရှိပါ"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"ဝိုင်ဖိုင်ပိတ်ရန်"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"သိမ်းဆည်းထား ကွန်ရက်များ မရှိ"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"ကာစ်တင်"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"အမည်မတပ် ကိရိယာ"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"ကာစ်တ် လုပ်ရန် အသင့် ရှိနေပြီ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 0a67650588a2..2a7c6a1823bf 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"lås opp"</string>
<string name="phone_label" msgid="2320074140205331708">"åpne telefonen"</string>
<string name="camera_label" msgid="7261107956054836961">"åpne kamera"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Zoomknapp for kompatibilitet."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom fra mindre til større skjerm."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth er tilkoblet."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ingen nettverk"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi er av"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Ingen lagrede nettverk er tilgjengelige"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Casting"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Enhet uten navn"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Klar til å caste"</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 71247d937e68..549bc8bbfca8 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -88,6 +88,8 @@
<string name="unlock_label" msgid="8779712358041029439">"खोल्नुहोस्"</string>
<string name="phone_label" msgid="2320074140205331708">"फोन खोल्नुहोस्"</string>
<string name="camera_label" msgid="7261107956054836961">"क्यामेरा खोल्नुहोस्"</string>
+ <string name="recents_caption_resize" msgid="3517056471774958200">"नयाँ कार्य लेआउट चयन गर्नुहोस्"</string>
+ <string name="cancel" msgid="6442560571259935130">"रद्द गर्नुहोस्"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"मिलाउने जुम बटन।"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"स्क्रिनलाई सानोबाट ठूलो पार्नुहोस्।"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब्लुटुथ जडान भयो।"</string>
@@ -257,8 +259,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"नेटवर्क छैन"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"वाइफाइ बन्द"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"उपलब्ध सञ्जाल सुरक्षित गरिएन"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"प्रसारण गर्दै"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"बेनाम उपकरण"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"प्रसारण गर्न तयार"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 16d4eeae33fd..3b9bb8510988 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"ontgrendelen"</string>
<string name="phone_label" msgid="2320074140205331708">"telefoon openen"</string>
<string name="camera_label" msgid="7261107956054836961">"camera openen"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Annuleren"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knop voor compatibiliteitszoom."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kleiner scherm uitzoomen naar groter scherm."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-verbinding ingesteld."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Geen netwerk"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wifi uit"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Geen opgeslagen netwerken beschikbaar"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Casten"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Casten"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Naamloos apparaat"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Klaar om te casten"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 3b9efe7f2d51..1989c8f34b96 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -90,6 +90,9 @@
<string name="unlock_label" msgid="8779712358041029439">"odblokuj"</string>
<string name="phone_label" msgid="2320074140205331708">"otwórz telefon"</string>
<string name="camera_label" msgid="7261107956054836961">"otwórz aparat"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Anuluj"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Przycisk powiększenia na potrzeby zgodności."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Powiększa mniejszy ekran do większego."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth połączony."</string>
@@ -259,8 +262,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Brak sieci"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi wyłączone"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Brak dostępnych zapisanych sieci"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Przesyłanie"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Przesyłam"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Urządzenie bez nazwy"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Wszystko gotowe do przesyłania"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 03ca5ee08e4d..cfe929035a16 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"desbloquear"</string>
<string name="phone_label" msgid="2320074140205331708">"abrir telemóvel"</string>
<string name="camera_label" msgid="7261107956054836961">"abrir câmara"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão zoom de compatibilidade."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom menor para ecrã maior."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ligado."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Sem Rede"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Desligado"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Sem redes guardadas disponíveis"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Transmitir"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Transmissão"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo sem nome"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pronto para transmitir"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 5a68f7dc0cb8..5d6fe7bda140 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"desbloquear"</string>
<string name="phone_label" msgid="2320074140205331708">"abrir telefone"</string>
<string name="camera_label" msgid="7261107956054836961">"abrir câmera"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão de zoom da compatibilidade."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aumentar a tela com zoom."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado."</string>
@@ -259,8 +262,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Sem rede"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desligado"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Não há redes salvas disponíveis"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Transmitir"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Transmitindo"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositivo sem nome"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pronto para transmitir"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 5887c7952a8c..1b67bb413d32 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -89,6 +89,9 @@
<string name="unlock_label" msgid="8779712358041029439">"deblocați"</string>
<string name="phone_label" msgid="2320074140205331708">"deschideți telefonul"</string>
<string name="camera_label" msgid="7261107956054836961">"deschideți camera foto"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Anulați"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Buton zoom pentru compatibilitate."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Faceţi zoom de la o imagine mai mică la una mai mare."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Conectat prin Bluetooth."</string>
@@ -258,8 +261,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nicio reţea"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi deconectat"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Nicio rețea salvată disponibilă"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Proiectați"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Se proiectează"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispozitiv nedenumit"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pregătit pentru proiecție"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 23e8b3ab30c3..1b6b2d2d396b 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -90,6 +90,9 @@
<string name="unlock_label" msgid="8779712358041029439">"Разблокировать."</string>
<string name="phone_label" msgid="2320074140205331708">"Открыть телефон."</string>
<string name="camera_label" msgid="7261107956054836961">"Открыть камеру."</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Отмена"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабирования (режим совместимости)"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Уменьшение изображения для увеличения свободного места на экране."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-соединение установлено."</string>
@@ -261,8 +264,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Нет сети"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi выкл."</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Нет доступных сохраненных сетей"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Wi-Fi-монитор"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Передача изображения"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Безымянное устройство"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Готово к передаче"</string>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index becf69dc55bd..28bedf56d7a8 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"අඟුල අරින්න"</string>
<string name="phone_label" msgid="2320074140205331708">"දුරකථනය විවෘත කරන්න"</string>
<string name="camera_label" msgid="7261107956054836961">"කැමරාව විවෘත කරන්න"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"අවලංගු කරන්න"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ගැළපෙන විශාලන බොත්තම."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"විශාල තිරය වෙත කුඩාව විශාලනය කරන්න."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"බ්ලූටූත් සම්බන්ධිතයි."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ජාලයක් නැත"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi අක්‍රියයි"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"තිබෙන ජාල සුරැකුවේ නැත"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Cast"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"කාස්ට් කිරීම"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"නම් නොකළ උපාංගය"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"කාස්ට් කිරීමට සුදානම්"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 4fc086de94e6..ab7d99bc1f8a 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -90,6 +90,9 @@
<string name="unlock_label" msgid="8779712358041029439">"odomknúť"</string>
<string name="phone_label" msgid="2320074140205331708">"otvoriť telefón"</string>
<string name="camera_label" msgid="7261107956054836961">"spustiť fotoaparát"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Zrušiť"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačidlo úpravy veľkosti z dôvodu kompatibility."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zväčšiť menší obrázok na väčšiu obrazovku."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth pripojené."</string>
@@ -261,8 +264,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Žiadna sieť"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Sieť Wi-Fi je vypnutá"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Nie sú k dispozícii žiadne uložené siete"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Prenášanie"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Prenáša sa"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Nepomenované zariadenie"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pripravené na prenášanie"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index f20596b59b2d..a75f16651909 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -90,6 +90,9 @@
<string name="unlock_label" msgid="8779712358041029439">"odkleni"</string>
<string name="phone_label" msgid="2320074140205331708">"odpri telefon"</string>
<string name="camera_label" msgid="7261107956054836961">"odpri fotoaparat"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Prekliči"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Gumb povečave za združljivost."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Povečava manjšega na večji zaslon."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Povezava Bluetooth vzpostavljena."</string>
@@ -259,8 +262,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ni omrežja"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi izklopljen"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Na voljo ni nobeno shranjeno omrežje"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Predvajanje"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Predvajanje"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Neimenovana naprava"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Pripravljeno za predvajanje"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 74b44f438ff8..1b442ac24adf 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -89,6 +89,9 @@
<string name="unlock_label" msgid="8779712358041029439">"откључај"</string>
<string name="phone_label" msgid="2320074140205331708">"отвори телефон"</string>
<string name="camera_label" msgid="7261107956054836961">"отвори камеру"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Откажи"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Дугме Зум компатибилности."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Зумирање са мањег на већи екран."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth је прикључен."</string>
@@ -258,8 +261,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Нема мреже"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi је искључен"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Није доступна ниједна сачувана мрежа"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Пребацивање"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Пребацивање"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Неименовани уређај"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Спремно за пребацивање"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index de4b84c643ea..22c7bbd744be 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"lås upp"</string>
<string name="phone_label" msgid="2320074140205331708">"öppna mobilen"</string>
<string name="camera_label" msgid="7261107956054836961">"öppna kameran"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knapp för kompatibilitetszoom."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zooma mindre skärm till större."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ansluten."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Inget nätverk"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi av"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Inga sparade nätverk tillgängliga"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Casta"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Castar"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Namnlös enhet"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Redo att casta"</string>
@@ -301,7 +303,7 @@
<string name="description_direction_left" msgid="7207478719805562165">"Dra åt vänster för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
<string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Inga avbrott. Inte ens alarm."</string>
<string name="zen_no_interruptions" msgid="7970973750143632592">"Inga avbrott"</string>
- <string name="zen_important_interruptions" msgid="3477041776609757628">"Endast prioriterade samtal och aviseringar"</string>
+ <string name="zen_important_interruptions" msgid="3477041776609757628">"Bara prioriterade samtal och aviseringar"</string>
<string name="zen_alarm_information_time" msgid="5235772206174372272">"Nästa alarm är kl. <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
<string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Nästa alarm är <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
<string name="zen_alarm_warning" msgid="6873910860111498041">"Alarmet kommer inte att höras kl. <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index c6c4ff0d482e..4ecb29767e76 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"fungua"</string>
<string name="phone_label" msgid="2320074140205331708">"fungua simu"</string>
<string name="camera_label" msgid="7261107956054836961">"fungua kamera"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Ghairi"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kichupo cha kukuza kwa utangamanifu"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kuza kidogo kwa skrini kubwa."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth imeunganishwa."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Hakuna Mtandao"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Imezimwa"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Hakuna mitandao iliyohifadhiwa inayopatikana"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Tuma"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Inatuma"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Kifaa hakina jina"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Tayari kutuma"</string>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index c9da1b8ea74a..eb809211bd61 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"திற"</string>
<string name="phone_label" msgid="2320074140205331708">"ஃபோனைத் திற"</string>
<string name="camera_label" msgid="7261107956054836961">"கேமராவைத் திற"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"ரத்துசெய்"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"பொருந்துமாறு அளவை மாற்றும் பொத்தான்."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"சிறியதிலிருந்து பெரிய திரைக்கு அளவை மாற்றும்."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"புளூடூத் இணைக்கப்பட்டது."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"நெட்வொர்க் இல்லை"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"வைஃபையை முடக்கு"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"சேமித்த நெட்வொர்க்குகள் இல்லை"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"அனுப்பு"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"அனுப்புகிறது"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"பெயரிடப்படாத சாதனம்"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"அனுப்பத் தயார்"</string>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index 62c377ea44e4..b2613ecdf312 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"అన్‌లాక్ చేయి"</string>
<string name="phone_label" msgid="2320074140205331708">"ఫోన్‌ను తెరువు"</string>
<string name="camera_label" msgid="7261107956054836961">"కెమెరాను తెరువు"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"రద్దు చేయండి"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"అనుకూలత జూమ్ బటన్."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"చిన్న స్క్రీన్ నుండి పెద్దదానికి జూమ్ చేయండి."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"బ్లూటూత్ కనెక్ట్ చేయబడింది."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"నెట్‌వర్క్ లేదు"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ఆఫ్‌లో ఉంది"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"సేవ్ చేసిన నెట్‌వర్క్‌లు ఏవీ అందుబాటులో లేవు"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"ప్రసారం చేయండి"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"ప్రసారం చేస్తోంది"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"పేరులేని పరికరం"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"ప్రసారం చేయడానికి సిద్ధంగా ఉంది"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 6ef27911813b..f4403b865c9b 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"ปลดล็อก"</string>
<string name="phone_label" msgid="2320074140205331708">"เปิดโทรศัพท์"</string>
<string name="camera_label" msgid="7261107956054836961">"เปิดกล้อง"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"ยกเลิก"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ปุ่มซูมที่ใช้งานร่วมกันได้"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ซูมหน้าจอให้มีขนาดใหญ่ขึ้น"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"เชื่อมต่อบลูทูธแล้ว"</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ไม่มีเครือข่าย"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"ปิด WiFi"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"เครือข่ายที่บันทึกไว้ทั้งหมดไม่พร้อมใช้งาน"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"ส่ง"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"กำลังส่ง"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"อุปกรณ์ที่ไม่มีชื่อ"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"พร้อมที่จะส่ง"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 493c9e712b92..4c3bb5de97bc 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"i-unlock"</string>
<string name="phone_label" msgid="2320074140205331708">"buksan ang telepono"</string>
<string name="camera_label" msgid="7261107956054836961">"buksan ang camera"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Kanselahin"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Button ng zoom ng pagiging tugma."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Mag-zoom nang mas maliit sa mas malaking screen."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Nakakonekta ang Bluetooth."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Walang Network"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Naka-off ang Wi-Fi"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Walang available na naka-save na mga network"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"I-cast"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Nagka-cast"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Walang pangalang device"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Handang mag-cast"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index df073424fbd5..46cff6fb3a40 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"kilidi aç"</string>
<string name="phone_label" msgid="2320074140205331708">"telefonu aç"</string>
<string name="camera_label" msgid="7261107956054836961">"kamerayı aç"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"İptal"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Uyumluluk zum düğmesi."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Daha büyük ekrana daha küçük yakınlaştır."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth bağlandı."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ağ yok"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Kablosuz Kapalı"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Kullanılabilir kaydedilmiş ağ yok"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Yayınlama"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Yayınlanıyor"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Adsız cihaz"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Yayın için hazır"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 879bbbca4ede..257884dc5815 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -90,6 +90,9 @@
<string name="unlock_label" msgid="8779712358041029439">"розблокувати"</string>
<string name="phone_label" msgid="2320074140205331708">"відкрити телефон"</string>
<string name="camera_label" msgid="7261107956054836961">"відкрити камеру"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Скасувати"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабування сумісності."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Збільшення екрана."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth під’єднано."</string>
@@ -259,8 +262,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Немає мережі"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi вимкнено"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Немає збережених мереж"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Трансляція"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Трансляція"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Пристрій без назви"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Можна транслювати"</string>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 25cdd2d6f346..3efe14c3eff6 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"غیر مقفل کریں"</string>
<string name="phone_label" msgid="2320074140205331708">"فون کھولیں"</string>
<string name="camera_label" msgid="7261107956054836961">"کیمرا کھولیں"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"منسوخ کریں"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"مطابقت پذیری زوم بٹن۔"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"چھوٹی سے بڑی اسکرین پر زوم کریں۔"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"بلوٹوتھ مربوط ہے۔"</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"کوئی نیٹ ورک نہیں ہے"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"‏Wi-Fi آف ہے"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"کوئی محفوظ کردہ نیٹ ورکس دستیاب نہیں ہیں"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"کاسٹ کریں"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"کاسٹنگ"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"بغیر نام والا آلہ"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"کاسٹ کرنے کیلئے تیار"</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 7d7df5f55bdf..c532f28cceae 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"qulfdan chiqarish"</string>
<string name="phone_label" msgid="2320074140205331708">"telefonni ochish"</string>
<string name="camera_label" msgid="7261107956054836961">"kamerani ochish"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Bekor qilish"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kattalashtirish tugmasi mosligi."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kattaroq ekran uchun kichikroqni kattalashtirish."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ulandi."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tarmoq mavjud emas"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi o‘chirilgan"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Saqlangan tarmoqlar mavjud emas"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Translatsiya"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Translatsiya qilinmoqda"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Nomsiz qurilma"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Tarqatish uchun tayyor"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 14b8e1e6194b..f6f3cae8fa21 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"mở khóa"</string>
<string name="phone_label" msgid="2320074140205331708">"mở điện thoại"</string>
<string name="camera_label" msgid="7261107956054836961">"mở máy ảnh"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Hủy"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Nút thu phóng khả năng tương thích."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Thu phóng màn hình lớn hơn hoặc nhỏ hơn."</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Đã kết nối bluetooth."</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Không có mạng nào"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Tắt Wi-Fi"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Không có mạng nào được lưu"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Truyền"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Đang truyền"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Thiết bị không có tên"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Sẵn sàng truyền"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 43dd4f187a04..03ba9a5ce399 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"解锁"</string>
<string name="phone_label" msgid="2320074140205331708">"打开电话"</string>
<string name="camera_label" msgid="7261107956054836961">"打开相机"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"取消"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"兼容性缩放按钮。"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"将小屏幕的图片放大在较大屏幕上显示。"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"蓝牙已连接。"</string>
@@ -259,8 +262,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"无网络"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"WLAN:关闭"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"没有可用的已保存网络"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"投射"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"正在投射"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"未命名设备"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"已准备好投射"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 78eadeeb98bd..f501815da86b 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"解鎖"</string>
<string name="phone_label" msgid="2320074140205331708">"開啟電話"</string>
<string name="camera_label" msgid="7261107956054836961">"開啟相機"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"取消"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"藍牙連線已建立。"</string>
@@ -259,8 +262,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"沒有網絡"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi 關閉"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"找不到已儲存的網絡"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"投放"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"正在放送"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"未命名的裝置"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"放送準備完成"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 5505db4a78a7..d51d1fb77f45 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"解除鎖定"</string>
<string name="phone_label" msgid="2320074140205331708">"開啟電話"</string>
<string name="camera_label" msgid="7261107956054836961">"開啟攝影機"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"取消"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"藍牙連線已建立。"</string>
@@ -259,8 +262,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"沒有網路"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi 已關閉"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"找不到已儲存的網路"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"投放"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"投放"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"未命名的裝置"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"可以開始投放了"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index a020f213240d..c17d723ce7f3 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -88,6 +88,9 @@
<string name="unlock_label" msgid="8779712358041029439">"vula"</string>
<string name="phone_label" msgid="2320074140205331708">"vula ifoni"</string>
<string name="camera_label" msgid="7261107956054836961">"vula ikhamera"</string>
+ <!-- no translation found for recents_caption_resize (3517056471774958200) -->
+ <skip />
+ <string name="cancel" msgid="6442560571259935130">"Khansela"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Inkinobho evumelekile yokusondeza"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Sondeza kancane esikrinini esikhudlwana"</string>
<string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ixhunyiwe"</string>
@@ -257,8 +260,7 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ayikho inethiwekhi"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"I-Wi-Fi icimile"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Awekho amanethiwekhi alondoloziwe atholakalayo"</string>
- <!-- no translation found for quick_settings_cast_title (7709016546426454729) -->
- <skip />
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Abalingisi"</string>
<string name="quick_settings_casting" msgid="6601710681033353316">"Ukusakaza"</string>
<string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Idivayisi engenalo igama"</string>
<string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Ilungele ukusakaza"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 66d494b87bf3..b696787d0147 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -216,6 +216,10 @@
<string name="phone_label">open phone</string>
<!-- Click action label for accessibility for the phone button. [CHAR LIMIT=NONE] -->
<string name="camera_label">open camera</string>
+ <!-- Caption for "Recents resize" developer debug feature. [CHAR LIMIT=NONE] -->
+ <string name="recents_caption_resize">Select new task layout</string>
+ <!-- Button name for "Cancel". [CHAR LIMIT=NONE] -->
+ <string name="cancel">Cancel</string>
<!-- Content description of the compatibility zoom button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_compatibility_zoom_button">Compatibility zoom button.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 275a6be5aefc..dd287349c735 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -436,7 +436,8 @@ public class KeyguardViewMediator extends SystemUI {
}
}
- public void onFingerprintRecognized(int userId) {
+ @Override
+ public void onFingerprintAuthenticated(int userId) {
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
mViewMediatorCallback.keyguardDone(true);
} else {
@@ -636,7 +637,7 @@ public class KeyguardViewMediator extends SystemUI {
doKeyguardLocked(null);
}
}
- KeyguardUpdateMonitor.getInstance(mContext).dispatchScreenTurndOff(why);
+ KeyguardUpdateMonitor.getInstance(mContext).dispatchScreenTurnedOff(why);
}
private void doKeyguardLaterLocked() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 5c1a3178d392..cb78debe0db3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -17,7 +17,6 @@
package com.android.systemui.qs.tiles;
import android.app.ActivityManager;
-import android.os.SystemClock;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
@@ -27,16 +26,11 @@ import com.android.systemui.statusbar.policy.FlashlightController;
public class FlashlightTile extends QSTile<QSTile.BooleanState> implements
FlashlightController.FlashlightListener {
- /** Grace period for which we consider the flashlight
- * still available because it was recently on. */
- private static final long RECENTLY_ON_DURATION_MILLIS = 500;
-
private final AnimationIcon mEnable
= new AnimationIcon(R.drawable.ic_signal_flashlight_enable_animation);
private final AnimationIcon mDisable
= new AnimationIcon(R.drawable.ic_signal_flashlight_disable_animation);
private final FlashlightController mFlashlightController;
- private long mWasLastOn;
public FlashlightTile(Host host) {
super(host);
@@ -69,33 +63,17 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements
return;
}
boolean newState = !mState.value;
- mFlashlightController.setFlashlight(newState);
refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
+ mFlashlightController.setFlashlight(newState);
}
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
- if (state.value) {
- mWasLastOn = SystemClock.uptimeMillis();
- }
-
+ state.visible = mFlashlightController.isAvailable();
+ state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);
if (arg instanceof UserBoolean) {
state.value = ((UserBoolean) arg).value;
}
-
- if (!state.value && mWasLastOn != 0) {
- if (SystemClock.uptimeMillis() > mWasLastOn + RECENTLY_ON_DURATION_MILLIS) {
- mWasLastOn = 0;
- } else {
- mHandler.removeCallbacks(mRecentlyOnTimeout);
- mHandler.postAtTime(mRecentlyOnTimeout, mWasLastOn + RECENTLY_ON_DURATION_MILLIS);
- }
- }
-
- // Always show the tile when the flashlight is or was recently on. This is needed because
- // the camera is not available while it is being used for the flashlight.
- state.visible = mWasLastOn != 0 || mFlashlightController.isAvailable();
- state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);
final AnimationIcon icon = state.value ? mEnable : mDisable;
icon.setAllowAnimation(arg instanceof UserBoolean && ((UserBoolean) arg).userInitiated);
state.icon = icon;
@@ -115,8 +93,8 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements
}
@Override
- public void onFlashlightOff() {
- refreshState(UserBoolean.BACKGROUND_FALSE);
+ public void onFlashlightChanged(boolean enabled) {
+ refreshState(enabled ? UserBoolean.BACKGROUND_TRUE : UserBoolean.BACKGROUND_FALSE);
}
@Override
@@ -128,11 +106,4 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements
public void onFlashlightAvailabilityChanged(boolean available) {
refreshState();
}
-
- private Runnable mRecentlyOnTimeout = new Runnable() {
- @Override
- public void run() {
- refreshState();
- }
- };
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 7f1e876f3242..2d1fab0e7f6b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -385,7 +385,7 @@ public class Recents extends SystemUI
}
// Return early if there are no tasks in the focused stack
- if (focusedStack.getTaskCount() == 0) return;
+ if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
ActivityManager.RunningTaskInfo runningTask = mSystemServicesProxy.getTopMostTask();
// Return early if there is no running task (can't determine affiliated tasks in this case)
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index c259c9d3ef51..f014f09834ed 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -592,14 +592,14 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
private RecentsResizeTaskDialog getResizeTaskDebugDialog() {
if (mResizeTaskDebugDialog == null) {
- mResizeTaskDebugDialog = new RecentsResizeTaskDialog(getFragmentManager());
+ mResizeTaskDebugDialog = new RecentsResizeTaskDialog(getFragmentManager(), this);
}
return mResizeTaskDebugDialog;
}
@Override
public void onTaskResize(Task t) {
- getResizeTaskDebugDialog().showResizeTaskDialog(t);
+ getResizeTaskDebugDialog().showResizeTaskDialog(t, mRecentsView);
}
/**** RecentsView.RecentsViewCallbacks Implementation ****/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 9263543f6bff..abeb2b0bcc54 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -292,7 +292,7 @@ public class RecentsConfiguration {
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED) != 0;
lockToAppEnabled = ssp.getSystemSetting(context,
Settings.System.LOCK_TO_APP_ENABLED) != 0;
- multiStackEnabled = "1".equals(ssp.getSystemProperty("overview.enableMultiStack"));
+ multiStackEnabled = "true".equals(ssp.getSystemProperty("persist.sys.debug.multi_window"));
}
/** Called when the configuration has changed, and we want to reset any configuration specific
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
index d67ecebd3533..4cd577dd88f7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
@@ -16,31 +16,26 @@
package com.android.systemui.recents;
-import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.FragmentManager;
-import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ResolveInfo;
import android.graphics.Rect;
import android.os.Bundle;
-import android.util.MutableInt;
-import android.util.SparseArray;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
-import android.widget.EditText;
-import android.widget.Toast;
+import android.widget.Button;
import com.android.systemui.R;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.views.RecentsView;
-import java.util.List;
+import java.util.ArrayList;
/**
* A helper for the dialogs that show when task debugging is on.
@@ -49,80 +44,197 @@ public class RecentsResizeTaskDialog extends DialogFragment {
static final String TAG = "RecentsResizeTaskDialog";
- // The task we want to resize.
- Task mTaskToResize;
- FragmentManager mFragmentManager;
- View mResizeTaskDialogContent;
+ // The various window arrangements we can handle.
+ private static final int PLACE_LEFT = 1;
+ private static final int PLACE_RIGHT = 2;
+ private static final int PLACE_TOP = 3;
+ private static final int PLACE_BOTTOM = 4;
+ private static final int PLACE_TOP_LEFT = 5;
+ private static final int PLACE_TOP_RIGHT = 6;
+ private static final int PLACE_BOTTOM_LEFT = 7;
+ private static final int PLACE_BOTTOM_RIGHT = 8;
+ private static final int PLACE_FULL = 9;
+
+ // The button resource ID combined with the arrangement command.
+ private static final int[][] BUTTON_DEFINITIONS =
+ {{R.id.place_left, PLACE_LEFT},
+ {R.id.place_right, PLACE_RIGHT},
+ {R.id.place_top, PLACE_TOP},
+ {R.id.place_bottom, PLACE_BOTTOM},
+ {R.id.place_top_left, PLACE_TOP_LEFT},
+ {R.id.place_top_right, PLACE_TOP_RIGHT},
+ {R.id.place_bottom_left, PLACE_BOTTOM_LEFT},
+ {R.id.place_bottom_right, PLACE_BOTTOM_RIGHT},
+ {R.id.place_full, PLACE_FULL}};
- public RecentsResizeTaskDialog() {}
+ // The task we want to resize.
+ private FragmentManager mFragmentManager;
+ private View mResizeTaskDialogContent;
+ private RecentsActivity mRecentsActivity;
+ private RecentsView mRecentsView;
+ private SystemServicesProxy mSsp;
+ private Rect[] mBounds = {new Rect(), new Rect(), new Rect(), new Rect()};
+ private Task[] mTasks = {null, null, null, null};
- public RecentsResizeTaskDialog(FragmentManager mgr) {
+ public RecentsResizeTaskDialog(FragmentManager mgr, RecentsActivity activity) {
mFragmentManager = mgr;
+ mRecentsActivity = activity;
+ mSsp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
}
/** Shows the resize-task dialog. */
- void showResizeTaskDialog(Task t) {
- mTaskToResize = t;
+ void showResizeTaskDialog(Task mainTask, RecentsView rv) {
+ mTasks[0] = mainTask;
+ mRecentsView = rv;
+
show(mFragmentManager, TAG);
}
/** Creates a new resize-task dialog. */
private void createResizeTaskDialog(final Context context, LayoutInflater inflater,
- AlertDialog.Builder builder, final SystemServicesProxy ssp) {
- builder.setTitle("Resize Task - Enter new dimensions");
+ AlertDialog.Builder builder) {
+ builder.setTitle(R.string.recents_caption_resize);
mResizeTaskDialogContent =
- inflater.inflate(R.layout.recents_multistack_stack_size_dialog, null, false);
- Rect bounds = ssp.getTaskBounds(mTaskToResize.key.stackId);
- setDimensionInEditText(mResizeTaskDialogContent, R.id.inset_left, bounds.left);
- setDimensionInEditText(mResizeTaskDialogContent, R.id.inset_top, bounds.top);
- setDimensionInEditText(mResizeTaskDialogContent, R.id.inset_right, bounds.right);
- setDimensionInEditText(mResizeTaskDialogContent, R.id.inset_bottom, bounds.bottom);
- builder.setView(mResizeTaskDialogContent);
- builder.setPositiveButton("Resize Task", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- int left = getDimensionFromEditText(mResizeTaskDialogContent, R.id.inset_left);
- int top = getDimensionFromEditText(mResizeTaskDialogContent, R.id.inset_top);
- int right = getDimensionFromEditText(mResizeTaskDialogContent, R.id.inset_right);
- int bottom = getDimensionFromEditText(mResizeTaskDialogContent, R.id.inset_bottom);
- if (bottom <= top || right <= left) {
- Toast.makeText(context, "Invalid dimensions", Toast.LENGTH_SHORT).show();
- dismiss();
- return;
- }
- ssp.resizeTask(mTaskToResize.key.id, new Rect(left, top, right, bottom));
- dismiss();
+ inflater.inflate(R.layout.recents_task_resize_dialog, null, false);
+
+ for (int i = 0; i < BUTTON_DEFINITIONS.length; i++) {
+ Button b = (Button)mResizeTaskDialogContent.findViewById(BUTTON_DEFINITIONS[i][0]);
+ if (b != null) {
+ final int action = BUTTON_DEFINITIONS[i][1];
+ b.setOnClickListener(
+ new View.OnClickListener() {
+ public void onClick(View v) {
+ placeTasks(action);
+ }
+ });
}
- });
- builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+ }
+
+ builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dismiss();
}
});
+
+ builder.setView(mResizeTaskDialogContent);
}
- /** Helper to get an integer value from an edit text. */
- private int getDimensionFromEditText(View container, int id) {
- String text = ((EditText) container.findViewById(id)).getText().toString();
- if (text.trim().length() != 0) {
- return Integer.parseInt(text.trim());
+ /** Helper function to place window(s) on the display according to an arrangement request. */
+ private void placeTasks(int arrangement) {
+ Rect rect = mSsp.getWindowRect();
+ for (int i = 0; i < mBounds.length; ++i) {
+ mBounds[i].set(rect);
+ if (i != 0) {
+ mTasks[i] = null;
+ }
+ }
+ int additionalTasks = 0;
+ switch (arrangement) {
+ case PLACE_LEFT:
+ mBounds[0].right = mBounds[0].centerX();
+ mBounds[1].left = mBounds[0].right;
+ additionalTasks = 1;
+ break;
+ case PLACE_RIGHT:
+ mBounds[1].right = mBounds[1].centerX();
+ mBounds[0].left = mBounds[1].right;
+ additionalTasks = 1;
+ break;
+ case PLACE_TOP:
+ mBounds[0].bottom = mBounds[0].centerY();
+ mBounds[1].top = mBounds[0].bottom;
+ additionalTasks = 1;
+ break;
+ case PLACE_BOTTOM:
+ mBounds[1].bottom = mBounds[1].centerY();
+ mBounds[0].top = mBounds[1].bottom;
+ additionalTasks = 1;
+ break;
+ case PLACE_TOP_LEFT: // TL, TR, BL, BR
+ mBounds[0].right = mBounds[0].centerX();
+ mBounds[0].bottom = mBounds[0].centerY();
+ mBounds[1].left = mBounds[0].right;
+ mBounds[1].bottom = mBounds[0].bottom;
+ mBounds[2].right = mBounds[0].right;
+ mBounds[2].top = mBounds[0].bottom;
+ mBounds[3].left = mBounds[0].right;
+ mBounds[3].top = mBounds[0].bottom;
+ additionalTasks = 3;
+ break;
+ case PLACE_TOP_RIGHT: // TR, TL, BR, BL
+ mBounds[0].left = mBounds[0].centerX();
+ mBounds[0].bottom = mBounds[0].centerY();
+ mBounds[1].right = mBounds[0].left;
+ mBounds[1].bottom = mBounds[0].bottom;
+ mBounds[2].left = mBounds[0].left;
+ mBounds[2].top = mBounds[0].bottom;
+ mBounds[3].right = mBounds[0].left;
+ mBounds[3].top = mBounds[0].bottom;
+ additionalTasks = 3;
+ break;
+ case PLACE_BOTTOM_LEFT: // BL, BR, TL, TR
+ mBounds[0].right = mBounds[0].centerX();
+ mBounds[0].top = mBounds[0].centerY();
+ mBounds[1].left = mBounds[0].right;
+ mBounds[1].top = mBounds[0].top;
+ mBounds[2].right = mBounds[0].right;
+ mBounds[2].bottom = mBounds[0].top;
+ mBounds[3].left = mBounds[0].right;
+ mBounds[3].bottom = mBounds[0].top;
+ additionalTasks = 3;
+ break;
+ case PLACE_BOTTOM_RIGHT: // BR, BL, TR, TL
+ mBounds[0].left = mBounds[0].centerX();
+ mBounds[0].top = mBounds[0].centerY();
+ mBounds[1].right = mBounds[0].left;
+ mBounds[1].top = mBounds[0].top;
+ mBounds[2].left = mBounds[0].left;
+ mBounds[2].bottom = mBounds[0].top;
+ mBounds[3].right = mBounds[0].left;
+ mBounds[3].bottom = mBounds[0].top;
+ additionalTasks = 3;
+ break;
+ case PLACE_FULL:
+ // Nothing to change.
+ break;
+ }
+
+ // Get the other tasks.
+ for (int i = 1; i <= additionalTasks && mTasks[i - 1] != null; ++i) {
+ mTasks[i] = mRecentsView.getNextTaskOrTopTask(mTasks[i - 1]);
+ // Do stop if we circled back to the first item.
+ if (mTasks[i] == mTasks[0]) {
+ mTasks[i] = null;
+ }
}
- return 0;
- }
- /** Helper to set an integer value to an edit text. */
- private void setDimensionInEditText(View container, int id, int value) {
- ((EditText) container.findViewById(id)).setText("" + value);
+ // Resize all tasks beginning from the "oldest" one.
+ for (int i = additionalTasks; i >= 0; --i) {
+ if (mTasks[i] != null) {
+ mSsp.resizeTask(mTasks[i].key.id, mBounds[i]);
+ }
+ }
+
+ // Get rid of the dialog.
+ dismiss();
+ mRecentsActivity.dismissRecentsToHomeRaw(false);
+
+ // Show tasks - beginning with the oldest so that the focus ends on the selected one.
+ // TODO: Remove this once issue b/19893373 is resolved.
+ for (int i = additionalTasks; i >= 0; --i) {
+ if (mTasks[i] != null) {
+ mRecentsView.launchTask(mTasks[i]);
+ }
+ }
}
@Override
public Dialog onCreateDialog(Bundle args) {
final Context context = this.getActivity();
- final SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
LayoutInflater inflater = getActivity().getLayoutInflater();
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- createResizeTaskDialog(context, inflater, builder, ssp);
+ createResizeTaskDialog(context, inflater, builder);
return builder.create();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index a473a29fd28b..d60df9ca30e2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -259,7 +259,7 @@ public class SystemServicesProxy {
public Rect getTaskBounds(int stackId) {
ActivityManager.StackInfo info = getAllStackInfos().get(stackId);
if (info != null)
- return getAllStackInfos().get(stackId).bounds;
+ return info.bounds;
return new Rect();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 448a7a9f3ceb..abed7a5b7ccd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -149,6 +149,31 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
return mTaskStackViews;
}
+ /** Gets the next task in the stack - or if the last - the top task */
+ public Task getNextTaskOrTopTask(Task taskToSearch) {
+ Task returnTask = null;
+ boolean found = false;
+ List<TaskStackView> stackViews = getTaskStackViews();
+ int stackCount = stackViews.size();
+ for (int i = stackCount - 1; i >= 0; --i) {
+ TaskStack stack = stackViews.get(i).getStack();
+ ArrayList<Task> taskList = stack.getTasks();
+ // Iterate the stack views and try and find the focused task
+ for (int j = taskList.size() - 1; j >= 0; --j) {
+ Task task = taskList.get(j);
+ // Return the next task in the line.
+ if (found)
+ return task;
+ // Remember the first possible task as the top task.
+ if (returnTask == null)
+ returnTask = task;
+ if (task == taskToSearch)
+ found = true;
+ }
+ }
+ return returnTask;
+ }
+
/** Launches the focused task from the first stack if possible */
public boolean launchFocusedTask() {
// Get the first stack view
@@ -172,6 +197,28 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
return false;
}
+ /** Launches a given task. */
+ public boolean launchTask(Task task) {
+ // Get the first stack view
+ List<TaskStackView> stackViews = getTaskStackViews();
+ int stackCount = stackViews.size();
+ for (int i = 0; i < stackCount; i++) {
+ TaskStackView stackView = stackViews.get(i);
+ TaskStack stack = stackView.getStack();
+ // Iterate the stack views and try and find the given task.
+ List<TaskView> taskViews = stackView.getTaskViews();
+ int taskViewCount = taskViews.size();
+ for (int j = 0; j < taskViewCount; j++) {
+ TaskView tv = taskViews.get(j);
+ if (tv.getTask() == task) {
+ onTaskViewClicked(stackView, tv, stack, task, false);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
/** Launches the task that Recents was launched from, if possible */
public boolean launchPreviousTask() {
// Get the first stack view
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index ca083196073a..60a91bf9b393 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -26,14 +26,15 @@ import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.RippleDrawable;
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.PorterDuffXfermode;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.RippleDrawable;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;
@@ -43,7 +44,9 @@ import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
@@ -51,6 +54,7 @@ import com.android.systemui.recents.model.Task;
public class TaskViewHeader extends FrameLayout {
RecentsConfiguration mConfig;
+ private SystemServicesProxy mSsp;
// Header views
ImageView mMoveTaskButton;
@@ -91,6 +95,7 @@ public class TaskViewHeader extends FrameLayout {
public TaskViewHeader(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mConfig = RecentsConfiguration.getInstance();
+ mSsp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
setWillNotDraw(false);
setClipToOutline(true);
setOutlineProvider(new ViewOutlineProvider() {
@@ -124,9 +129,6 @@ public class TaskViewHeader extends FrameLayout {
mActivityDescription = (TextView) findViewById(R.id.activity_description);
mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
mMoveTaskButton = (ImageView) findViewById(R.id.move_task);
- if (mConfig.multiStackEnabled) {
- mMoveTaskButton.setVisibility(View.VISIBLE);
- }
// Hide the backgrounds if they are ripple drawables
if (!Constants.DebugFlags.App.EnableTaskFiltering) {
@@ -189,10 +191,7 @@ public class TaskViewHeader extends FrameLayout {
mApplicationIcon.setImageDrawable(t.applicationIcon);
}
mApplicationIcon.setContentDescription(t.activityLabel);
- // Always update when multi stack debugging is enabled as the stack id can change
- if (mConfig.multiStackEnabled) {
- mActivityDescription.setText("[" + t.key.stackId + "] " + t.activityLabel);
- } else if (!mActivityDescription.getText().toString().equals(t.activityLabel)) {
+ if (!mActivityDescription.getText().toString().equals(t.activityLabel)) {
mActivityDescription.setText(t.activityLabel);
}
// Try and apply the system ui tint
@@ -209,6 +208,43 @@ public class TaskViewHeader extends FrameLayout {
mLightDismissDrawable : mDarkDismissDrawable);
mDismissButton.setContentDescription(String.format(mDismissContentDescription,
t.activityLabel));
+ mMoveTaskButton.setVisibility((mConfig.multiStackEnabled) ? View.VISIBLE : View.INVISIBLE);
+ if (mConfig.multiStackEnabled) {
+ updateResizeTaskBarIcon(t);
+ }
+ }
+
+ /** Updates the resize task bar button. */
+ void updateResizeTaskBarIcon(Task t) {
+ Rect display = mSsp.getWindowRect();
+ Rect taskRect = mSsp.getTaskBounds(t.key.stackId);
+ int resId = R.drawable.star;
+ if (display.equals(taskRect) || taskRect.isEmpty()) {
+ resId = R.drawable.vector_drawable_place_fullscreen;
+ } else {
+ boolean top = display.top == taskRect.top;
+ boolean bottom = display.bottom == taskRect.bottom;
+ boolean left = display.left == taskRect.left;
+ boolean right = display.right == taskRect.right;
+ if (top && bottom && left) {
+ resId = R.drawable.vector_drawable_place_left;
+ } else if (top && bottom && right) {
+ resId = R.drawable.vector_drawable_place_right;
+ } else if (top && left && right) {
+ resId = R.drawable.vector_drawable_place_top;
+ } else if (bottom && left && right) {
+ resId = R.drawable.vector_drawable_place_bottom;
+ } else if (top && right) {
+ resId = R.drawable.vector_drawable_place_top_right;
+ } else if (top && left) {
+ resId = R.drawable.vector_drawable_place_top_left;
+ } else if (bottom && right) {
+ resId = R.drawable.vector_drawable_place_bottom_right;
+ } else if (bottom && left) {
+ resId = R.drawable.vector_drawable_place_bottom_left;
+ }
+ }
+ mMoveTaskButton.setImageResource(resId);
}
/** Unbinds the bar view from the task */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index bba7682f1b04..a55e0266ce23 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -132,6 +132,8 @@ public class TaskViewTransform {
/** Reset the transform on a view. */
public static void reset(View v) {
+ // Cancel any running animations
+ v.animate().cancel();
v.setTranslationX(0f);
v.setTranslationY(0f);
v.setTranslationZ(0f);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 0c21b2044643..a247c8e8f074 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -336,7 +336,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
public void launchCamera() {
- mFlashlightController.killFlashlight();
Intent intent = getCameraIntent();
boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity(
mContext, intent, mLockPatternUtils.getCurrentUser());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index 5ef345bd7cbd..65cd2684198c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -125,7 +125,7 @@ public class UnlockMethodCache {
}
@Override
- public void onFingerprintRecognized(int userId) {
+ public void onFingerprintAuthenticated(int userId) {
update(false /* updateAlways */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
index c9ba8f6fc36b..cd1914c55663 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
@@ -17,20 +17,14 @@
package com.android.systemui.statusbar.policy;
import android.content.Context;
-import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
-import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
-import android.hardware.camera2.CameraMetadata;
-import android.hardware.camera2.CaptureRequest;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
+import android.text.TextUtils;
import android.util.Log;
-import android.util.Size;
-import android.view.Surface;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -44,7 +38,7 @@ public class FlashlightController {
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final int DISPATCH_ERROR = 0;
- private static final int DISPATCH_OFF = 1;
+ private static final int DISPATCH_CHANGED = 1;
private static final int DISPATCH_AVAILABILITY_CHANGED = 2;
private final CameraManager mCameraManager;
@@ -57,52 +51,50 @@ public class FlashlightController {
/** Lock on {@code this} when accessing */
private boolean mFlashlightEnabled;
- private String mCameraId;
- private boolean mCameraAvailable;
- private CameraDevice mCameraDevice;
- private CaptureRequest mFlashlightRequest;
- private CameraCaptureSession mSession;
- private SurfaceTexture mSurfaceTexture;
- private Surface mSurface;
+ private final String mCameraId;
+ private boolean mTorchAvailable;
public FlashlightController(Context mContext) {
mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
- initialize();
- }
- public void initialize() {
+ String cameraId = null;
try {
- mCameraId = getCameraId();
+ cameraId = getCameraId();
} catch (Throwable e) {
Log.e(TAG, "Couldn't initialize.", e);
return;
+ } finally {
+ mCameraId = cameraId;
}
if (mCameraId != null) {
ensureHandler();
- mCameraManager.registerAvailabilityCallback(mAvailabilityCallback, mHandler);
+ mCameraManager.registerTorchCallback(mTorchCallback, mHandler);
}
}
- public synchronized void setFlashlight(boolean enabled) {
- if (mFlashlightEnabled != enabled) {
- mFlashlightEnabled = enabled;
- postUpdateFlashlight();
- }
- }
-
- public void killFlashlight() {
- boolean enabled;
+ public void setFlashlight(boolean enabled) {
+ boolean pendingError = false;
synchronized (this) {
- enabled = mFlashlightEnabled;
+ if (mFlashlightEnabled != enabled) {
+ mFlashlightEnabled = enabled;
+ try {
+ mCameraManager.setTorchMode(mCameraId, enabled);
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "Couldn't set torch mode", e);
+ mFlashlightEnabled = false;
+ pendingError = true;
+ }
+ }
}
- if (enabled) {
- mHandler.post(mKillFlashlightRunnable);
+ dispatchModeChanged(mFlashlightEnabled);
+ if (pendingError) {
+ dispatchError();
}
}
public synchronized boolean isAvailable() {
- return mCameraAvailable;
+ return mTorchAvailable;
}
public void addListener(FlashlightListener l) {
@@ -126,42 +118,6 @@ public class FlashlightController {
}
}
- private void startDevice() throws CameraAccessException {
- mCameraManager.openCamera(getCameraId(), mCameraListener, mHandler);
- }
-
- private void startSession() throws CameraAccessException {
- mSurfaceTexture = new SurfaceTexture(false);
- Size size = getSmallestSize(mCameraDevice.getId());
- mSurfaceTexture.setDefaultBufferSize(size.getWidth(), size.getHeight());
- mSurface = new Surface(mSurfaceTexture);
- ArrayList<Surface> outputs = new ArrayList<>(1);
- outputs.add(mSurface);
- mCameraDevice.createCaptureSession(outputs, mSessionListener, mHandler);
- }
-
- private Size getSmallestSize(String cameraId) throws CameraAccessException {
- Size[] outputSizes = mCameraManager.getCameraCharacteristics(cameraId)
- .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
- .getOutputSizes(SurfaceTexture.class);
- if (outputSizes == null || outputSizes.length == 0) {
- throw new IllegalStateException(
- "Camera " + cameraId + "doesn't support any outputSize.");
- }
- Size chosen = outputSizes[0];
- for (Size s : outputSizes) {
- if (chosen.getWidth() >= s.getWidth() && chosen.getHeight() >= s.getHeight()) {
- chosen = s;
- }
- }
- return chosen;
- }
-
- private void postUpdateFlashlight() {
- ensureHandler();
- mHandler.post(mUpdateFlashlightRunnable);
- }
-
private String getCameraId() throws CameraAccessException {
String[] ids = mCameraManager.getCameraIdList();
for (String id : ids) {
@@ -176,70 +132,12 @@ public class FlashlightController {
return null;
}
- private void updateFlashlight(boolean forceDisable) {
- try {
- boolean enabled;
- synchronized (this) {
- enabled = mFlashlightEnabled && !forceDisable;
- }
- if (enabled) {
- if (mCameraDevice == null) {
- startDevice();
- return;
- }
- if (mSession == null) {
- startSession();
- return;
- }
- if (mFlashlightRequest == null) {
- CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(
- CameraDevice.TEMPLATE_PREVIEW);
- builder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);
- builder.addTarget(mSurface);
- CaptureRequest request = builder.build();
- mSession.capture(request, null, mHandler);
- mFlashlightRequest = request;
- }
- } else {
- if (mCameraDevice != null) {
- mCameraDevice.close();
- teardown();
- }
- }
-
- } catch (CameraAccessException|IllegalStateException|UnsupportedOperationException e) {
- Log.e(TAG, "Error in updateFlashlight", e);
- handleError();
- }
- }
-
- private void teardown() {
- mCameraDevice = null;
- mSession = null;
- mFlashlightRequest = null;
- if (mSurface != null) {
- mSurface.release();
- mSurfaceTexture.release();
- }
- mSurface = null;
- mSurfaceTexture = null;
- }
-
- private void handleError() {
- synchronized (this) {
- mFlashlightEnabled = false;
- }
- dispatchError();
- dispatchOff();
- updateFlashlight(true /* forceDisable */);
- }
-
- private void dispatchOff() {
- dispatchListeners(DISPATCH_OFF, false /* argument (ignored) */);
+ private void dispatchModeChanged(boolean enabled) {
+ dispatchListeners(DISPATCH_CHANGED, enabled);
}
private void dispatchError() {
- dispatchListeners(DISPATCH_ERROR, false /* argument (ignored) */);
+ dispatchListeners(DISPATCH_CHANGED, false /* argument (ignored) */);
}
private void dispatchAvailabilityChanged(boolean available) {
@@ -255,8 +153,8 @@ public class FlashlightController {
if (l != null) {
if (message == DISPATCH_ERROR) {
l.onFlashlightError();
- } else if (message == DISPATCH_OFF) {
- l.onFlashlightOff();
+ } else if (message == DISPATCH_CHANGED) {
+ l.onFlashlightChanged(argument);
} else if (message == DISPATCH_AVAILABILITY_CHANGED) {
l.onFlashlightAvailabilityChanged(argument);
}
@@ -279,106 +177,57 @@ public class FlashlightController {
}
}
- private final CameraDevice.StateListener mCameraListener = new CameraDevice.StateListener() {
- @Override
- public void onOpened(CameraDevice camera) {
- mCameraDevice = camera;
- postUpdateFlashlight();
- }
-
- @Override
- public void onDisconnected(CameraDevice camera) {
- if (mCameraDevice == camera) {
- dispatchOff();
- teardown();
- }
- }
-
- @Override
- public void onError(CameraDevice camera, int error) {
- Log.e(TAG, "Camera error: camera=" + camera + " error=" + error);
- if (camera == mCameraDevice || mCameraDevice == null) {
- handleError();
- }
- }
- };
+ private final CameraManager.TorchCallback mTorchCallback =
+ new CameraManager.TorchCallback() {
- private final CameraCaptureSession.StateListener mSessionListener =
- new CameraCaptureSession.StateListener() {
@Override
- public void onConfigured(CameraCaptureSession session) {
- if (session.getDevice() == mCameraDevice) {
- mSession = session;
- } else {
- session.close();
- }
- postUpdateFlashlight();
- }
-
- @Override
- public void onConfigureFailed(CameraCaptureSession session) {
- Log.e(TAG, "Configure failed.");
- if (mSession == null || mSession == session) {
- handleError();
- }
- }
- };
-
- private final Runnable mUpdateFlashlightRunnable = new Runnable() {
- @Override
- public void run() {
- updateFlashlight(false /* forceDisable */);
- }
- };
-
- private final Runnable mKillFlashlightRunnable = new Runnable() {
- @Override
- public void run() {
- synchronized (this) {
- mFlashlightEnabled = false;
+ public void onTorchModeUnavailable(String cameraId) {
+ if (TextUtils.equals(cameraId, mCameraId)) {
+ setCameraAvailable(false);
}
- updateFlashlight(true /* forceDisable */);
- dispatchOff();
}
- };
- private final CameraManager.AvailabilityCallback mAvailabilityCallback =
- new CameraManager.AvailabilityCallback() {
@Override
- public void onCameraAvailable(String cameraId) {
- if (DEBUG) Log.d(TAG, "onCameraAvailable(" + cameraId + ")");
- if (cameraId.equals(mCameraId)) {
+ public void onTorchModeChanged(String cameraId, boolean enabled) {
+ if (TextUtils.equals(cameraId, mCameraId)) {
setCameraAvailable(true);
- }
- }
-
- @Override
- public void onCameraUnavailable(String cameraId) {
- if (DEBUG) Log.d(TAG, "onCameraUnavailable(" + cameraId + ")");
- if (cameraId.equals(mCameraId)) {
- setCameraAvailable(false);
+ setTorchMode(enabled);
}
}
private void setCameraAvailable(boolean available) {
boolean changed;
synchronized (FlashlightController.this) {
- changed = mCameraAvailable != available;
- mCameraAvailable = available;
+ changed = mTorchAvailable != available;
+ mTorchAvailable = available;
}
if (changed) {
if (DEBUG) Log.d(TAG, "dispatchAvailabilityChanged(" + available + ")");
dispatchAvailabilityChanged(available);
}
}
+
+ private void setTorchMode(boolean enabled) {
+ boolean changed;
+ synchronized (FlashlightController.this) {
+ changed = mFlashlightEnabled != enabled;
+ mFlashlightEnabled = enabled;
+ }
+ if (changed) {
+ if (DEBUG) Log.d(TAG, "dispatchModeChanged(" + enabled + ")");
+ dispatchModeChanged(enabled);
+ }
+ }
};
public interface FlashlightListener {
/**
- * Called when the flashlight turns off unexpectedly.
+ * Called when the flashlight was turned off or on.
+ * @param enabled true if the flashlight is currently turned on.
*/
- void onFlashlightOff();
+ void onFlashlightChanged(boolean enabled);
+
/**
* Called when there is an error that turns the flashlight off.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 2fbb8128e8b0..f0dd943e93f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -190,7 +190,8 @@ public class SecurityControllerImpl implements SecurityController {
NetworkCapabilities networkCapabilities =
mConnectivityManager.getNetworkCapabilities(network);
if (DEBUG) Log.d(TAG, "onAvailable " + network.netId + " : " + networkCapabilities);
- if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
+ if (networkCapabilities != null &&
+ networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
setCurrentNetid(network.netId);
}
};
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index 523c8fb7b189..c4daaa9814e3 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -802,7 +802,7 @@ public class Allocation extends BaseObj {
/**
* This is only intended to be used by auto-generated code reflected from
- * the RenderScript script files.
+ * the RenderScript script files and should not be used by developers.
*
* @param xoff
* @param component_number
@@ -813,9 +813,8 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* This is only intended to be used by auto-generated code reflected from
- * the RenderScript script files.
+ * the RenderScript script files and should not be used by developers.
*
* @param xoff
* @param yoff
@@ -1247,8 +1246,11 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
+ * Copy a rectangular region from the array into the allocation.
+ * The array is assumed to be tightly packed.
*
+ * The data type of the array is not required to be the same as
+ * the element data type.
*/
private void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d,
Object array, Element.DataType dt, int arrayLen) {
@@ -1277,7 +1279,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* Copy a rectangular region from the array into the allocation.
* The array is assumed to be tightly packed.
*
@@ -1298,7 +1299,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* Copy a rectangular region into the allocation from another
* allocation.
*
@@ -1415,7 +1415,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* This is only intended to be used by auto-generated code reflected from
* the RenderScript script files and should not be used by developers.
*
@@ -1423,7 +1422,7 @@ public class Allocation extends BaseObj {
* @param yoff
* @param zoff
* @param component_number
- * @param array
+ * @param fp
*/
public void copyToFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) {
mRS.validate();
@@ -1501,7 +1500,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* guarantee that the Allocation is compatible with the input buffer.
*
@@ -1516,7 +1514,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* guarantee that the Allocation is compatible with the input buffer.
*
@@ -1529,7 +1526,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* guarantee that the Allocation is compatible with the input buffer.
*
@@ -1542,7 +1538,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* guarantee that the Allocation is compatible with the input buffer.
*
@@ -1555,7 +1550,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* guarantee that the Allocation is compatible with the input buffer.
*
@@ -1569,7 +1563,6 @@ public class Allocation extends BaseObj {
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* and will generate exceptions if the Allocation type does not
* match the component type of the array passed in.
@@ -1585,7 +1578,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* and will generate exceptions if the Allocation type is not a 32 bit
* integer type.
@@ -1600,7 +1592,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* and will generate exceptions if the Allocation type is not a 16 bit
* integer type.
@@ -1615,7 +1606,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* and will generate exceptions if the Allocation type is not an 8 bit
* integer type.
@@ -1630,7 +1620,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* Copy part of this Allocation into an array. This method does not
* and will generate exceptions if the Allocation type is not a 32 bit float
* type.
@@ -1671,7 +1660,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
@@ -1687,7 +1675,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
@@ -1703,7 +1690,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
@@ -1719,7 +1705,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
@@ -1735,7 +1720,6 @@ public class Allocation extends BaseObj {
}
/**
- * @hide
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
@@ -1752,8 +1736,11 @@ public class Allocation extends BaseObj {
/**
- * @hide
+ * Copy from a rectangular region in this Allocation into an array.
+ * The array is assumed to be tightly packed.
*
+ * The data type of the array is not required to be the same as
+ * the element data type.
*/
private void copy3DRangeToUnchecked(int xoff, int yoff, int zoff, int w, int h, int d,
Object array, Element.DataType dt, int arrayLen) {
@@ -1780,8 +1767,7 @@ public class Allocation extends BaseObj {
Trace.traceEnd(RenderScript.TRACE_TAG);
}
- /**
- * @hide
+ /*
* Copy from a rectangular region in this Allocation into an array.
*
* @param xoff X offset of the region to copy in this Allocation
diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java
index 287b3f127386..60ff996d0505 100644
--- a/rs/java/android/renderscript/Element.java
+++ b/rs/java/android/renderscript/Element.java
@@ -114,7 +114,8 @@ public class Element extends BaseObj {
* MATRIX the three matrix types contain FLOAT_32 elements and are treated
* as 32 bits for alignment purposes.
*
- * RS_* objects. 32 bit opaque handles.
+ * RS_* objects: opaque handles with implementation dependent
+ * sizes.
*/
public enum DataType {
NONE (0, 0),
diff --git a/rs/java/android/renderscript/FileA3D.java b/rs/java/android/renderscript/FileA3D.java
index 41648101cc88..9d8f1624a051 100644
--- a/rs/java/android/renderscript/FileA3D.java
+++ b/rs/java/android/renderscript/FileA3D.java
@@ -145,6 +145,9 @@ public class FileA3D extends BaseObj {
case MESH:
entry.mLoadedObj = new Mesh(objectID, rs);
break;
+
+ default:
+ throw new RSRuntimeException("Unrecognized object type in file.");
}
entry.mLoadedObj.updateFromNative();
diff --git a/rs/java/android/renderscript/Mesh.java b/rs/java/android/renderscript/Mesh.java
index 5b4cadb6c98e..13c8e1c91052 100644
--- a/rs/java/android/renderscript/Mesh.java
+++ b/rs/java/android/renderscript/Mesh.java
@@ -363,6 +363,9 @@ public class Mesh extends BaseObj {
alloc = Allocation.createTyped(mRS, entry.t, mUsage);
} else if(entry.e != null) {
alloc = Allocation.createSized(mRS, entry.e, entry.size, mUsage);
+ } else {
+ // Should never happen because the builder will always set one
+ throw new IllegalStateException("Builder corrupt, no valid element in entry.");
}
vertexBuffers[ct] = alloc;
vtx[ct] = alloc.getID(mRS);
@@ -375,6 +378,9 @@ public class Mesh extends BaseObj {
alloc = Allocation.createTyped(mRS, entry.t, mUsage);
} else if(entry.e != null) {
alloc = Allocation.createSized(mRS, entry.e, entry.size, mUsage);
+ } else {
+ // Should never happen because the builder will always set one
+ throw new IllegalStateException("Builder corrupt, no valid element in entry.");
}
long allocID = (alloc == null) ? 0 : alloc.getID(mRS);
indexBuffers[ct] = alloc;
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 8562288aa3f5..e8e942c8db8d 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -1351,7 +1351,7 @@ public class RenderScript {
}
/**
- * calls create(cts, ContextType.NORMAL, CREATE_FLAG_NONE)
+ * calls create(ctx, ContextType.NORMAL, CREATE_FLAG_NONE)
*
* See documentation for @create for details
*
@@ -1363,7 +1363,7 @@ public class RenderScript {
}
/**
- * calls create(cts, ct, CREATE_FLAG_NONE)
+ * calls create(ctx, ct, CREATE_FLAG_NONE)
*
* See documentation for @create for details
*
@@ -1375,7 +1375,8 @@ public class RenderScript {
return create(ctx, ct, CREATE_FLAG_NONE);
}
- /**
+
+ /**
* Gets or creates a RenderScript context of the specified type.
*
* The returned context will be cached for future reuse within
@@ -1397,21 +1398,49 @@ public class RenderScript {
*/
public static RenderScript create(Context ctx, ContextType ct, int flags) {
int v = ctx.getApplicationInfo().targetSdkVersion;
- if (v < 23) {
- return internalCreate(ctx, v, ct, flags);
+ return create(ctx, v, ct, flags);
+ }
+
+ /**
+ * calls create(ctx, sdkVersion, ContextType.NORMAL, CREATE_FLAG_NONE)
+ *
+ * Used by the RenderScriptThunker to maintain backward compatibility.
+ *
+ * @hide
+ * @param ctx The context.
+ * @param sdkVersion The target SDK Version.
+ * @return RenderScript
+ */
+ public static RenderScript create(Context ctx, int sdkVersion) {
+ return create(ctx, sdkVersion, ContextType.NORMAL, CREATE_FLAG_NONE);
+ }
+
+ /**
+ * Gets or creates a RenderScript context of the specified type.
+ *
+ * @hide
+ * @param ctx The context.
+ * @param ct The type of context to be created.
+ * @param sdkVersion The target SDK Version.
+ * @param flags The OR of the CREATE_FLAG_* options desired
+ * @return RenderScript
+ */
+ public static RenderScript create(Context ctx, int sdkVersion, ContextType ct, int flags) {
+ if (sdkVersion < 23) {
+ return internalCreate(ctx, sdkVersion, ct, flags);
}
synchronized (mProcessContextList) {
for (RenderScript prs : mProcessContextList) {
if ((prs.mContextType == ct) &&
(prs.mContextFlags == flags) &&
- (prs.mContextSdkVersion == v)) {
+ (prs.mContextSdkVersion == sdkVersion)) {
return prs;
}
}
- RenderScript prs = internalCreate(ctx, v, ct, flags);
+ RenderScript prs = internalCreate(ctx, sdkVersion, ct, flags);
prs.mIsProcessContext = true;
mProcessContextList.add(prs);
return prs;
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 8fcdd39192e8..31f9e22c8ad9 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -22,6 +22,7 @@ import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.IApplicationThread;
import android.app.IBackupAgent;
+import android.app.PackageInstallObserver;
import android.app.PendingIntent;
import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
@@ -45,7 +46,6 @@ import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
-import android.content.pm.IPackageInstallObserver;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -200,7 +200,6 @@ public class BackupManagerService {
private static final String RUN_BACKUP_ACTION = "android.app.backup.intent.RUN";
private static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT";
- private static final String RUN_CLEAR_ACTION = "android.app.backup.intent.CLEAR";
private static final int MSG_RUN_BACKUP = 1;
private static final int MSG_RUN_ADB_BACKUP = 2;
private static final int MSG_RUN_RESTORE = 3;
@@ -1198,11 +1197,13 @@ public class BackupManagerService {
temp = new RandomAccessFile(tempProcessedFile, "rws");
in = new RandomAccessFile(mEverStored, "r");
+ // Loop until we hit EOF
while (true) {
- PackageInfo info;
String pkg = in.readUTF();
try {
- info = mPackageManager.getPackageInfo(pkg, 0);
+ // is this package still present?
+ mPackageManager.getPackageInfo(pkg, 0);
+ // if we get here then yes it is; remember it
mEverStoredApps.add(pkg);
temp.writeUTF(pkg);
if (MORE_DEBUG) Slog.v(TAG, " + " + pkg);
@@ -4100,7 +4101,6 @@ public class BackupManagerService {
SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target,
AtomicBoolean latch) throws IOException {
- int oldfd = output.getFd();
mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor());
mTarget = target;
mLatch = latch;
@@ -4812,7 +4812,7 @@ public class BackupManagerService {
}
}
- class RestoreInstallObserver extends IPackageInstallObserver.Stub {
+ class RestoreInstallObserver extends PackageInstallObserver {
final AtomicBoolean mDone = new AtomicBoolean();
String mPackageName;
int mResult;
@@ -4838,8 +4838,8 @@ public class BackupManagerService {
}
@Override
- public void packageInstalled(String packageName, int returnCode)
- throws RemoteException {
+ public void onPackageInstalled(String packageName, int returnCode,
+ String msg, Bundle extras) {
synchronized (mDone) {
mResult = returnCode;
mPackageName = packageName;
@@ -5095,7 +5095,9 @@ public class BackupManagerService {
offset = extractLine(buffer, offset, str);
version = Integer.parseInt(str[0]); // app version
offset = extractLine(buffer, offset, str);
- int platformVersion = Integer.parseInt(str[0]);
+ // This is the platform version, which we don't use, but we parse it
+ // as a safety against corruption in the manifest.
+ Integer.parseInt(str[0]);
offset = extractLine(buffer, offset, str);
info.installerPackageName = (str[0].length() > 0) ? str[0] : null;
offset = extractLine(buffer, offset, str);
@@ -6156,7 +6158,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
}
}
- class RestoreInstallObserver extends IPackageInstallObserver.Stub {
+ class RestoreInstallObserver extends PackageInstallObserver {
final AtomicBoolean mDone = new AtomicBoolean();
String mPackageName;
int mResult;
@@ -6182,8 +6184,8 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
}
@Override
- public void packageInstalled(String packageName, int returnCode)
- throws RemoteException {
+ public void onPackageInstalled(String packageName, int returnCode,
+ String msg, Bundle extras) {
synchronized (mDone) {
mResult = returnCode;
mPackageName = packageName;
@@ -6432,7 +6434,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
offset = extractLine(buffer, offset, str);
version = Integer.parseInt(str[0]); // app version
offset = extractLine(buffer, offset, str);
- int platformVersion = Integer.parseInt(str[0]);
+ // This is the platform version, which we don't use, but we parse it
+ // as a safety against corruption in the manifest.
+ Integer.parseInt(str[0]);
offset = extractLine(buffer, offset, str);
info.installerPackageName = (str[0].length() > 0) ? str[0] : null;
offset = extractLine(buffer, offset, str);
@@ -8357,7 +8361,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
}
// make sure the screen is lit for the user interaction
- mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
+ mPowerManager.userActivity(SystemClock.uptimeMillis(),
+ PowerManager.USER_ACTIVITY_EVENT_OTHER,
+ 0);
// start the confirmation countdown
startConfirmationTimeout(token, params);
@@ -8440,7 +8446,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
}
// make sure the screen is lit for the user interaction
- mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
+ mPowerManager.userActivity(SystemClock.uptimeMillis(),
+ PowerManager.USER_ACTIVITY_EVENT_OTHER,
+ 0);
// start the confirmation countdown
startConfirmationTimeout(token, params);
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 983d83aee50e..694e851ef364 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -221,3 +221,4 @@ option java_package com.android.server
# AudioService.java
# ---------------------------
40000 volume_changed (stream|1), (prev_level|1), (level|1), (max_level|1), (caller|3)
+40001 stream_devices_changed (stream|1), (prev_devices|1), (devices|1)
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index fd35b5ef990e..4677f65eb46b 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -86,7 +86,10 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
+import android.text.TextUtils.SimpleStringSplitter;
import android.text.style.SuggestionSpan;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.EventLog;
import android.util.LruCache;
@@ -125,6 +128,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@@ -134,8 +138,12 @@ import java.util.Locale;
public class InputMethodManagerService extends IInputMethodManager.Stub
implements ServiceConnection, Handler.Callback {
static final boolean DEBUG = false;
+ static final boolean DEBUG_RESTORE = DEBUG || false;
static final String TAG = "InputMethodManagerService";
+ private static final char INPUT_METHOD_SEPARATOR = ':';
+ private static final char INPUT_METHOD_SUBTYPE_SEPARATOR = ';';
+
static final int MSG_SHOW_IM_PICKER = 1;
static final int MSG_SHOW_IM_SUBTYPE_PICKER = 2;
static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 3;
@@ -466,12 +474,101 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|| Intent.ACTION_USER_REMOVED.equals(action)) {
updateCurrentProfileIds();
return;
+ } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) {
+ final String name = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
+ if (Settings.Secure.ENABLED_INPUT_METHODS.equals(name)) {
+ final String prevValue = intent.getStringExtra(
+ Intent.EXTRA_SETTING_PREVIOUS_VALUE);
+ final String newValue = intent.getStringExtra(
+ Intent.EXTRA_SETTING_NEW_VALUE);
+ restoreEnabledInputMethods(mContext, prevValue, newValue);
+ }
} else {
Slog.w(TAG, "Unexpected intent " + intent);
}
}
}
+ // Apply the results of a restore operation to the set of enabled IMEs. Note that this
+ // does not attempt to validate on the fly with any installed device policy, so must only
+ // be run in the context of initial device setup.
+ //
+ // TODO: Move this method to InputMethodUtils with adding unit tests.
+ static void restoreEnabledInputMethods(Context context, String prevValue, String newValue) {
+ if (DEBUG_RESTORE) {
+ Slog.i(TAG, "Restoring enabled input methods:");
+ Slog.i(TAG, "prev=" + prevValue);
+ Slog.i(TAG, " new=" + newValue);
+ }
+ // 'new' is the just-restored state, 'prev' is what was in settings prior to the restore
+ ArrayMap<String, ArraySet<String>> prevMap = parseInputMethodsAndSubtypesString(prevValue);
+ ArrayMap<String, ArraySet<String>> newMap = parseInputMethodsAndSubtypesString(newValue);
+
+ // Merge the restored ime+subtype enabled states into the live state
+ for (ArrayMap.Entry<String, ArraySet<String>> entry : newMap.entrySet()) {
+ final String imeId = entry.getKey();
+ ArraySet<String> prevSubtypes = prevMap.get(imeId);
+ if (prevSubtypes == null) {
+ prevSubtypes = new ArraySet<String>(2);
+ prevMap.put(imeId, prevSubtypes);
+ }
+ prevSubtypes.addAll(entry.getValue());
+ }
+
+ final String mergedImesAndSubtypesString = buildInputMethodsAndSubtypesString(prevMap);
+ if (DEBUG_RESTORE) {
+ Slog.i(TAG, "Merged IME string:");
+ Slog.i(TAG, " " + mergedImesAndSubtypesString);
+ }
+ Settings.Secure.putString(context.getContentResolver(),
+ Settings.Secure.ENABLED_INPUT_METHODS, mergedImesAndSubtypesString);
+ }
+
+ // TODO: Move this method to InputMethodUtils with adding unit tests.
+ static String buildInputMethodsAndSubtypesString(ArrayMap<String, ArraySet<String>> map) {
+ // we want to use the canonical InputMethodSettings implementation,
+ // so we convert data structures first.
+ List<Pair<String, ArrayList<String>>> imeMap =
+ new ArrayList<Pair<String, ArrayList<String>>>(4);
+ for (ArrayMap.Entry<String, ArraySet<String>> entry : map.entrySet()) {
+ final String imeName = entry.getKey();
+ final ArraySet<String> subtypeSet = entry.getValue();
+ final ArrayList<String> subtypes = new ArrayList<String>(2);
+ if (subtypeSet != null) {
+ subtypes.addAll(subtypeSet);
+ }
+ imeMap.add(new Pair<String, ArrayList<String>>(imeName, subtypes));
+ }
+ return InputMethodSettings.buildInputMethodsSettingString(imeMap);
+ }
+
+ // TODO: Move this method to InputMethodUtils with adding unit tests.
+ static ArrayMap<String, ArraySet<String>> parseInputMethodsAndSubtypesString(
+ final String inputMethodsAndSubtypesString) {
+ final ArrayMap<String, ArraySet<String>> imeMap =
+ new ArrayMap<String, ArraySet<String>>();
+ if (TextUtils.isEmpty(inputMethodsAndSubtypesString)) {
+ return imeMap;
+ }
+
+ final SimpleStringSplitter typeSplitter =
+ new SimpleStringSplitter(INPUT_METHOD_SEPARATOR);
+ final SimpleStringSplitter subtypeSplitter =
+ new SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATOR);
+ List<Pair<String, ArrayList<String>>> allImeSettings =
+ InputMethodSettings.buildInputMethodsAndSubtypeList(inputMethodsAndSubtypesString,
+ typeSplitter,
+ subtypeSplitter);
+ for (Pair<String, ArrayList<String>> ime : allImeSettings) {
+ ArraySet<String> subtypes = new ArraySet<String>();
+ if (ime.second != null) {
+ subtypes.addAll(ime.second);
+ }
+ imeMap.put(ime.first, subtypes);
+ }
+ return imeMap;
+ }
+
class MyPackageMonitor extends PackageMonitor {
private boolean isChangingPackagesOfCurrentUser() {
final int userId = getChangingUserId();
@@ -675,6 +772,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
broadcastFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
broadcastFilter.addAction(Intent.ACTION_USER_ADDED);
broadcastFilter.addAction(Intent.ACTION_USER_REMOVED);
+ broadcastFilter.addAction(Intent.ACTION_SETTING_RESTORED);
mContext.registerReceiver(new ImmsBroadcastReceiver(), broadcastFilter);
mNotificationShown = false;
diff --git a/services/core/java/com/android/server/MidiService.java b/services/core/java/com/android/server/MidiService.java
index 3418930c3744..e75366402797 100644
--- a/services/core/java/com/android/server/MidiService.java
+++ b/services/core/java/com/android/server/MidiService.java
@@ -47,6 +47,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
public class MidiService extends IMidiManager.Stub {
@@ -269,7 +270,9 @@ public class MidiService extends IMidiManager.Stub {
public void binderDied() {
synchronized (mDevicesByInfo) {
- removeDeviceLocked(this);
+ if (mDevicesByInfo.remove(mDeviceInfo) != null) {
+ removeDeviceLocked(this);
+ }
}
}
@@ -368,6 +371,7 @@ public class MidiService extends IMidiManager.Stub {
synchronized (mDevicesByInfo) {
Device device = mDevicesByServer.get(server.asBinder());
if (device != null) {
+ mDevicesByInfo.remove(device.getDeviceInfo());
removeDeviceLocked(device);
}
}
@@ -454,16 +458,14 @@ public class MidiService extends IMidiManager.Stub {
// synchronize on mDevicesByInfo
private void removeDeviceLocked(Device device) {
- if (mDevicesByInfo.remove(device.getDeviceInfo()) != null) {
- IMidiDeviceServer server = device.getDeviceServer();
- if (server != null) {
- mDevicesByServer.remove(server);
- }
+ IMidiDeviceServer server = device.getDeviceServer();
+ if (server != null) {
+ mDevicesByServer.remove(server);
+ }
- synchronized (mClients) {
- for (Client c : mClients.values()) {
- c.deviceRemoved(device);
- }
+ synchronized (mClients) {
+ for (Client c : mClients.values()) {
+ c.deviceRemoved(device);
}
}
}
@@ -616,8 +618,11 @@ public class MidiService extends IMidiManager.Stub {
private void removePackageDeviceServers(String packageName) {
synchronized (mDevicesByInfo) {
- for (Device device : mDevicesByInfo.values()) {
+ Iterator<Device> iterator = mDevicesByInfo.values().iterator();
+ while (iterator.hasNext()) {
+ Device device = iterator.next();
if (packageName.equals(device.getPackageName())) {
+ iterator.remove();
removeDeviceLocked(device);
}
}
@@ -634,15 +639,19 @@ public class MidiService extends IMidiManager.Stub {
pw.println("Devices:");
pw.increaseIndent();
- for (Device device : mDevicesByInfo.values()) {
- pw.println(device.toString());
+ synchronized (mDevicesByInfo) {
+ for (Device device : mDevicesByInfo.values()) {
+ pw.println(device.toString());
+ }
}
pw.decreaseIndent();
pw.println("Clients:");
pw.increaseIndent();
- for (Client client : mClients.values()) {
- pw.println(client.toString());
+ synchronized (mClients) {
+ for (Client client : mClients.values()) {
+ pw.println(client.toString());
+ }
}
pw.decreaseIndent();
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 1e3b46b9244b..b8d9ec59b323 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -123,6 +123,27 @@ class MountService extends IMountService.Stub
// TODO: listen for user creation/deletion
+ public static class Lifecycle extends SystemService {
+ private MountService mMountService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mMountService = new MountService(getContext());
+ publishBinderService("mount", mMountService);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ mMountService.systemReady();
+ }
+ }
+ }
+
private static final boolean LOCAL_LOGD = false;
private static final boolean DEBUG_UNMOUNT = false;
private static final boolean DEBUG_EVENTS = false;
@@ -574,7 +595,8 @@ class MountService extends IMountService.Stub
private final Handler mHandler;
- void waitForAsecScan() {
+ @Override
+ public void waitForAsecScan() {
waitForLatch(mAsecsScanned);
}
@@ -1538,7 +1560,7 @@ class MountService extends IMountService.Stub
}
}
- public void systemReady() {
+ private void systemReady() {
mSystemReady = true;
mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
}
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index 97d16c00d6c4..b36f5158513c 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -70,6 +70,7 @@ public class PersistentDataBlockService extends SystemService {
// Limit to 100k as blocks larger than this might cause strain on Binder.
private static final int MAX_DATA_BLOCK_SIZE = 1024 * 100;
public static final int DIGEST_SIZE_BYTES = 32;
+ private static final String OEM_UNLOCK_PROP = "sys.oem_unlock_allowed";
private final Context mContext;
private final String mDataBlockFile;
@@ -108,11 +109,14 @@ public class PersistentDataBlockService extends SystemService {
}
private void formatIfOemUnlockEnabled() {
- if (doGetOemUnlockEnabled()) {
+ boolean enabled = doGetOemUnlockEnabled();
+ if (enabled) {
synchronized (mLock) {
formatPartitionLocked(true);
}
}
+
+ SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0");
}
private void enforceOemUnlockPermission() {
@@ -132,7 +136,6 @@ public class PersistentDataBlockService extends SystemService {
throw new SecurityException("Only the Owner is allowed to change OEM unlock state");
}
}
-
private int getTotalDataSizeLocked(DataInputStream inputStream) throws IOException {
// skip over checksum
inputStream.skipBytes(DIGEST_SIZE_BYTES);
@@ -290,6 +293,7 @@ public class PersistentDataBlockService extends SystemService {
Slog.e(TAG, "unable to access persistent partition", e);
return;
} finally {
+ SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0");
IoUtils.closeQuietly(outputStream);
}
}
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index 6ad128c982c4..4c9d7d3ba3b2 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -71,9 +71,11 @@ public class SystemConfig {
public static final class PermissionEntry {
public final String name;
public int[] gids;
+ public boolean perUser;
- PermissionEntry(String _name) {
- name = _name;
+ PermissionEntry(String name, boolean perUser) {
+ this.name = name;
+ this.perUser = perUser;
}
}
@@ -363,14 +365,14 @@ public class SystemConfig {
void readPermission(XmlPullParser parser, String name)
throws IOException, XmlPullParserException {
+ if (mPermissions.containsKey(name)) {
+ throw new IllegalStateException("Duplicate permission definition for " + name);
+ }
- name = name.intern();
+ final boolean perUser = XmlUtils.readBooleanAttribute(parser, "perUser", false);
+ final PermissionEntry perm = new PermissionEntry(name, perUser);
+ mPermissions.put(name, perm);
- PermissionEntry perm = mPermissions.get(name);
- if (perm == null) {
- perm = new PermissionEntry(name);
- mPermissions.put(name, perm);
- }
int outerDepth = parser.getDepth();
int type;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 87dc4201f0db..64f307008a9f 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -157,7 +157,6 @@ final class UiModeManagerService extends SystemService {
@Override
public void onStart() {
final Context context = getContext();
- mTwilightManager = getLocalService(TwilightManager.class);
final PowerManager powerManager =
(PowerManager) context.getSystemService(Context.POWER_SERVICE);
@@ -188,7 +187,11 @@ final class UiModeManagerService extends SystemService {
mNightMode = Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.UI_NIGHT_MODE, defaultNightMode);
- mTwilightManager.registerListener(mTwilightListener, mHandler);
+ // Update the initial, static configurations.
+ synchronized (this) {
+ updateConfigurationLocked();
+ sendConfigurationLocked();
+ }
publishBinderService(Context.UI_MODE_SERVICE, mService);
}
@@ -297,8 +300,11 @@ final class UiModeManagerService extends SystemService {
pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration);
pw.print(" mSystemReady="); pw.println(mSystemReady);
- pw.print(" mTwilightService.getCurrentState()=");
- pw.println(mTwilightManager.getCurrentState());
+ if (mTwilightManager != null) {
+ // We may not have a TwilightManager.
+ pw.print(" mTwilightService.getCurrentState()=");
+ pw.println(mTwilightManager.getCurrentState());
+ }
}
}
@@ -306,6 +312,10 @@ final class UiModeManagerService extends SystemService {
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
synchronized (mLock) {
+ mTwilightManager = getLocalService(TwilightManager.class);
+ if (mTwilightManager != null) {
+ mTwilightManager.registerListener(mTwilightListener, mHandler);
+ }
mSystemReady = true;
mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
updateComputedNightModeLocked();
@@ -623,9 +633,11 @@ final class UiModeManagerService extends SystemService {
}
private void updateComputedNightModeLocked() {
- TwilightState state = mTwilightManager.getCurrentState();
- if (state != null) {
- mComputedNightMode = state.isNight();
+ if (mTwilightManager != null) {
+ TwilightState state = mTwilightManager.getCurrentState();
+ if (state != null) {
+ mComputedNightMode = state.isNight();
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 11c3ea661e01..b5e1de9a6b3b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -76,6 +76,7 @@ import com.android.internal.os.IResultReceiver;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.TransferPipe;
import com.android.internal.os.Zygote;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.MemInfoReader;
@@ -1231,7 +1232,7 @@ public final class ActivityManagerService extends ActivityManagerNative
TAG, "Death received in " + this
+ " for thread " + mAppThread.asBinder());
synchronized(ActivityManagerService.this) {
- appDiedLocked(mApp, mPid, mAppThread);
+ appDiedLocked(mApp, mPid, mAppThread, true);
}
}
}
@@ -2187,7 +2188,7 @@ public final class ActivityManagerService extends ActivityManagerNative
systemDir.mkdirs();
mBatteryStatsService = new BatteryStatsService(systemDir, mHandler);
mBatteryStatsService.getActiveStatistics().readLocked();
- mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
+ mBatteryStatsService.scheduleWriteToDisk();
mOnBattery = DEBUG_POWER ? true
: mBatteryStatsService.getActiveStatistics().getIsOnBattery();
mBatteryStatsService.getActiveStatistics().setCallback(this);
@@ -2431,7 +2432,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
mLastWriteTime = now;
- mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
+ mBatteryStatsService.scheduleWriteToDisk();
}
}
}
@@ -3045,12 +3046,12 @@ public final class ActivityManagerService extends ActivityManagerNative
int[] permGids = null;
try {
checkTime(startTime, "startProcess: getting gids from package manager");
- final PackageManager pm = mContext.getPackageManager();
- permGids = pm.getPackageGids(app.info.packageName);
+ permGids = AppGlobals.getPackageManager().getPackageGids(app.info.packageName,
+ app.userId);
if (Environment.isExternalStorageEmulated()) {
checkTime(startTime, "startProcess: checking external storage perm");
- if (pm.checkPermission(
+ if (mContext.getPackageManager().checkPermission(
android.Manifest.permission.ACCESS_ALL_EXTERNAL_STORAGE,
app.info.packageName) == PERMISSION_GRANTED) {
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL;
@@ -3058,7 +3059,7 @@ public final class ActivityManagerService extends ActivityManagerNative
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
}
}
- } catch (PackageManager.NameNotFoundException e) {
+ } catch (RemoteException e) {
Slog.w(TAG, "Unable to retrieve gids", e);
}
@@ -3066,7 +3067,7 @@ public final class ActivityManagerService extends ActivityManagerNative
* Add shared application and profile GIDs so applications can share some
* resources like shared libraries and access user-wide resources
*/
- if (permGids == null) {
+ if (ArrayUtils.isEmpty(permGids)) {
gids = new int[2];
} else {
gids = new int[permGids.length + 2];
@@ -4303,10 +4304,11 @@ public final class ActivityManagerService extends ActivityManagerNative
}
final void appDiedLocked(ProcessRecord app) {
- appDiedLocked(app, app.pid, app.thread);
+ appDiedLocked(app, app.pid, app.thread, false);
}
- final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread) {
+ final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread,
+ boolean fromBinderDied) {
// First check if this ProcessRecord is actually active for the pid.
synchronized (mPidsSelfLocked) {
ProcessRecord curProc = mPidsSelfLocked.get(pid);
@@ -4322,7 +4324,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (!app.killed) {
- Process.killProcessQuiet(pid);
+ if (!fromBinderDied) {
+ Process.killProcessQuiet(pid);
+ }
Process.killProcessGroup(app.info.uid, pid);
app.killed = true;
}
@@ -6322,31 +6326,38 @@ public final class ActivityManagerService extends ActivityManagerNative
}
try {
PendingIntentRecord res = (PendingIntentRecord)pendingResult;
- Intent intent = res.key.requestIntent;
- if (intent != null) {
- if (res.lastTag != null && res.lastTagPrefix == prefix && (res.lastTagPrefix == null
- || res.lastTagPrefix.equals(prefix))) {
- return res.lastTag;
- }
- res.lastTagPrefix = prefix;
- StringBuilder sb = new StringBuilder(128);
- if (prefix != null) {
- sb.append(prefix);
- }
- if (intent.getAction() != null) {
- sb.append(intent.getAction());
- } else if (intent.getComponent() != null) {
- intent.getComponent().appendShortString(sb);
- } else {
- sb.append("?");
- }
- return res.lastTag = sb.toString();
+ synchronized (this) {
+ return getTagForIntentSenderLocked(res, prefix);
}
} catch (ClassCastException e) {
}
return null;
}
+ String getTagForIntentSenderLocked(PendingIntentRecord res, String prefix) {
+ final Intent intent = res.key.requestIntent;
+ if (intent != null) {
+ if (res.lastTag != null && res.lastTagPrefix == prefix && (res.lastTagPrefix == null
+ || res.lastTagPrefix.equals(prefix))) {
+ return res.lastTag;
+ }
+ res.lastTagPrefix = prefix;
+ final StringBuilder sb = new StringBuilder(128);
+ if (prefix != null) {
+ sb.append(prefix);
+ }
+ if (intent.getAction() != null) {
+ sb.append(intent.getAction());
+ } else if (intent.getComponent() != null) {
+ intent.getComponent().appendShortString(sb);
+ } else {
+ sb.append("?");
+ }
+ return res.lastTag = sb.toString();
+ }
+ return null;
+ }
+
@Override
public void setProcessLimit(int max) {
enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
@@ -6530,7 +6541,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (permission == null) {
return PackageManager.PERMISSION_DENIED;
}
- return checkComponentPermission(permission, pid, UserHandle.getAppId(uid), -1, true);
+ return checkComponentPermission(permission, pid, uid, -1, true);
}
@Override
@@ -6550,7 +6561,7 @@ public final class ActivityManagerService extends ActivityManagerNative
pid = tlsIdentity.pid;
}
- return checkComponentPermission(permission, pid, UserHandle.getAppId(uid), -1, true);
+ return checkComponentPermission(permission, pid, uid, -1, true);
}
/**
@@ -10475,17 +10486,21 @@ public final class ActivityManagerService extends ActivityManagerNative
if (!(sender instanceof PendingIntentRecord)) {
return;
}
- BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+ final PendingIntentRecord rec = (PendingIntentRecord)sender;
+ final String tag;
+ synchronized (this) {
+ tag = getTagForIntentSenderLocked(rec, "*walarm*:");
+ }
+ final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
if (mBatteryStatsService.isOnBattery()) {
mBatteryStatsService.enforceCallingPermission();
- PendingIntentRecord rec = (PendingIntentRecord)sender;
int MY_UID = Binder.getCallingUid();
int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
BatteryStatsImpl.Uid.Pkg pkg =
stats.getPackageStatsLocked(sourceUid >= 0 ? sourceUid : uid,
sourcePkg != null ? sourcePkg : rec.key.packageName);
- pkg.incWakeupsLocked();
+ pkg.noteWakeupAlarmLocked(tag);
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index b102a0731736..066ff372522a 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1112,7 +1112,7 @@ final class ActivityStack {
}
}
- private void setVisibile(ActivityRecord r, boolean visible) {
+ private void setVisible(ActivityRecord r, boolean visible) {
r.visible = visible;
mWindowManager.setAppVisibility(r.appToken, visible);
final ArrayList<ActivityContainer> containers = r.mChildContainers;
@@ -1297,7 +1297,7 @@ final class ActivityStack {
if (!r.visible || r.mLaunchTaskBehind) {
if (DEBUG_VISBILITY) Slog.v(
TAG, "Starting and making visible: " + r);
- setVisibile(r, true);
+ setVisible(r, true);
}
if (r != starting) {
mStackSupervisor.startSpecificActivityLocked(r, false, false);
@@ -1329,7 +1329,7 @@ final class ActivityStack {
r.updateOptionsLocked(r.returningOptions);
mUndrawnActivitiesBelowTopTranslucent.add(r);
}
- setVisibile(r, true);
+ setVisible(r, true);
r.sleeping = false;
r.app.pendingUiClean = true;
r.app.thread.scheduleWindowVisibility(r.appToken, true);
@@ -1364,7 +1364,7 @@ final class ActivityStack {
if (r.visible) {
if (DEBUG_VISBILITY) Slog.v(TAG, "Making invisible: " + r);
try {
- setVisibile(r, false);
+ setVisible(r, false);
switch (r.state) {
case STOPPING:
case STOPPED:
@@ -3896,8 +3896,7 @@ final class ActivityStack {
return true;
}
- private boolean relaunchActivityLocked(ActivityRecord r,
- int changes, boolean andResume) {
+ private boolean relaunchActivityLocked(ActivityRecord r, int changes, boolean andResume) {
List<ResultInfo> results = null;
List<ReferrerIntent> newIntents = null;
if (andResume) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index e9e6496537c4..f874244df07b 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -129,7 +129,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
static final boolean DEBUG_RELEASE = DEBUG || false;
static final boolean DEBUG_SAVED_STATE = DEBUG || false;
static final boolean DEBUG_SCREENSHOTS = DEBUG || false;
- static final boolean DEBUG_STATES = DEBUG || false;
+ static final boolean DEBUG_STATES = DEBUG || true;
static final boolean DEBUG_VISIBLE_BEHIND = DEBUG || false;
public static final int HOME_STACK_ID = 0;
@@ -273,8 +273,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
* until the task exits or #stopLockTaskMode() is called. */
TaskRecord mLockTaskModeTask;
/** Store the current lock task mode. Possible values:
- * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActicityManager#LOCK_TASK_MODE_LOCKED},
- * {@link ActicityManager#LOCK_TASK_MODE_PINNED}
+ * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
+ * {@link ActivityManager#LOCK_TASK_MODE_PINNED}
*/
private int mLockTaskModeState;
/**
@@ -1132,12 +1132,13 @@ public final class ActivityStackSupervisor implements DisplayListener {
ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException {
- r.startFreezingScreenLocked(app, 0);
- if (false) Slog.d(TAG, "realStartActivity: setting app visibility true");
- mWindowManager.setAppVisibility(r.appToken, true);
+ if (andResume) {
+ r.startFreezingScreenLocked(app, 0);
+ mWindowManager.setAppVisibility(r.appToken, true);
- // schedule launch ticks to collect information about slow apps.
- r.startLaunchTickingLocked();
+ // schedule launch ticks to collect information about slow apps.
+ r.startLaunchTickingLocked();
+ }
// Have the window manager re-evaluate the orientation of
// the screen based on the new activity order. Note that
@@ -1195,34 +1196,37 @@ public final class ActivityStackSupervisor implements DisplayListener {
r.forceNewConfig = false;
mService.showAskCompatModeDialogLocked(r);
r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
- String profileFile = null;
- ParcelFileDescriptor profileFd = null;
+ ProfilerInfo profilerInfo = null;
if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName)) {
if (mService.mProfileProc == null || mService.mProfileProc == app) {
mService.mProfileProc = app;
- profileFile = mService.mProfileFile;
- profileFd = mService.mProfileFd;
- }
- }
- app.hasShownUi = true;
- app.pendingUiClean = true;
- if (profileFd != null) {
- try {
- profileFd = profileFd.dup();
- } catch (IOException e) {
- if (profileFd != null) {
- try {
- profileFd.close();
- } catch (IOException o) {
+ 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;
+ }
+ }
}
- profileFd = null;
+
+ profilerInfo = new ProfilerInfo(profileFile, profileFd,
+ mService.mSamplingInterval, mService.mAutoStopProfiler);
}
}
}
- ProfilerInfo profilerInfo = profileFile != null
- ? new ProfilerInfo(profileFile, profileFd, mService.mSamplingInterval,
- mService.mAutoStopProfiler) : null;
+ if (andResume) {
+ app.hasShownUi = true;
+ app.pendingUiClean = true;
+ }
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 197b51ddbc1f..c8db3befb977 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -16,20 +16,26 @@
package com.android.server.am;
+import android.bluetooth.BluetoothActivityEnergyInfo;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.net.wifi.IWifiManager;
+import android.net.wifi.WifiActivityEnergyInfo;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.PowerManagerInternal;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -38,10 +44,12 @@ import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.PowerProfile;
+import com.android.server.FgThread;
import com.android.server.LocalServices;
import java.io.File;
@@ -59,15 +67,52 @@ public final class BatteryStatsService extends IBatteryStats.Stub
static final String TAG = "BatteryStatsService";
static IBatteryStats sService;
-
final BatteryStatsImpl mStats;
+ final BatteryStatsHandler mHandler;
Context mContext;
private boolean mBluetoothPendingStats;
private BluetoothHeadset mBluetoothHeadset;
PowerManagerInternal mPowerManagerInternal;
+ class BatteryStatsHandler extends Handler implements BatteryStatsImpl.ExternalStatsSync {
+ public static final int MSG_SYNC_EXTERNAL_STATS = 1;
+ public static final int MSG_WRITE_TO_DISK = 2;
+
+ public BatteryStatsHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SYNC_EXTERNAL_STATS:
+ updateExternalStats();
+ break;
+
+ case MSG_WRITE_TO_DISK:
+ updateExternalStats();
+ synchronized (mStats) {
+ mStats.writeAsyncLocked();
+ }
+ break;
+ }
+ }
+
+ @Override
+ public void scheduleSync() {
+ if (!hasMessages(MSG_SYNC_EXTERNAL_STATS)) {
+ sendEmptyMessage(MSG_SYNC_EXTERNAL_STATS);
+ }
+ }
+ }
+
BatteryStatsService(File systemDir, Handler handler) {
- mStats = new BatteryStatsImpl(systemDir, handler);
+ // Our handler here will be accessing the disk, use a different thread than
+ // what the ActivityManagerService gave us (no I/O on that one!).
+ mHandler = new BatteryStatsHandler(FgThread.getHandler().getLooper());
+
+ // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through.
+ mStats = new BatteryStatsImpl(systemDir, handler, mHandler);
}
public void publish(Context context) {
@@ -92,6 +137,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub
public void shutdown() {
Slog.w("BatteryStats", "Writing battery stats before shutdown...");
+
+ updateExternalStats();
synchronized (mStats) {
mStats.shutdownLocked();
}
@@ -122,6 +169,14 @@ public final class BatteryStatsService extends IBatteryStats.Stub
return mStats;
}
+ /**
+ * Schedules a write to disk to occur. This will cause the BatteryStatsImpl
+ * object to update with the latest info, then write to disk.
+ */
+ public void scheduleWriteToDisk() {
+ mHandler.sendEmptyMessage(BatteryStatsHandler.MSG_WRITE_TO_DISK);
+ }
+
// These are for direct use by the activity manager...
void addIsolatedUid(int isolatedUid, int appUid) {
@@ -174,7 +229,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
//Slog.i("foo", "SENDING BATTERY INFO:");
//mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
Parcel out = Parcel.obtain();
- mStats.writeToParcel(out, 0);
+ updateExternalStats();
+ synchronized (mStats) {
+ mStats.writeToParcel(out, 0);
+ }
byte[] data = out.marshall();
out.recycle();
return data;
@@ -186,7 +244,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
//Slog.i("foo", "SENDING BATTERY INFO:");
//mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
Parcel out = Parcel.obtain();
- mStats.writeToParcel(out, 0);
+ updateExternalStats();
+ synchronized (mStats) {
+ mStats.writeToParcel(out, 0);
+ }
byte[] data = out.marshall();
out.recycle();
try {
@@ -663,6 +724,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
}
+ @Override
public void noteWifiMulticastDisabledFromSource(WorkSource ws) {
enforceCallingPermission();
synchronized (mStats) {
@@ -671,10 +733,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
@Override
- public void noteNetworkInterfaceType(String iface, int type) {
+ public void noteNetworkInterfaceType(String iface, int networkType) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.noteNetworkInterfaceTypeLocked(iface, type);
+ mStats.noteNetworkInterfaceTypeLocked(iface, networkType);
}
}
@@ -715,7 +777,22 @@ public final class BatteryStatsService extends IBatteryStats.Stub
public void setBatteryState(int status, int health, int plugType, int level,
int temp, int volt) {
enforceCallingPermission();
- mStats.setBatteryState(status, health, plugType, level, temp, volt);
+ synchronized (mStats) {
+ final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE;
+ if (mStats.isOnBattery() == onBattery) {
+ // The battery state has not changed, so we don't need to sync external
+ // stats immediately.
+ mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt);
+ return;
+ }
+ }
+
+ // Sync external stats first as the battery has changed states. If we don't sync
+ // immediately here, we may not collect the relevant data later.
+ updateExternalStats();
+ synchronized (mStats) {
+ mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt);
+ }
}
public long getAwakeTimeBattery() {
@@ -772,12 +849,11 @@ public final class BatteryStatsService extends IBatteryStats.Stub
private void dumpHelp(PrintWriter pw) {
pw.println("Battery stats (batterystats) dump options:");
- pw.println(" [--checkin] [--history] [--history-start] [--unplugged] [--charged] [-c]");
+ pw.println(" [--checkin] [--history] [--history-start] [--charged] [-c]");
pw.println(" [--daily] [--reset] [--write] [--new-daily] [--read-daily] [-h] [<package.name>]");
pw.println(" --checkin: format output for a checkin report.");
pw.println(" --history: show only history data.");
pw.println(" --history-start <num>: show only history data starting at given time offset.");
- pw.println(" --unplugged: only output data since last unplugged.");
pw.println(" --charged: only output data since last charged.");
pw.println(" --daily: only output full daily data.");
pw.println(" --reset: reset the stats, clearing all current data.");
@@ -818,6 +894,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
return i;
}
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -856,8 +933,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub
} else if ("-c".equals(arg)) {
useCheckinFormat = true;
flags |= BatteryStats.DUMP_INCLUDE_HISTORY;
- } else if ("--unplugged".equals(arg)) {
- flags |= BatteryStats.DUMP_UNPLUGGED_ONLY;
} else if ("--charged".equals(arg)) {
flags |= BatteryStats.DUMP_CHARGED_ONLY;
} else if ("--daily".equals(arg)) {
@@ -868,7 +943,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub
pw.println("Battery stats reset.");
noOutput = true;
}
+ updateExternalStats();
} else if ("--write".equals(arg)) {
+ updateExternalStats();
synchronized (mStats) {
mStats.writeSyncLocked();
pw.println("Battery stats written.");
@@ -931,13 +1008,16 @@ public final class BatteryStatsService extends IBatteryStats.Stub
if (reqUid >= 0) {
// By default, if the caller is only interested in a specific package, then
// we only dump the aggregated data since charged.
- if ((flags&(BatteryStats.DUMP_HISTORY_ONLY|BatteryStats.DUMP_UNPLUGGED_ONLY
- |BatteryStats.DUMP_CHARGED_ONLY)) == 0) {
+ if ((flags&(BatteryStats.DUMP_HISTORY_ONLY|BatteryStats.DUMP_CHARGED_ONLY)) == 0) {
flags |= BatteryStats.DUMP_CHARGED_ONLY;
// Also if they are doing -c, we don't want history.
flags &= ~BatteryStats.DUMP_INCLUDE_HISTORY;
}
}
+
+ // Fetch data from external sources and update the BatteryStatsImpl object with them.
+ updateExternalStats();
+
if (useCheckinFormat) {
List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0);
if (isRealCheckin) {
@@ -952,7 +1032,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
in.unmarshall(raw, 0, raw.length);
in.setDataPosition(0);
BatteryStatsImpl checkinStats = new BatteryStatsImpl(
- null, mStats.mHandler);
+ null, mStats.mHandler, null);
checkinStats.readSummaryFromParcel(in);
in.recycle();
checkinStats.dumpCheckinLocked(mContext, pw, apps, flags,
@@ -982,4 +1062,85 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
}
}
+
+ // Objects for extracting data from external sources.
+ private final Object mExternalStatsLock = new Object();
+
+ @GuardedBy("mExternalStatsLock")
+ private IWifiManager mWifiManager;
+
+ // WiFi keeps an accumulated total of stats, unlike Bluetooth.
+ // Keep the last WiFi stats so we can compute a delta.
+ @GuardedBy("mExternalStatsLock")
+ private WifiActivityEnergyInfo mLastInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0);
+
+ @GuardedBy("mExternalStatsLock")
+ private WifiActivityEnergyInfo pullWifiEnergyInfoLocked() {
+ if (mWifiManager == null) {
+ mWifiManager = IWifiManager.Stub.asInterface(
+ ServiceManager.getService(Context.WIFI_SERVICE));
+ if (mWifiManager == null) {
+ return null;
+ }
+ }
+
+ try {
+ // We read the data even if we are not on battery. This is so that we keep the
+ // correct delta from when we should start reading (aka when we are on battery).
+ WifiActivityEnergyInfo info = mWifiManager.reportActivityInfo();
+ if (info != null && info.isValid()) {
+ // We will modify the last info object to be the delta, and store the new
+ // WifiActivityEnergyInfo object as our last one.
+ final WifiActivityEnergyInfo result = mLastInfo;
+ result.mTimestamp = info.getTimeStamp();
+ result.mStackState = info.getStackState();
+ result.mControllerTxTimeMs =
+ info.getControllerTxTimeMillis()- mLastInfo.mControllerTxTimeMs;
+ result.mControllerRxTimeMs =
+ info.getControllerRxTimeMillis() - mLastInfo.mControllerRxTimeMs;
+ result.mControllerIdleTimeMs =
+ info.getControllerIdleTimeMillis() - mLastInfo.mControllerIdleTimeMs;
+ result.mControllerEnergyUsed =
+ info.getControllerEnergyUsed() - mLastInfo.mControllerEnergyUsed;
+ mLastInfo = info;
+ return result;
+ }
+ } catch (RemoteException e) {
+ // Nothing to report, WiFi is dead.
+ }
+ return null;
+ }
+
+ @GuardedBy("mExternalStatsLock")
+ private BluetoothActivityEnergyInfo pullBluetoothEnergyInfoLocked() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null) {
+ BluetoothActivityEnergyInfo info = adapter.getControllerActivityEnergyInfo(
+ BluetoothAdapter.ACTIVITY_ENERGY_INFO_REFRESHED);
+ if (info != null && info.isValid()) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Fetches data from external sources (WiFi controller, bluetooth chipset) and updates
+ * batterystats with that information.
+ *
+ * We first grab a lock specific to this method, then once all the data has been collected,
+ * we grab the mStats lock and update the data.
+ */
+ void updateExternalStats() {
+ synchronized (mExternalStatsLock) {
+ final WifiActivityEnergyInfo wifiEnergyInfo = pullWifiEnergyInfoLocked();
+ final BluetoothActivityEnergyInfo bluetoothEnergyInfo = pullBluetoothEnergyInfoLocked();
+ synchronized (mStats) {
+ mStats.updateKernelWakelocksLocked();
+ mStats.updateMobileRadioStateLocked(SystemClock.elapsedRealtime());
+ mStats.updateWifiStateLocked(wifiEnergyInfo);
+ mStats.updateBluetoothStateLocked(bluetoothEnergyInfo);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 8fe123811a04..34c1c5393195 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -765,7 +765,7 @@ public final class BroadcastQueue {
try {
perm = AppGlobals.getPackageManager().
checkPermission(r.requiredPermission,
- info.activityInfo.applicationInfo.packageName);
+ info.activityInfo.applicationInfo.packageName, r.userId);
} catch (RemoteException e) {
perm = PackageManager.PERMISSION_DENIED;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 65b2ae2d81d6..1eddc8e21aa2 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -234,9 +234,6 @@ public class AudioService extends IAudioService.Stub {
private final Object mSoundEffectsLock = new Object();
private static final int NUM_SOUNDPOOL_CHANNELS = 4;
- // Maximum volume adjust steps allowed in a single batch call.
- private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
-
/* Sound effect file names */
private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
@@ -988,6 +985,7 @@ public class AudioService extends IAudioService.Stub {
} else {
streamType = getActiveStreamType(suggestedStreamType);
}
+ ensureValidStreamType(streamType);
final int resolvedStream = mStreamVolumeAlias[streamType];
// Play sounds on STREAM_RING only.
@@ -1421,6 +1419,8 @@ public class AudioService extends IAudioService.Stub {
private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
streamType = AudioSystem.STREAM_NOTIFICATION;
+ } else {
+ streamType = mStreamVolumeAlias[streamType];
}
if (streamType == AudioSystem.STREAM_MUSIC) {
@@ -3131,12 +3131,6 @@ public class AudioService extends IAudioService.Stub {
}
}
- private void ensureValidSteps(int steps) {
- if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
- throw new IllegalArgumentException("Bad volume adjust steps " + steps);
- }
- }
-
private void ensureValidStreamType(int streamType) {
if (streamType < 0 || streamType >= mStreamStates.length) {
throw new IllegalArgumentException("Bad stream type " + streamType);
@@ -3305,7 +3299,7 @@ public class AudioService extends IAudioService.Stub {
}
private int getDeviceForStream(int stream) {
- int device = AudioSystem.getDevicesForStream(stream);
+ int device = getDevicesForStream(stream);
if ((device & (device - 1)) != 0) {
// Multiple device selection is either:
// - speaker + one other device: give priority to speaker in this case.
@@ -3328,6 +3322,27 @@ public class AudioService extends IAudioService.Stub {
return device;
}
+ private int getDevicesForStream(int stream) {
+ return getDevicesForStream(stream, true /*checkOthers*/);
+ }
+
+ private int getDevicesForStream(int stream, boolean checkOthers) {
+ ensureValidStreamType(stream);
+ synchronized (VolumeStreamState.class) {
+ return mStreamStates[stream].observeDevicesForStream_syncVSS(checkOthers);
+ }
+ }
+
+ private void observeDevicesForStreams(int skipStream) {
+ synchronized (VolumeStreamState.class) {
+ for (int stream = 0; stream < mStreamStates.length; stream++) {
+ if (stream != skipStream) {
+ mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/);
+ }
+ }
+ }
+ }
+
/*
* A class just for packaging up a set of connection parameters.
*/
@@ -3406,9 +3421,11 @@ public class AudioService extends IAudioService.Stub {
private boolean mIsMuted;
private String mVolumeIndexSettingName;
+ private int mObservedDevices;
private final SparseIntArray mIndexMap = new SparseIntArray(8);
private final Intent mVolumeChanged;
+ private final Intent mStreamDevicesChanged;
private VolumeStreamState(String settingName, int streamType) {
@@ -3422,6 +3439,29 @@ public class AudioService extends IAudioService.Stub {
readSettings();
mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
+ mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
+ mStreamDevicesChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
+ }
+
+ public int observeDevicesForStream_syncVSS(boolean checkOthers) {
+ final int devices = AudioSystem.getDevicesForStream(mStreamType);
+ if (devices == mObservedDevices) {
+ return devices;
+ }
+ final int prevDevices = mObservedDevices;
+ mObservedDevices = devices;
+ if (checkOthers) {
+ // one stream's devices have changed, check the others
+ observeDevicesForStreams(mStreamType);
+ }
+ // log base stream changes to the event log
+ if (mStreamVolumeAlias[mStreamType] == mStreamType) {
+ EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices);
+ }
+ sendBroadcastToAll(mStreamDevicesChanged
+ .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices)
+ .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices));
+ return devices;
}
public String getSettingNameForDevice(int device) {
@@ -3716,7 +3756,7 @@ public class AudioService extends IAudioService.Stub {
}
pw.println();
pw.print(" Devices: ");
- final int devices = AudioSystem.getDevicesForStream(mStreamType);
+ final int devices = getDevicesForStream(mStreamType);
int device, i = 0, n = 0;
// iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
// (the default device is not returned by getDevicesForStream)
@@ -4250,6 +4290,7 @@ public class AudioService extends IAudioService.Stub {
}
}
mRoutesObservers.finishBroadcast();
+ observeDevicesForStreams(-1);
break;
}
@@ -5348,7 +5389,7 @@ public class AudioService extends IAudioService.Stub {
on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
AudioSystem.FORCE_NONE);
}
- device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
+ device = getDevicesForStream(AudioSystem.STREAM_MUSIC);
}
}
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 7f47678d4f2f..0b430ea45624 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1021,6 +1021,14 @@ public class Vpn {
public synchronized LegacyVpnInfo getLegacyVpnInfo() {
// Check if the caller is authorized.
enforceControlPermission();
+ return getLegacyVpnInfoPrivileged();
+ }
+
+ /**
+ * Return the information of the current ongoing legacy VPN.
+ * Callers are responsible for checking permissions if needed.
+ */
+ public synchronized LegacyVpnInfo getLegacyVpnInfoPrivileged() {
if (mLegacyVpnRunner == null) return null;
final LegacyVpnInfo info = new LegacyVpnInfo();
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index b398f412f5e7..ab56b34864db 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -16,6 +16,7 @@
package com.android.server.fingerprint;
+import android.content.ContentResolver;
import android.content.Context;
import android.os.Handler;
import android.os.IBinder;
@@ -29,12 +30,16 @@ import android.util.Slog;
import com.android.server.SystemService;
import android.service.fingerprint.FingerprintUtils;
+import android.service.fingerprint.Fingerprint;
import android.service.fingerprint.IFingerprintService;
import android.service.fingerprint.IFingerprintServiceReceiver;
+
import static android.Manifest.permission.MANAGE_FINGERPRINT;
import static android.Manifest.permission.USE_FINGERPRINT;
import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
/**
* A service to manage multiple clients that want to access the fingerprint HAL API.
@@ -50,11 +55,14 @@ public class FingerprintService extends SystemService {
private static final int MSG_NOTIFY = 10;
+ private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
+
Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_NOTIFY:
- handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj);
+ FpHalMsg m = (FpHalMsg) msg.obj;
+ handleNotify(m.type, m.arg1, m.arg2, m.arg3);
break;
default:
@@ -66,7 +74,7 @@ public class FingerprintService extends SystemService {
private int mHalDeviceId;
private static final int STATE_IDLE = 0;
- private static final int STATE_LISTENING = 1;
+ private static final int STATE_AUTHENTICATING = 1;
private static final int STATE_ENROLLING = 2;
private static final int STATE_REMOVING = 3;
private static final long MS_PER_SEC = 1000;
@@ -76,7 +84,10 @@ public class FingerprintService extends SystemService {
int state;
int userId;
public TokenWatcher tokenWatcher;
- IBinder getToken() { return tokenWatcher.getToken(); }
+
+ IBinder getToken() {
+ return tokenWatcher.getToken();
+ }
}
private class TokenWatcher implements IBinder.DeathRecipient {
@@ -86,7 +97,10 @@ public class FingerprintService extends SystemService {
this.token = new WeakReference<IBinder>(token);
}
- IBinder getToken() { return token.get(); }
+ IBinder getToken() {
+ return token.get();
+ }
+
public void binderDied() {
mClients.remove(token);
this.token = null;
@@ -112,21 +126,42 @@ public class FingerprintService extends SystemService {
// TODO: Move these into separate process
// JNI methods to communicate from FingerprintManagerService to HAL
- static native int nativeEnroll(int timeout);
+ static native int nativeEnroll(int timeout, int groupId);
+
+ static native int nativeAuthenticate(long sessionId, int groupId);
+
static native int nativeEnrollCancel();
- static native int nativeRemove(int fingerprintId);
+
+ static native int nativeRemove(int fingerId, int groupId);
+
static native int nativeOpenHal();
+
static native int nativeCloseHal();
+
static native void nativeInit(MessageQueue queue, FingerprintService service);
+ static final class FpHalMsg {
+ int type; // Type of the message. One of the constants in fingerprint.h
+ int arg1; // optional arguments
+ int arg2;
+ int arg3;
+
+ FpHalMsg(int type, int arg1, int arg2, int arg3) {
+ this.type = type;
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ this.arg3 = arg3;
+ }
+ }
+
// JNI methods for communicating from HAL to clients
- void notify(int msg, int arg1, int arg2) {
- mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget();
+ void notify(int type, int arg1, int arg2, int arg3) {
+ mHandler.obtainMessage(MSG_NOTIFY, new FpHalMsg(type, arg1, arg2, arg3)).sendToTarget();
}
- void handleNotify(int msg, int arg1, int arg2) {
- Slog.v(TAG, "handleNotify(msg=" + msg + ", arg1=" + arg1 + ", arg2=" + arg2 + ")"
- + ", " + mClients.size() + " clients");
+ void handleNotify(int type, int arg1, int arg2, int arg3) {
+ Slog.v(TAG, "handleNotify(type=" + type + ", arg1=" + arg1 + ", arg2=" + arg2 + ")" + ", "
+ + mClients.size() + " clients");
for (int i = 0; i < mClients.size(); i++) {
if (DEBUG) Slog.v(TAG, "Client[" + i + "] binder token: " + mClients.keyAt(i));
ClientData clientData = mClients.valueAt(i);
@@ -134,21 +169,20 @@ public class FingerprintService extends SystemService {
if (DEBUG) Slog.v(TAG, "clientData is invalid!!");
continue;
}
- switch (msg) {
+ ContentResolver contentResolver = mContext.getContentResolver();
+ switch (type) {
case FingerprintManager.FINGERPRINT_ERROR: {
- final int error = arg1;
try {
- clientData.receiver.onError(error);
+ clientData.receiver.onError(mHalDeviceId, arg1 /* error */);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
}
}
- break;
+ break;
case FingerprintManager.FINGERPRINT_ACQUIRED: {
- final int acquireInfo = arg1;
try {
- clientData.receiver.onAcquired(acquireInfo);
+ clientData.receiver.onAcquired(mHalDeviceId, arg1 /* acquireInfo */);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
@@ -156,9 +190,9 @@ public class FingerprintService extends SystemService {
break;
}
case FingerprintManager.FINGERPRINT_PROCESSED: {
- final int fingerId = arg1;
try {
- clientData.receiver.onProcessed(fingerId);
+ clientData.receiver
+ .onProcessed(mHalDeviceId, arg1 /* fingerId */, arg2 /* groupId */);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
@@ -167,11 +201,13 @@ public class FingerprintService extends SystemService {
}
case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
final int fingerId = arg1;
- final int remaining = arg2;
+ final int groupId = arg2;
+ final int remaining = arg3;
if (clientData.state == STATE_ENROLLING) {
// Only send enroll updates to clients that are actually enrolling
try {
- clientData.receiver.onEnrollResult(fingerId, remaining);
+ clientData.receiver.onEnrollResult(mHalDeviceId, fingerId, groupId,
+ remaining);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
@@ -179,8 +215,8 @@ public class FingerprintService extends SystemService {
// Update the database with new finger id.
// TODO: move to client code (Settings)
if (remaining == 0) {
- FingerprintUtils.addFingerprintIdForUser(fingerId,
- mContext.getContentResolver(), clientData.userId);
+ FingerprintUtils.addFingerprintIdForUser(contentResolver, fingerId,
+ clientData.userId);
clientData.state = STATE_IDLE; // Nothing left to do
}
} else {
@@ -191,30 +227,50 @@ public class FingerprintService extends SystemService {
}
case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
int fingerId = arg1;
- if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
- FingerprintUtils.removeFingerprintIdForUser(fingerId,
- mContext.getContentResolver(), clientData.userId);
+ int groupId = arg2;
+ if (fingerId == 0) {
+ throw new IllegalStateException("Got illegal id from HAL");
+ }
+ FingerprintUtils.removeFingerprintIdForUser(fingerId, contentResolver,
+ clientData.userId);
if (clientData.receiver != null) {
try {
- clientData.receiver.onRemoved(fingerId);
+ clientData.receiver.onRemoved(mHalDeviceId, fingerId, groupId);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
}
}
- clientData.state = STATE_LISTENING;
+ clientData.state = STATE_IDLE;
}
- break;
+ break;
}
}
}
- void startEnroll(IBinder token, long timeout, int userId) {
+ void startEnroll(IBinder token, int groupId, int flags) {
ClientData clientData = mClients.get(token);
if (clientData != null) {
- if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ if (clientData.userId != groupId) {
+ throw new IllegalStateException("Bad user");
+ }
clientData.state = STATE_ENROLLING;
- nativeEnroll((int) (timeout / MS_PER_SEC));
+ final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
+ nativeEnroll(timeout, groupId);
+ } else {
+ Slog.w(TAG, "enroll(): No listener registered");
+ }
+ }
+
+ void startAuthenticate(IBinder token, long sessionId, int groupId, int flags) {
+ ClientData clientData = mClients.get(token);
+ if (clientData != null) {
+ if (clientData.userId != groupId) {
+ throw new IllegalStateException("Bad user");
+ }
+ clientData.state = STATE_AUTHENTICATING;
+ final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
+ nativeAuthenticate(sessionId, groupId);
} else {
Slog.w(TAG, "enroll(): No listener registered");
}
@@ -224,7 +280,7 @@ public class FingerprintService extends SystemService {
ClientData clientData = mClients.get(token);
if (clientData != null) {
if (clientData.userId != userId) throw new IllegalStateException("Bad user");
- clientData.state = STATE_LISTENING;
+ clientData.state = STATE_IDLE;
nativeEnrollCancel();
} else {
Slog.w(TAG, "enrollCancel(): No listener registered");
@@ -238,7 +294,7 @@ public class FingerprintService extends SystemService {
if (clientData.userId != userId) throw new IllegalStateException("Bad user");
clientData.state = STATE_REMOVING;
// The fingerprint id will be removed when we get confirmation from the HAL
- int result = nativeRemove(fingerId);
+ int result = nativeRemove(fingerId, userId);
if (result != 0) {
Slog.w(TAG, "Error removing fingerprint with id = " + fingerId);
}
@@ -251,7 +307,7 @@ public class FingerprintService extends SystemService {
if (DEBUG) Slog.v(TAG, "startListening(" + receiver + ")");
if (mClients.get(token) == null) {
ClientData clientData = new ClientData();
- clientData.state = STATE_LISTENING;
+ clientData.state = STATE_IDLE;
clientData.receiver = receiver;
clientData.userId = userId;
clientData.tokenWatcher = new TokenWatcher(token);
@@ -266,7 +322,7 @@ public class FingerprintService extends SystemService {
}
}
- void removeListener(IBinder token, int userId) {
+ void removeListener(IBinder token, IFingerprintServiceReceiver receiver) {
if (DEBUG) Slog.v(TAG, "stopListening(" + token + ")");
ClientData clientData = mClients.get(token);
if (clientData != null) {
@@ -278,61 +334,91 @@ public class FingerprintService extends SystemService {
mClients.remove(token);
}
+ public List<Fingerprint> getEnrolledFingerprints(int groupId) {
+ ContentResolver resolver = mContext.getContentResolver();
+ int[] ids = FingerprintUtils.getFingerprintIdsForUser(resolver, groupId);
+ List<Fingerprint> result = new ArrayList<Fingerprint>();
+ for (int i = 0; i < ids.length; i++) {
+ // TODO: persist names in Settings
+ CharSequence name = "Finger" + ids[i];
+ final int group = 0; // TODO
+ final int fingerId = ids[i];
+ final long deviceId = 0; // TODO
+ Fingerprint item = new Fingerprint(name, 0, ids[i], 0);
+ result.add(item);
+ }
+ return result;
+ }
+
void checkPermission(String permission) {
- getContext().enforceCallingOrSelfPermission(permission, "Must have "
- + permission + " permission.");
+ getContext().enforceCallingOrSelfPermission(permission,
+ "Must have " + permission + " permission.");
}
private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
- @Override // Binder call
- public void enroll(IBinder token, long timeout, int userId) {
+ @Override
+ // Binder call
+ public void enroll(IBinder token, int groupId, int flags) {
checkPermission(MANAGE_FINGERPRINT);
- startEnroll(token, timeout, userId);
+ startEnroll(token, groupId, flags);
}
- @Override // Binder call
- public void enrollCancel(IBinder token,int userId) {
- checkPermission(MANAGE_FINGERPRINT);
- startEnrollCancel(token, userId);
+ @Override
+ // Binder call
+ public void authenticate(IBinder token, long sessionId, int groupId, int flags) {
+ checkPermission(USE_FINGERPRINT);
+ startAuthenticate(token, sessionId, groupId, flags);
}
- @Override // Binder call
- public void remove(IBinder token, int fingerprintId, int userId) {
+ @Override
+ // Binder call
+ public void remove(IBinder token, int fingerId, int groupId) {
checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
- startRemove(token, fingerprintId, userId);
+ startRemove(token, fingerId, groupId);
}
- @Override // Binder call
- public void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId)
- {
+ @Override
+ // Binder call
+ public void addListener(IBinder token, IFingerprintServiceReceiver receiver, int userId) {
checkPermission(USE_FINGERPRINT);
- addListener(token, receiver, userId);
+ FingerprintService.this.addListener(token, receiver, userId);
}
- @Override // Binder call
- public void stopListening(IBinder token, int userId) {
+ @Override
+ // Binder call
+ public void removeListener(IBinder token, IFingerprintServiceReceiver receiver) {
checkPermission(USE_FINGERPRINT);
- removeListener(token, userId);
+ FingerprintService.this.removeListener(token, receiver);
}
- @Override // Binder call
- public boolean isHardwareDetected() {
+ @Override
+ // Binder call
+ public boolean isHardwareDetected(long deviceId) {
checkPermission(USE_FINGERPRINT);
- return mHalDeviceId != 0;
+ return mHalDeviceId != 0; // TODO
}
@Override
- public void rename(int fpId, String name) {
+ // Binder call
+ public void rename(int fingerId, int groupId, String name) {
checkPermission(MANAGE_FINGERPRINT);
+ Slog.w(TAG, "rename id=" + fingerId + ",gid=" + groupId + ",name=" + name);
// TODO
}
+
+ @Override
+ // Binder call
+ public List<Fingerprint> getEnrolledFingerprints(int groupId) {
+ checkPermission(USE_FINGERPRINT);
+ return FingerprintService.this.getEnrolledFingerprints(groupId);
+ }
}
@Override
public void onStart() {
- publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
- mHalDeviceId = nativeOpenHal();
- if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
+ publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
+ mHalDeviceId = nativeOpenHal();
+ if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 70fa4410165f..89ffe457fd0e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -192,6 +192,13 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
}
}
+ @ServiceThreadOnly
+ protected boolean handleUserControlPressed(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+ wakeUpIfActiveSource();
+ return super.handleUserControlPressed(message);
+ }
+
@Override
@ServiceThreadOnly
protected boolean handleSetStreamPath(HdmiCecMessage message) {
@@ -229,7 +236,12 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
}
private void wakeUpIfActiveSource() {
- if (mIsActiveSource && mService.isPowerStandbyOrTransient()) {
+ if (!mIsActiveSource) {
+ return;
+ }
+ // Wake up the device if the power is in standby mode, or its screen is off -
+ // which can happen if the device is holding a partial lock.
+ if (mService.isPowerStandbyOrTransient() || !mService.getPowerManager().isScreenOn()) {
mService.wakeUp();
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 7c93e56715bb..d5cb5e34217e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -251,7 +251,9 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
int targetAddress = targetDevice.getLogicalAddress();
ActiveSource active = getActiveSource();
- if (active.isValid() && targetAddress == active.logicalAddress) {
+ if (targetDevice.getDevicePowerStatus() == HdmiControlManager.POWER_STATUS_ON
+ && active.isValid()
+ && targetAddress == active.logicalAddress) {
invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
return;
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index fe1260d5ab72..d79b5fd21d7b 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -41,6 +41,7 @@ import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -109,21 +110,22 @@ public class JobSchedulerService extends com.android.server.SystemService
* Track Services that have currently active or pending jobs. The index is provided by
* {@link JobStatus#getServiceToken()}
*/
- final List<JobServiceContext> mActiveServices = new ArrayList<JobServiceContext>();
+ final List<JobServiceContext> mActiveServices = new ArrayList<>();
/** List of controllers that will notify this service of updates to jobs. */
List<StateController> mControllers;
/**
* Queue of pending jobs. The JobServiceContext class will receive jobs from this list
* when ready to execute them.
*/
- final ArrayList<JobStatus> mPendingJobs = new ArrayList<JobStatus>();
+ final ArrayList<JobStatus> mPendingJobs = new ArrayList<>();
- final ArrayList<Integer> mStartedUsers = new ArrayList();
+ final ArrayList<Integer> mStartedUsers = new ArrayList<>();
final JobHandler mHandler;
final JobSchedulerStub mJobSchedulerStub;
IBatteryStats mBatteryStats;
+ PowerManager mPowerManager;
/**
* Set to true once we are allowed to run third party apps.
@@ -131,6 +133,11 @@ public class JobSchedulerService extends com.android.server.SystemService
boolean mReadyToRock;
/**
+ * True when in device idle mode, so we don't want to schedule any jobs.
+ */
+ boolean mDeviceIdleMode;
+
+ /**
* Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we
* still clean up. On reinstall the package will have a new uid.
*/
@@ -154,6 +161,8 @@ public class JobSchedulerService extends com.android.server.SystemService
Slog.d(TAG, "Removing jobs for user: " + userId);
}
cancelJobsForUser(userId);
+ } else if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())) {
+ updateIdleMode(mPowerManager != null ? mPowerManager.isDeviceIdleMode() : false);
}
}
};
@@ -199,7 +208,7 @@ public class JobSchedulerService extends com.android.server.SystemService
return outList;
}
- private void cancelJobsForUser(int userHandle) {
+ void cancelJobsForUser(int userHandle) {
List<JobStatus> jobsForUser;
synchronized (mJobs) {
jobsForUser = mJobs.getJobsByUser(userHandle);
@@ -257,6 +266,40 @@ public class JobSchedulerService extends com.android.server.SystemService
}
}
+ void updateIdleMode(boolean enabled) {
+ boolean changed = false;
+ boolean rocking;
+ synchronized (mJobs) {
+ if (mDeviceIdleMode != enabled) {
+ changed = true;
+ }
+ rocking = mReadyToRock;
+ }
+ if (changed) {
+ if (rocking) {
+ for (int i=0; i<mControllers.size(); i++) {
+ mControllers.get(i).deviceIdleModeChanged(enabled);
+ }
+ }
+ synchronized (mJobs) {
+ mDeviceIdleMode = enabled;
+ if (enabled) {
+ // When becoming idle, make sure no jobs are actively running.
+ for (int i=0; i<mActiveServices.size(); i++) {
+ JobServiceContext jsc = mActiveServices.get(i);
+ final JobStatus executing = jsc.getRunningJob();
+ if (executing != null) {
+ jsc.cancelExecutingJob();
+ }
+ }
+ } else {
+ // When coming out of idle, allow thing to start back up.
+ mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
+ }
+ }
+ }
+ }
+
/**
* Initializes the system service.
* <p>
@@ -294,8 +337,10 @@ public class JobSchedulerService extends com.android.server.SystemService
getContext().registerReceiverAsUser(
mBroadcastReceiver, UserHandle.ALL, filter, null, null);
final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
+ userFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
getContext().registerReceiverAsUser(
mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
+ mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE);
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
synchronized (mJobs) {
// Let's go!
@@ -313,6 +358,7 @@ public class JobSchedulerService extends com.android.server.SystemService
for (int i=0; i<jobs.size(); i++) {
JobStatus job = jobs.valueAt(i);
for (int controller=0; controller<mControllers.size(); controller++) {
+ mControllers.get(controller).deviceIdleModeChanged(mDeviceIdleMode);
mControllers.get(controller).maybeStartTrackingJob(job);
}
}
@@ -667,6 +713,10 @@ public class JobSchedulerService extends com.android.server.SystemService
*/
private void maybeRunPendingJobsH() {
synchronized (mJobs) {
+ if (mDeviceIdleMode) {
+ // If device is idle, we will not schedule jobs to run.
+ return;
+ }
Iterator<JobStatus> it = mPendingJobs.iterator();
if (DEBUG) {
Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");
@@ -878,6 +928,7 @@ public class JobSchedulerService extends com.android.server.SystemService
}
pw.println();
pw.print("mReadyToRock="); pw.println(mReadyToRock);
+ pw.print("mDeviceIdleMode="); pw.println(mDeviceIdleMode);
}
pw.println();
}
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
index 7d76fc02b44b..efd192844c34 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -31,12 +31,17 @@ public abstract class StateController {
protected static final boolean DEBUG = false;
protected Context mContext;
protected StateChangedListener mStateChangedListener;
+ protected boolean mDeviceIdleMode;
public StateController(StateChangedListener stateChangedListener, Context context) {
mStateChangedListener = stateChangedListener;
mContext = context;
}
+ public void deviceIdleModeChanged(boolean enabled) {
+ mDeviceIdleMode = enabled;
+ }
+
/**
* Implement the logic here to decide whether a job should be tracked by this controller.
* This logic is put here so the JobManger can be completely agnostic of Controller logic.
@@ -50,5 +55,4 @@ public abstract class StateController {
public abstract void maybeStopTrackingJob(JobStatus jobStatus);
public abstract void dumpControllerState(PrintWriter pw);
-
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index b5036dbaf190..09d050148df1 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -40,6 +40,7 @@ import android.media.session.MediaSession;
import android.media.session.ParcelableVolumeInfo;
import android.media.session.PlaybackState;
import android.media.AudioAttributes;
+import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.DeadObjectException;
@@ -887,6 +888,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
}
+ public void playFromUri(Uri uri, Bundle extras) {
+ try {
+ mCb.onPlayFromUri(uri, extras);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in playFromUri.", e);
+ }
+ }
+
public void skipToTrack(long id) {
try {
mCb.onSkipToTrack(id);
@@ -1103,6 +1112,11 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
}
@Override
+ public void playFromUri(Uri uri, Bundle extras) throws RemoteException {
+ mSessionCb.playFromUri(uri, extras);
+ }
+
+ @Override
public void skipToQueueItem(long id) {
mSessionCb.skipToTrack(id);
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index a530dfa7d1e5..65949bf80aa0 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -55,6 +55,7 @@ import android.provider.Settings;
import android.speech.RecognizerIntent;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Slog;
import android.util.SparseArray;
import android.view.KeyEvent;
@@ -743,15 +744,23 @@ public class MediaSessionService extends SystemService implements Monitor {
Log.w(TAG, "Attempted to dispatch null or non-media key event.");
return;
}
+
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
- if (DEBUG) {
- Log.d(TAG, "dispatchMediaKeyEvent, pid=" + pid + ", uid=" + uid + ", event="
- + keyEvent);
- }
-
try {
+ if (DEBUG) {
+ Log.d(TAG, "dispatchMediaKeyEvent, pid=" + pid + ", uid=" + uid + ", event="
+ + keyEvent);
+ }
+ if (!isUserSetupComplete()) {
+ // Global media key handling can have the side-effect of starting new
+ // activities which is undesirable while setup is in progress.
+ Slog.i(TAG, "Not dispatching media key event because user "
+ + "setup is in progress.");
+ return;
+ }
+
synchronized (mLock) {
// If we don't have a media button receiver to fall back on
// include non-playing sessions for dispatching
@@ -1025,6 +1034,11 @@ public class MediaSessionService extends SystemService implements Monitor {
return keyCode == KeyEvent.KEYCODE_HEADSETHOOK;
}
+ private boolean isUserSetupComplete() {
+ return Settings.Secure.getIntForUser(getContext().getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
+ }
+
// we only handle public stream types, which are 0-5
private boolean isValidLocalStreamType(int streamType) {
return streamType >= AudioManager.STREAM_VOICE_CALL
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 8d467756c67d..5de7d422ee80 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -71,7 +71,9 @@ import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UP
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
+import android.Manifest;
import android.app.ActivityManager;
+import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.IProcessObserver;
@@ -83,6 +85,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.Resources;
@@ -2021,6 +2024,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
void updateRulesForUidLocked(int uid) {
if (!isUidValidForRules(uid)) return;
+ // quick check: if this uid doesn't have INTERNET permission, it doesn't have
+ // network access anyway, so it is a waste to mess with it here.
+ final IPackageManager ipm = AppGlobals.getPackageManager();
+ try {
+ if (ipm.checkUidPermission(Manifest.permission.INTERNET, uid)
+ != PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+ } catch (RemoteException e) {
+ }
+
final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
final boolean uidForeground = isUidForegroundLocked(uid);
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 20f5f97c4b4b..a415a84b454d 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -22,21 +22,28 @@ import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_REMOVED;
+import static android.net.TrafficStats.UID_TETHERING;
+import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
+import android.net.ConnectivityManager;
import android.net.NetworkIdentity;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TrafficStats;
+import android.os.Binder;
+import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.AtomicFile;
+import android.util.IntArray;
import libcore.io.IoUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
+
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -129,6 +136,23 @@ public class NetworkStatsCollection implements FileRotator.Reader {
return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE;
}
+ public int[] getRelevantUids() {
+ final int callerUid = Binder.getCallingUid();
+ IntArray uids = new IntArray();
+ for (int i = 0; i < mStats.size(); i++) {
+ final Key key = mStats.keyAt(i);
+ if (isAccessibleToUser(key.uid, callerUid)) {
+ int j = uids.binarySearch(key.uid);
+
+ if (j < 0) {
+ j = ~j;
+ uids.add(j, key.uid);
+ }
+ }
+ }
+ return uids.toArray();
+ }
+
/**
* Combine all {@link NetworkStatsHistory} in this collection which match
* the requested parameters.
@@ -144,12 +168,21 @@ public class NetworkStatsCollection implements FileRotator.Reader {
*/
public NetworkStatsHistory getHistory(
NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) {
+ final int callerUid = Binder.getCallingUid();
+ if (!isAccessibleToUser(uid, callerUid)) {
+ throw new SecurityException("Network stats history of uid " + uid
+ + " is forbidden for caller " + callerUid);
+ }
+
final NetworkStatsHistory combined = new NetworkStatsHistory(
- mBucketDuration, estimateBuckets(), fields);
+ mBucketDuration, start == end ? 1 : estimateBuckets(), fields);
+
+ // shortcut when we know stats will be empty
+ if (start == end) return combined;
+
for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i);
- final boolean setMatches = set == SET_ALL || key.set == set;
- if (key.uid == uid && setMatches && key.tag == tag
+ if (key.uid == uid && NetworkStats.setMatches(set, key.set) && key.tag == tag
&& templateMatches(template, key.ident)) {
final NetworkStatsHistory value = mStats.valueAt(i);
combined.recordHistory(value, start, end);
@@ -166,15 +199,17 @@ public class NetworkStatsCollection implements FileRotator.Reader {
final long now = System.currentTimeMillis();
final NetworkStats stats = new NetworkStats(end - start, 24);
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- NetworkStatsHistory.Entry historyEntry = null;
-
// shortcut when we know stats will be empty
if (start == end) return stats;
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
+ NetworkStatsHistory.Entry historyEntry = null;
+
+ final int callerUid = Binder.getCallingUid();
for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i);
- if (templateMatches(template, key.ident)) {
+ if (templateMatches(template, key.ident) && isAccessibleToUser(key.uid, callerUid)
+ && key.set < NetworkStats.SET_DEBUG_START) {
final NetworkStatsHistory value = mStats.valueAt(i);
historyEntry = value.getValues(start, end, now, historyEntry);
@@ -507,6 +542,7 @@ public class NetworkStatsCollection implements FileRotator.Reader {
final NetworkStatsHistory value = mStats.valueAt(i);
if (!templateMatches(groupTemplate, key.ident)) continue;
+ if (key.set >= NetworkStats.SET_DEBUG_START) continue;
final Key groupKey = new Key(null, key.uid, key.set, key.tag);
NetworkStatsHistory groupHistory = grouped.get(groupKey);
@@ -534,6 +570,12 @@ public class NetworkStatsCollection implements FileRotator.Reader {
}
}
+ private static boolean isAccessibleToUser(int uid, int callerUid) {
+ return callerUid == android.os.Process.SYSTEM_UID ||
+ uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED || uid == UID_TETHERING
+ || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
+ }
+
/**
* Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
* in the given {@link NetworkIdentitySet}.
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 0b596aa11900..50e03a2b67e0 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -62,9 +62,13 @@ import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
+import android.Manifest;
import android.app.AlarmManager;
+import android.app.AppOpsManager;
import android.app.IAlarmManager;
import android.app.PendingIntent;
+import android.app.admin.DeviceAdminInfo;
+import android.app.admin.DevicePolicyManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -93,7 +97,9 @@ import android.os.HandlerThread;
import android.os.INetworkManagementService;
import android.os.Message;
import android.os.PowerManager;
+import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
@@ -116,6 +122,7 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.EventLogTags;
+import com.android.server.LocalServices;
import com.android.server.connectivity.Tethering;
import java.io.File;
@@ -429,7 +436,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public INetworkStatsSession openSession() {
- mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+ return openSessionForUsageStats(null);
+ }
+
+ @Override
+ public INetworkStatsSession openSessionForUsageStats(final String callingPackage) {
assertBandwidthControlEnabled();
// return an IBinder which holds strong references to any loaded stats
@@ -438,6 +449,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return new INetworkStatsSession.Stub() {
private NetworkStatsCollection mUidComplete;
private NetworkStatsCollection mUidTagComplete;
+ private String mCallingPackage = callingPackage;
private NetworkStatsCollection getUidComplete() {
synchronized (mStatsLock) {
@@ -458,8 +470,29 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
@Override
+ public int[] getRelevantUids() {
+ enforcePermissionForManagedAdmin(mCallingPackage);
+ return getUidComplete().getRelevantUids();
+ }
+
+ @Override
+ public NetworkStats getDeviceSummaryForNetwork(NetworkTemplate template, long start,
+ long end) {
+ enforcePermission(mCallingPackage);
+ NetworkStats result = new NetworkStats(end - start, 1);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ result.combineAllValues(internalGetSummaryForNetwork(template, start, end));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ return result;
+ }
+
+ @Override
public NetworkStats getSummaryForNetwork(
NetworkTemplate template, long start, long end) {
+ enforcePermission(mCallingPackage);
return internalGetSummaryForNetwork(template, start, end);
}
@@ -471,6 +504,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public NetworkStats getSummaryForAllUid(
NetworkTemplate template, long start, long end, boolean includeTags) {
+ enforcePermissionForManagedAdmin(mCallingPackage);
final NetworkStats stats = getUidComplete().getSummary(template, start, end);
if (includeTags) {
final NetworkStats tagStats = getUidTagComplete()
@@ -483,6 +517,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public NetworkStatsHistory getHistoryForUid(
NetworkTemplate template, int uid, int set, int tag, int fields) {
+ enforcePermissionForManagedAdmin(mCallingPackage);
if (tag == TAG_NONE) {
return getUidComplete().getHistory(template, uid, set, tag, fields);
} else {
@@ -498,6 +533,53 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
};
}
+ private boolean hasAppOpsPermission(String callingPackage) {
+ final int callingUid = Binder.getCallingUid();
+ boolean appOpsAllow = false;
+ if (callingPackage != null) {
+ AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
+ Context.APP_OPS_SERVICE);
+
+ final int mode = appOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS,
+ callingUid, callingPackage);
+ if (mode == AppOpsManager.MODE_DEFAULT) {
+ // The default behavior here is to check if PackageManager has given the app
+ // permission.
+ final int permissionCheck = mContext.checkCallingPermission(
+ Manifest.permission.PACKAGE_USAGE_STATS);
+ appOpsAllow = permissionCheck == PackageManager.PERMISSION_GRANTED;
+ }
+ appOpsAllow = (mode == AppOpsManager.MODE_ALLOWED);
+ }
+ return appOpsAllow;
+ }
+
+ private void enforcePermissionForManagedAdmin(String callingPackage) {
+ boolean hasPermission = hasAppOpsPermission(callingPackage);
+ if (!hasPermission) {
+ // Profile and device owners are exempt from permission checking.
+ final int callingUid = Binder.getCallingUid();
+ final DevicePolicyManagerInternal dpmi = LocalServices.getService(
+ DevicePolicyManagerInternal.class);
+ if (dpmi.isActiveAdminWithPolicy(callingUid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)
+ || dpmi.isActiveAdminWithPolicy(callingUid,
+ DeviceAdminInfo.USES_POLICY_DEVICE_OWNER)) {
+ return;
+ }
+ }
+ if (!hasPermission) {
+ mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+ }
+ }
+
+ private void enforcePermission(String callingPackage) {
+ boolean appOpsAllow = hasAppOpsPermission(callingPackage);
+ if (!appOpsAllow) {
+ mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+ }
+ }
+
+
/**
* Return network summary, splicing between DEV and XT stats when
* appropriate.
diff --git a/services/core/java/com/android/server/pm/BasePermission.java b/services/core/java/com/android/server/pm/BasePermission.java
index 4f27408a6fff..ec290ef3adcf 100644
--- a/services/core/java/com/android/server/pm/BasePermission.java
+++ b/services/core/java/com/android/server/pm/BasePermission.java
@@ -18,6 +18,9 @@ package com.android.server.pm;
import android.content.pm.PackageParser;
import android.content.pm.PermissionInfo;
+import android.os.UserHandle;
+
+import com.android.internal.util.ArrayUtils;
final class BasePermission {
final static int TYPE_NORMAL = 0;
@@ -40,9 +43,17 @@ final class BasePermission {
PermissionInfo pendingInfo;
+ /** UID that owns the definition of this permission */
int uid;
- int[] gids;
+ /** Additional GIDs given to apps granted this permission */
+ private int[] gids;
+
+ /**
+ * Flag indicating that {@link #gids} should be adjusted based on the
+ * {@link UserHandle} the granted app is running as.
+ */
+ private boolean perUser;
BasePermission(String _name, String _sourcePackage, int _type) {
name = _name;
@@ -52,8 +63,35 @@ final class BasePermission {
protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
}
+ @Override
public String toString() {
return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " + name
+ "}";
}
+
+ public void setGids(int[] gids, boolean perUser) {
+ this.gids = gids;
+ this.perUser = perUser;
+ }
+
+ public boolean hasGids() {
+ return ArrayUtils.isEmpty(gids);
+ }
+
+ public int[] computeGids(int userId) {
+ if (perUser) {
+ final int[] userGids = new int[gids.length];
+ for (int i = 0; i < gids.length; i++) {
+ userGids[i] = UserHandle.getUid(userId, gids[i]);
+ }
+ return userGids;
+ } else {
+ return gids;
+ }
+ }
+
+ public boolean isRuntime() {
+ return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+ == PermissionInfo.PROTECTION_DANGEROUS;
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 52411bf66a02..1b8ed22b2dbc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -54,7 +54,6 @@ import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO
import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
import static com.android.internal.util.ArrayUtils.appendInt;
-import static com.android.internal.util.ArrayUtils.removeInt;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
@@ -249,6 +248,9 @@ public class PackageManagerService extends IPackageManager.Stub {
private static final boolean DEBUG_DEXOPT = false;
private static final boolean DEBUG_ABI_SELECTION = false;
+ static final boolean RUNTIME_PERMISSIONS_ENABLED =
+ SystemProperties.getInt("ro.runtime.permissions.enabled", 0) == 1;
+
private static final int RADIO_UID = Process.PHONE_UID;
private static final int LOG_UID = Process.LOG_UID;
private static final int NFC_UID = Process.NFC_UID;
@@ -273,6 +275,7 @@ public class PackageManagerService extends IPackageManager.Stub {
static final int SCAN_TRUSTED_OVERLAY = 1<<9;
static final int SCAN_DELETE_DATA_ON_FAILURES = 1<<10;
static final int SCAN_REPLACING = 1<<11;
+ static final int SCAN_REQUIRE_KNOWN = 1<<12;
static final int REMOVE_CHATTY = 1<<16;
@@ -321,10 +324,28 @@ public class PackageManagerService extends IPackageManager.Stub {
DEFAULT_CONTAINER_PACKAGE,
"com.android.defcontainer.DefaultContainerService");
+ private static final String KILL_APP_REASON_GIDS_CHANGED =
+ "permission grant or revoke changed gids";
+
+ private static final String KILL_APP_REASON_PERMISSIONS_REVOKED =
+ "permissions revoked";
+
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
+ /** Permission grant: not grant the permission. */
+ private static final int GRANT_DENIED = 1;
+
+ /** Permission grant: grant the permission as an install permission. */
+ private static final int GRANT_INSTALL = 2;
+
+ /** Permission grant: grant the permission as a runtime one. */
+ private static final int GRANT_RUNTIME = 3;
+
+ /** Permission grant: grant as runtime a permission that was granted as an install time one. */
+ private static final int GRANT_UPGRADE = 4;
+
final ServiceThread mHandlerThread;
final PackageHandler mHandler;
@@ -994,6 +1015,15 @@ public class PackageManagerService extends IPackageManager.Stub {
res.removedInfo.sendBroadcast(false, true, false);
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, res.uid);
+
+ // Now that we successfully installed the package, grant runtime
+ // permissions if requested before broadcasting the install.
+ if ((args.installFlags
+ & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0) {
+ grantRequestedRuntimePermissions(res.pkg,
+ args.user.getIdentifier());
+ }
+
// Determine the set of users who are adding this
// package for the first time vs. those who are seeing
// an update.
@@ -1214,6 +1244,32 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int userId) {
+ if (userId >= UserHandle.USER_OWNER) {
+ grantRequestedRuntimePermissionsForUser(pkg, userId);
+ } else if (userId == UserHandle.USER_ALL) {
+ for (int someUserId : UserManagerService.getInstance().getUserIds()) {
+ grantRequestedRuntimePermissionsForUser(pkg, someUserId);
+ }
+ }
+ }
+
+ private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId) {
+ SettingBase sb = (SettingBase) pkg.mExtras;
+ if (sb == null) {
+ return;
+ }
+
+ PermissionsState permissionsState = sb.getPermissionsState();
+
+ for (String permission : pkg.requestedPermissions) {
+ BasePermission bp = mSettings.mPermissions.get(permission);
+ if (bp != null && bp.isRuntime()) {
+ permissionsState.grantRuntimePermission(bp, userId);
+ }
+ }
+ }
+
Bundle extrasForInstallResult(PackageInstalledInfo res) {
Bundle extras = null;
switch (res.returnCode) {
@@ -1243,7 +1299,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- public static final PackageManagerService main(Context context, Installer installer,
+ public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
@@ -1293,7 +1349,7 @@ public class PackageManagerService extends IPackageManager.Stub {
mOnlyCore = onlyCore;
mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
mMetrics = new DisplayMetrics();
- mSettings = new Settings(context);
+ mSettings = new Settings(mContext, mPackages);
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
@@ -1374,7 +1430,7 @@ public class PackageManagerService extends IPackageManager.Stub {
mSettings.mPermissions.put(perm.name, bp);
}
if (perm.gids != null) {
- bp.gids = appendInts(bp.gids, perm.gids);
+ bp.setGids(perm.gids, perm.perUser);
}
}
@@ -1644,10 +1700,10 @@ public class PackageManagerService extends IPackageManager.Stub {
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
- scanDirLI(mAppInstallDir, 0, scanFlags, 0);
+ scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
- scanFlags, 0);
+ scanFlags | SCAN_REQUIRE_KNOWN, 0);
/**
* Remove disable package settings for any updated system
@@ -1755,7 +1811,26 @@ public class PackageManagerService extends IPackageManager.Stub {
+ mSettings.mInternalSdkPlatform + " to " + mSdkVersion
+ "; regranting permissions for internal storage");
mSettings.mInternalSdkPlatform = mSdkVersion;
-
+
+
+ // We keep track for which users we granted permissions to be able
+ // to grant runtime permissions to system apps for newly appeared
+ // users. If we supported runtime permissions during the previous
+ // boot, then we already granted permissions for all device users.
+ // In such a case we set the users for which we granted permissions
+ // to avoid clobbering of runtime permissions we granted to system
+ // apps but the user revoked later.
+ if (PackageManagerService.RUNTIME_PERMISSIONS_ENABLED &&
+ mSettings.mRuntimePermissionEnabled) {
+ final int[] userIds = UserManagerService.getInstance().getUserIds();
+ for (PackageSetting ps : mSettings.mPackages.values()) {
+ ps.setPermissionsUpdatedForUserIds(userIds);
+ }
+ for (SharedUserSetting sus : mSettings.mSharedUsers.values()) {
+ sus.setPermissionsUpdatedForUserIds(userIds);
+ }
+ }
+
updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL
| (regrantPermissions
? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
@@ -1787,7 +1862,6 @@ public class PackageManagerService extends IPackageManager.Stub {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
-
mRequiredVerifierPackage = getRequiredVerifierLPr();
} // synchronized (mPackages)
} // synchronized (mInstallLock)
@@ -1832,14 +1906,8 @@ public class PackageManagerService extends IPackageManager.Stub {
final String packageName = info.activityInfo.packageName;
- final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps == null) {
- continue;
- }
-
- final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
- if (!gp.grantedPermissions
- .contains(android.Manifest.permission.PACKAGE_VERIFICATION_AGENT)) {
+ if (checkPermission(android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
+ packageName, UserHandle.USER_OWNER) != PackageManager.PERMISSION_GRANTED) {
continue;
}
@@ -1895,27 +1963,21 @@ public class PackageManagerService extends IPackageManager.Stub {
return cur;
}
- static int[] removeInts(int[] cur, int[] rem) {
- if (rem == null) return cur;
- if (cur == null) return cur;
- final int N = rem.length;
- for (int i=0; i<N; i++) {
- cur = removeInt(cur, rem[i]);
- }
- return cur;
- }
-
PackageInfo generatePackageInfo(PackageParser.Package p, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
final PackageSetting ps = (PackageSetting) p.mExtras;
if (ps == null) {
return null;
}
- final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
+
+ final PermissionsState permissionsState = ps.getPermissionsState();
+
+ final int[] gids = permissionsState.computeGids(userId);
+ final Set<String> permissions = permissionsState.getPermissions(userId);
final PackageUserState state = ps.readUserState(userId);
- return PackageParser.generatePackageInfo(p, gp.gids, flags,
- ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions,
- state, userId);
+
+ return PackageParser.generatePackageInfo(p, gids, flags,
+ ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
}
@Override
@@ -1986,6 +2048,7 @@ public class PackageManagerService extends IPackageManager.Stub {
public int getPackageUid(String packageName, int userId) {
if (!sUserManager.exists(userId)) return -1;
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get package uid");
+
// reader
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
@@ -2002,22 +2065,30 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
- public int[] getPackageGids(String packageName) {
+ public int[] getPackageGids(String packageName, int userId) throws RemoteException {
+ if (!sUserManager.exists(userId)) {
+ return null;
+ }
+
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false,
+ "getPackageGids");
+
// reader
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
- if (DEBUG_PACKAGE_INFO)
+ if (DEBUG_PACKAGE_INFO) {
Log.v(TAG, "getPackageGids" + packageName + ": " + p);
+ }
if (p != null) {
- final PackageSetting ps = (PackageSetting)p.mExtras;
- return ps.getGids();
+ PackageSetting ps = (PackageSetting) p.mExtras;
+ return ps.getPermissionsState().computeGids(userId);
}
}
- // stupid thing to indicate an error.
- return new int[0];
+
+ return null;
}
- static final PermissionInfo generatePermissionInfo(
+ static PermissionInfo generatePermissionInfo(
BasePermission bp, int flags) {
if (bp.perm != null) {
return PackageParser.generatePermissionInfo(bp.perm, flags);
@@ -2381,30 +2452,37 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
- public int checkPermission(String permName, String pkgName) {
+ public int checkPermission(String permName, String pkgName, int userId) {
+ if (!sUserManager.exists(userId)) {
+ return PackageManager.PERMISSION_DENIED;
+ }
+
synchronized (mPackages) {
- PackageParser.Package p = mPackages.get(pkgName);
+ final PackageParser.Package p = mPackages.get(pkgName);
if (p != null && p.mExtras != null) {
- PackageSetting ps = (PackageSetting)p.mExtras;
- if (ps.sharedUser != null) {
- if (ps.sharedUser.grantedPermissions.contains(permName)) {
- return PackageManager.PERMISSION_GRANTED;
- }
- } else if (ps.grantedPermissions.contains(permName)) {
+ final PackageSetting ps = (PackageSetting) p.mExtras;
+ if (ps.getPermissionsState().hasPermission(permName, userId)) {
return PackageManager.PERMISSION_GRANTED;
}
}
}
+
return PackageManager.PERMISSION_DENIED;
}
@Override
public int checkUidPermission(String permName, int uid) {
+ final int userId = UserHandle.getUserId(uid);
+
+ if (!sUserManager.exists(userId)) {
+ return PackageManager.PERMISSION_DENIED;
+ }
+
synchronized (mPackages) {
Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
if (obj != null) {
- GrantedPermissions gp = (GrantedPermissions)obj;
- if (gp.grantedPermissions.contains(permName)) {
+ final SettingBase ps = (SettingBase) obj;
+ if (ps.getPermissionsState().hasPermission(permName, userId)) {
return PackageManager.PERMISSION_GRANTED;
}
} else {
@@ -2414,6 +2492,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
}
+
return PackageManager.PERMISSION_DENIED;
}
@@ -2620,120 +2699,114 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- private static void checkGrantRevokePermissions(PackageParser.Package pkg, BasePermission bp) {
+ private static void enforceDeclaredAsUsedAndRuntimePermission(PackageParser.Package pkg,
+ BasePermission bp) {
int index = pkg.requestedPermissions.indexOf(bp.name);
if (index == -1) {
throw new SecurityException("Package " + pkg.packageName
+ " has not requested permission " + bp.name);
}
- boolean isNormal =
- ((bp.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE)
- == PermissionInfo.PROTECTION_NORMAL);
- boolean isDangerous =
- ((bp.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE)
- == PermissionInfo.PROTECTION_DANGEROUS);
- boolean isDevelopment =
- ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0);
-
- if (!isNormal && !isDangerous && !isDevelopment) {
+ if (!bp.isRuntime()) {
throw new SecurityException("Permission " + bp.name
+ " is not a changeable permission type");
}
-
- if (isNormal || isDangerous) {
- if (pkg.requestedPermissionsRequired.get(index)) {
- throw new SecurityException("Can't change " + bp.name
- + ". It is required by the application");
- }
- }
}
@Override
- public void grantPermission(String packageName, String permissionName) {
+ public boolean grantPermission(String packageName, String name, int userId) {
+ if (!sUserManager.exists(userId)) {
+ return false;
+ }
+
mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, null);
+ android.Manifest.permission.GRANT_REVOKE_PERMISSIONS,
+ "grantPermission");
+
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+ "grantPermission");
+
synchronized (mPackages) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- final BasePermission bp = mSettings.mPermissions.get(permissionName);
+
+ final BasePermission bp = mSettings.mPermissions.get(name);
if (bp == null) {
- throw new IllegalArgumentException("Unknown permission: " + permissionName);
+ throw new IllegalArgumentException("Unknown permission: " + name);
}
- checkGrantRevokePermissions(pkg, bp);
+ enforceDeclaredAsUsedAndRuntimePermission(pkg, bp);
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null) {
- return;
+ final SettingBase sb = (SettingBase) pkg.mExtras;
+ if (sb == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
}
- final GrantedPermissions gp = (ps.sharedUser != null) ? ps.sharedUser : ps;
- if (gp.grantedPermissions.add(permissionName)) {
- if (ps.haveGids) {
- gp.gids = appendInts(gp.gids, bp.gids);
+
+ final PermissionsState permissionsState = sb.getPermissionsState();
+
+ final int result = permissionsState.grantRuntimePermission(bp, userId);
+ switch (result) {
+ case PermissionsState.PERMISSION_OPERATION_FAILURE: {
+ return false;
}
- mSettings.writeLPr();
+
+ case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
+ killSettingPackagesForUser(sb, userId, KILL_APP_REASON_GIDS_CHANGED);
+ } break;
}
+
+ // Not critical if that is lost - app has to request again.
+ mSettings.writeRuntimePermissionsForUserLPr(userId, false);
+
+ return true;
}
}
@Override
- public void revokePermission(String packageName, String permissionName) {
- int changedAppId = -1;
+ public boolean revokePermission(String packageName, String name, int userId) {
+ if (!sUserManager.exists(userId)) {
+ return false;
+ }
+
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.GRANT_REVOKE_PERMISSIONS,
+ "revokePermission");
+
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+ "revokePermission");
synchronized (mPackages) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- if (pkg.applicationInfo.uid != Binder.getCallingUid()) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, null);
- }
- final BasePermission bp = mSettings.mPermissions.get(permissionName);
+
+ final BasePermission bp = mSettings.mPermissions.get(name);
if (bp == null) {
- throw new IllegalArgumentException("Unknown permission: " + permissionName);
+ throw new IllegalArgumentException("Unknown permission: " + name);
}
- checkGrantRevokePermissions(pkg, bp);
+ enforceDeclaredAsUsedAndRuntimePermission(pkg, bp);
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null) {
- return;
- }
- final GrantedPermissions gp = (ps.sharedUser != null) ? ps.sharedUser : ps;
- if (gp.grantedPermissions.remove(permissionName)) {
- gp.grantedPermissions.remove(permissionName);
- if (ps.haveGids) {
- gp.gids = removeInts(gp.gids, bp.gids);
- }
- mSettings.writeLPr();
- changedAppId = ps.appId;
+ final SettingBase sb = (SettingBase) pkg.mExtras;
+ if (sb == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
}
- }
- if (changedAppId >= 0) {
- // We changed the perm on someone, kill its processes.
- IActivityManager am = ActivityManagerNative.getDefault();
- if (am != null) {
- final int callingUserId = UserHandle.getCallingUserId();
- final long ident = Binder.clearCallingIdentity();
- try {
- //XXX we should only revoke for the calling user's app permissions,
- // but for now we impact all users.
- //am.killUid(UserHandle.getUid(callingUserId, changedAppId),
- // "revoke " + permissionName);
- int[] users = sUserManager.getUserIds();
- for (int user : users) {
- am.killUid(UserHandle.getUid(user, changedAppId),
- "revoke " + permissionName);
- }
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ final PermissionsState permissionsState = sb.getPermissionsState();
+
+ if (permissionsState.revokeRuntimePermission(bp, userId) ==
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ return false;
}
+
+ killSettingPackagesForUser(sb, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
+
+ // Critical, after this call all should never have the permission.
+ mSettings.writeRuntimePermissionsForUserLPr(userId, true);
+
+ return true;
}
}
@@ -2794,6 +2867,46 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ private void killSettingPackagesForUser(SettingBase sb, int userId, String reason) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ if (sb instanceof SharedUserSetting) {
+ SharedUserSetting sus = (SharedUserSetting) sb;
+ final int packageCount = sus.packages.size();
+ for (int i = 0; i < packageCount; i++) {
+ PackageSetting susPs = sus.packages.valueAt(i);
+ if (userId == UserHandle.USER_ALL) {
+ killApplication(susPs.pkg.packageName, susPs.appId, reason);
+ } else {
+ final int uid = UserHandle.getUid(userId, susPs.appId);
+ killUid(uid, reason);
+ }
+ }
+ } else if (sb instanceof PackageSetting) {
+ PackageSetting ps = (PackageSetting) sb;
+ if (userId == UserHandle.USER_ALL) {
+ killApplication(ps.pkg.packageName, ps.appId, reason);
+ } else {
+ final int uid = UserHandle.getUid(userId, ps.appId);
+ killUid(uid, reason);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private static void killUid(int uid, String reason) {
+ IActivityManager am = ActivityManagerNative.getDefault();
+ if (am != null) {
+ try {
+ am.killUid(uid, reason);
+ } catch (RemoteException e) {
+ /* ignore - same process */
+ }
+ }
+ }
+
/**
* Compares two sets of signatures. Returns:
* <br />
@@ -3875,9 +3988,10 @@ public class PackageManagerService extends IPackageManager.Stub {
private void addPackageHoldingPermissions(ArrayList<PackageInfo> list, PackageSetting ps,
String[] permissions, boolean[] tmp, int flags, int userId) {
int numMatch = 0;
- final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
+ final PermissionsState permissionsState = ps.getPermissionsState();
for (int i=0; i<permissions.length; i++) {
- if (gp.grantedPermissions.contains(permissions[i])) {
+ final String permission = permissions[i];
+ if (permissionsState.hasPermission(permission, userId)) {
tmp[i] = true;
numMatch++;
} else {
@@ -5164,6 +5278,28 @@ public class PackageManagerService extends IPackageManager.Stub {
+ " already installed. Skipping duplicate.");
}
+ // If we're only installing presumed-existing packages, require that the
+ // scanned APK is both already known and at the path previously established
+ // for it. Previously unknown packages we pick up normally, but if we have an
+ // a priori expectation about this package's install presence, enforce it.
+ if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) {
+ PackageSetting known = mSettings.peekPackageLPr(pkg.packageName);
+ if (known != null) {
+ if (DEBUG_PACKAGE_SCANNING) {
+ Log.d(TAG, "Examining " + pkg.codePath
+ + " and requiring known paths " + known.codePathString
+ + " & " + known.resourcePathString);
+ }
+ if (!pkg.applicationInfo.getCodePath().equals(known.codePathString)
+ || !pkg.applicationInfo.getResourcePath().equals(known.resourcePathString)) {
+ throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
+ "Application package " + pkg.packageName
+ + " found at " + pkg.applicationInfo.getCodePath()
+ + " but expected at " + known.codePathString + "; ignoring.");
+ }
+ }
+ }
+
// Initialize package source and resource directories
File destCodeFile = new File(pkg.applicationInfo.getCodePath());
File destResourceFile = new File(pkg.applicationInfo.getResourcePath());
@@ -6853,36 +6989,47 @@ public class PackageManagerService extends IPackageManager.Stub {
private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace,
String packageOfInterest) {
+ // IMPORTANT: There are two types of permissions: install and runtime.
+ // Install time permissions are granted when the app is installed to
+ // all device users and users added in the future. Runtime permissions
+ // are granted at runtime explicitly to specific users. Normal and signature
+ // protected permissions are install time permissions. Dangerous permissions
+ // are install permissions if the app's target SDK is Lollipop MR1 or older,
+ // otherwise they are runtime permissions. This function does not manage
+ // runtime permissions except for the case an app targeting Lollipop MR1
+ // being upgraded to target a newer SDK, in which case dangerous permissions
+ // are transformed from install time to runtime ones.
+
final PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps == null) {
return;
}
- final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
- ArraySet<String> origPermissions = gp.grantedPermissions;
- boolean changedPermission = false;
+
+ PermissionsState permissionsState = ps.getPermissionsState();
+ PermissionsState origPermissions = permissionsState;
+
+ final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
+
+ int[] upgradeUserIds = PermissionsState.USERS_NONE;
+ int[] changedRuntimePermissionUserIds = PermissionsState.USERS_NONE;
+
+ boolean changedInstallPermission = false;
if (replace) {
- ps.permissionsFixed = false;
- if (gp == ps) {
- origPermissions = new ArraySet<String>(gp.grantedPermissions);
- gp.grantedPermissions.clear();
- gp.gids = mGlobalGids;
- }
+ ps.installPermissionsFixed = false;
+ origPermissions = new PermissionsState(permissionsState);
+ permissionsState.reset();
}
- if (gp.gids == null) {
- gp.gids = mGlobalGids;
- }
+ permissionsState.setGlobalGids(mGlobalGids);
final int N = pkg.requestedPermissions.size();
for (int i=0; i<N; i++) {
final String name = pkg.requestedPermissions.get(i);
- final boolean required = pkg.requestedPermissionsRequired.get(i);
final BasePermission bp = mSettings.mPermissions.get(name);
+
if (DEBUG_INSTALL) {
- if (gp != ps) {
- Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
- }
+ Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
}
if (bp == null || bp.packageSetting == null) {
@@ -6894,10 +7041,11 @@ public class PackageManagerService extends IPackageManager.Stub {
}
final String perm = bp.name;
- boolean allowed;
boolean allowedSig = false;
- if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
- // Keep track of app op permissions.
+ int grant = GRANT_DENIED;
+
+ // Keep track of app op permissions.
+ if ((bp.protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
ArraySet<String> pkgs = mAppOpPermissionPackages.get(bp.name);
if (pkgs == null) {
pkgs = new ArraySet<>();
@@ -6905,65 +7053,126 @@ public class PackageManagerService extends IPackageManager.Stub {
}
pkgs.add(pkg.packageName);
}
+
final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
- if (level == PermissionInfo.PROTECTION_NORMAL
- || level == PermissionInfo.PROTECTION_DANGEROUS) {
- // We grant a normal or dangerous permission if any of the following
- // are true:
- // 1) The permission is required
- // 2) The permission is optional, but was granted in the past
- // 3) The permission is optional, but was requested by an
- // app in /system (not /data)
- //
- // Otherwise, reject the permission.
- allowed = (required || origPermissions.contains(perm)
- || (isSystemApp(ps) && !isUpdatedSystemApp(ps)));
- } else if (bp.packageSetting == null) {
- // This permission is invalid; skip it.
- allowed = false;
- } else if (level == PermissionInfo.PROTECTION_SIGNATURE) {
- allowed = grantSignaturePermission(perm, pkg, bp, origPermissions);
- if (allowed) {
- allowedSig = true;
- }
- } else {
- allowed = false;
+ switch (level) {
+ case PermissionInfo.PROTECTION_NORMAL: {
+ // For all apps normal permissions are install time ones.
+ grant = GRANT_INSTALL;
+ } break;
+
+ case PermissionInfo.PROTECTION_DANGEROUS: {
+ if (!RUNTIME_PERMISSIONS_ENABLED
+ || pkg.applicationInfo.targetSdkVersion
+ <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+ // For legacy apps dangerous permissions are install time ones.
+ grant = GRANT_INSTALL;
+ } else if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ final int[] updatedUserIds = ps.getPermissionsUpdatedForUserIds();
+ if (origPermissions.hasInstallPermission(bp.name)) {
+ // If a system app had an install permission, then the app was
+ // upgraded and we grant the permissions as runtime to all users.
+ grant = GRANT_UPGRADE;
+ upgradeUserIds = currentUserIds;
+ } else if (!Arrays.equals(updatedUserIds, currentUserIds)) {
+ // If users changed since the last permissions update for a
+ // system app, we grant the permission as runtime to the new users.
+ grant = GRANT_UPGRADE;
+ upgradeUserIds = currentUserIds;
+ for (int userId : updatedUserIds) {
+ upgradeUserIds = ArrayUtils.removeInt(upgradeUserIds, userId);
+ }
+ } else {
+ // Otherwise, we grant the permission as runtime if the app
+ // already had it, i.e. we preserve runtime permissions.
+ grant = GRANT_RUNTIME;
+ }
+ } else if (origPermissions.hasInstallPermission(bp.name)) {
+ // For legacy apps that became modern, install becomes runtime.
+ grant = GRANT_UPGRADE;
+ upgradeUserIds = currentUserIds;
+ } else if (replace) {
+ // For upgraded modern apps keep runtime permissions unchanged.
+ grant = GRANT_RUNTIME;
+ }
+ } break;
+
+ case PermissionInfo.PROTECTION_SIGNATURE: {
+ // For all apps signature permissions are install time ones.
+ allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions);
+ if (allowedSig) {
+ grant = GRANT_INSTALL;
+ }
+ } break;
}
+
if (DEBUG_INSTALL) {
- if (gp != ps) {
- Log.i(TAG, "Package " + pkg.packageName + " granting " + perm);
- }
+ Log.i(TAG, "Package " + pkg.packageName + " granting " + perm);
}
- if (allowed) {
- if (!isSystemApp(ps) && ps.permissionsFixed) {
+
+ if (grant != GRANT_DENIED) {
+ if (!isSystemApp(ps) && ps.installPermissionsFixed) {
// If this is an existing, non-system package, then
// we can't add any new permissions to it.
- if (!allowedSig && !gp.grantedPermissions.contains(perm)) {
+ if (!allowedSig && !origPermissions.hasInstallPermission(perm)) {
// Except... if this is a permission that was added
// to the platform (note: need to only do this when
// updating the platform).
- allowed = isNewPlatformPermissionForPackage(perm, pkg);
+ if (!isNewPlatformPermissionForPackage(perm, pkg)) {
+ grant = GRANT_DENIED;
+ }
}
}
- if (allowed) {
- if (!gp.grantedPermissions.contains(perm)) {
- changedPermission = true;
- gp.grantedPermissions.add(perm);
- gp.gids = appendInts(gp.gids, bp.gids);
- } else if (!ps.haveGids) {
- gp.gids = appendInts(gp.gids, bp.gids);
- }
- } else {
- if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
- Slog.w(TAG, "Not granting permission " + perm
- + " to package " + pkg.packageName
- + " because it was previously installed without");
- }
+
+ switch (grant) {
+ case GRANT_INSTALL: {
+ // Grant an install permission.
+ if (permissionsState.grantInstallPermission(bp) !=
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ changedInstallPermission = true;
+ }
+ } break;
+
+ case GRANT_RUNTIME: {
+ // Grant previously granted runtime permissions.
+ for (int userId : UserManagerService.getInstance().getUserIds()) {
+ if (origPermissions.hasRuntimePermission(bp.name, userId)) {
+ if (permissionsState.grantRuntimePermission(bp, userId) ==
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ // If we cannot put the permission as it was, we have to write.
+ changedRuntimePermissionUserIds = ArrayUtils.appendInt(
+ changedRuntimePermissionUserIds, userId);
+ }
+ }
+ }
+ } break;
+
+ case GRANT_UPGRADE: {
+ // Grant runtime permissions for a previously held install permission.
+ permissionsState.revokeInstallPermission(bp);
+ for (int userId : upgradeUserIds) {
+ if (permissionsState.grantRuntimePermission(bp, userId) !=
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ // If we granted the permission, we have to write.
+ changedRuntimePermissionUserIds = ArrayUtils.appendInt(
+ changedRuntimePermissionUserIds, userId);
+ }
+ }
+ } break;
+
+ default: {
+ if (packageOfInterest == null
+ || packageOfInterest.equals(pkg.packageName)) {
+ Slog.w(TAG, "Not granting permission " + perm
+ + " to package " + pkg.packageName
+ + " because it was previously installed without");
+ }
+ } break;
}
} else {
- if (gp.grantedPermissions.remove(perm)) {
- changedPermission = true;
- gp.gids = removeInts(gp.gids, bp.gids);
+ if (permissionsState.revokeInstallPermission(bp) !=
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ changedInstallPermission = true;
Slog.i(TAG, "Un-granting permission " + perm
+ " from package " + pkg.packageName
+ " (protectionLevel=" + bp.protectionLevel
@@ -6983,14 +7192,20 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- if ((changedPermission || replace) && !ps.permissionsFixed &&
+ if ((changedInstallPermission || replace) && !ps.installPermissionsFixed &&
!isSystemApp(ps) || isUpdatedSystemApp(ps)){
// This is the first that we have heard about this package, so the
// permissions we have now selected are fixed until explicitly
// changed.
- ps.permissionsFixed = true;
+ ps.installPermissionsFixed = true;
+ }
+
+ ps.setPermissionsUpdatedForUserIds(changedRuntimePermissionUserIds);
+
+ // Persist the runtime permissions state for users with changes.
+ for (int userId : changedRuntimePermissionUserIds) {
+ mSettings.writeRuntimePermissionsForUserLPr(userId, true);
}
- ps.haveGids = true;
}
private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) {
@@ -7011,7 +7226,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private boolean grantSignaturePermission(String perm, PackageParser.Package pkg,
- BasePermission bp, ArraySet<String> origPermissions) {
+ BasePermission bp, PermissionsState origPermissions) {
boolean allowed;
allowed = (compareSignatures(
bp.packageSetting.signatures.mSignatures, pkg.mSignatures)
@@ -7026,10 +7241,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (isUpdatedSystemApp(pkg)) {
final PackageSetting sysPs = mSettings
.getDisabledSystemPkgLPr(pkg.packageName);
- final GrantedPermissions origGp = sysPs.sharedUser != null
- ? sysPs.sharedUser : sysPs;
-
- if (origGp.grantedPermissions.contains(perm)) {
+ if (sysPs.getPermissionsState().hasInstallPermission(perm)) {
// If the original was granted this permission, we take
// that grant decision as read and propagate it to the
// update.
@@ -7063,7 +7275,7 @@ public class PackageManagerService extends IPackageManager.Stub {
& PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
// For development permissions, a development permission
// is granted only if it was already granted.
- allowed = origPermissions.contains(perm);
+ allowed = origPermissions.hasInstallPermission(perm);
}
return allowed;
}
@@ -10821,11 +11033,26 @@ public class PackageManagerService extends IPackageManager.Stub {
mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
outInfo.removedAppId = mSettings.removePackageLPw(packageName);
}
- if (deletedPs != null) {
- updatePermissionsLPw(deletedPs.name, null, 0);
- if (deletedPs.sharedUser != null) {
- // remove permissions associated with package
- mSettings.updateSharedUserPermsLPw(deletedPs, mGlobalGids);
+ updatePermissionsLPw(deletedPs.name, null, 0);
+ if (deletedPs.sharedUser != null) {
+ // Remove permissions associated with package. Since runtime
+ // permissions are per user we have to kill the removed package
+ // or packages running under the shared user of the removed
+ // package if revoking the permissions requested only by the removed
+ // package is successful and this causes a change in gids.
+ for (int userId : UserManagerService.getInstance().getUserIds()) {
+ final int userIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs,
+ userId);
+ if (userIdToKill == userId) {
+ // If gids changed for this user, kill all affected packages.
+ killSettingPackagesForUser(deletedPs, userIdToKill,
+ KILL_APP_REASON_GIDS_CHANGED);
+ } else if (userIdToKill == UserHandle.USER_ALL) {
+ // If gids changed for all users, kill them all - done.
+ killSettingPackagesForUser(deletedPs, userIdToKill,
+ KILL_APP_REASON_GIDS_CHANGED);
+ break;
+ }
}
}
clearPackagePreferredActivitiesLPw(deletedPs.name, UserHandle.USER_ALL);
@@ -13204,6 +13431,11 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ void newUserCreatedLILPw(int userHandle) {
+ // Adding a user requires updating runtime permissions for system apps.
+ updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL);
+ }
+
@Override
public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException {
mContext.enforceCallingOrSelfPermission(
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 06d842a1f0b9..889164c6c5b0 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -57,8 +57,10 @@ final class PackageSetting extends PackageSettingBase {
+ " " + name + "/" + appId + "}";
}
- public int[] getGids() {
- return sharedUser != null ? sharedUser.gids : gids;
+ public PermissionsState getPermissionsState() {
+ return (sharedUser != null)
+ ? sharedUser.getPermissionsState()
+ : super.getPermissionsState();
}
public boolean isPrivileged() {
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 4b8ca4219edf..35df33ba7d5f 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -29,7 +29,7 @@ import java.io.File;
/**
* Settings base class for pending and resolved classes.
*/
-class PackageSettingBase extends GrantedPermissions {
+abstract class PackageSettingBase extends SettingBase {
/**
* Indicates the state of installation. Used by PackageManager to figure out
* incomplete installations. Say a package is being installed (the state is
@@ -92,8 +92,7 @@ class PackageSettingBase extends GrantedPermissions {
PackageSignatures signatures = new PackageSignatures();
- boolean permissionsFixed;
- boolean haveGids;
+ boolean installPermissionsFixed;
PackageKeySetData keySetData = new PackageKeySetData();
@@ -146,8 +145,7 @@ class PackageSettingBase extends GrantedPermissions {
signatures = new PackageSignatures(base.signatures);
- permissionsFixed = base.permissionsFixed;
- haveGids = base.haveGids;
+ installPermissionsFixed = base.installPermissionsFixed;
userState.clear();
for (int i=0; i<base.userState.size(); i++) {
userState.put(base.userState.keyAt(i),
@@ -160,7 +158,6 @@ class PackageSettingBase extends GrantedPermissions {
installerPackageName = base.installerPackageName;
keySetData = new PackageKeySetData(base.keySetData);
-
}
void init(File codePath, File resourcePath, String legacyNativeLibraryPathString,
@@ -201,9 +198,8 @@ class PackageSettingBase extends GrantedPermissions {
* Make a shallow copy of this package settings.
*/
public void copyFrom(PackageSettingBase base) {
- grantedPermissions = base.grantedPermissions;
- gids = base.gids;
-
+ setPermissionsUpdatedForUserIds(base.getPermissionsUpdatedForUserIds());
+ getPermissionsState().copyFrom(base.getPermissionsState());
primaryCpuAbiString = base.primaryCpuAbiString;
secondaryCpuAbiString = base.secondaryCpuAbiString;
cpuAbiOverrideString = base.cpuAbiOverrideString;
@@ -211,8 +207,7 @@ class PackageSettingBase extends GrantedPermissions {
firstInstallTime = base.firstInstallTime;
lastUpdateTime = base.lastUpdateTime;
signatures = base.signatures;
- permissionsFixed = base.permissionsFixed;
- haveGids = base.haveGids;
+ installPermissionsFixed = base.installPermissionsFixed;
userState.clear();
for (int i=0; i<base.userState.size(); i++) {
userState.put(base.userState.keyAt(i), base.userState.valueAt(i));
diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java
new file mode 100644
index 000000000000..705abf81dc5a
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PermissionsState.java
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * This class encapsulates the permissions for a package or a shared user.
+ * <p>
+ * There are two types of permissions: install (granted at installation)
+ * and runtime (granted at runtime). Install permissions are granted to
+ * all device users while runtime permissions are granted explicitly to
+ * specific users.
+ * </p>
+ * <p>
+ * The permissions are kept on a per device user basis. For example, an
+ * application may have some runtime permissions granted under the device
+ * owner but not granted under the secondary user.
+ * <p>
+ * This class is also responsible for keeping track of the Linux gids per
+ * user for a package or a shared user. The gids are computed as a set of
+ * the gids for all granted permissions' gids on a per user basis.
+ * </p>
+ */
+public final class PermissionsState {
+
+ /** The permission operation succeeded and no gids changed. */
+ public static final int PERMISSION_OPERATION_SUCCESS = 1;
+
+ /** The permission operation succeeded and gids changed. */
+ public static final int PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED = 2;
+
+ /** The permission operation failed. */
+ public static final int PERMISSION_OPERATION_FAILURE = 3;
+
+ public static final int[] USERS_ALL = {UserHandle.USER_ALL};
+
+ public static final int[] USERS_NONE = {};
+
+ private static final int[] NO_GIDS = {};
+
+ private ArrayMap<String, PermissionData> mPermissions;
+
+ private int[] mGlobalGids = NO_GIDS;
+
+ public PermissionsState() {
+ /* do nothing */
+ }
+
+ public PermissionsState(PermissionsState prototype) {
+ copyFrom(prototype);
+ }
+
+ /**
+ * Sets the global gids, applicable to all users.
+ *
+ * @param globalGids The global gids.
+ */
+ public void setGlobalGids(int[] globalGids) {
+ if (!ArrayUtils.isEmpty(globalGids)) {
+ mGlobalGids = Arrays.copyOf(globalGids, globalGids.length);
+ }
+ }
+
+ /**
+ * Initialized this instance from another one.
+ *
+ * @param other The other instance.
+ */
+ public void copyFrom(PermissionsState other) {
+ if (mPermissions != null) {
+ if (other.mPermissions == null) {
+ mPermissions = null;
+ } else {
+ mPermissions.clear();
+ }
+ }
+ if (other.mPermissions != null) {
+ if (mPermissions == null) {
+ mPermissions = new ArrayMap<>();
+ }
+ final int permissionCount = other.mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ String name = other.mPermissions.keyAt(i);
+ PermissionData permissionData = other.mPermissions.valueAt(i);
+ mPermissions.put(name, new PermissionData(permissionData));
+ }
+ }
+
+ mGlobalGids = NO_GIDS;
+ if (other.mGlobalGids != NO_GIDS) {
+ mGlobalGids = Arrays.copyOf(other.mGlobalGids,
+ other.mGlobalGids.length);
+ }
+ }
+
+ /**
+ * Grant an install permission.
+ *
+ * @param permission The permission to grant.
+ * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
+ * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
+ * #PERMISSION_OPERATION_FAILURE}.
+ */
+ public int grantInstallPermission(BasePermission permission) {
+ return grantPermission(permission, UserHandle.USER_ALL);
+ }
+
+ /**
+ * Revoke an install permission.
+ *
+ * @param permission The permission to revoke.
+ * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
+ * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
+ * #PERMISSION_OPERATION_FAILURE}.
+ */
+ public int revokeInstallPermission(BasePermission permission) {
+ return revokePermission(permission, UserHandle.USER_ALL);
+ }
+
+ /**
+ * Grant a runtime permission.
+ *
+ * @param permission The permission to grant.
+ * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
+ * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
+ * #PERMISSION_OPERATION_FAILURE}.
+ */
+ public int grantRuntimePermission(BasePermission permission, int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ return PERMISSION_OPERATION_FAILURE;
+ }
+ return grantPermission(permission, userId);
+ }
+
+ /**
+ * Revoke a runtime permission for a given device user.
+ *
+ * @param permission The permission to revoke.
+ * @param userId The device user id.
+ * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
+ * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
+ * #PERMISSION_OPERATION_FAILURE}.
+ */
+ public int revokeRuntimePermission(BasePermission permission, int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ return PERMISSION_OPERATION_FAILURE;
+ }
+ return revokePermission(permission, userId);
+ }
+
+ /**
+ * Gets whether this state has a given permission, regardless if
+ * it is install time or runtime one.
+ *
+ * @param name The permission name.
+ * @return Whether this state has the permission.
+ */
+ public boolean hasPermission(String name) {
+ return mPermissions != null && mPermissions.get(name) != null;
+ }
+
+ /**
+ * Gets whether this state has a given runtime permission for a
+ * given device user id.
+ *
+ * @param name The permission name.
+ * @param userId The device user id.
+ * @return Whether this state has the permission.
+ */
+ public boolean hasRuntimePermission(String name, int userId) {
+ return !hasInstallPermission(name) && hasPermission(name, userId);
+ }
+
+ /**
+ * Gets whether this state has a given install permission.
+ *
+ * @param name The permission name.
+ * @return Whether this state has the permission.
+ */
+ public boolean hasInstallPermission(String name) {
+ return hasPermission(name, UserHandle.USER_ALL);
+ }
+
+ /**
+ * Revokes a permission for all users regardless if it is an install or
+ * a runtime permission.
+ *
+ * @param permission The permission to revoke.
+ * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
+ * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
+ * #PERMISSION_OPERATION_FAILURE}.
+ */
+ public int revokePermission(BasePermission permission) {
+ if (!hasPermission(permission.name)) {
+ return PERMISSION_OPERATION_FAILURE;
+ }
+
+ int result = PERMISSION_OPERATION_SUCCESS;
+
+ PermissionData permissionData = mPermissions.get(permission.name);
+ if (permissionData.hasGids()) {
+ for (int userId : permissionData.getUserIds()) {
+ if (revokePermission(permission, userId)
+ == PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
+ result = PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
+ break;
+ }
+ }
+ }
+
+ mPermissions.remove(permission.name);
+
+ return result;
+ }
+
+ /**
+ * Gets whether the state has a given permission for the specified
+ * user, regardless if this is an install or a runtime permission.
+ *
+ * @param name The permission name.
+ * @param userId The device user id.
+ * @return Whether the user has the permission.
+ */
+ public boolean hasPermission(String name, int userId) {
+ enforceValidUserId(userId);
+
+ if (mPermissions == null) {
+ return false;
+ }
+
+ PermissionData permissionData = mPermissions.get(name);
+ return permissionData != null && permissionData.hasUserId(userId);
+ }
+
+ /**
+ * Gets all permissions regardless if they are install or runtime.
+ *
+ * @return The permissions or an empty set.
+ */
+ public Set<String> getPermissions() {
+ if (mPermissions != null) {
+ return mPermissions.keySet();
+ }
+
+ return Collections.emptySet();
+ }
+
+ /**
+ * Gets all permissions for a given device user id regardless if they
+ * are install time or runtime permissions.
+ *
+ * @param userId The device user id.
+ * @return The permissions or an empty set.
+ */
+ public Set<String> getPermissions(int userId) {
+ enforceValidUserId(userId);
+
+ if (mPermissions == null) {
+ return Collections.emptySet();
+ }
+
+ Set<String> permissions = new ArraySet<>();
+
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ String permission = mPermissions.keyAt(i);
+ if (userId == UserHandle.USER_ALL) {
+ if (hasInstallPermission(permission)) {
+ permissions.add(permission);
+ }
+ } else {
+ if (hasRuntimePermission(permission, userId)) {
+ permissions.add(permission);
+ }
+ }
+ }
+
+ return permissions;
+ }
+
+ /**
+ * Gets all runtime permissions.
+ *
+ * @return The permissions or an empty set.
+ */
+ public Set<String> getRuntimePermissions(int userId) {
+ return getPermissions(userId);
+ }
+
+ /**
+ * Gets all install permissions.
+ *
+ * @return The permissions or an empty set.
+ */
+ public Set<String> getInstallPermissions() {
+ return getPermissions(UserHandle.USER_ALL);
+ }
+
+ /**
+ * Compute the Linux gids for a given device user from the permissions
+ * granted to this user. Note that these are computed to avoid additional
+ * state as they are rarely accessed.
+ *
+ * @param userId The device user id.
+ * @return The gids for the device user.
+ */
+ public int[] computeGids(int userId) {
+ enforceValidUserId(userId);
+
+ int[] gids = mGlobalGids;
+
+ if (mPermissions != null) {
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ String permission = mPermissions.keyAt(i);
+ if (!hasPermission(permission, userId)) {
+ continue;
+ }
+ PermissionData permissionData = mPermissions.valueAt(i);
+ final int[] permGids = permissionData.computeGids(userId);
+ if (permGids != NO_GIDS) {
+ gids = appendInts(gids, permGids);
+ }
+ }
+ }
+
+ return gids;
+ }
+
+ /**
+ * Compute the Linux gids for all device users from the permissions
+ * granted to these users.
+ *
+ * @return The gids for all device users.
+ */
+ public int[] computeGids() {
+ int[] gids = mGlobalGids;
+
+ for (int userId : UserManagerService.getInstance().getUserIds()) {
+ final int[] userGids = computeGids(userId);
+ gids = appendInts(gids, userGids);
+ }
+
+ return gids;
+ }
+
+ /**
+ * Resets the internal state of this object.
+ */
+ public void reset() {
+ mGlobalGids = NO_GIDS;
+ mPermissions = null;
+ }
+
+ private int grantPermission(BasePermission permission, int userId) {
+ if (hasPermission(permission.name, userId)) {
+ return PERMISSION_OPERATION_FAILURE;
+ }
+
+ final boolean hasGids = permission.hasGids();
+ final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
+
+ if (mPermissions == null) {
+ mPermissions = new ArrayMap<>();
+ }
+
+ PermissionData permissionData = mPermissions.get(permission.name);
+ if (permissionData == null) {
+ permissionData = new PermissionData(permission);
+ mPermissions.put(permission.name, permissionData);
+ }
+
+ if (!permissionData.addUserId(userId)) {
+ return PERMISSION_OPERATION_FAILURE;
+ }
+
+ if (hasGids) {
+ final int[] newGids = computeGids(userId);
+ if (oldGids.length != newGids.length) {
+ return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
+ }
+ }
+
+ return PERMISSION_OPERATION_SUCCESS;
+ }
+
+ private int revokePermission(BasePermission permission, int userId) {
+ if (!hasPermission(permission.name, userId)) {
+ return PERMISSION_OPERATION_FAILURE;
+ }
+
+ final boolean hasGids = permission.hasGids();
+ final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
+
+ PermissionData permissionData = mPermissions.get(permission.name);
+
+ if (!permissionData.removeUserId(userId)) {
+ return PERMISSION_OPERATION_FAILURE;
+ }
+
+ if (permissionData.getUserIds() == USERS_NONE) {
+ mPermissions.remove(permission.name);
+ }
+
+ if (mPermissions.isEmpty()) {
+ mPermissions = null;
+ }
+
+ if (hasGids) {
+ final int[] newGids = computeGids(userId);
+ if (oldGids.length != newGids.length) {
+ return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
+ }
+ }
+
+ return PERMISSION_OPERATION_SUCCESS;
+ }
+
+ private static int[] appendInts(int[] current, int[] added) {
+ if (current != null && added != null) {
+ for (int guid : added) {
+ current = ArrayUtils.appendInt(current, guid);
+ }
+ }
+ return current;
+ }
+
+ private static void enforceValidUserId(int userId) {
+ if (userId != UserHandle.USER_ALL && userId < 0) {
+ throw new IllegalArgumentException("Invalid userId:" + userId);
+ }
+ }
+
+ private static final class PermissionData {
+ private final BasePermission mPerm;
+ private int[] mUserIds = USERS_NONE;
+
+ public PermissionData(BasePermission perm) {
+ mPerm = perm;
+ }
+
+ public PermissionData(PermissionData other) {
+ this(other.mPerm);
+
+ if (other.mUserIds == USERS_ALL || other.mUserIds == USERS_NONE) {
+ mUserIds = other.mUserIds;
+ } else {
+ mUserIds = Arrays.copyOf(other.mUserIds, other.mUserIds.length);
+ }
+ }
+
+ public boolean hasGids() {
+ return mPerm.hasGids();
+ }
+
+ public int[] computeGids(int userId) {
+ return mPerm.computeGids(userId);
+ }
+
+ public int[] getUserIds() {
+ return mUserIds;
+ }
+
+ public boolean hasUserId(int userId) {
+ if (mUserIds == USERS_ALL) {
+ return true;
+ }
+
+ if (userId != UserHandle.USER_ALL) {
+ return ArrayUtils.contains(mUserIds, userId);
+ }
+
+ return false;
+ }
+
+ public boolean addUserId(int userId) {
+ if (hasUserId(userId)) {
+ return false;
+ }
+
+ if (userId == UserHandle.USER_ALL) {
+ mUserIds = USERS_ALL;
+ return true;
+ }
+
+ mUserIds = ArrayUtils.appendInt(mUserIds, userId);
+
+ return true;
+ }
+
+ public boolean removeUserId(int userId) {
+ if (!hasUserId(userId)) {
+ return false;
+ }
+
+ if (mUserIds == USERS_ALL) {
+ mUserIds = UserManagerService.getInstance().getUserIds();
+ }
+
+ mUserIds = ArrayUtils.removeInt(mUserIds, userId);
+
+ if (mUserIds.length == 0) {
+ mUserIds = USERS_NONE;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/GrantedPermissions.java b/services/core/java/com/android/server/pm/SettingBase.java
index e87546cef8b0..3a7b6eea1ae7 100644
--- a/services/core/java/com/android/server/pm/GrantedPermissions.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -17,28 +17,46 @@
package com.android.server.pm;
import android.content.pm.ApplicationInfo;
-import android.util.ArraySet;
-class GrantedPermissions {
+import java.util.Arrays;
+
+abstract class SettingBase {
int pkgFlags;
int pkgPrivateFlags;
- ArraySet<String> grantedPermissions = new ArraySet<String>();
-
- int[] gids;
+ private final PermissionsState mPermissionsState;
+ private int[] mPermissionsUpdatedForUserIds = PermissionsState.USERS_NONE;
- GrantedPermissions(int pkgFlags, int pkgPrivateFlags) {
+ SettingBase(int pkgFlags, int pkgPrivateFlags) {
setFlags(pkgFlags);
setPrivateFlags(pkgPrivateFlags);
+ mPermissionsState = new PermissionsState();
}
- @SuppressWarnings("unchecked")
- GrantedPermissions(GrantedPermissions base) {
+ SettingBase(SettingBase base) {
pkgFlags = base.pkgFlags;
- grantedPermissions = new ArraySet<>(base.grantedPermissions);
+ pkgPrivateFlags = base.pkgPrivateFlags;
+ mPermissionsState = new PermissionsState(base.mPermissionsState);
+ setPermissionsUpdatedForUserIds(base.mPermissionsUpdatedForUserIds);
+ }
+
+ public PermissionsState getPermissionsState() {
+ return mPermissionsState;
+ }
+
+ public int[] getPermissionsUpdatedForUserIds() {
+ return mPermissionsUpdatedForUserIds;
+ }
+
+ public void setPermissionsUpdatedForUserIds(int[] userIds) {
+ if (Arrays.equals(mPermissionsUpdatedForUserIds, userIds)) {
+ return;
+ }
- if (base.gids != null) {
- gids = base.gids.clone();
+ if (userIds == PermissionsState.USERS_NONE || userIds == PermissionsState.USERS_ALL) {
+ mPermissionsUpdatedForUserIds = userIds;
+ } else {
+ mPermissionsUpdatedForUserIds = Arrays.copyOf(userIds, userIds.length);
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index b820d7e85182..0a2389f93ca8 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -25,6 +25,7 @@ import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.PACKAGE_INFO_GID;
+import android.content.Context;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
@@ -33,17 +34,27 @@ import android.os.Binder;
import android.os.Build;
import android.os.Environment;
import android.os.FileUtils;
+import android.os.Handler;
+import android.os.Message;
import android.os.PatternMatcher;
import android.os.Process;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.AtomicFile;
import android.util.LogPrinter;
+import android.util.SparseBooleanArray;
+import android.util.SparseLongArray;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
import com.android.server.pm.PackageManagerService.DumpState;
+import java.io.FileNotFoundException;
import java.util.Collection;
import org.xmlpull.v1.XmlPullParser;
@@ -51,7 +62,6 @@ import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
@@ -134,6 +144,8 @@ final class Settings {
private static final boolean DEBUG_STOPPED = false;
private static final boolean DEBUG_MU = false;
+ private static final String RUNTIME_PERMISSIONS_FILE_NAME = "runtime-permissions.xml";
+
private static final String TAG_READ_EXTERNAL_STORAGE = "read-external-storage";
private static final String ATTR_ENFORCEMENT = "enforcement";
@@ -142,6 +154,9 @@ final class Settings {
private static final String TAG_ENABLED_COMPONENTS = "enabled-components";
private static final String TAG_PACKAGE_RESTRICTIONS = "package-restrictions";
private static final String TAG_PACKAGE = "pkg";
+ private static final String TAG_SHARED_USER = "shared-user";
+ private static final String TAG_RUNTIME_PERMISSIONS = "runtime-permissions";
+ private static final String TAG_PERMISSIONS = "perms";
private static final String TAG_PERSISTENT_PREFERRED_ACTIVITIES =
"persistent-preferred-activities";
static final String TAG_CROSS_PROFILE_INTENT_FILTERS =
@@ -160,6 +175,12 @@ final class Settings {
private static final String ATTR_HIDDEN = "hidden";
private static final String ATTR_INSTALLED = "inst";
private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
+ private static final String ATTR_RUNTIME_PERMSISSIONS_ENABLED = "runtime-permissions-enabled";
+
+ private final Object mLock;
+ private final Context mContext;
+
+ private final RuntimePermissionPersistence mRuntimePermissionsPersistence;
private final File mSettingsFilename;
private final File mBackupSettingsFilename;
@@ -181,6 +202,10 @@ final class Settings {
int mInternalSdkPlatform;
int mExternalSdkPlatform;
+
+ // Whether runtime permissions are enabled.
+ boolean mRuntimePermissionEnabled;
+
/**
* The current database version for apps on internal storage. This is
* used to upgrade the format of the packages.xml database not necessarily
@@ -257,11 +282,16 @@ final class Settings {
public final KeySetManagerService mKeySetManagerService = new KeySetManagerService(mPackages);
- Settings(Context context) {
- this(context, Environment.getDataDirectory());
+ Settings(Context context, Object lock) {
+ this(context, Environment.getDataDirectory(), lock);
}
- Settings(Context context, File dataDir) {
+ Settings(Context context, File dataDir, Object lock) {
+ mContext = context;
+ mLock = lock;
+
+ mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);
+
mSystemDir = new File(dataDir, "system");
mSystemDir.mkdirs();
FileUtils.setPermissions(mSystemDir.toString(),
@@ -460,7 +490,7 @@ final class Settings {
bp.pendingInfo.packageName = newPkg;
}
bp.uid = 0;
- bp.gids = null;
+ bp.setGids(null, false);
}
}
}
@@ -468,9 +498,9 @@ final class Settings {
private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
- String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,
- int vc, int pkgFlags, int pkgPrivateFlags, UserHandle installUser, boolean add,
- boolean allowInstall) {
+ String legacyNativeLibraryPathString, String primaryCpuAbiString,
+ String secondaryCpuAbiString, int vc, int pkgFlags, int pkgPrivateFlags,
+ UserHandle installUser, boolean add, boolean allowInstall) {
PackageSetting p = mPackages.get(name);
UserManagerService userManager = UserManagerService.getInstance();
if (p != null) {
@@ -589,7 +619,7 @@ final class Settings {
}
p.appId = dis.appId;
// Clone permissions
- p.grantedPermissions = new ArraySet<String>(dis.grantedPermissions);
+ p.getPermissionsState().copyFrom(dis.getPermissionsState());
// Clone component info
List<UserInfo> users = getAllUsers();
if (users != null) {
@@ -732,45 +762,60 @@ final class Settings {
* not in use by other permissions of packages in the
* shared user setting.
*/
- void updateSharedUserPermsLPw(PackageSetting deletedPs, int[] globalGids) {
+ int updateSharedUserPermsLPw(PackageSetting deletedPs, int userId) {
if ((deletedPs == null) || (deletedPs.pkg == null)) {
Slog.i(PackageManagerService.TAG,
"Trying to update info for null package. Just ignoring");
- return;
+ return UserHandle.USER_NULL;
}
+
// No sharedUserId
if (deletedPs.sharedUser == null) {
- return;
+ return UserHandle.USER_NULL;
}
+
SharedUserSetting sus = deletedPs.sharedUser;
+
// Update permissions
for (String eachPerm : deletedPs.pkg.requestedPermissions) {
- boolean used = false;
- if (!sus.grantedPermissions.contains(eachPerm)) {
+ BasePermission bp = mPermissions.get(eachPerm);
+ if (bp == null) {
continue;
}
- for (PackageSetting pkg:sus.packages) {
- if (pkg.pkg != null &&
- !pkg.pkg.packageName.equals(deletedPs.pkg.packageName) &&
- pkg.pkg.requestedPermissions.contains(eachPerm)) {
+
+ // If no user has the permission, nothing to remove.
+ if (!sus.getPermissionsState().hasPermission(bp.name, userId)) {
+ continue;
+ }
+
+ boolean used = false;
+
+ // Check if another package in the shared user needs the permission.
+ for (PackageSetting pkg : sus.packages) {
+ if (pkg.pkg != null
+ && !pkg.pkg.packageName.equals(deletedPs.pkg.packageName)
+ && pkg.pkg.requestedPermissions.contains(eachPerm)) {
used = true;
break;
}
}
+
if (!used) {
- // can safely delete this permission from list
- sus.grantedPermissions.remove(eachPerm);
- }
- }
- // Update gids
- int newGids[] = globalGids;
- for (String eachPerm : sus.grantedPermissions) {
- BasePermission bp = mPermissions.get(eachPerm);
- if (bp != null) {
- newGids = PackageManagerService.appendInts(newGids, bp.gids);
+ // Try to revoke as an install permission which is for all users.
+ if (sus.getPermissionsState().revokeInstallPermission(bp) ==
+ PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
+ return UserHandle.USER_ALL;
+ }
+
+ // Try to revoke as an install permission which is per user.
+ if (sus.getPermissionsState().revokeRuntimePermission(bp, userId) ==
+ PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
+ return userId;
+ }
}
}
- sus.gids = newGids;
+
+ return UserHandle.USER_NULL;
}
int removePackageLPw(String name) {
@@ -895,7 +940,17 @@ final class Settings {
}
private File getUserPackagesStateFile(int userId) {
- return new File(Environment.getUserSystemDirectory(userId), "package-restrictions.xml");
+ // TODO: Implement a cleaner solution when adding tests.
+ // This instead of Environment.getUserSystemDirectory(userId) to support testing.
+ File userDir = new File(new File(mSystemDir, "users"), Integer.toString(userId));
+ return new File(userDir, "package-restrictions.xml");
+ }
+
+ private File getUserRuntimePermissionsFile(int userId) {
+ // TODO: Implement a cleaner solution when adding tests.
+ // This instead of Environment.getUserSystemDirectory(userId) to support testing.
+ File userDir = new File(new File(mSystemDir, "users"), Integer.toString(userId));
+ return new File(userDir, RUNTIME_PERMISSIONS_FILE_NAME);
}
private File getUserPackagesStateBackupFile(int userId) {
@@ -912,15 +967,9 @@ final class Settings {
}
}
- void readAllUsersPackageRestrictionsLPr() {
- List<UserInfo> users = getAllUsers();
- if (users == null) {
- readPackageRestrictionsLPr(0);
- return;
- }
-
- for (UserInfo user : users) {
- readPackageRestrictionsLPr(user.id);
+ void writeAllRuntimePermissionsLPr() {
+ for (int userId : UserManagerService.getInstance().getUserIds()) {
+ mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId);
}
}
@@ -1360,6 +1409,7 @@ final class Settings {
}
serializer.endTag(null, TAG_DISABLED_COMPONENTS);
}
+
serializer.endTag(null, TAG_PACKAGE);
}
}
@@ -1403,6 +1453,58 @@ final class Settings {
}
}
+ void readInstallPermissionsLPr(XmlPullParser parser,
+ PermissionsState permissionsState) throws IOException, XmlPullParserException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG
+ || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_ITEM)) {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+
+ BasePermission bp = mPermissions.get(name);
+ if (bp == null) {
+ Slog.w(PackageManagerService.TAG, "Unknown permission: " + name);
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+
+ if (permissionsState.grantInstallPermission(bp) ==
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ Slog.w(PackageManagerService.TAG, "Permission already added: " + name);
+ XmlUtils.skipCurrentTag(parser);
+ }
+ } else {
+ Slog.w(PackageManagerService.TAG, "Unknown element under <permissions>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ void writePermissionsLPr(XmlSerializer serializer, Set<String> permissions)
+ throws IOException {
+ if (permissions.isEmpty()) {
+ return;
+ }
+
+ serializer.startTag(null, TAG_PERMISSIONS);
+
+ for (String permission : permissions) {
+ serializer.startTag(null, TAG_ITEM);
+ serializer.attribute(null, ATTR_NAME, permission);
+ serializer.endTag(null, TAG_ITEM);
+ }
+
+ serializer.endTag(null, TAG_PERMISSIONS);
+ }
+
// Note: assumed "stopped" field is already cleared in all packages.
// Legacy reader, used to read in the old file format after an upgrade. Not used after that.
void readStoppedLPw() {
@@ -1548,6 +1650,8 @@ final class Settings {
serializer.attribute(null, "internal", Integer.toString(mInternalSdkPlatform));
serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform));
serializer.attribute(null, "fingerprint", mFingerprint);
+ serializer.attribute(null, ATTR_RUNTIME_PERMSISSIONS_ENABLED,
+ String.valueOf(PackageManagerService.RUNTIME_PERMISSIONS_ENABLED));
serializer.endTag(null, "last-platform-version");
serializer.startTag(null, "database-version");
@@ -1594,13 +1698,7 @@ final class Settings {
serializer.attribute(null, "userId",
Integer.toString(usr.userId));
usr.signatures.writeXml(serializer, "sigs", mPastSignatures);
- serializer.startTag(null, "perms");
- for (String name : usr.grantedPermissions) {
- serializer.startTag(null, TAG_ITEM);
- serializer.attribute(null, ATTR_NAME, name);
- serializer.endTag(null, TAG_ITEM);
- }
- serializer.endTag(null, "perms");
+ writePermissionsLPr(serializer, usr.getPermissionsState().getInstallPermissions());
serializer.endTag(null, "shared-user");
}
@@ -1614,7 +1712,7 @@ final class Settings {
serializer.endTag(null, "cleaning-package");
}
}
-
+
if (mRenamedPackages.size() > 0) {
for (Map.Entry<String, String> e : mRenamedPackages.entrySet()) {
serializer.startTag(null, "renamed-package");
@@ -1623,7 +1721,7 @@ final class Settings {
serializer.endTag(null, "renamed-package");
}
}
-
+
mKeySetManagerService.writeKeySetManagerServiceLPr(serializer);
serializer.endTag(null, "packages");
@@ -1662,7 +1760,7 @@ final class Settings {
final ApplicationInfo ai = pkg.pkg.applicationInfo;
final String dataPath = ai.dataDir;
final boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
- final int[] gids = pkg.getGids();
+ final int[] gids = pkg.getPermissionsState().computeGids();
// Avoid any application that has a space in its path.
if (dataPath.indexOf(" ") >= 0)
@@ -1718,6 +1816,8 @@ final class Settings {
}
writeAllUsersPackageRestrictionsLPr();
+
+ writeAllRuntimePermissionsLPr();
return;
} catch(XmlPullParserException e) {
@@ -1770,26 +1870,12 @@ final class Settings {
} else {
serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId));
}
- serializer.startTag(null, "perms");
+
+ // If this is a shared user, the permissions will be written there.
if (pkg.sharedUser == null) {
- // If this is a shared user, the permissions will
- // be written there. We still need to write an
- // empty permissions list so permissionsFixed will
- // be set.
- for (final String name : pkg.grantedPermissions) {
- BasePermission bp = mPermissions.get(name);
- if (bp != null) {
- // We only need to write signature or system permissions but
- // this wont
- // match the semantics of grantedPermissions. So write all
- // permissions.
- serializer.startTag(null, TAG_ITEM);
- serializer.attribute(null, ATTR_NAME, name);
- serializer.endTag(null, TAG_ITEM);
- }
- }
+ writePermissionsLPr(serializer, pkg.getPermissionsState().getInstallPermissions());
}
- serializer.endTag(null, "perms");
+
serializer.endTag(null, "updated-package");
}
@@ -1840,19 +1926,7 @@ final class Settings {
}
pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
if ((pkg.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
- serializer.startTag(null, "perms");
- if (pkg.sharedUser == null) {
- // If this is a shared user, the permissions will
- // be written there. We still need to write an
- // empty permissions list so permissionsFixed will
- // be set.
- for (final String name : pkg.grantedPermissions) {
- serializer.startTag(null, TAG_ITEM);
- serializer.attribute(null, ATTR_NAME, name);
- serializer.endTag(null, TAG_ITEM);
- }
- }
- serializer.endTag(null, "perms");
+ writePermissionsLPr(serializer, pkg.getPermissionsState().getInstallPermissions());
}
writeSigningKeySetsLPr(serializer, pkg.keySetData);
@@ -2074,6 +2148,8 @@ final class Settings {
} catch (NumberFormatException e) {
}
mFingerprint = parser.getAttributeValue(null, "fingerprint");
+ mRuntimePermissionEnabled = XmlUtils.readBooleanAttribute(parser,
+ ATTR_RUNTIME_PERMSISSIONS_ENABLED);
} else if (tagName.equals("database-version")) {
mInternalDatabaseVersion = mExternalDatabaseVersion = 0;
try {
@@ -2161,9 +2237,11 @@ final class Settings {
} else {
if (users == null) {
readPackageRestrictionsLPr(0);
+ mRuntimePermissionsPersistence.readStateForUserSyncLPr(UserHandle.USER_OWNER);
} else {
for (UserInfo user : users) {
readPackageRestrictionsLPr(user.id);
+ mRuntimePermissionsPersistence.readStateForUserSyncLPr(user.id);
}
}
}
@@ -2537,7 +2615,7 @@ final class Settings {
final String ptype = parser.getAttributeValue(null, "type");
if (name != null && sourcePackage != null) {
final boolean dynamic = "dynamic".equals(ptype);
- final BasePermission bp = new BasePermission(name, sourcePackage,
+ final BasePermission bp = new BasePermission(name.intern(), sourcePackage,
dynamic ? BasePermission.TYPE_DYNAMIC : BasePermission.TYPE_NORMAL);
bp.protectionLevel = readInt(parser, null, "protection",
PermissionInfo.PROTECTION_NORMAL);
@@ -2643,6 +2721,7 @@ final class Settings {
String sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
ps.appId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
}
+
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -2651,9 +2730,8 @@ final class Settings {
continue;
}
- String tagName = parser.getName();
- if (tagName.equals("perms")) {
- readGrantedPermissionsLPw(parser, ps.grantedPermissions);
+ if (parser.getName().equals(TAG_PERMISSIONS)) {
+ readInstallPermissionsLPr(parser, ps.getPermissionsState());
} else {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Unknown element under <updated-package>: " + parser.getName());
@@ -2711,7 +2789,7 @@ final class Settings {
if (primaryCpuAbiString == null && legacyCpuAbiString != null) {
primaryCpuAbiString = legacyCpuAbiString;
}
-;
+
version = parser.getAttributeValue(null, "version");
if (version != null) {
try {
@@ -2902,7 +2980,6 @@ final class Settings {
packageSetting.installStatus = PackageSettingBase.PKG_INSTALL_COMPLETE;
}
}
-
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -2919,9 +2996,10 @@ final class Settings {
readEnabledComponentsLPw(packageSetting, parser, 0);
} else if (tagName.equals("sigs")) {
packageSetting.signatures.readXml(parser, mPastSignatures);
- } else if (tagName.equals("perms")) {
- readGrantedPermissionsLPw(parser, packageSetting.grantedPermissions);
- packageSetting.permissionsFixed = true;
+ } else if (tagName.equals(TAG_PERMISSIONS)) {
+ readInstallPermissionsLPr(parser,
+ packageSetting.getPermissionsState());
+ packageSetting.installPermissionsFixed = true;
} else if (tagName.equals("proper-signing-keyset")) {
long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
packageSetting.keySetData.setProperSigningKeySet(id);
@@ -2941,8 +3019,6 @@ final class Settings {
XmlUtils.skipCurrentTag(parser);
}
}
-
-
} else {
XmlUtils.skipCurrentTag(parser);
}
@@ -3039,7 +3115,6 @@ final class Settings {
"Error in package manager settings: package " + name + " has bad userId "
+ idStr + " at " + parser.getPositionDescription());
}
- ;
if (su != null) {
int outerDepth = parser.getDepth();
@@ -3054,47 +3129,18 @@ final class Settings {
if (tagName.equals("sigs")) {
su.signatures.readXml(parser, mPastSignatures);
} else if (tagName.equals("perms")) {
- readGrantedPermissionsLPw(parser, su.grantedPermissions);
+ readInstallPermissionsLPr(parser, su.getPermissionsState());
} else {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Unknown element under <shared-user>: " + parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}
-
} else {
XmlUtils.skipCurrentTag(parser);
}
}
- private void readGrantedPermissionsLPw(XmlPullParser parser, ArraySet<String> outPerms)
- throws IOException, XmlPullParserException {
- int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals(TAG_ITEM)) {
- String name = parser.getAttributeValue(null, ATTR_NAME);
- if (name != null) {
- outPerms.add(name.intern());
- } else {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <perms> has" + " no name at "
- + parser.getPositionDescription());
- }
- } else {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Unknown element under <perms>: " + parser.getName());
- }
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
void createNewUserLILPw(PackageManagerService service, Installer installer,
int userHandle, File path) {
path.mkdir();
@@ -3126,6 +3172,8 @@ final class Settings {
file = getUserPackagesStateBackupFile(userId);
file.delete();
removeCrossProfileIntentFiltersLPw(userId);
+
+ mRuntimePermissionsPersistence.onUserRemoved(userId);
}
void removeCrossProfileIntentFiltersLPw(int userId) {
@@ -3317,7 +3365,7 @@ final class Settings {
return null;
}
- static final void printFlags(PrintWriter pw, int val, Object[] spec) {
+ static void printFlags(PrintWriter pw, int val, Object[] spec) {
pw.print("[ ");
for (int i=0; i<spec.length; i+=2) {
int mask = (Integer)spec[i];
@@ -3414,8 +3462,8 @@ final class Settings {
pw.println(ps.name);
}
- pw.print(prefix); pw.print(" userId="); pw.print(ps.appId);
- pw.print(" gids="); pw.println(PackageManagerService.arrayToString(ps.gids));
+ pw.print(prefix); pw.print(" userId="); pw.println(ps.appId);
+
if (ps.sharedUser != null) {
pw.print(prefix); pw.print(" sharedUser="); pw.println(ps.sharedUser);
}
@@ -3524,11 +3572,17 @@ final class Settings {
pw.println(ps.installerPackageName);
}
pw.print(prefix); pw.print(" signatures="); pw.println(ps.signatures);
- pw.print(prefix); pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
- pw.print(" haveGids="); pw.print(ps.haveGids);
+ pw.print(prefix); pw.print(" installPermissionsFixed=");
+ pw.print(ps.installPermissionsFixed);
pw.print(" installStatus="); pw.println(ps.installStatus);
pw.print(prefix); pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
pw.println();
+
+ if (ps.sharedUser == null) {
+ PermissionsState permissionsState = ps.getPermissionsState();
+ dumpInstallPermissionsLPr(pw, prefix + " ", permissionsState);
+ }
+
for (UserInfo user : users) {
pw.print(prefix); pw.print(" User "); pw.print(user.id); pw.print(": ");
pw.print(" installed=");
@@ -3546,6 +3600,14 @@ final class Settings {
pw.print(prefix); pw.print(" lastDisabledCaller: ");
pw.println(lastDisabledAppCaller);
}
+
+ if (ps.sharedUser == null) {
+ PermissionsState permissionsState = ps.getPermissionsState();
+ dumpGidsLPr(pw, prefix + " ", permissionsState.computeGids(user.id));
+ dumpRuntimePermissionsLPr(pw, prefix + " ", permissionsState
+ .getRuntimePermissions(user.id));
+ }
+
ArraySet<String> cmp = ps.getDisabledComponents(user.id);
if (cmp != null && cmp.size() > 0) {
pw.print(prefix); pw.println(" disabledComponents:");
@@ -3561,12 +3623,6 @@ final class Settings {
}
}
}
- if (ps.grantedPermissions.size() > 0) {
- pw.print(prefix); pw.println(" grantedPermissions:");
- for (String s : ps.grantedPermissions) {
- pw.print(prefix); pw.print(" "); pw.println(s);
- }
- }
}
void dumpPackagesLPr(PrintWriter pw, String packageName, DumpState dumpState, boolean checkin) {
@@ -3652,7 +3708,8 @@ final class Settings {
pw.println("):");
pw.print(" sourcePackage="); pw.println(p.sourcePackage);
pw.print(" uid="); pw.print(p.uid);
- pw.print(" gids="); pw.print(PackageManagerService.arrayToString(p.gids));
+ pw.print(" gids="); pw.print(Arrays.toString(
+ p.computeGids(UserHandle.USER_OWNER)));
pw.print(" type="); pw.print(p.type);
pw.print(" prot=");
pw.println(PermissionInfo.protectionToString(p.protectionLevel));
@@ -3688,14 +3745,21 @@ final class Settings {
pw.print("] (");
pw.print(Integer.toHexString(System.identityHashCode(su)));
pw.println("):");
- pw.print(" userId=");
- pw.print(su.userId);
- pw.print(" gids=");
- pw.println(PackageManagerService.arrayToString(su.gids));
- pw.println(" grantedPermissions:");
- for (String s : su.grantedPermissions) {
- pw.print(" ");
- pw.println(s);
+
+ String prefix = " ";
+ pw.print(prefix); pw.print("userId="); pw.println(su.userId);
+
+ PermissionsState permissionsState = su.getPermissionsState();
+ dumpInstallPermissionsLPr(pw, prefix, permissionsState);
+
+ for (int userId : UserManagerService.getInstance().getUserIds()) {
+ final int[] gids = permissionsState.computeGids(userId);
+ Set<String> permissions = permissionsState.getRuntimePermissions(userId);
+ if (!ArrayUtils.isEmpty(gids) || !permissions.isEmpty()) {
+ pw.print(prefix); pw.print("User "); pw.print(userId); pw.println(": ");
+ dumpGidsLPr(pw, prefix + " ", gids);
+ dumpRuntimePermissionsLPr(pw, prefix + " ", permissions);
+ }
}
} else {
pw.print("suid,"); pw.print(su.userId); pw.print(","); pw.println(su.name);
@@ -3730,4 +3794,373 @@ final class Settings {
pw.print("]");
}
}
+
+ void dumpGidsLPr(PrintWriter pw, String prefix, int[] gids) {
+ if (!ArrayUtils.isEmpty(gids)) {
+ pw.print(prefix); pw.print("gids="); pw.println(
+ PackageManagerService.arrayToString(gids));
+ }
+ }
+
+ void dumpRuntimePermissionsLPr(PrintWriter pw, String prefix, Set<String> permissions) {
+ if (!permissions.isEmpty()) {
+ pw.print(prefix); pw.println("runtime permissions:");
+ for (String permission : permissions) {
+ pw.print(prefix); pw.print(" "); pw.println(permission);
+ }
+ }
+ }
+
+ void dumpInstallPermissionsLPr(PrintWriter pw, String prefix,
+ PermissionsState permissionsState) {
+ Set<String> permissions = permissionsState.getInstallPermissions();
+ if (!permissions.isEmpty()) {
+ pw.print(prefix); pw.println("install permissions:");
+ for (String permission : permissions) {
+ pw.print(prefix); pw.print(" "); pw.println(permission);
+ }
+ }
+ }
+
+ public void writeRuntimePermissionsForUserLPr(int userId, boolean sync) {
+ if (sync) {
+ mRuntimePermissionsPersistence.writePermissionsForUserSyncLPr(userId);
+ } else {
+ mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId);
+ }
+ }
+
+ private final class RuntimePermissionPersistence {
+ private static final long WRITE_PERMISSIONS_DELAY_MILLIS = 200;
+
+ private static final long MAX_WRITE_PERMISSIONS_DELAY_MILLIS = 2000;
+
+ private final Handler mHandler = new MyHandler();
+
+ private final Object mLock;
+
+ @GuardedBy("mLock")
+ private SparseBooleanArray mWriteScheduled = new SparseBooleanArray();
+
+ @GuardedBy("mLock")
+ private SparseLongArray mLastNotWrittenMutationTimesMillis = new SparseLongArray();
+
+ public RuntimePermissionPersistence(Object lock) {
+ mLock = lock;
+ }
+
+ public void writePermissionsForUserSyncLPr(int userId) {
+ mHandler.removeMessages(userId);
+ writePermissionsSync(userId);
+ }
+
+ public void writePermissionsForUserAsyncLPr(int userId) {
+ final long currentTimeMillis = SystemClock.uptimeMillis();
+
+ if (mWriteScheduled.get(userId)) {
+ mHandler.removeMessages(userId);
+
+ // If enough time passed, write without holding off anymore.
+ final long lastNotWrittenMutationTimeMillis = mLastNotWrittenMutationTimesMillis
+ .get(userId);
+ final long timeSinceLastNotWrittenMutationMillis = currentTimeMillis
+ - lastNotWrittenMutationTimeMillis;
+ if (timeSinceLastNotWrittenMutationMillis >= MAX_WRITE_PERMISSIONS_DELAY_MILLIS) {
+ mHandler.obtainMessage(userId).sendToTarget();
+ return;
+ }
+
+ // Hold off a bit more as settings are frequently changing.
+ final long maxDelayMillis = Math.max(lastNotWrittenMutationTimeMillis
+ + MAX_WRITE_PERMISSIONS_DELAY_MILLIS - currentTimeMillis, 0);
+ final long writeDelayMillis = Math.min(WRITE_PERMISSIONS_DELAY_MILLIS,
+ maxDelayMillis);
+
+ Message message = mHandler.obtainMessage(userId);
+ mHandler.sendMessageDelayed(message, writeDelayMillis);
+ } else {
+ mLastNotWrittenMutationTimesMillis.put(userId, currentTimeMillis);
+ Message message = mHandler.obtainMessage(userId);
+ mHandler.sendMessageDelayed(message, WRITE_PERMISSIONS_DELAY_MILLIS);
+ mWriteScheduled.put(userId, true);
+ }
+ }
+
+ private void writePermissionsSync(int userId) {
+ AtomicFile destination = new AtomicFile(getUserRuntimePermissionsFile(userId));
+
+ ArrayMap<String, Set<String>> permissionsForPackage = new ArrayMap<>();
+ ArrayMap<String, Set<String>> permissionsForSharedUser = new ArrayMap<>();
+
+ synchronized (mLock) {
+ mWriteScheduled.delete(userId);
+
+ final int packageCount = mPackages.size();
+ for (int i = 0; i < packageCount; i++) {
+ String packageName = mPackages.keyAt(i);
+ PackageSetting packageSetting = mPackages.valueAt(i);
+ if (packageSetting.sharedUser == null) {
+ PermissionsState permissionsState = packageSetting.getPermissionsState();
+ Set<String> permissions = permissionsState.getRuntimePermissions(userId);
+ if (!permissions.isEmpty()) {
+ permissionsForPackage.put(packageName, permissions);
+ }
+ }
+ }
+
+ final int sharedUserCount = mSharedUsers.size();
+ for (int i = 0; i < sharedUserCount; i++) {
+ String sharedUserName = mSharedUsers.keyAt(i);
+ SharedUserSetting sharedUser = mSharedUsers.valueAt(i);
+ PermissionsState permissionsState = sharedUser.getPermissionsState();
+ Set<String> permissions = permissionsState.getRuntimePermissions(userId);
+ if (!permissions.isEmpty()) {
+ permissionsForSharedUser.put(sharedUserName, permissions);
+ }
+ }
+ }
+
+ FileOutputStream out = null;
+ try {
+ out = destination.startWrite();
+
+ XmlSerializer serializer = Xml.newSerializer();
+ serializer.setOutput(out, "utf-8");
+ serializer.setFeature(
+ "http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ serializer.startDocument(null, true);
+ serializer.startTag(null, TAG_RUNTIME_PERMISSIONS);
+
+ final int packageCount = permissionsForPackage.size();
+ for (int i = 0; i < packageCount; i++) {
+ String packageName = permissionsForPackage.keyAt(i);
+ Set<String> permissions = permissionsForPackage.valueAt(i);
+ serializer.startTag(null, TAG_PACKAGE);
+ serializer.attribute(null, ATTR_NAME, packageName);
+ writePermissions(serializer, permissions);
+ serializer.endTag(null, TAG_PACKAGE);
+ }
+
+ final int sharedUserCount = permissionsForSharedUser.size();
+ for (int i = 0; i < sharedUserCount; i++) {
+ String packageName = permissionsForSharedUser.keyAt(i);
+ Set<String> permissions = permissionsForSharedUser.valueAt(i);
+ serializer.startTag(null, TAG_SHARED_USER);
+ serializer.attribute(null, ATTR_NAME, packageName);
+ writePermissions(serializer, permissions);
+ serializer.endTag(null, TAG_SHARED_USER);
+ }
+
+ serializer.endTag(null, TAG_RUNTIME_PERMISSIONS);
+ serializer.endDocument();
+ destination.finishWrite(out);
+ } catch (IOException e) {
+ Slog.wtf(PackageManagerService.TAG,
+ "Failed to write settings, restoring backup", e);
+ destination.failWrite(out);
+ } finally {
+ IoUtils.closeQuietly(out);
+ }
+ }
+
+ private void onUserRemoved(int userId) {
+ // Make sure we do not
+ mHandler.removeMessages(userId);
+
+ for (SettingBase sb : mPackages.values()) {
+ revokeRuntimePermissions(sb, userId);
+ }
+
+ for (SettingBase sb : mSharedUsers.values()) {
+ revokeRuntimePermissions(sb, userId);
+ }
+ }
+
+ private void revokeRuntimePermissions(SettingBase sb, int userId) {
+ PermissionsState permissionsState = sb.getPermissionsState();
+ for (String permission : permissionsState.getRuntimePermissions(userId)) {
+ BasePermission bp = mPermissions.get(permission);
+ if (bp != null) {
+ permissionsState.revokeRuntimePermission(bp, userId);
+ }
+ }
+ }
+
+ public void readStateForUserSyncLPr(int userId) {
+ File permissionsFile = getUserRuntimePermissionsFile(userId);
+ if (!permissionsFile.exists()) {
+ return;
+ }
+
+ FileInputStream in;
+ try {
+ in = new FileInputStream(permissionsFile);
+ } catch (FileNotFoundException fnfe) {
+ Slog.i(PackageManagerService.TAG, "No permissions state");
+ return;
+ }
+
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+ parseRuntimePermissionsLPr(parser, userId);
+ } catch (XmlPullParserException | IOException ise) {
+ throw new IllegalStateException("Failed parsing permissions file: "
+ + permissionsFile , ise);
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ }
+
+ private void parseRuntimePermissionsLPr(XmlPullParser parser, int userId)
+ throws IOException, XmlPullParserException {
+ parser.next();
+ skipEmptyTextTags(parser);
+ if (!accept(parser, XmlPullParser.START_TAG, TAG_RUNTIME_PERMISSIONS)) {
+ return;
+ }
+
+ parser.next();
+
+ while (parsePackageLPr(parser, userId)
+ || parseSharedUserLPr(parser, userId)) {
+ parser.next();
+ }
+
+ skipEmptyTextTags(parser);
+ expect(parser, XmlPullParser.END_TAG, TAG_RUNTIME_PERMISSIONS);
+ }
+
+ private boolean parsePackageLPr(XmlPullParser parser, int userId)
+ throws IOException, XmlPullParserException {
+ skipEmptyTextTags(parser);
+ if (!accept(parser, XmlPullParser.START_TAG, TAG_PACKAGE)) {
+ return false;
+ }
+
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+
+ parser.next();
+
+ PackageSetting ps = mPackages.get(name);
+ if (ps != null) {
+ while (parsePermissionLPr(parser, ps.getPermissionsState(), userId)) {
+ parser.next();
+ }
+ }
+
+ skipEmptyTextTags(parser);
+ expect(parser, XmlPullParser.END_TAG, TAG_PACKAGE);
+
+ return true;
+ }
+
+ private boolean parseSharedUserLPr(XmlPullParser parser, int userId)
+ throws IOException, XmlPullParserException {
+ skipEmptyTextTags(parser);
+ if (!accept(parser, XmlPullParser.START_TAG, TAG_SHARED_USER)) {
+ return false;
+ }
+
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+
+ parser.next();
+
+ SharedUserSetting sus = mSharedUsers.get(name);
+ if (sus != null) {
+ while (parsePermissionLPr(parser, sus.getPermissionsState(), userId)) {
+ parser.next();
+ }
+ }
+
+ skipEmptyTextTags(parser);
+ expect(parser, XmlPullParser.END_TAG, TAG_SHARED_USER);
+
+ return true;
+ }
+
+ private boolean parsePermissionLPr(XmlPullParser parser, PermissionsState permissionsState,
+ int userId) throws IOException, XmlPullParserException {
+ skipEmptyTextTags(parser);
+ if (!accept(parser, XmlPullParser.START_TAG, TAG_ITEM)) {
+ return false;
+ }
+
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+
+ parser.next();
+
+ BasePermission bp = mPermissions.get(name);
+ if (bp != null) {
+ if (permissionsState.grantRuntimePermission(bp, userId) ==
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ Slog.w(PackageManagerService.TAG, "Duplicate permission:" + name);
+ }
+ } else {
+ Slog.w(PackageManagerService.TAG, "Unknown permission:" + name);
+ }
+
+ skipEmptyTextTags(parser);
+ expect(parser, XmlPullParser.END_TAG, TAG_ITEM);
+
+ return true;
+ }
+
+ private void expect(XmlPullParser parser, int type, String tag)
+ throws IOException, XmlPullParserException {
+ if (!accept(parser, type, tag)) {
+ throw new XmlPullParserException("Expected event: " + type
+ + " and tag: " + tag + " but got event: " + parser.getEventType()
+ + " and tag:" + parser.getName());
+ }
+ }
+
+ private void skipEmptyTextTags(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ while (accept(parser, XmlPullParser.TEXT, null)
+ && parser.isWhitespace()) {
+ parser.next();
+ }
+ }
+
+ private boolean accept(XmlPullParser parser, int type, String tag)
+ throws IOException, XmlPullParserException {
+ if (parser.getEventType() != type) {
+ return false;
+ }
+ if (tag != null) {
+ if (!tag.equals(parser.getName())) {
+ return false;
+ }
+ } else if (parser.getName() != null) {
+ return false;
+ }
+ return true;
+ }
+
+ private void writePermissions(XmlSerializer serializer, Set<String> permissions)
+ throws IOException {
+ for (String permission : permissions) {
+ serializer.startTag(null, TAG_ITEM);
+ serializer.attribute(null, ATTR_NAME, permission);
+ serializer.endTag(null, TAG_ITEM);
+ }
+ }
+
+ private final class MyHandler extends Handler {
+ public MyHandler() {
+ super(BackgroundThread.getHandler().getLooper());
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ final int userId = message.what;
+ Runnable callback = (Runnable) message.obj;
+ writePermissionsSync(userId);
+ if (callback != null) {
+ callback.run();
+ }
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index d95739c84e43..06e020a056fd 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -21,7 +21,7 @@ import android.util.ArraySet;
/**
* Settings data for a particular shared user ID we know about.
*/
-final class SharedUserSetting extends GrantedPermissions {
+final class SharedUserSetting extends SettingBase {
final String name;
int userId;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 26ecb729ab27..8cc9d192caa6 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1219,6 +1219,7 @@ public class UserManagerService extends IUserManager.Stub {
updateUserIdsLocked();
Bundle restrictions = new Bundle();
mUserRestrictions.append(userId, restrictions);
+ mPm.newUserCreatedLILPw(userId);
}
}
if (userInfo != null) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 930ef9a15342..be6550c1c324 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4025,7 +4025,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private void offsetInputMethodWindowLw(WindowState win) {
- int top = win.getDisplayFrameLw().top;
+ int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
top += win.getGivenContentInsetsLw().top;
if (mContentBottom > top) {
mContentBottom = top;
@@ -4044,7 +4044,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private void offsetVoiceInputWindowLw(WindowState win) {
- int top = win.getDisplayFrameLw().top;
+ int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
top += win.getGivenContentInsetsLw().top;
if (mVoiceContentBottom > top) {
mVoiceContentBottom = top;
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/power/DeviceIdleController.java
index 062992d684bb..dd0044654c9c 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/power/DeviceIdleController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.power;
import android.app.AlarmManager;
import android.app.PendingIntent;
@@ -30,12 +30,16 @@ import android.hardware.TriggerEventListener;
import android.hardware.display.DisplayManager;
import android.net.INetworkPolicyManager;
import android.os.Binder;
+import android.os.PowerManager;
+import android.os.PowerManagerInternal;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.util.TimeUtils;
import android.view.Display;
import com.android.internal.app.IBatteryStats;
+import com.android.server.SystemService;
import com.android.server.am.BatteryStatsService;
import java.io.FileDescriptor;
@@ -60,6 +64,11 @@ public class DeviceIdleController extends SystemService {
*/
private static final long DEFAULT_INACTIVE_TIMEOUT = 30*60*1000L;
/**
+ * This is the time, after seeing motion, that we wait after becoming inactive from
+ * that until we start looking for motion again.
+ */
+ private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT = 10*60*1000L;
+ /**
* This is the time, after the inactive timeout elapses, that we will wait looking
* for significant motion until we truly consider the device to be idle.
*/
@@ -94,11 +103,13 @@ public class DeviceIdleController extends SystemService {
private AlarmManager mAlarmManager;
private IBatteryStats mBatteryStats;
+ private PowerManagerInternal mLocalPowerManager;
private INetworkPolicyManager mNetworkPolicyManager;
private DisplayManager mDisplayManager;
private SensorManager mSensorManager;
private Sensor mSigMotionSensor;
private PendingIntent mAlarmIntent;
+ private Intent mIdleIntent;
private Display mCurDisplay;
private boolean mScreenOn;
private boolean mCharging;
@@ -124,6 +135,7 @@ public class DeviceIdleController extends SystemService {
private int mState;
+ private long mInactiveTimeout;
private long mNextAlarmTime;
private long mNextIdlePendingDelay;
private long mNextIdleDelay;
@@ -181,6 +193,7 @@ public class DeviceIdleController extends SystemService {
synchronized (this) {
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
mBatteryStats = BatteryStatsService.getService();
+ mLocalPowerManager = getLocalService(PowerManagerInternal.class);
mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
mDisplayManager = (DisplayManager) getContext().getSystemService(
@@ -193,6 +206,9 @@ public class DeviceIdleController extends SystemService {
.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mAlarmIntent = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
+ mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+ mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(ACTION_STEP_IDLE_STATE);
@@ -205,6 +221,7 @@ public class DeviceIdleController extends SystemService {
// a battery update the next time the level drops.
mCharging = true;
mState = STATE_ACTIVE;
+ mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT;
updateDisplayLocked();
}
@@ -238,12 +255,17 @@ public class DeviceIdleController extends SystemService {
void becomeActiveLocked() {
if (mState != STATE_ACTIVE) {
+ mLocalPowerManager.setDeviceIdleMode(false);
try {
mNetworkPolicyManager.setDeviceIdleMode(false);
mBatteryStats.noteDeviceIdleMode(false, true, false);
} catch (RemoteException e) {
}
+ if (mState == STATE_IDLE) {
+ getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
+ }
mState = STATE_ACTIVE;
+ mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT;
mNextIdlePendingDelay = 0;
mNextIdleDelay = 0;
cancelAlarmLocked();
@@ -256,7 +278,9 @@ public class DeviceIdleController extends SystemService {
// Screen has turned off; we are now going to become inactive and start
// waiting to see if we will ultimately go idle.
mState = STATE_INACTIVE;
- scheduleAlarmLocked(DEFAULT_INACTIVE_TIMEOUT, false);
+ mNextIdlePendingDelay = 0;
+ mNextIdleDelay = 0;
+ scheduleAlarmLocked(mInactiveTimeout, false);
}
}
@@ -283,11 +307,13 @@ public class DeviceIdleController extends SystemService {
mNextIdleDelay = DEFAULT_MAX_IDLE_TIMEOUT;
}
mState = STATE_IDLE;
+ mLocalPowerManager.setDeviceIdleMode(true);
try {
mNetworkPolicyManager.setDeviceIdleMode(true);
mBatteryStats.noteDeviceIdleMode(true, false, false);
} catch (RemoteException e) {
}
+ getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
break;
case STATE_IDLE:
// We have been idling long enough, now it is time to do some work.
@@ -297,11 +323,13 @@ public class DeviceIdleController extends SystemService {
mNextIdlePendingDelay = DEFAULT_MAX_IDLE_PENDING_TIMEOUT;
}
mState = STATE_IDLE_PENDING;
+ mLocalPowerManager.setDeviceIdleMode(false);
try {
mNetworkPolicyManager.setDeviceIdleMode(false);
mBatteryStats.noteDeviceIdleMode(false, false, false);
} catch (RemoteException e) {
}
+ getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
break;
}
}
@@ -313,13 +341,18 @@ public class DeviceIdleController extends SystemService {
// state to wait again for no motion. Note that we only monitor for significant
// motion after moving out of the inactive state, so no need to worry about that.
if (mState != STATE_ACTIVE) {
- mState = STATE_INACTIVE;
+ mLocalPowerManager.setDeviceIdleMode(false);
try {
mNetworkPolicyManager.setDeviceIdleMode(false);
mBatteryStats.noteDeviceIdleMode(false, false, true);
} catch (RemoteException e) {
}
- stepIdleStateLocked();
+ if (mState == STATE_IDLE) {
+ getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
+ }
+ mState = STATE_ACTIVE;
+ mInactiveTimeout = DEFAULT_MOTION_INACTIVE_TIMEOUT;
+ becomeInactiveIfAppropriateLocked();
}
}
@@ -399,26 +432,30 @@ public class DeviceIdleController extends SystemService {
}
}
- pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor);
- pw.print(" mCurDisplay="); pw.println(mCurDisplay);
- pw.print(" mScreenOn="); pw.println(mScreenOn);
- pw.print(" mCharging="); pw.println(mCharging);
- pw.print(" mSigMotionActive="); pw.println(mSigMotionActive);
- pw.print(" mState="); pw.println(stateToString(mState));
- if (mNextAlarmTime != 0) {
- pw.print(" mNextAlarmTime=");
- TimeUtils.formatDuration(mNextAlarmTime, SystemClock.elapsedRealtime(), pw);
- pw.println();
- }
- if (mNextIdlePendingDelay != 0) {
- pw.print(" mNextIdlePendingDelay=");
- TimeUtils.formatDuration(mNextIdlePendingDelay, pw);
- pw.println();
- }
- if (mNextIdleDelay != 0) {
- pw.print(" mNextIdleDelay=");
- TimeUtils.formatDuration(mNextIdleDelay, pw);
+ synchronized (this) {
+ pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor);
+ pw.print(" mCurDisplay="); pw.println(mCurDisplay);
+ pw.print(" mScreenOn="); pw.println(mScreenOn);
+ pw.print(" mCharging="); pw.println(mCharging);
+ pw.print(" mSigMotionActive="); pw.println(mSigMotionActive);
+ pw.print(" mState="); pw.println(stateToString(mState));
+ pw.print(" mInactiveTimeout="); TimeUtils.formatDuration(mInactiveTimeout, pw);
pw.println();
+ if (mNextAlarmTime != 0) {
+ pw.print(" mNextAlarmTime=");
+ TimeUtils.formatDuration(mNextAlarmTime, SystemClock.elapsedRealtime(), pw);
+ pw.println();
+ }
+ if (mNextIdlePendingDelay != 0) {
+ pw.print(" mNextIdlePendingDelay=");
+ TimeUtils.formatDuration(mNextIdlePendingDelay, pw);
+ pw.println();
+ }
+ if (mNextIdleDelay != 0) {
+ pw.print(" mNextIdleDelay=");
+ TimeUtils.formatDuration(mNextIdleDelay, pw);
+ pw.println();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 1349926e8697..c48367e3e6d0 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -78,6 +78,7 @@ final class Notifier {
private static final int MSG_USER_ACTIVITY = 1;
private static final int MSG_BROADCAST = 2;
private static final int MSG_WIRELESS_CHARGING_STARTED = 3;
+ private static final int MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED = 4;
private final Object mLock = new Object();
@@ -92,6 +93,7 @@ final class Notifier {
private final NotifierHandler mHandler;
private final Intent mScreenOnIntent;
private final Intent mScreenOffIntent;
+ private final Intent mScreenBrightnessBoostIntent;
// The current interactive state.
private int mActualInteractiveState;
@@ -128,6 +130,10 @@ final class Notifier {
mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
mScreenOffIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
+ mScreenBrightnessBoostIntent =
+ new Intent(PowerManager.ACTION_SCREEN_BRIGHTNESS_BOOST_CHANGED);
+ mScreenBrightnessBoostIntent.addFlags(
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
// Initialize interactive state for battery stats.
try {
@@ -349,6 +355,19 @@ final class Notifier {
}
/**
+ * Called when screen brightness boost begins or ends.
+ */
+ public void onScreenBrightnessBoostChanged() {
+ if (DEBUG) {
+ Slog.d(TAG, "onScreenBrightnessBoostChanged");
+ }
+
+ mSuspendBlocker.acquire();
+ Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED);
+ msg.setAsynchronous(true);
+ mHandler.sendMessage(msg);
+ }
+ /**
* Called when there has been user activity.
*/
public void onUserActivity(int event, int uid) {
@@ -457,6 +476,22 @@ final class Notifier {
}
}
+ private void sendBrightnessBoostChangedBroadcast() {
+ if (DEBUG) {
+ Slog.d(TAG, "Sending brightness boost changed broadcast.");
+ }
+
+ mContext.sendOrderedBroadcastAsUser(mScreenBrightnessBoostIntent, UserHandle.ALL, null,
+ mScreeBrightnessBoostChangedDone, mHandler, 0, null, null);
+ }
+
+ private final BroadcastReceiver mScreeBrightnessBoostChangedDone = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mSuspendBlocker.release();
+ }
+ };
+
private void sendWakeUpBroadcast() {
if (DEBUG) {
Slog.d(TAG, "Sending wake up broadcast.");
@@ -539,6 +574,9 @@ final class Notifier {
case MSG_WIRELESS_CHARGING_STARTED:
playWirelessChargingStartedSound();
break;
+ case MSG_SCREEN_BRIGHTNESS_BOOST_CHANGED:
+ sendBrightnessBoostChangedBroadcast();
+ break;
}
}
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 9e373b72d445..6c8959c933d9 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -420,6 +420,9 @@ public final class PowerManagerService extends SystemService
// True if the battery level is currently considered low.
private boolean mBatteryLevelLow;
+ // True if we are currently in device idle mode.
+ private boolean mDeviceIdleMode;
+
// True if theater mode is enabled
private boolean mTheaterModeEnabled;
@@ -1900,6 +1903,7 @@ public final class PowerManagerService extends SystemService
}
}
mScreenBrightnessBoostInProgress = false;
+ mNotifier.onScreenBrightnessBoostChanged();
userActivityNoUpdateLocked(now,
PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
}
@@ -2178,6 +2182,12 @@ public final class PowerManagerService extends SystemService
}
}
+ private boolean isDeviceIdleModeInternal() {
+ synchronized (mLock) {
+ return mDeviceIdleMode;
+ }
+ }
+
private void handleBatteryStateChangedLocked() {
mDirty |= DIRTY_BATTERY_STATE;
updatePowerStateLocked();
@@ -2275,7 +2285,10 @@ public final class PowerManagerService extends SystemService
Slog.i(TAG, "Brightness boost activated (uid " + uid +")...");
mLastScreenBrightnessBoostTime = eventTime;
- mScreenBrightnessBoostInProgress = true;
+ if (!mScreenBrightnessBoostInProgress) {
+ mScreenBrightnessBoostInProgress = true;
+ mNotifier.onScreenBrightnessBoostChanged();
+ }
mDirty |= DIRTY_SCREEN_BRIGHTNESS_BOOST;
userActivityNoUpdateLocked(eventTime,
@@ -2284,6 +2297,12 @@ public final class PowerManagerService extends SystemService
}
}
+ private boolean isScreenBrightnessBoostedInternal() {
+ synchronized (mLock) {
+ return mScreenBrightnessBoostInProgress;
+ }
+ }
+
/**
* Called when a screen brightness boost timeout has occurred.
*
@@ -3050,6 +3069,16 @@ public final class PowerManagerService extends SystemService
}
}
+ @Override // Binder call
+ public boolean isDeviceIdleMode() {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return isDeviceIdleModeInternal();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
/**
* Reboots the device.
*
@@ -3218,6 +3247,16 @@ public final class PowerManagerService extends SystemService
}
@Override // Binder call
+ public boolean isScreenBrightnessBoosted() {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return isScreenBrightnessBoostedInternal();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
@@ -3295,5 +3334,12 @@ public final class PowerManagerService extends SystemService
mLowPowerModeListeners.add(listener);
}
}
+
+ @Override
+ public void setDeviceIdleMode(boolean enabled) {
+ synchronized (mLock) {
+ mDeviceIdleMode = enabled;
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 010931387671..dec195d8172c 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -272,13 +272,14 @@ public class TrustAgentWrapper {
alarmFilter.addDataScheme(mAlarmIntent.getScheme());
final String pathUri = mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME);
alarmFilter.addDataPath(pathUri, PatternMatcher.PATTERN_LITERAL);
- mContext.registerReceiver(mBroadcastReceiver, alarmFilter, PERMISSION, null);
// Schedules a restart for when connecting times out. If the connection succeeds,
// the restart is canceled in mCallback's onConnected.
scheduleRestart();
mBound = context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user);
- if (!mBound) {
+ if (mBound) {
+ mContext.registerReceiver(mBroadcastReceiver, alarmFilter, PERMISSION, null);
+ } else {
Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString());
}
}
@@ -398,7 +399,6 @@ public class TrustAgentWrapper {
}
public void destroy() {
- mContext.unregisterReceiver(mBroadcastReceiver);
mHandler.removeMessages(MSG_RESTART_TIMEOUT);
if (!mBound) {
@@ -408,6 +408,7 @@ public class TrustAgentWrapper {
mTrustManagerService.mArchive.logAgentStopped(mUserId, mName);
mContext.unbindService(mConnection);
mBound = false;
+ mContext.unregisterReceiver(mBroadcastReceiver);
mTrustAgentService = null;
mSetTrustAgentFeaturesToken = null;
mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index c09ea5cead82..e385be3f3551 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -140,10 +140,9 @@ public class DimLayer {
}
/**
- * @param layer The new layer value.
- * @param inTransaction Whether the call is made within a surface transaction.
+ * NOTE: Must be called with Surface transaction open.
*/
- void adjustSurface(int layer, boolean inTransaction) {
+ private void adjustBounds() {
final int dw, dh;
final float xPos, yPos;
if (!mStack.isFullscreen()) {
@@ -163,29 +162,24 @@ public class DimLayer {
yPos = -1 * dh / 6;
}
- try {
- if (!inTransaction) {
- SurfaceControl.openTransaction();
- }
- mDimSurface.setPosition(xPos, yPos);
- mDimSurface.setSize(dw, dh);
- mDimSurface.setLayer(layer);
- } catch (RuntimeException e) {
- Slog.w(TAG, "Failure setting size or layer", e);
- } finally {
- if (!inTransaction) {
- SurfaceControl.closeTransaction();
- }
- }
+ mDimSurface.setPosition(xPos, yPos);
+ mDimSurface.setSize(dw, dh);
+
mLastBounds.set(mBounds);
- mLayer = layer;
}
- // Assumes that surface transactions are currently closed.
+ /** @param bounds The new bounds to set */
void setBounds(Rect bounds) {
mBounds.set(bounds);
if (isDimming() && !mLastBounds.equals(bounds)) {
- adjustSurface(mLayer, false);
+ try {
+ SurfaceControl.openTransaction();
+ adjustBounds();
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting size", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
}
}
@@ -224,9 +218,10 @@ public class DimLayer {
return;
}
- if (!mLastBounds.equals(mBounds) || mLayer != layer) {
- adjustSurface(layer, true);
+ if (!mLastBounds.equals(mBounds)) {
+ adjustBounds();
}
+ setLayer(layer);
long curTime = SystemClock.uptimeMillis();
final boolean animating = isAnimating();
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 6d09f5518a44..b61a6f74b72d 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -373,10 +373,8 @@ public class TaskStack {
mService.requestTraversalLocked();
}
- mAnimationBackgroundSurface.destroySurface();
- mAnimationBackgroundSurface = null;
- mDimLayer.destroySurface();
- mDimLayer = null;
+ close();
+
mDisplayContent = null;
}
@@ -501,8 +499,14 @@ public class TaskStack {
}
void close() {
- mDimLayer.mDimSurface.destroy();
- mAnimationBackgroundSurface.mDimSurface.destroy();
+ if (mAnimationBackgroundSurface != null) {
+ mAnimationBackgroundSurface.destroySurface();
+ mAnimationBackgroundSurface = null;
+ }
+ if (mDimLayer != null) {
+ mDimLayer.destroySurface();
+ mDimLayer = null;
+ }
}
public void dump(String prefix, PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4c80b07763c8..957eb9ef18aa 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -178,7 +178,7 @@ public class WindowManagerService extends IWindowManager.Stub
static final boolean DEBUG_ORIENTATION = false;
static final boolean DEBUG_APP_ORIENTATION = false;
static final boolean DEBUG_CONFIGURATION = false;
- static final boolean DEBUG_APP_TRANSITIONS = false;
+ static final boolean DEBUG_APP_TRANSITIONS = true;
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_WALLPAPER = false;
static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
@@ -189,7 +189,7 @@ public class WindowManagerService extends IWindowManager.Stub
static final boolean DEBUG_LAYOUT_REPEATS = true;
static final boolean DEBUG_SURFACE_TRACE = false;
static final boolean DEBUG_WINDOW_TRACE = false;
- static final boolean DEBUG_TASK_MOVEMENT = false;
+ static final boolean DEBUG_TASK_MOVEMENT = true;
static final boolean DEBUG_STACK = false;
static final boolean DEBUG_DISPLAY = false;
static final boolean DEBUG_POWER = false;
@@ -507,6 +507,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean mClientFreezingScreen = false;
int mAppsFreezingScreen = 0;
int mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ int mLastKeyguardForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
int mLayoutSeq = 0;
@@ -3055,7 +3056,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- if (DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility
+ if (true || DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility
+ " req=" + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
win.mEnforceSizeCompat =
@@ -3115,6 +3116,10 @@ public class WindowManagerService extends IWindowManager.Stub
}
winAnimator.mEnteringAnimation = true;
if (toBeDisplayed) {
+ if ((win.mAttrs.softInputMode & SOFT_INPUT_MASK_ADJUST)
+ == SOFT_INPUT_ADJUST_RESIZE) {
+ win.mLayoutNeeded = true;
+ }
if (win.isDrawnLw() && okToDisplay()) {
winAnimator.applyEnterAnimationLocked();
}
@@ -3700,41 +3705,68 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- public int getOrientationFromWindowsLocked() {
- if (mDisplayFrozen || mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
- // If the display is frozen, some activities may be in the middle
- // of restarting, and thus have removed their old window. If the
- // window has the flag to hide the lock screen, then the lock screen
- // can re-appear and inflict its own orientation on us. Keep the
- // orientation stable until this all settles down.
- return mLastWindowForcedOrientation;
- }
-
- // TODO(multidisplay): Change to the correct display.
- final WindowList windows = getDefaultWindowListLocked();
- for (int pos = windows.size() - 1; pos >= 0; --pos) {
- WindowState win = windows.get(pos);
- if (win.mAppToken != null) {
- // We hit an application window. so the orientation will be determined by the
- // app window. No point in continuing further.
- return (mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
- }
- if (!win.isVisibleLw() || !win.mPolicyVisibilityAfterAnim) {
- continue;
+ public int getOrientationLocked() {
+ if (mDisplayFrozen) {
+ if (mLastWindowForcedOrientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
+ if (DEBUG_ORIENTATION) Slog.v(TAG, "Display is frozen, return "
+ + mLastWindowForcedOrientation);
+ // If the display is frozen, some activities may be in the middle
+ // of restarting, and thus have removed their old window. If the
+ // window has the flag to hide the lock screen, then the lock screen
+ // can re-appear and inflict its own orientation on us. Keep the
+ // orientation stable until this all settles down.
+ return mLastWindowForcedOrientation;
}
- int req = win.mAttrs.screenOrientation;
- if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) ||
- (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
- continue;
+ } else {
+ // TODO(multidisplay): Change to the correct display.
+ final WindowList windows = getDefaultWindowListLocked();
+ for (int pos = windows.size() - 1; pos >= 0; --pos) {
+ WindowState win = windows.get(pos);
+ if (win.mAppToken != null) {
+ // We hit an application window. so the orientation will be determined by the
+ // app window. No point in continuing further.
+ break;
+ }
+ if (!win.isVisibleLw() || !win.mPolicyVisibilityAfterAnim) {
+ continue;
+ }
+ int req = win.mAttrs.screenOrientation;
+ if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) ||
+ (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
+ continue;
+ }
+
+ if (DEBUG_ORIENTATION) Slog.v(TAG, win + " forcing orientation to " + req);
+ if (mPolicy.isKeyguardHostWindow(win.mAttrs)) {
+ mLastKeyguardForcedOrientation = req;
+ }
+ return (mLastWindowForcedOrientation = req);
}
+ mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
- if (DEBUG_ORIENTATION) Slog.v(TAG, win + " forcing orientation to " + req);
- return (mLastWindowForcedOrientation = req);
+ if (mPolicy.isKeyguardLocked()) {
+ // The screen is locked and no top system window is requesting an orientation.
+ // Return either the orientation of the show-when-locked app (if there is any) or
+ // the orientation of the keyguard. No point in searching from the rest of apps.
+ WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
+ AppWindowToken appShowWhenLocked = winShowWhenLocked == null ?
+ null : winShowWhenLocked.mAppToken;
+ if (appShowWhenLocked != null) {
+ int req = appShowWhenLocked.requestedOrientation;
+ if (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
+ req = mLastKeyguardForcedOrientation;
+ }
+ if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + appShowWhenLocked
+ + " -- show when locked, return " + req);
+ return req;
+ }
+ if (DEBUG_ORIENTATION) Slog.v(TAG,
+ "No one is requesting an orientation when the screen is locked");
+ return mLastKeyguardForcedOrientation;
+ }
}
- return (mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
- }
- public int getOrientationFromAppTokensLocked() {
+ // Top system windows are not requesting an orientation. Start searching from apps.
int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
boolean findingBehind = false;
boolean lastFullscreen = false;
@@ -3804,8 +3836,11 @@ public class WindowManagerService extends IWindowManager.Stub
findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
}
}
- if (DEBUG_ORIENTATION) Slog.v(TAG, "No app is requesting an orientation");
- return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ if (DEBUG_ORIENTATION) Slog.v(TAG, "No app is requesting an orientation, return "
+ + mForcedAppOrientation);
+ // The next app has not been requested to be visible, so we keep the current orientation
+ // to prevent freezing/unfreezing the display too early.
+ return mForcedAppOrientation;
}
@Override
@@ -3887,11 +3922,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean updateOrientationFromAppTokensLocked(boolean inTransaction) {
long ident = Binder.clearCallingIdentity();
try {
- int req = getOrientationFromWindowsLocked();
- if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
- req = getOrientationFromAppTokensLocked();
- }
-
+ int req = getOrientationLocked();
if (req != mForcedAppOrientation) {
mForcedAppOrientation = req;
//send a message to Policy indicating orientation change to take
@@ -4140,8 +4171,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
synchronized(mWindowMap) {
- if (DEBUG_APP_TRANSITIONS) Slog.w(TAG, "Execute app transition: " + mAppTransition,
- new RuntimeException("here").fillInStackTrace());
+ if (DEBUG_APP_TRANSITIONS) Slog.w(TAG, "Execute app transition: " + mAppTransition
+ + " Callers=" + Debug.getCallers(5));
if (mAppTransition.isTransitionSet()) {
mAppTransition.setReady();
final long origId = Binder.clearCallingIdentity();
diff --git a/services/core/jni/com_android_server_UsbMidiDevice.cpp b/services/core/jni/com_android_server_UsbMidiDevice.cpp
index 94853b8deb46..cb70144d9687 100644
--- a/services/core/jni/com_android_server_UsbMidiDevice.cpp
+++ b/services/core/jni/com_android_server_UsbMidiDevice.cpp
@@ -94,9 +94,20 @@ android_server_UsbMidiDevice_open(JNIEnv *env, jobject /* thiz */, jint card, ji
return fds;
}
+static void
+android_server_UsbMidiDevice_close(JNIEnv *env, jobject /* thiz */, jobjectArray fds)
+{
+ int count = env->GetArrayLength(fds);
+ for (int i = 0; i < count; i++) {
+ jobject fd = env->GetObjectArrayElement(fds, i);
+ close(jniGetFDFromFileDescriptor(env, fd));
+ }
+}
+
static JNINativeMethod method_table[] = {
{ "nativeGetSubdeviceCount", "(II)I", (void*)android_server_UsbMidiDevice_get_subdevice_count },
{ "nativeOpen", "(III)[Ljava/io/FileDescriptor;", (void*)android_server_UsbMidiDevice_open },
+ { "nativeClose", "([Ljava/io/FileDescriptor;)V", (void*)android_server_UsbMidiDevice_close },
};
int register_android_server_UsbMidiDevice(JNIEnv *env)
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d07cd984392d..73b5de1b42f9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1140,70 +1140,85 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
throws SecurityException {
final int callingUid = Binder.getCallingUid();
- final int userHandle = UserHandle.getUserId(callingUid);
- final DevicePolicyData policy = getUserData(userHandle);
- List<ActiveAdmin> candidates = new ArrayList<ActiveAdmin>();
+ ActiveAdmin result = getActiveAdminWithPolicyForUidLocked(who, reqPolicy, callingUid);
+ if (result != null) {
+ return result;
+ }
+
+ if (who != null) {
+ final int userId = UserHandle.getUserId(callingUid);
+ final DevicePolicyData policy = getUserData(userId);
+ ActiveAdmin admin = policy.mAdminMap.get(who);
+ if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
+ throw new SecurityException("Admin " + admin.info.getComponent()
+ + " does not own the device");
+ }
+ if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
+ throw new SecurityException("Admin " + admin.info.getComponent()
+ + " does not own the profile");
+ }
+ throw new SecurityException("Admin " + admin.info.getComponent()
+ + " did not specify uses-policy for: "
+ + admin.info.getTagForPolicy(reqPolicy));
+ } else {
+ throw new SecurityException("No active admin owned by uid "
+ + Binder.getCallingUid() + " for policy #" + reqPolicy);
+ }
+ }
- // Build a list of admins for this uid matching the given ComponentName
+ private ActiveAdmin getActiveAdminWithPolicyForUidLocked(ComponentName who, int reqPolicy,
+ int uid) {
+ // Try to find an admin which can use reqPolicy
+ final int userId = UserHandle.getUserId(uid);
+ final DevicePolicyData policy = getUserData(userId);
if (who != null) {
ActiveAdmin admin = policy.mAdminMap.get(who);
if (admin == null) {
throw new SecurityException("No active admin " + who);
}
- if (admin.getUid() != callingUid) {
+ if (admin.getUid() != uid) {
throw new SecurityException("Admin " + who + " is not owned by uid "
+ Binder.getCallingUid());
}
- candidates.add(admin);
+ if (isActiveAdminWithPolicyForUserLocked(admin, reqPolicy, userId)) {
+ return admin;
+ }
} else {
for (ActiveAdmin admin : policy.mAdminList) {
- if (admin.getUid() == callingUid) {
- candidates.add(admin);
+ if (admin.getUid() == uid && isActiveAdminWithPolicyForUserLocked(admin, reqPolicy,
+ userId)) {
+ return admin;
}
}
}
- // Try to find an admin which can use reqPolicy
- for (ActiveAdmin admin : candidates) {
- boolean ownsDevice = isDeviceOwner(admin.info.getPackageName());
- boolean ownsProfile = (getProfileOwner(userHandle) != null
- && getProfileOwner(userHandle).getPackageName()
- .equals(admin.info.getPackageName()));
- boolean ownsInitialization = isDeviceInitializer(admin.info.getPackageName())
- && !hasUserSetupCompleted(userHandle);
+ return null;
+ }
- if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
- if (ownsDevice || (userHandle == UserHandle.USER_OWNER && ownsInitialization)) {
- return admin;
- }
- } else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
- if (ownsDevice || ownsProfile || ownsInitialization) {
- return admin;
- }
- } else {
- if (admin.info.usesPolicy(reqPolicy)) {
- return admin;
- }
- }
- }
+ private boolean isActiveAdminWithPolicyForUserLocked(ActiveAdmin admin, int reqPolicy,
+ int userId) {
+ boolean ownsDevice = isDeviceOwner(admin.info.getPackageName());
+ boolean ownsProfile = (getProfileOwner(userId) != null
+ && getProfileOwner(userId).getPackageName()
+ .equals(admin.info.getPackageName()));
+ boolean ownsInitialization = isDeviceInitializer(admin.info.getPackageName())
+ && !hasUserSetupCompleted(userId);
- if (who != null) {
- if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
- throw new SecurityException("Admin " + candidates.get(0).info.getComponent()
- + " does not own the device");
+ if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
+ if (ownsDevice || (userId == UserHandle.USER_OWNER && ownsInitialization)) {
+ return true;
}
- if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
- throw new SecurityException("Admin " + candidates.get(0).info.getComponent()
- + " does not own the profile");
+ } else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
+ if (ownsDevice || ownsProfile || ownsInitialization) {
+ return true;
}
- throw new SecurityException("Admin " + candidates.get(0).info.getComponent()
- + " did not specify uses-policy for: "
- + candidates.get(0).info.getTagForPolicy(reqPolicy));
} else {
- throw new SecurityException("No active admin owned by uid "
- + Binder.getCallingUid() + " for policy #" + reqPolicy);
+ if (admin.info.usesPolicy(reqPolicy)) {
+ return true;
+ }
}
+ return false;
}
void sendAdminCommandLocked(ActiveAdmin admin, String action) {
@@ -3159,7 +3174,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
PersistentDataBlockManager manager = (PersistentDataBlockManager)
mContext.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
- manager.wipe();
+ if (manager != null) {
+ manager.wipe();
+ }
}
boolean wipeExtRequested = (flags & WIPE_EXTERNAL_STORAGE) != 0;
wipeDeviceOrUserLocked(wipeExtRequested, userHandle,
@@ -5702,6 +5719,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ @Override
+ public boolean isActiveAdminWithPolicy(int uid, int reqPolicy) {
+ final int userId = UserHandle.getUserId(uid);
+ synchronized(DevicePolicyManagerService.this) {
+ return getActiveAdminWithPolicyForUidLocked(null, reqPolicy, uid) != null;
+ }
+ }
+
private void notifyCrossProfileProvidersChanged(int userId, List<String> packages) {
final List<OnCrossProfileWidgetProvidersChangeListener> listeners;
synchronized (DevicePolicyManagerService.this) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ed55c56fdded..65e3534732da 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -39,6 +39,7 @@ import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.storage.IMountService;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Slog;
@@ -65,7 +66,6 @@ import com.android.server.lights.LightsService;
import com.android.server.media.MediaRouterService;
import com.android.server.media.MediaSessionService;
import com.android.server.media.projection.MediaProjectionManagerService;
-import com.android.server.MidiService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
import com.android.server.notification.NotificationManagerService;
@@ -75,6 +75,7 @@ import com.android.server.pm.Installer;
import com.android.server.pm.LauncherAppsService;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.UserManagerService;
+import com.android.server.power.DeviceIdleController;
import com.android.server.power.PowerManagerService;
import com.android.server.power.ShutdownThread;
import com.android.server.restrictions.RestrictionsManagerService;
@@ -131,6 +132,8 @@ public final class SystemServer {
"com.android.server.ethernet.EthernetService";
private static final String JOB_SCHEDULER_SERVICE_CLASS =
"com.android.server.job.JobSchedulerService";
+ private static final String MOUNT_SERVICE_CLASS =
+ "com.android.server.MountService$Lifecycle";
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
private final int mFactoryTestMode;
@@ -384,7 +387,7 @@ public final class SystemServer {
ContentService contentService = null;
VibratorService vibrator = null;
IAlarmManager alarm = null;
- MountService mountService = null;
+ IMountService mountService = null;
NetworkManagementService networkManagement = null;
NetworkStatsService networkStats = null;
NetworkPolicyManagerService networkPolicy = null;
@@ -403,12 +406,9 @@ public final class SystemServer {
AudioService audioService = null;
MmsServiceBroker mmsService = null;
EntropyMixer entropyMixer = null;
- MidiService midiService = null;
boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
- boolean disableMedia = SystemProperties.getBoolean("config.disable_media", false);
boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
- boolean disableTelephony = SystemProperties.getBoolean("config.disable_telephony", false);
boolean disableLocation = SystemProperties.getBoolean("config.disable_location", false);
boolean disableSystemUI = SystemProperties.getBoolean("config.disable_systemui", false);
boolean disableNonCoreServices = SystemProperties.getBoolean("config.disable_noncore", false);
@@ -517,7 +517,6 @@ public final class SystemServer {
LockSettingsService lockSettings = null;
AssetAtlasService atlas = null;
MediaRouterService mediaRouter = null;
- MidiService midi = null;
// Bring up services needed for UI.
if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
@@ -552,15 +551,19 @@ public final class SystemServer {
* NotificationManagerService is dependant on MountService,
* (for media / usb notifications) so we must start MountService first.
*/
- Slog.i(TAG, "Mount Service");
- mountService = new MountService(context);
- ServiceManager.addService("mount", mountService);
+ mSystemServiceManager.startService(MOUNT_SERVICE_CLASS);
+ mountService = IMountService.Stub.asInterface(
+ ServiceManager.getService("mount"));
} catch (Throwable e) {
reportWtf("starting Mount Service", e);
}
}
}
+ // We start this here so that we update our configuration to set watch or television
+ // as appropriate.
+ mSystemServiceManager.startService(UiModeManagerService.class);
+
try {
mPackageManagerService.performBootDexOpt();
} catch (Throwable e) {
@@ -711,7 +714,10 @@ public final class SystemServer {
* first before continuing.
*/
if (mountService != null && !mOnlyCore) {
- mountService.waitForAsecScan();
+ try {
+ mountService.waitForAsecScan();
+ } catch (RemoteException ignored) {
+ }
}
try {
@@ -782,29 +788,25 @@ public final class SystemServer {
}
}
- if (!disableMedia && !"0".equals(SystemProperties.get("system_init.startaudioservice"))) {
- try {
- Slog.i(TAG, "Audio Service");
- audioService = new AudioService(context);
- ServiceManager.addService(Context.AUDIO_SERVICE, audioService);
- } catch (Throwable e) {
- reportWtf("starting Audio Service", e);
- }
+ try {
+ Slog.i(TAG, "Audio Service");
+ audioService = new AudioService(context);
+ ServiceManager.addService(Context.AUDIO_SERVICE, audioService);
+ } catch (Throwable e) {
+ reportWtf("starting Audio Service", e);
}
if (!disableNonCoreServices) {
mSystemServiceManager.startService(DockObserver.class);
}
- if (!disableMedia) {
- try {
- Slog.i(TAG, "Wired Accessory Manager");
- // Listen for wired headset changes
- inputManager.setWiredAccessoryCallbacks(
- new WiredAccessoryManager(context, inputManager));
- } catch (Throwable e) {
- reportWtf("starting WiredAccessoryManager", e);
- }
+ try {
+ Slog.i(TAG, "Wired Accessory Manager");
+ // Listen for wired headset changes
+ inputManager.setWiredAccessoryCallbacks(
+ new WiredAccessoryManager(context, inputManager));
+ } catch (Throwable e) {
+ reportWtf("starting WiredAccessoryManager", e);
}
if (!disableNonCoreServices) {
@@ -837,8 +839,6 @@ public final class SystemServer {
mSystemServiceManager.startService(TwilightService.class);
- mSystemServiceManager.startService(UiModeManagerService.class);
-
mSystemServiceManager.startService(JobSchedulerService.class);
if (!disableNonCoreServices) {
@@ -883,14 +883,12 @@ public final class SystemServer {
}
}
- if (!disableMedia) {
- try {
- Slog.i(TAG, "CommonTimeManagementService");
- commonTimeMgmtService = new CommonTimeManagementService(context);
- ServiceManager.addService("commontime_management", commonTimeMgmtService);
- } catch (Throwable e) {
- reportWtf("starting CommonTimeManagementService service", e);
- }
+ try {
+ Slog.i(TAG, "CommonTimeManagementService");
+ commonTimeMgmtService = new CommonTimeManagementService(context);
+ ServiceManager.addService("commontime_management", commonTimeMgmtService);
+ } catch (Throwable e) {
+ reportWtf("starting CommonTimeManagementService service", e);
}
if (!disableNetwork) {
@@ -1039,7 +1037,6 @@ public final class SystemServer {
}
// These are needed to propagate to the runnable below.
- final MountService mountServiceF = mountService;
final NetworkManagementService networkManagementF = networkManagement;
final NetworkStatsService networkStatsF = networkStats;
final NetworkPolicyManagerService networkPolicyF = networkPolicy;
@@ -1087,11 +1084,6 @@ public final class SystemServer {
reportWtf("starting System UI", e);
}
try {
- if (mountServiceF != null) mountServiceF.systemReady();
- } catch (Throwable e) {
- reportWtf("making Mount Service ready", e);
- }
- try {
if (networkScoreF != null) networkScoreF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Score Service ready", e);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index b631331e9546..4dc1131f59bb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -32,7 +32,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
public class PackageManagerSettingsTests extends AndroidTestCase {
-
private static final String PACKAGE_NAME_2 = "com.google.app2";
private static final String PACKAGE_NAME_3 = "com.android.app3";
private static final String PACKAGE_NAME_1 = "com.google.app1";
@@ -56,7 +55,7 @@ public class PackageManagerSettingsTests extends AndroidTestCase {
writeFile(new File(getContext().getFilesDir(), "system/packages.xml"),
("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<packages>"
- + "<last-platform-version internal=\"15\" external=\"0\" />"
+ + "<last-platform-version internal=\"15\" external=\"0\" fingerprint=\"foo\" />"
+ "<permission-trees>"
+ "<item name=\"com.google.android.permtree\" package=\"com.google.android.permpackage\" />"
+ "</permission-trees>"
@@ -110,28 +109,32 @@ public class PackageManagerSettingsTests extends AndroidTestCase {
.getBytes());
}
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ private void deleteSystemFolder() {
+ File systemFolder = new File(getContext().getFilesDir(), "system");
+ deleteFolder(systemFolder);
+ }
+
+ private static void deleteFolder(File folder) {
+ File[] files = folder.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ deleteFolder(file);
+ }
+ }
+ folder.delete();
}
private void writeOldFiles() {
+ deleteSystemFolder();
writePackagesXml();
writeStoppedPackagesXml();
writePackagesList();
}
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- }
-
public void testSettingsReadOld() {
- // Debug.waitForDebugger();
-
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
- Settings settings = new Settings(getContext(), getContext().getFilesDir());
+ Settings settings = new Settings(getContext(), getContext().getFilesDir(), new Object());
assertEquals(true, settings.readLPw(null, null, 0, false));
assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_3));
assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_1));
@@ -149,11 +152,12 @@ public class PackageManagerSettingsTests extends AndroidTestCase {
public void testNewPackageRestrictionsFile() {
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
- Settings settings = new Settings(getContext(), getContext().getFilesDir());
+ Settings settings = new Settings(getContext(), getContext().getFilesDir(), new Object());
assertEquals(true, settings.readLPw(null, null, 0, false));
+ settings.writeLPr();
// Create Settings again to make it read from the new files
- settings = new Settings(getContext(), getContext().getFilesDir());
+ settings = new Settings(getContext(), getContext().getFilesDir(), new Object());
assertEquals(true, settings.readLPw(null, null, 0, false));
PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_2);
@@ -164,7 +168,7 @@ public class PackageManagerSettingsTests extends AndroidTestCase {
public void testEnableDisable() {
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
- Settings settings = new Settings(getContext(), getContext().getFilesDir());
+ Settings settings = new Settings(getContext(), getContext().getFilesDir(), new Object());
assertEquals(true, settings.readLPw(null, null, 0, false));
// Enable/Disable a package
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 23e19700b56d..c0410291678b 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -459,7 +459,7 @@ public final class UsbAlsaManager {
}
/* package */ void setPeripheralMidiState(boolean enabled, int card, int device) {
- if (enabled) {
+ if (enabled && mPeripheralMidiDevice == null) {
Bundle properties = new Bundle();
Resources r = mContext.getResources();
properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, r.getString(
@@ -469,7 +469,7 @@ public final class UsbAlsaManager {
properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, card);
properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, device);
mPeripheralMidiDevice = UsbMidiDevice.create(mContext, properties, card, device);
- } else if (mPeripheralMidiDevice != null) {
+ } else if (!enabled && mPeripheralMidiDevice != null) {
IoUtils.closeQuietly(mPeripheralMidiDevice);
mPeripheralMidiDevice = null;
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 41cf2ef90cf6..6adb8be6c78b 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -126,6 +126,8 @@ public class UsbDeviceManager {
private boolean mAdbEnabled;
private boolean mAudioSourceEnabled;
private boolean mMidiEnabled;
+ private int mMidiCard;
+ private int mMidiDevice;
private Map<String, List<Pair<String, String>>> mOemModeMap;
private String[] mAccessoryStrings;
private UsbDebuggingManager mDebuggingManager;
@@ -363,18 +365,6 @@ public class UsbDeviceManager {
updateState(state);
mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
- // Upgrade step for previous versions that used persist.service.adb.enable
- String value = SystemProperties.get("persist.service.adb.enable", "");
- if (value.length() > 0) {
- char enable = value.charAt(0);
- if (enable == '1') {
- setAdbEnabled(true);
- } else if (enable == '0') {
- setAdbEnabled(false);
- }
- SystemProperties.set("persist.service.adb.enable", "");
- }
-
// register observer to listen for settings changes
mContentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
@@ -623,26 +613,24 @@ public class UsbDeviceManager {
private void updateMidiFunction() {
boolean enabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MIDI);
if (enabled != mMidiEnabled) {
- int card = -1;
- int device = -1;
-
if (enabled) {
Scanner scanner = null;
try {
scanner = new Scanner(new File(MIDI_ALSA_PATH));
- card = scanner.nextInt();
- device = scanner.nextInt();
+ mMidiCard = scanner.nextInt();
+ mMidiDevice = scanner.nextInt();
} catch (FileNotFoundException e) {
Slog.e(TAG, "could not open MIDI PCM file", e);
+ enabled = false;
} finally {
if (scanner != null) {
scanner.close();
}
}
}
- mUsbAlsaManager.setPeripheralMidiState(enabled, card, device);
mMidiEnabled = enabled;
}
+ mUsbAlsaManager.setPeripheralMidiState(mMidiEnabled && mConfigured, mMidiCard, mMidiDevice);
}
@Override
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index f23bb9343ba6..3b6570999a0a 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -47,6 +47,8 @@ public final class UsbMidiDevice implements Closeable {
private static final int BUFFER_SIZE = 512;
+ private final FileDescriptor[] mFileDescriptors;
+
// for polling multiple FileDescriptors for MIDI events
private final StructPollfd[] mPollFDs;
// streams for reading from ALSA driver
@@ -69,7 +71,7 @@ public final class UsbMidiDevice implements Closeable {
return null;
}
- UsbMidiDevice midiDevice = new UsbMidiDevice(fileDescriptors, fileDescriptors);
+ UsbMidiDevice midiDevice = new UsbMidiDevice(fileDescriptors);
if (!midiDevice.register(context, properties)) {
IoUtils.closeQuietly(midiDevice);
Log.e(TAG, "createDeviceServer failed");
@@ -78,14 +80,15 @@ public final class UsbMidiDevice implements Closeable {
return midiDevice;
}
- private UsbMidiDevice(FileDescriptor[] inputFiles, FileDescriptor[] outputFiles) {
- int inputCount = inputFiles.length;
- int outputCount = outputFiles.length;
+ private UsbMidiDevice(FileDescriptor[] fileDescriptors) {
+ mFileDescriptors = fileDescriptors;
+ int inputCount = fileDescriptors.length;
+ int outputCount = fileDescriptors.length;
mPollFDs = new StructPollfd[inputCount];
mInputStreams = new FileInputStream[inputCount];
for (int i = 0; i < inputCount; i++) {
- FileDescriptor fd = inputFiles[i];
+ FileDescriptor fd = fileDescriptors[i];
StructPollfd pollfd = new StructPollfd();
pollfd.fd = fd;
pollfd.events = (short)OsConstants.POLLIN;
@@ -95,7 +98,7 @@ public final class UsbMidiDevice implements Closeable {
mOutputStreams = new FileOutputStream[outputCount];
for (int i = 0; i < outputCount; i++) {
- mOutputStreams[i] = new FileOutputStream(outputFiles[i]);
+ mOutputStreams[i] = new FileOutputStream(fileDescriptors[i]);
}
mInputPortReceivers = new MidiReceiver[inputCount];
@@ -176,8 +179,10 @@ public final class UsbMidiDevice implements Closeable {
for (int i = 0; i < mOutputStreams.length; i++) {
mOutputStreams[i].close();
}
+ nativeClose(mFileDescriptors);
}
private static native int nativeGetSubdeviceCount(int card, int device);
private static native FileDescriptor[] nativeOpen(int card, int device, int subdeviceCount);
+ private static native void nativeClose(FileDescriptor[] fileDescriptors);
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 22b7bb1df89c..6fa653df5dd9 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -223,7 +223,7 @@ public final class Call {
//**********************************************************************************************
// Next CAPABILITY value: 0x00080000
- //**********************************************************************************************
+ //******************************************************************************************
private final Uri mHandle;
private final int mHandlePresentation;
@@ -323,7 +323,7 @@ public final class Call {
builder.append(" CAPABILITY_SHOW_CALLBACK_NUMBER");
}
if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
- builder.append(" CAPABILITY_SPEED_UP_IMS_MT_AUDIO");
+ builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
}
builder.append("]");
return builder.toString();
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index a335e4758279..082474bd5af0 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -171,7 +171,7 @@ public abstract class Connection implements IConferenceable {
* Connection is using WIFI.
* @hide
*/
- public static final int CAPABILITY_WIFI = 0x000010000;
+ public static final int CAPABILITY_WIFI = 0x00010000;
/**
* Indicates that the current device callback number should be shown.
@@ -292,7 +292,7 @@ public abstract class Connection implements IConferenceable {
builder.append(" CAPABILITY_SHOW_CALLBACK_NUMBER");
}
if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
- builder.append(" CAPABILITY_SPEED_UP_IMS_MT_AUDIO");
+ builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
}
builder.append("]");
return builder.toString();
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b44fa6cf9481..fbc70db2ef13 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -258,11 +258,19 @@ public class TelephonyManager {
* <p>
* Output: nothing.
*/
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ @SdkConstant(SdkConstantType.SERVICE_ACTION)
public static final String ACTION_RESPOND_VIA_MESSAGE =
"android.intent.action.RESPOND_VIA_MESSAGE";
/**
+ * The emergency dialer may choose to present activities with intent filters for this
+ * action as emergency assistance buttons that launch the activity when clicked.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_EMERGENCY_ASSISTANCE =
+ "android.telephony.action.EMERGENCY_ASSISTANCE";
+
+ /**
* The lookup key used with the {@link #ACTION_PHONE_STATE_CHANGED} broadcast
* for a String containing the new call state.
*
@@ -4057,6 +4065,34 @@ public class TelephonyManager {
}
/**
+ * Returns the Status of Volte
+ *@hide
+ */
+ public boolean isVolteEnabled() {
+ try {
+ return getITelephony().isVolteEnabled();
+ } catch (RemoteException ex) {
+ return false;
+ } catch (NullPointerException ex) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the Status of Wi-Fi Calling
+ *@hide
+ */
+ public boolean isWifiCallingEnabled() {
+ try {
+ return getITelephony().isWifiCallingEnabled();
+ } catch (RemoteException ex) {
+ return false;
+ } catch (NullPointerException ex) {
+ return false;
+ }
+ }
+
+ /**
* Set TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC for the default phone.
*
* @hide
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index f9e15f3968c2..c18e3b69d3ac 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -901,6 +901,18 @@ interface ITelephony {
boolean isImsRegistered();
/**
+ * Returns the Status of Wi-Fi Calling
+ *@hide
+ */
+ boolean isWifiCallingEnabled();
+
+ /**
+ * Returns the Status of Volte
+ *@hide
+ */
+ boolean isVolteEnabled();
+
+ /**
* Returns the unique device ID of phone, for example, the IMEI for
* GSM and the MEID for CDMA phones. Return null if device ID is not available.
*
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index cfbebba88c31..b265d470dbe9 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -506,6 +506,11 @@ public class MockContext extends Context {
}
@Override
+ public int checkSelfPermission(String permission) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public void enforcePermission(
String permission, int pid, int uid, String message) {
throw new UnsupportedOperationException();
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 7531d7b846ed..67a8c2b512e2 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -191,13 +191,13 @@ public class MockPackageManager extends PackageManager {
/** @hide */
@Override
- public void grantPermission(String packageName, String permissionName) {
+ public void grantPermission(String packageName, String permissionName, UserHandle user) {
throw new UnsupportedOperationException();
}
/** @hide */
@Override
- public void revokePermission(String packageName, String permissionName) {
+ public void revokePermission(String packageName, String permissionName, UserHandle user) {
throw new UnsupportedOperationException();
}
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
index ecc778241368..56c81191ba80 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
@@ -14,9 +14,12 @@
package com.android.test.dynamic;
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
import android.app.Activity;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.os.Bundle;
+import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.GridLayout;
@@ -52,6 +55,26 @@ public class AnimatedVectorDrawableTest extends Activity implements View.OnClick
button.setWidth(400);
button.setHeight(400);
button.setBackgroundResource(icon[i]);
+ AnimatedVectorDrawable d = (AnimatedVectorDrawable) button.getBackground();
+ d.addListener(new AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ Log.v(LOGCAT, "Animator start");
+ }
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ Log.v(LOGCAT, "Animator repeat");
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ Log.v(LOGCAT, "Animator end");
+ }
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ Log.v(LOGCAT, "Animator cancel");
+ }
+ });
+
container.addView(button);
button.setOnClickListener(this);
}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
index 2ad23ed51791..bdc1276f9d6f 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
@@ -47,12 +47,12 @@ public class AssistVisualizer extends View {
public void setAssistStructure(AssistStructure as) {
mAssistStructure = as;
mTextRects.clear();
- final int N = as.getWindowCount();
+ final int N = as.getWindowNodeCount();
if (N > 0) {
- AssistStructure.ViewNode window = new AssistStructure.ViewNode();
for (int i=0; i<N; i++) {
- as.getWindowAt(i, window);
- buildTextRects(window, 0, 0);
+ AssistStructure.WindowNode windowNode = as.getWindowNodeAt(i);
+ buildTextRects(windowNode.getRootViewNode(), windowNode.getLeft(),
+ windowNode.getTop());
}
}
invalidate();
@@ -79,9 +79,8 @@ public class AssistVisualizer extends View {
if (N > 0) {
left -= root.getScrollX();
top -= root.getScrollY();
- AssistStructure.ViewNode child = new AssistStructure.ViewNode();
for (int i=0; i<N; i++) {
- root.getChildAt(i, child);
+ AssistStructure.ViewNode child = root.getChildAt(i);
buildTextRects(child, left, top);
}
}
diff --git a/tools/layoutlib/.idea/libraries/guava.xml b/tools/layoutlib/.idea/libraries/guava.xml
index d47fc06d587f..eb6071977c56 100644
--- a/tools/layoutlib/.idea/libraries/guava.xml
+++ b/tools/layoutlib/.idea/libraries/guava.xml
@@ -1,11 +1,11 @@
<component name="libraryTable">
<library name="guava">
<CLASSES>
- <root url="jar://$PROJECT_DIR$/../../../../out/host/common/obj/JAVA_LIBRARIES/guavalib_intermediates/javalib.jar!/" />
+ <root url="jar://$PROJECT_DIR$/../../../../prebuilts/tools/common/m2/repository/com/google/guava/guava/15.0/guava-15.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="file://$PROJECT_DIR$/../../../../external/guava/guava/src" />
+ <root url="jar://$PROJECT_DIR$/../../../../prebuilts/tools/common/m2/repository/com/google/guava/guava/15.0/guava-15.0-sources.jar!/" />
</SOURCES>
</library>
</component> \ No newline at end of file
diff --git a/tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml b/tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml
index f965ba7f8e6c..0b227175c0d2 100644
--- a/tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml
+++ b/tools/layoutlib/.idea/runConfigurations/All_in_bridge.xml
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
- <configuration default="false" name="All in bridge" type="JUnit" factoryName="JUnit" singleton="true" nameIsGenerated="true">
+ <configuration default="false" name="All in bridge" type="JUnit" factoryName="JUnit" singleton="true">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
<module name="bridge" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
@@ -8,7 +8,7 @@
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" />
- <option name="VM_PARAMETERS" value="-ea -Dtest_res.dir=&quot;$PROJECT_DIR$/bridge/tests/res&quot;" />
+ <option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
<option name="ENV_VARIABLES" />
@@ -18,13 +18,7 @@
</option>
<envs />
<patterns />
- <RunnerSettings RunnerId="Debug">
- <option name="DEBUG_PORT" value="" />
- <option name="TRANSPORT" value="0" />
- <option name="LOCAL" value="true" />
- </RunnerSettings>
<RunnerSettings RunnerId="Run" />
- <ConfigurationWrapper RunnerId="Debug" />
<ConfigurationWrapper RunnerId="Run" />
<method />
</configuration>
diff --git a/tools/layoutlib/.idea/runConfigurations/Bridge_quick.xml b/tools/layoutlib/.idea/runConfigurations/Bridge_quick.xml
new file mode 100644
index 000000000000..4f0eb8dc23a4
--- /dev/null
+++ b/tools/layoutlib/.idea/runConfigurations/Bridge_quick.xml
@@ -0,0 +1,29 @@
+<component name="ProjectRunConfigurationManager">
+ <configuration default="false" name="Bridge quick" type="JUnit" factoryName="JUnit">
+ <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
+ <module name="bridge" />
+ <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
+ <option name="ALTERNATIVE_JRE_PATH" value="" />
+ <option name="PACKAGE_NAME" />
+ <option name="MAIN_CLASS_NAME" value="" />
+ <option name="METHOD_NAME" value="" />
+ <option name="TEST_OBJECT" value="pattern" />
+ <option name="VM_PARAMETERS" value="-ea" />
+ <option name="PARAMETERS" value="" />
+ <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
+ <option name="ENV_VARIABLES" />
+ <option name="PASS_PARENT_ENVS" value="true" />
+ <option name="TEST_SEARCH_SCOPE">
+ <value defaultName="singleModule" />
+ </option>
+ <envs />
+ <patterns>
+ <pattern testClass="com.android.layoutlib.bridge.TestDelegates" />
+ <pattern testClass="android.graphics.Matrix_DelegateTest" />
+ <pattern testClass="com.android.layoutlib.bridge.android.BridgeXmlBlockParserTest" />
+ </patterns>
+ <RunnerSettings RunnerId="Run" />
+ <ConfigurationWrapper RunnerId="Run" />
+ <method />
+ </configuration>
+</component> \ No newline at end of file
diff --git a/tools/layoutlib/.idea/runConfigurations/Create.xml b/tools/layoutlib/.idea/runConfigurations/Create.xml
index fb0b866376c5..ff173e53f965 100644
--- a/tools/layoutlib/.idea/runConfigurations/Create.xml
+++ b/tools/layoutlib/.idea/runConfigurations/Create.xml
@@ -5,8 +5,8 @@
<option name="VM_PARAMETERS" value="" />
<option name="PROGRAM_PARAMETERS" value="out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar out/target/common/obj/JAVA_LIBRARIES/core-libart_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/javalib.jar" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/../../../../" />
- <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
- <option name="ALTERNATIVE_JRE_PATH" value="1.6" />
+ <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
+ <option name="ALTERNATIVE_JRE_PATH" value="" />
<option name="ENABLE_SWING_INSPECTOR" value="false" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index be75dde91bc7..4d2d1000c5eb 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -675,7 +675,7 @@ public final class Canvas_Delegate {
graphics.fillRoundRect(
(int)left, (int)top,
(int)(right - left), (int)(bottom - top),
- (int)rx, (int)ry);
+ 2 * (int)rx, 2 * (int)ry);
}
if (style == Paint.Style.STROKE.nativeInt ||
@@ -683,7 +683,7 @@ public final class Canvas_Delegate {
graphics.drawRoundRect(
(int)left, (int)top,
(int)(right - left), (int)(bottom - top),
- (int)rx, (int)ry);
+ 2 * (int)rx, 2 * (int)ry);
}
}
});
diff --git a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
index e24b3d5ec7ef..86d8da369d36 100644
--- a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
@@ -4,10 +4,15 @@ import com.android.annotations.NonNull;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+import android.graphics.BidiRenderer;
+import android.graphics.Paint;
+import android.graphics.Paint_Delegate;
+import android.graphics.RectF;
import android.text.StaticLayout.LineBreaks;
import android.text.Primitive.PrimitiveType;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import com.ibm.icu.text.BreakIterator;
@@ -33,7 +38,7 @@ public class StaticLayout_Delegate {
new DelegateManager<Builder>(Builder.class);
@LayoutlibDelegate
- /*package*/ static int nComputeLineBreaks(long nativeBuilder, char[] inputText, float[] widths,
+ /*package*/ static int nComputeLineBreaks(long nativeBuilder,
int length, float firstWidth, int firstWidthLineCount, float restWidth,
int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle,
int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength) {
@@ -41,7 +46,7 @@ public class StaticLayout_Delegate {
Builder builder = sBuilderManager.getDelegate(nativeBuilder);
// compute all possible breakpoints.
BreakIterator it = BreakIterator.getLineInstance(new ULocale(builder.mLocale));
- it.setText(new Segment(inputText, 0, length));
+ it.setText(new Segment(builder.mText, 0, length));
// average word length in english is 5. So, initialize the possible breaks with a guess.
List<Integer> breaks = new ArrayList<Integer>((int) Math.ceil(length / 5d));
int loc;
@@ -52,7 +57,7 @@ public class StaticLayout_Delegate {
LineWidth lineWidth = new LineWidth(firstWidth, firstWidthLineCount, restWidth);
TabStops tabStopCalculator = new TabStops(variableTabStops, defaultTabStop);
- List<Primitive> primitives = computePrimitives(inputText, widths, length, breaks);
+ List<Primitive> primitives = computePrimitives(builder.mText, builder.mWidths, length, breaks);
LineBreaker lineBreaker;
if (optimize) {
lineBreaker = new OptimizingLineBreaker(primitives, lineWidth, tabStopCalculator);
@@ -119,16 +124,62 @@ public class StaticLayout_Delegate {
}
@LayoutlibDelegate
- /*package*/ static void nBuilderSetLocale(long nativeBuilder, String locale) {
+ /*package*/ static void nSetLocale(long nativeBuilder, String locale) {
Builder builder = sBuilderManager.getDelegate(nativeBuilder);
builder.mLocale = locale;
}
+ @LayoutlibDelegate
+ /*package*/ static void nSetText(long nativeBuilder, char[] text, int length) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+ builder.mText = text;
+ builder.mWidths = new float[length];
+ }
+
+
+ @LayoutlibDelegate
+ /*package*/ static float nAddStyleRun(long nativeBuilder, long nativePaint, long nativeTypeface,
+ int start, int end, boolean isRtl) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+
+ int bidiFlags = isRtl ? Paint.BIDI_FORCE_RTL : Paint.BIDI_FORCE_LTR;
+ return measureText(nativePaint, builder.mText, start, end - start, builder.mWidths, bidiFlags);
+ }
+
+
+ @LayoutlibDelegate
+ /*package*/ static void nAddMeasuredRun(long nativeBuilder, int start, int end, float[] widths) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+ System.arraycopy(widths, start, builder.mWidths, start, end - start);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nAddReplacementRun(long nativeBuilder, int start, int end, float width) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+ builder.mWidths[start] = width;
+ Arrays.fill(builder.mWidths, start + 1, end, 0.0f);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nGetWidths(long nativeBuilder, float[] floatsArray) {
+ Builder builder = sBuilderManager.getDelegate(nativeBuilder);
+ System.arraycopy(builder.mWidths, 0, floatsArray, 0, builder.mWidths.length);
+ }
+
+ private static float measureText(long nativePaint, char []text, int index, int count,
+ float[] widths, int bidiFlags) {
+ Paint_Delegate paint = Paint_Delegate.getDelegate(nativePaint);
+ RectF bounds = new BidiRenderer(null, paint, text)
+ .renderText(index, index + count, bidiFlags, widths, 0, false);
+ return bounds.right - bounds.left;
+ }
+
/**
- * Java representation of the native Builder class. It currently only stores the locale
- * set by nBuilderSetLocale.
+ * Java representation of the native Builder class.
*/
static class Builder {
String mLocale;
+ char[] mText;
+ float[] mWidths;
}
}
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 4acbd1cded0a..80036e5ecd61 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -131,11 +131,11 @@ public final class BridgeInflater extends LayoutInflater {
}
@Override
- public View createViewFromTag(View parent, String name, AttributeSet attrs,
- boolean inheritContext) {
+ public View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
+ boolean ignoreThemeAttrs) {
View view;
try {
- view = super.createViewFromTag(parent, name, attrs, inheritContext);
+ view = super.createViewFromTag(parent, name, context, attrs, ignoreThemeAttrs);
} catch (InflateException e) {
// try to load the class from using the custom view loader
try {
diff --git a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
index 7a73fae516b7..7f1e977f5b49 100644
--- a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
@@ -21,9 +21,11 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.content.Context;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.util.AttributeSet;
+import android.util.TypedValue;
import android.util.Xml;
import java.io.IOException;
@@ -36,9 +38,13 @@ import java.io.IOException;
*
*/
public class LayoutInflater_Delegate {
-
private static final String TAG_MERGE = "merge";
+ private static final String ATTR_LAYOUT = "layout";
+
+ private static final int[] ATTRS_THEME = new int[] {
+ com.android.internal.R.attr.theme };
+
public static boolean sIsInInclude = false;
/**
@@ -49,7 +55,7 @@ public class LayoutInflater_Delegate {
*/
@LayoutlibDelegate
/* package */ static void rInflate(LayoutInflater thisInflater, XmlPullParser parser,
- View parent, final AttributeSet attrs, boolean finishInflate, boolean inheritContext)
+ View parent, Context context, AttributeSet attrs, boolean finishInflate)
throws XmlPullParserException, IOException {
if (finishInflate == false) {
@@ -61,7 +67,7 @@ public class LayoutInflater_Delegate {
// ---- START DEFAULT IMPLEMENTATION.
- thisInflater.rInflate_Original(parser, parent, attrs, finishInflate, inheritContext);
+ thisInflater.rInflate_Original(parser, parent, context, attrs, finishInflate);
// ---- END DEFAULT IMPLEMENTATION.
@@ -74,15 +80,50 @@ public class LayoutInflater_Delegate {
}
@LayoutlibDelegate
- public static void parseInclude(LayoutInflater thisInflater, XmlPullParser parser, View parent,
- AttributeSet attrs, boolean inheritContext) throws XmlPullParserException, IOException {
-
+ public static void parseInclude(LayoutInflater thisInflater, XmlPullParser parser,
+ Context context, View parent, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
int type;
if (parent instanceof ViewGroup) {
- final int layout = attrs.getAttributeResourceValue(null, "layout", 0);
+ // Apply a theme wrapper, if requested. This is sort of a weird
+ // edge case, since developers think the <include> overwrites
+ // values in the AttributeSet of the included View. So, if the
+ // included View has a theme attribute, we'll need to ignore it.
+ final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
+ final int themeResId = ta.getResourceId(0, 0);
+ final boolean hasThemeOverride = themeResId != 0;
+ if (hasThemeOverride) {
+ context = new ContextThemeWrapper(context, themeResId);
+ }
+ ta.recycle();
+
+ // If the layout is pointing to a theme attribute, we have to
+ // massage the value to get a resource identifier out of it.
+ int layout = attrs.getAttributeResourceValue(null, ATTR_LAYOUT, 0);
if (layout == 0) {
- final String value = attrs.getAttributeValue(null, "layout");
+ final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
+ if (value == null || value.length() <= 0) {
+ throw new InflateException("You must specify a layout in the"
+ + " include tag: <include layout=\"@layout/layoutID\" />");
+ }
+
+ // Attempt to resolve the "?attr/name" string to an identifier.
+ layout = context.getResources().getIdentifier(value.substring(1), null, null);
+ }
+
+ // The layout might be referencing a theme attribute.
+ // ---- START CHANGES
+ if (layout != 0) {
+ final TypedValue tempValue = new TypedValue();
+ if (context.getTheme().resolveAttribute(layout, tempValue, true)) {
+ layout = tempValue.resourceId;
+ }
+ }
+ // ---- END CHANGES
+
+ if (layout == 0) {
+ final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
if (value == null) {
throw new InflateException("You must specifiy a layout in the"
+ " include tag: <include layout=\"@layout/layoutID\" />");
@@ -111,13 +152,24 @@ public class LayoutInflater_Delegate {
if (TAG_MERGE.equals(childName)) {
// Inflate all children.
- thisInflater.rInflate(childParser, parent, childAttrs, false,
- inheritContext);
+ thisInflater.rInflate(childParser, parent, context, childAttrs, false);
} else {
final View view = thisInflater.createViewFromTag(parent, childName,
- childAttrs, inheritContext);
+ context, childAttrs, hasThemeOverride);
final ViewGroup group = (ViewGroup) parent;
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, com.android.internal.R.styleable.Include);
+ final int id = a.getResourceId(
+ com.android.internal.R.styleable.Include_id, View.NO_ID);
+ final int visibility = a.getInt(
+ com.android.internal.R.styleable.Include_visibility, -1);
+ final boolean hasWidth = a.hasValue(
+ com.android.internal.R.styleable.Include_layout_width);
+ final boolean hasHeight = a.hasValue(
+ com.android.internal.R.styleable.Include_layout_height);
+ a.recycle();
+
// We try to load the layout params set in the <include /> tag. If
// they don't exist, we will rely on the layout params set in the
// included XML file.
@@ -127,40 +179,27 @@ public class LayoutInflater_Delegate {
// successfully loaded layout params from the <include /> tag,
// false means we need to rely on the included layout params.
ViewGroup.LayoutParams params = null;
- try {
- // ---- START CHANGES
- sIsInInclude = true;
- // ---- END CHANGES
-
- params = group.generateLayoutParams(attrs);
-
- } catch (RuntimeException e) {
- // ---- START CHANGES
- sIsInInclude = false;
- // ---- END CHANGES
-
- params = group.generateLayoutParams(childAttrs);
- } finally {
- // ---- START CHANGES
- sIsInInclude = false;
- // ---- END CHANGES
-
- if (params != null) {
- view.setLayoutParams(params);
+ if (hasWidth && hasHeight) {
+ try {
+ // ---- START CHANGES
+ sIsInInclude = true;
+ // ---- END CHANGES
+
+ params = group.generateLayoutParams(attrs);
+
+ } finally {
+ // ---- START CHANGES
+ sIsInInclude = false;
+ // ---- END CHANGES
}
}
+ if (params == null) {
+ params = group.generateLayoutParams(childAttrs);
+ }
+ view.setLayoutParams(params);
// Inflate all children.
- thisInflater.rInflate(childParser, view, childAttrs, true, true);
-
- // Attempt to override the included layout's android:id with the
- // one set on the <include /> tag itself.
- TypedArray a = thisInflater.mContext.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.View, 0, 0);
- int id = a.getResourceId(com.android.internal.R.styleable.View_id, View.NO_ID);
- // While we're at it, let's try to override android:visibility.
- int visibility = a.getInt(com.android.internal.R.styleable.View_visibility, -1);
- a.recycle();
+ thisInflater.rInflateChildren(childParser, view, childAttrs, true);
if (id != View.NO_ID) {
view.setId(id);
@@ -188,12 +227,6 @@ public class LayoutInflater_Delegate {
throw new InflateException("<include /> can only be used inside of a ViewGroup");
}
- final int currentDepth = parser.getDepth();
- while (((type = parser.next()) != XmlPullParser.END_TAG ||
- parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) {
- // Empty
- }
+ LayoutInflater.consumeChildElements(parser);
}
-
-
}
diff --git a/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java b/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java
new file mode 100644
index 000000000000..ec3a8d627fcc
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import com.android.layoutlib.bridge.impl.ResourceHelper;
+
+import android.graphics.Canvas;
+import android.graphics.LinearGradient;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Path;
+import android.graphics.Path.FillType;
+import android.graphics.RadialGradient;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Region.Op;
+import android.graphics.Shader.TileMode;
+
+/**
+ * Paints shadow for rounded rectangles. Inspiration from CardView. Couldn't use that directly,
+ * since it modifies the size of the content, that we can't do.
+ */
+public class RectShadowPainter {
+
+
+ private static final int START_COLOR = ResourceHelper.getColor("#37000000");
+ private static final int END_COLOR = ResourceHelper.getColor("#03000000");
+ private static final float PERPENDICULAR_ANGLE = 90f;
+
+ public static void paintShadow(Outline viewOutline, float elevation, Canvas canvas) {
+ float shadowSize = elevationToShadow(elevation);
+ int saved = modifyCanvas(canvas, shadowSize);
+ if (saved == -1) {
+ return;
+ }
+ try {
+ Paint cornerPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
+ cornerPaint.setStyle(Style.FILL);
+ Paint edgePaint = new Paint(cornerPaint);
+ edgePaint.setAntiAlias(false);
+ Rect outline = viewOutline.mRect;
+ float radius = viewOutline.mRadius;
+ float outerArcRadius = radius + shadowSize;
+ int[] colors = {START_COLOR, START_COLOR, END_COLOR};
+ cornerPaint.setShader(new RadialGradient(0, 0, outerArcRadius, colors,
+ new float[]{0f, radius / outerArcRadius, 1f}, TileMode.CLAMP));
+ edgePaint.setShader(new LinearGradient(0, 0, -shadowSize, 0, START_COLOR, END_COLOR,
+ TileMode.CLAMP));
+ Path path = new Path();
+ path.setFillType(FillType.EVEN_ODD);
+ // A rectangle bounding the complete shadow.
+ RectF shadowRect = new RectF(outline);
+ shadowRect.inset(-shadowSize, -shadowSize);
+ // A rectangle with edges corresponding to the straight edges of the outline.
+ RectF inset = new RectF(outline);
+ inset.inset(radius, radius);
+ // A rectangle used to represent the edge shadow.
+ RectF edgeShadowRect = new RectF();
+
+
+ // left and right sides.
+ edgeShadowRect.set(-shadowSize, 0f, 0f, inset.height());
+ // Left shadow
+ sideShadow(canvas, edgePaint, edgeShadowRect, outline.left, inset.top, 0);
+ // Right shadow
+ sideShadow(canvas, edgePaint, edgeShadowRect, outline.right, inset.bottom, 2);
+ // Top shadow
+ edgeShadowRect.set(-shadowSize, 0, 0, inset.width());
+ sideShadow(canvas, edgePaint, edgeShadowRect, inset.right, outline.top, 1);
+ // bottom shadow. This needs an inset so that blank doesn't appear when the content is
+ // moved up.
+ edgeShadowRect.set(-shadowSize, 0, shadowSize / 2f, inset.width());
+ edgePaint.setShader(new LinearGradient(edgeShadowRect.right, 0, edgeShadowRect.left, 0,
+ colors, new float[]{0f, 1 / 3f, 1f}, TileMode.CLAMP));
+ sideShadow(canvas, edgePaint, edgeShadowRect, inset.left, outline.bottom, 3);
+
+ // Draw corners.
+ drawCorner(canvas, cornerPaint, path, inset.right, inset.bottom, outerArcRadius, 0);
+ drawCorner(canvas, cornerPaint, path, inset.left, inset.bottom, outerArcRadius, 1);
+ drawCorner(canvas, cornerPaint, path, inset.left, inset.top, outerArcRadius, 2);
+ drawCorner(canvas, cornerPaint, path, inset.right, inset.top, outerArcRadius, 3);
+ } finally {
+ canvas.restoreToCount(saved);
+ }
+ }
+
+ private static float elevationToShadow(float elevation) {
+ // The factor is chosen by eyeballing the shadow size on device and preview.
+ return elevation * 0.5f;
+ }
+
+ /**
+ * Translate canvas by half of shadow size up, so that it appears that light is coming
+ * slightly from above. Also, remove clipping, so that shadow is not clipped.
+ */
+ private static int modifyCanvas(Canvas canvas, float shadowSize) {
+ Rect clipBounds = canvas.getClipBounds();
+ if (clipBounds.isEmpty()) {
+ return -1;
+ }
+ int saved = canvas.save();
+ // Usually canvas has been translated to the top left corner of the view when this is
+ // called. So, setting a clip rect at 0,0 will clip the top left part of the shadow.
+ // Thus, we just expand in each direction by width and height of the canvas.
+ canvas.clipRect(-canvas.getWidth(), -canvas.getHeight(), canvas.getWidth(),
+ canvas.getHeight(), Op.REPLACE);
+ canvas.translate(0, shadowSize / 2f);
+ return saved;
+ }
+
+ private static void sideShadow(Canvas canvas, Paint edgePaint,
+ RectF edgeShadowRect, float dx, float dy, int rotations) {
+ int saved = canvas.save();
+ canvas.translate(dx, dy);
+ canvas.rotate(rotations * PERPENDICULAR_ANGLE);
+ canvas.drawRect(edgeShadowRect, edgePaint);
+ canvas.restoreToCount(saved);
+ }
+
+ /**
+ * @param canvas Canvas to draw the rectangle on.
+ * @param paint Paint to use when drawing the corner.
+ * @param path A path to reuse. Prevents allocating memory for each path.
+ * @param x Center of circle, which this corner is a part of.
+ * @param y Center of circle, which this corner is a part of.
+ * @param radius radius of the arc
+ * @param rotations number of quarter rotations before starting to paint the arc.
+ */
+ private static void drawCorner(Canvas canvas, Paint paint, Path path, float x, float y,
+ float radius, int rotations) {
+ int saved = canvas.save();
+ canvas.translate(x, y);
+ path.reset();
+ path.arcTo(-radius, -radius, radius, radius, rotations * PERPENDICULAR_ANGLE,
+ PERPENDICULAR_ANGLE, false);
+ path.lineTo(0, 0);
+ path.close();
+ canvas.drawPath(path, paint);
+ canvas.restoreToCount(saved);
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java b/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
index 82ae1df33583..e72a0db47c09 100644
--- a/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
@@ -16,12 +16,9 @@
package android.view;
-import com.android.annotations.NonNull;
-import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.resources.Density;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap_Delegate;
import android.graphics.Canvas;
@@ -29,8 +26,6 @@ import android.graphics.Outline;
import android.graphics.Path_Delegate;
import android.graphics.Rect;
import android.graphics.Region.Op;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
import android.view.animation.Transformation;
import java.awt.Graphics2D;
@@ -50,33 +45,36 @@ public class ViewGroup_Delegate {
@LayoutlibDelegate
/*package*/ static boolean drawChild(ViewGroup thisVG, Canvas canvas, View child,
long drawingTime) {
- boolean retVal = thisVG.drawChild_Original(canvas, child, drawingTime);
if (child.getZ() > thisVG.getZ()) {
ViewOutlineProvider outlineProvider = child.getOutlineProvider();
Outline outline = new Outline();
outlineProvider.getOutline(child, outline);
-
+ if (outline.mPath == null && outline.mRect == null) {
+ // Sometimes, the bounds of the background drawable are not set until View.draw()
+ // is called. So, we set the bounds manually and try to get the outline again.
+ child.getBackground().setBounds(0, 0, child.mRight - child.mLeft,
+ child.mBottom - child.mTop);
+ outlineProvider.getOutline(child, outline);
+ }
if (outline.mPath != null || (outline.mRect != null && !outline.mRect.isEmpty())) {
int restoreTo = transformCanvas(thisVG, canvas, child);
drawShadow(thisVG, canvas, child, outline);
canvas.restoreToCount(restoreTo);
}
}
- return retVal;
+ return thisVG.drawChild_Original(canvas, child, drawingTime);
}
private static void drawShadow(ViewGroup parent, Canvas canvas, View child,
Outline outline) {
+ float elevation = getElevation(child, parent);
+ if(outline.mRect != null) {
+ RectShadowPainter.paintShadow(outline, elevation, canvas);
+ return;
+ }
BufferedImage shadow = null;
- int x = 0;
- if (outline.mRect != null) {
- Shadow s = getRectShadow(parent, canvas, child, outline);
- if (s != null) {
- shadow = s.mShadow;
- x = -s.mShadowWidth;
- }
- } else if (outline.mPath != null) {
- shadow = getPathShadow(child, outline, canvas);
+ if (outline.mPath != null) {
+ shadow = getPathShadow(outline, canvas, elevation);
}
if (shadow == null) {
return;
@@ -85,52 +83,17 @@ public class ViewGroup_Delegate {
Density.getEnum(canvas.getDensity()));
Rect clipBounds = canvas.getClipBounds();
Rect newBounds = new Rect(clipBounds);
- newBounds.left = newBounds.left + x;
+ newBounds.inset((int)-elevation, (int)-elevation);
canvas.clipRect(newBounds, Op.REPLACE);
- canvas.drawBitmap(bitmap, x, 0, null);
+ canvas.drawBitmap(bitmap, 0, 0, null);
canvas.clipRect(clipBounds, Op.REPLACE);
}
- private static Shadow getRectShadow(ViewGroup parent, Canvas canvas, View child,
- Outline outline) {
- BufferedImage shadow;
- Rect clipBounds = canvas.getClipBounds();
- if (clipBounds.isEmpty()) {
- return null;
- }
- float height = child.getZ() - parent.getZ();
- // Draw large shadow if difference in z index is more than 10dp
- float largeShadowThreshold = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10f,
- getMetrics(child));
- boolean largeShadow = height > largeShadowThreshold;
- int shadowSize = largeShadow ? ShadowPainter.SHADOW_SIZE : ShadowPainter.SMALL_SHADOW_SIZE;
- shadow = new BufferedImage(clipBounds.width() + shadowSize, clipBounds.height(),
- BufferedImage.TYPE_INT_ARGB);
- Graphics2D graphics = shadow.createGraphics();
- Rect rect = outline.mRect;
- if (largeShadow) {
- ShadowPainter.drawRectangleShadow(graphics,
- rect.left + shadowSize, rect.top, rect.width(), rect.height());
- } else {
- ShadowPainter.drawSmallRectangleShadow(graphics,
- rect.left + shadowSize, rect.top, rect.width(), rect.height());
- }
- graphics.dispose();
- return new Shadow(shadow, shadowSize);
- }
-
- @NonNull
- private static DisplayMetrics getMetrics(View view) {
- Context context = view.getContext();
- context = BridgeContext.getBaseContext(context);
- if (context instanceof BridgeContext) {
- return ((BridgeContext) context).getMetrics();
- }
- throw new RuntimeException("View " + view.getClass().getName() + " not created with the " +
- "right context");
+ private static float getElevation(View child, ViewGroup parent) {
+ return child.getZ() - parent.getZ();
}
- private static BufferedImage getPathShadow(View child, Outline outline, Canvas canvas) {
+ private static BufferedImage getPathShadow(Outline outline, Canvas canvas, float elevation) {
Rect clipBounds = canvas.getClipBounds();
if (clipBounds.isEmpty()) {
return null;
@@ -140,7 +103,7 @@ public class ViewGroup_Delegate {
Graphics2D graphics = image.createGraphics();
graphics.draw(Path_Delegate.getDelegate(outline.mPath.mNativePath).getJavaShape());
graphics.dispose();
- return ShadowPainter.createDropShadow(image, ((int) child.getZ()));
+ return ShadowPainter.createDropShadow(image, (int) elevation);
}
// Copied from android.view.View#draw(Canvas, ViewGroup, long) and removed code paths
@@ -194,15 +157,4 @@ public class ViewGroup_Delegate {
}
return restoreTo;
}
-
- private static class Shadow {
- public BufferedImage mShadow;
- public int mShadowWidth;
-
- public Shadow(BufferedImage shadow, int shadowWidth) {
- mShadow = shadow;
- mShadowWidth = shadowWidth;
- }
-
- }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index e1c58fd5b5f5..8e74ce1527b6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -1010,6 +1010,12 @@ public final class BridgeContext extends Context {
}
@Override
+ public int checkSelfPermission(String arg0) {
+ // pass
+ return 0;
+ }
+
+ @Override
public int checkPermission(String arg0, int arg1, int arg2, IBinder arg3) {
// pass
return 0;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 39ebdfce2cf2..085df859a963 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -145,4 +145,14 @@ public class BridgePowerManager implements IPowerManager {
public void boostScreenBrightness(long time) throws RemoteException {
// pass for now.
}
+
+ @Override
+ public boolean isDeviceIdleMode() throws RemoteException {
+ return false;
+ }
+
+ @Override
+ public boolean isScreenBrightnessBoosted() throws RemoteException {
+ return false;
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
index dde041ba1550..9f9b968a6598 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
@@ -16,6 +16,8 @@
package com.android.layoutlib.bridge.bars;
+import android.os.Build.VERSION_CODES;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -40,12 +42,12 @@ public class Config {
private static final int BLACK = 0xFF000000;
public static boolean showOnScreenNavBar(int platformVersion) {
- return platformVersion == 0 || platformVersion >= ICE_CREAM_SANDWICH;
+ return isGreaterOrEqual(platformVersion, ICE_CREAM_SANDWICH);
}
public static int getStatusBarColor(int platformVersion) {
// return white for froyo and earlier; black otherwise.
- return platformVersion == 0 || platformVersion >= GINGERBREAD ? BLACK : WHITE;
+ return isGreaterOrEqual(platformVersion, GINGERBREAD) ? BLACK : WHITE;
}
public static List<String> getResourceDirs(int platformVersion) {
@@ -98,7 +100,7 @@ public class Config {
}
public static int getTimeColor(int platformVersion) {
- if (platformVersion == 0 || platformVersion >= KITKAT ||
+ if (isGreaterOrEqual(platformVersion, KITKAT) ||
platformVersion > FROYO && platformVersion < HONEYCOMB) {
// Gingerbread and KitKat onwards.
return WHITE;
@@ -117,4 +119,13 @@ public class Config {
public static String getWifiIconType(int platformVersion) {
return platformVersion == 0 ? "xml" : "png";
}
+
+ /**
+ * Compare simulated platform version and code from {@link VERSION_CODES} to check if
+ * the simulated platform is greater than or equal to the version code.
+ */
+ public static boolean isGreaterOrEqual(int platformVersion, int code) {
+ // simulated platform version = 0 means that we use the latest.
+ return platformVersion == 0 || platformVersion >= code;
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index 13ddf078c98a..bc1a41d48bfb 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -16,6 +16,7 @@
package com.android.layoutlib.bridge.bars;
+import com.android.annotations.NonNull;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.StyleResourceValue;
@@ -26,6 +27,7 @@ import com.android.layoutlib.bridge.impl.ParserFactory;
import com.android.layoutlib.bridge.impl.ResourceHelper;
import com.android.resources.Density;
import com.android.resources.LayoutDirection;
+import com.android.resources.ResourceType;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -47,6 +49,8 @@ import android.widget.TextView;
import java.io.IOException;
import java.io.InputStream;
+import static android.os.Build.VERSION_CODES.LOLLIPOP;
+
/**
* Base "bar" class for the window decor around the the edited layout.
* This is basically an horizontal layout that loads a given layout on creation (it is read
@@ -63,7 +67,7 @@ abstract class CustomBar extends LinearLayout {
protected abstract TextView getStyleableTextView();
- protected CustomBar(Context context, int orientation, String layoutPath,
+ protected CustomBar(BridgeContext context, int orientation, String layoutPath,
String name, int simulatedPlatformVersion) throws XmlPullParserException {
super(context);
mSimulatedPlatformVersion = simulatedPlatformVersion;
@@ -197,7 +201,7 @@ abstract class CustomBar extends LinearLayout {
ResourceValue textColor = res.findItemInStyle(textStyle, "textColor",
- true /*isFrameworkAttr*/);
+ true);
textColor = res.resolveResValue(textColor);
if (textColor != null) {
ColorStateList stateList = ResourceHelper.getColorStateList(
@@ -210,12 +214,39 @@ abstract class CustomBar extends LinearLayout {
}
}
+ /**
+ * Given a theme attribute name, get the color referenced by it. The theme attribute may be
+ * used in a layout like "?attr/foo".
+ * <p/>
+ * Returns 0 if not found.
+ *
+ * @throws NumberFormatException if color resolved to an invalid string.
+ */
+ protected int getThemeAttrColor(@NonNull String attrName, boolean isFramework) {
+ if (!Config.isGreaterOrEqual(mSimulatedPlatformVersion, LOLLIPOP)) {
+ return 0;
+ }
+ assert mContext instanceof BridgeContext;
+ BridgeContext context = ((BridgeContext) mContext);
+ RenderResources renderResources = context.getRenderResources();
+ // From ?attr/foo to @color/bar. This is most likely an ItemResourceValue.
+ ResourceValue resource = renderResources.findItemInTheme(attrName, isFramework);
+ if (resource != null) {
+ // Form @color/bar to the #AARRGGBB
+ resource = renderResources.resolveResValue(resource);
+ }
+ if (resource != null && ResourceType.COLOR.equals(resource.getResourceType())) {
+ return ResourceHelper.getColor(resource.getValue());
+ }
+ return 0;
+ }
+
private ResourceValue getResourceValue(String reference) {
BridgeContext bridgeContext = (BridgeContext) mContext;
RenderResources res = bridgeContext.getRenderResources();
// find the resource
- ResourceValue value = res.findResValue(reference, false /*isFramework*/);
+ ResourceValue value = res.findResValue(reference, false);
// resolve it if needed
return res.resolveResValue(value);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
index 283ff57d3825..9450b6c3d3e7 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
@@ -16,22 +16,26 @@
package com.android.layoutlib.bridge.bars;
+import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.resources.Density;
import org.xmlpull.v1.XmlPullParserException;
-import android.content.Context;
import android.widget.LinearLayout;
import android.widget.TextView;
public class NavigationBar extends CustomBar {
- public NavigationBar(Context context, Density density, int orientation, boolean isRtl,
+ /** Navigation bar background color attribute name. */
+ private static final String ATTR_COLOR = "navigationBarColor";
+
+ public NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
boolean rtlEnabled, int simulatedPlatformVersion) throws XmlPullParserException {
super(context, orientation, "/bars/navigation_bar.xml", "navigation_bar.xml",
simulatedPlatformVersion);
- setBackgroundColor(0xFF000000);
+ int color = getThemeAttrColor(ATTR_COLOR, true);
+ setBackgroundColor(color == 0 ? 0xFF000000 : color);
// Cannot access the inside items through id because no R.id values have been
// created for them.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
index c7c62d670f6e..e5f1f68459e6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
@@ -25,7 +25,6 @@ import com.android.resources.Density;
import org.xmlpull.v1.XmlPullParserException;
-import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.Gravity;
import android.view.View;
@@ -38,20 +37,21 @@ import java.io.InputStream;
public class StatusBar extends CustomBar {
- private final Context mContext;
private final int mSimulatedPlatformVersion;
+ /** Status bar background color attribute name. */
+ private static final String ATTR_COLOR = "colorPrimaryDark";
- public StatusBar(Context context, Density density, int direction, boolean RtlEnabled,
+ public StatusBar(BridgeContext context, Density density, int direction, boolean RtlEnabled,
int simulatedPlatformVersion) throws XmlPullParserException {
// FIXME: if direction is RTL but it's not enabled in application manifest, mirror this bar.
super(context, LinearLayout.HORIZONTAL, "/bars/status_bar.xml", "status_bar.xml",
simulatedPlatformVersion);
- mContext = context;
mSimulatedPlatformVersion = simulatedPlatformVersion;
// FIXME: use FILL_H?
setGravity(Gravity.START | Gravity.TOP | Gravity.RIGHT);
- setBackgroundColor(Config.getStatusBarColor(simulatedPlatformVersion));
+ int color = getThemeAttrColor(ATTR_COLOR, true);
+ setBackgroundColor(color == 0 ? Config.getStatusBarColor(simulatedPlatformVersion) : color);
// Cannot access the inside items through id because no R.id values have been
// created for them.
@@ -82,10 +82,8 @@ public class StatusBar extends CustomBar {
try {
BridgeXmlBlockParser parser = new BridgeXmlBlockParser(
ParserFactory.create(stream, null), (BridgeContext) mContext, true);
- Drawable drawable = Drawable.createFromXml(mContext.getResources(), parser);
- if (drawable != null) {
- imageView.setImageDrawable(drawable);
- }
+ imageView.setImageDrawable(
+ Drawable.createFromXml(mContext.getResources(), parser));
} catch (XmlPullParserException e) {
Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Unable to draw wifi icon", e,
null);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
index 10f138388c8a..c610601ef019 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
@@ -16,9 +16,10 @@
package com.android.layoutlib.bridge.bars;
+import com.android.layoutlib.bridge.android.BridgeContext;
+
import org.xmlpull.v1.XmlPullParserException;
-import android.content.Context;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -26,7 +27,7 @@ public class TitleBar extends CustomBar {
private TextView mTextView;
- public TitleBar(Context context, String label, int simulatedPlatformVersion)
+ public TitleBar(BridgeContext context, String label, int simulatedPlatformVersion)
throws XmlPullParserException {
super(context, LinearLayout.HORIZONTAL, "/bars/title_bar.xml", "title_bar.xml",
simulatedPlatformVersion);
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle
index 80be12d767c4..0f37fce20104 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build.gradle
@@ -3,7 +3,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:0.12.+'
+ classpath 'com.android.tools.build:gradle:1.1.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@@ -19,22 +19,24 @@ allprojects {
apply plugin: 'com.android.application'
android {
- compileSdkVersion 20
- buildToolsVersion '20'
+ compileSdkVersion 21
+ buildToolsVersion '21.1.2'
defaultConfig {
applicationId 'com.android.layoutlib.test.myapplication'
minSdkVersion 19
- targetSdkVersion 20
+ targetSdkVersion 21
versionCode 1
versionName '1.0'
}
buildTypes {
release {
- runProguard false
+ minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
- productFlavors {
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_6
+ targetCompatibility JavaVersion.VERSION_1_6
}
}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/androidTest/debug/com/android/layoutlib/test/myapplication/test/BuildConfig.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/androidTest/debug/com/android/layoutlib/test/myapplication/test/BuildConfig.class
new file mode 100644
index 000000000000..1ca7e01d80ae
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/androidTest/debug/com/android/layoutlib/test/myapplication/test/BuildConfig.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/BuildConfig.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/BuildConfig.class
index 2b4f7bf37dde..ceb56bff3e7f 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/BuildConfig.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/BuildConfig.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class
new file mode 100644
index 000000000000..c3630552c7fe
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomCalendar.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class
new file mode 100644
index 000000000000..edda3de57058
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/CustomDate.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
index 943cdf1bbcc5..e38f437a0ce4 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/activity.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradle/wrapper/gradle-wrapper.properties b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradle/wrapper/gradle-wrapper.properties
index 5de946b072f1..3b51ffe88bc7 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradle/wrapper/gradle-wrapper.properties
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed Apr 10 15:27:10 PDT 2013
+#Tue Mar 17 15:13:06 PDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/androidTest/java/com/android/layoulib/test/myapplication/ApplicationTest.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/androidTest/java/com/android/layoulib/test/myapplication/ApplicationTest.java
deleted file mode 100644
index 7304af13b129..000000000000
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/androidTest/java/com/android/layoulib/test/myapplication/ApplicationTest.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.android.layoulib.test.myapplication;
-
-import android.app.Application;
-import android.test.ApplicationTestCase;
-
-/**
- * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
- */
-public class ApplicationTest extends ApplicationTestCase<Application> {
- public ApplicationTest() {
- super(Application.class);
- }
-} \ No newline at end of file
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomCalendar.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomCalendar.java
new file mode 100644
index 000000000000..80bbaf139b4c
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomCalendar.java
@@ -0,0 +1,31 @@
+package com.android.layoutlib.test.myapplication;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.CalendarView;
+
+public class CustomCalendar extends CalendarView {
+ public CustomCalendar(Context context) {
+ super(context);
+ init();
+ }
+
+ public CustomCalendar(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public CustomCalendar(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ public CustomCalendar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init();
+ }
+
+ private void init() {
+ setDate(871703200000L, false, true);
+ }
+}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomDate.java b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomDate.java
new file mode 100644
index 000000000000..cb750f49322b
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/java/com/android/layoutlib/test/myapplication/CustomDate.java
@@ -0,0 +1,31 @@
+package com.android.layoutlib.test.myapplication;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.DatePicker;
+
+public class CustomDate extends DatePicker {
+ public CustomDate(Context context) {
+ super(context);
+ init();
+ }
+
+ public CustomDate(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public CustomDate(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ public CustomDate(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init();
+ }
+
+ private void init() {
+ init(2015, 0, 20, null);
+ }
+}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/layout.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/layout.xml
index b8ec566159dd..c1f663e9fa8a 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/layout.xml
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/layout.xml
@@ -1,17 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical" android:layout_width="match_parent"
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:columnCount="2"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Some text"/>
- <DatePicker
- android:layout_width="100dp"
- android:layout_height="100dp"/>
- <CalendarView
+ <Switch
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:checked="true"
+ android:layout_gravity="center"
+ />
+ <com.android.layoutlib.test.myapplication.CustomDate
android:layout_width="100dp"
- android:layout_height="100dp"/>
-</LinearLayout> \ No newline at end of file
+ android:layout_height="wrap_content"/>
+ <com.android.layoutlib.test.myapplication.CustomCalendar
+ android:layout_width="200dp"
+ android:layout_gravity="center_horizontal"
+ android:layout_height="200dp"/>
+</GridLayout> \ No newline at end of file
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java
index e13ad721d19e..d7e5486cfa8b 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/ImageUtils.java
@@ -56,7 +56,7 @@ public class ImageUtils {
private static final int THUMBNAIL_SIZE = 250;
- private static final double MAX_PERCENT_DIFFERENCE = 0.1;
+ private static final double MAX_PERCENT_DIFFERENCE = 0.3;
public static void requireSimilar(@NonNull String relativePath, @NonNull BufferedImage image)
throws IOException {
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index a86fcdd95f7f..ac23564012b3 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -316,7 +316,8 @@ public class Main {
FolderConfiguration config = configGenerator.getFolderConfig();
ResourceResolver resourceResolver =
ResourceResolver.create(mProjectResources.getConfiguredResources(config),
- mFrameworkRepo.getConfiguredResources(config), "Theme.Material", false);
+ mFrameworkRepo.getConfiguredResources(config),
+ "Theme.Material.Light.DarkActionBar", false);
return new SessionParams(
layoutParser,
@@ -336,7 +337,7 @@ public class Main {
@Override
public void warning(String tag, String message, Object data) {
System.out.println("Warning " + tag + ": " + message);
- fail(message);
+ failWithMsg(message);
}
@Override
@@ -346,13 +347,13 @@ public class Main {
if (throwable != null) {
throwable.printStackTrace();
}
- fail(message);
+ failWithMsg(message);
}
@Override
public void error(String tag, String message, Object data) {
System.out.println("Error " + tag + ": " + message);
- fail(message);
+ failWithMsg(message);
}
@Override
@@ -361,7 +362,7 @@ public class Main {
if (throwable != null) {
throwable.printStackTrace();
}
- fail(message);
+ failWithMsg(message);
}
};
}
@@ -376,12 +377,12 @@ public class Main {
if (t != null) {
t.printStackTrace();
}
- fail(String.format(msgFormat, args));
+ failWithMsg(msgFormat, args);
}
@Override
public void warning(String msgFormat, Object... args) {
- fail(String.format(msgFormat, args));
+ failWithMsg(msgFormat, args);
}
@Override
@@ -397,4 +398,8 @@ public class Main {
}
return mLogger;
}
+
+ private static void failWithMsg(String msgFormat, Object... args) {
+ fail(msgFormat == null || args == null ? "" : String.format(msgFormat, args));
+ }
}
diff --git a/wifi/java/android/net/wifi/IRttManager.aidl b/wifi/java/android/net/wifi/IRttManager.aidl
index d929f55987ee..90f66c4adc1a 100644
--- a/wifi/java/android/net/wifi/IRttManager.aidl
+++ b/wifi/java/android/net/wifi/IRttManager.aidl
@@ -15,8 +15,8 @@
*/
package android.net.wifi;
-
import android.os.Messenger;
+import android.net.wifi.RttManager;
/**
* {@hide}
@@ -24,4 +24,5 @@ import android.os.Messenger;
interface IRttManager
{
Messenger getMessenger();
+ RttManager.RttCapabilities getRttCapabilities();
}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index bc95a36a0f69..53424948d359 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -155,6 +155,10 @@ interface IWifiManager
void setAllowScansWithTraffic(int enabled);
+ boolean getAllowScansWhileAssociated();
+
+ void setAllowScansWhileAssociated(boolean enabled);
+
WifiConnectionStatistics getConnectionStatistics();
void disableEphemeralNetwork(String SSID);
diff --git a/wifi/java/android/net/wifi/RttManager.aidl b/wifi/java/android/net/wifi/RttManager.aidl
new file mode 100644
index 000000000000..5c6d44710ea5
--- /dev/null
+++ b/wifi/java/android/net/wifi/RttManager.aidl
@@ -0,0 +1,18 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+parcelable RttManager.RttCapabilities; \ No newline at end of file
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index 57343c52262d..65ecf5d728a6 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -26,10 +26,19 @@ public class RttManager {
private static final boolean DBG = true;
private static final String TAG = "RttManager";
- public static final int RTT_TYPE_UNSPECIFIED = 0;
- public static final int RTT_TYPE_ONE_SIDED = 1;
- public static final int RTT_TYPE_11_V = 2;
- public static final int RTT_TYPE_11_MC = 4;
+ /** @deprecated Type must be specified*/
+ @Deprecated
+ public static final int RTT_TYPE_UNSPECIFIED = 0;
+ public static final int RTT_TYPE_ONE_SIDED = 1;
+
+ /** @deprecated It is not supported*/
+ @Deprecated
+ public static final int RTT_TYPE_11_V = 2;
+ public static final int RTT_TYPE_TWO_SIDED = 4;
+
+ /** @deprecated It is not supported*/
+ @Deprecated
+ public static final int RTT_TYPE_11_MC = 4;
public static final int RTT_PEER_TYPE_UNSPECIFIED = 0;
public static final int RTT_PEER_TYPE_AP = 1;
@@ -42,6 +51,9 @@ public class RttManager {
public static final int RTT_CHANNEL_WIDTH_80P80 = 4;
public static final int RTT_CHANNEL_WIDTH_5 = 5;
public static final int RTT_CHANNEL_WIDTH_10 = 6;
+
+ /** @deprecated channel info must be specified*/
+ @Deprecated
public static final int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1;
public static final int RTT_STATUS_SUCCESS = 0;
@@ -53,6 +65,12 @@ public class RttManager {
public static final int RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6;
public static final int RTT_STATUS_FAIL_NO_CAPABILITY = 7;
public static final int RTT_STATUS_ABORTED = 8;
+ //if the T1-T4 or TOD/TOA Timestamp is illegal
+ public static final int RTT_STATUS_FAIL_INVALID_TS = 9;
+ //11mc protocol failed, eg, unrecognized FTMR/FTM
+ public static final int RTT_STATUS_FAIL_PROTOCOL = 10;
+ public static final int RTT_STATUS_FAIL_SCHEDULE = 11;
+ public static final int RTT_STATUS_FAIL_BUSY_TRY_LATER = 12;
public static final int REASON_UNSPECIFIED = -1;
public static final int REASON_NOT_AVAILABLE = -2;
@@ -61,41 +79,269 @@ public class RttManager {
public static final String DESCRIPTION_KEY = "android.net.wifi.RttManager.Description";
+ /**
+ * RTT BW supported bit mask
+ */
+ public static final int RTT_BW_5_SUPPORT = 0x1;
+ public static final int RTT_BW_10_SUPPORT = 0x2;
+ public static final int RTT_BW_20_SUPPORT = 0x4;
+ public static final int RTT_BW_40_SUPPORT = 0x8;
+ public static final int RTT_BW_80_SUPPORT = 0x10;
+ public static final int RTT_BW_160_SUPPORT = 0x20;
+
+ /**
+ * RTT Preamble Support bit mask
+ */
+ public static final int PREAMBLE_LEGACY = 0x1;
+ public static final int PREAMBLE_HT = 0x2;
+ public static final int PREAMBLE_VHT = 0x4;
+
+ /** @deprecated It has been replaced by RttCapabilities*/
+ @Deprecated
public class Capabilities {
public int supportedType;
public int supportedPeerType;
}
+ /** @deprecated It has been replaced by getRttCapabilities*/
+ @Deprecated
public Capabilities getCapabilities() {
return new Capabilities();
}
+ /**
+ * This class describe the RTT capability of the Hardware
+ */
+ public static class RttCapabilities implements Parcelable {
+ /** @deprecated It is not supported*/
+ @Deprecated
+ public boolean supportedType;
+ /** @deprecated It is not supported*/
+ @Deprecated
+ public boolean supportedPeerType;
+ //1-sided rtt measurement is supported
+ public boolean oneSidedRttSupported;
+ //11mc 2-sided rtt measurement is supported
+ public boolean twoSided11McRttSupported;
+ //location configuration information supported
+ public boolean lciSupported;
+ //location civic records supported
+ public boolean lcrSupported;
+ //preamble supported, see bit mask definition above
+ public int preambleSupported;
+ //RTT bandwidth supported
+ public int bwSupported;
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("oneSidedRtt ").
+ append(oneSidedRttSupported ? "is Supported. " : "is not supported. ").
+ append("twoSided11McRtt ").
+ append(twoSided11McRttSupported ? "is Supported. " : "is not supported. ").
+ append("lci ").
+ append(lciSupported ? "is Supported. " : "is not supported. ").
+ append("lcr ").
+ append(lcrSupported ? "is Supported. " : "is not supported. ");
+
+ if ((preambleSupported & PREAMBLE_LEGACY) != 0) {
+ sb.append("Legacy ");
+ }
+
+ if ((preambleSupported & PREAMBLE_HT) != 0) {
+ sb.append("HT ");
+ }
+
+ if ((preambleSupported & PREAMBLE_VHT) != 0) {
+ sb.append("VHT ");
+ }
+
+ sb.append("is supported. \n");
+
+ if ((bwSupported & RTT_BW_5_SUPPORT) != 0) {
+ sb.append("5 MHz ");
+ }
+
+ if ((bwSupported & RTT_BW_10_SUPPORT) != 0) {
+ sb.append("10 MHz ");
+ }
+
+ if ((bwSupported & RTT_BW_20_SUPPORT) != 0) {
+ sb.append("20 MHz ");
+ }
+
+ if ((bwSupported & RTT_BW_40_SUPPORT) != 0) {
+ sb.append("40 MHz ");
+ }
+
+ if ((bwSupported & RTT_BW_80_SUPPORT) != 0) {
+ sb.append("80 MHz ");
+ }
+
+ if ((bwSupported & RTT_BW_160_SUPPORT) != 0) {
+ sb.append("160 MHz ");
+ }
+
+ sb.append("is supported.");
+
+ return sb.toString();
+ }
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(oneSidedRttSupported ? 1 : 0);
+ dest.writeInt(twoSided11McRttSupported ? 1 : 0);
+ dest.writeInt(lciSupported ? 1 : 0);
+ dest.writeInt(lcrSupported ? 1 : 0);
+ dest.writeInt(preambleSupported);
+ dest.writeInt(bwSupported);
+
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<RttCapabilities> CREATOR =
+ new Creator<RttCapabilities>() {
+ public RttCapabilities createFromParcel(Parcel in) {
+ RttCapabilities capabilities = new RttCapabilities();
+ capabilities.oneSidedRttSupported = in.readInt() == 1 ? true : false;
+ capabilities.twoSided11McRttSupported = in.readInt() == 1 ? true : false;
+ capabilities.lciSupported = in.readInt() == 1 ? true : false;
+ capabilities.lcrSupported = in.readInt() == 1 ? true : false;
+ capabilities.preambleSupported = in.readInt();
+ capabilities.bwSupported = in.readInt();
+ return capabilities;
+ }
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public RttCapabilities[] newArray(int size) {
+ return new RttCapabilities[size];
+ }
+ };
+ }
+
+ public RttCapabilities getRttCapabilities() {
+ synchronized (sCapabilitiesLock) {
+ if (mRttCapabilities == null) {
+ try {
+ mRttCapabilities = mService.getRttCapabilities();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can not get RTT Capabilities");
+ }
+ }
+ return mRttCapabilities;
+ }
+ }
+
/** specifies parameters for RTT request */
public static class RttParams {
-
- /** type of device being ranged; one of RTT_PEER_TYPE_AP or RTT_PEER_TYPE_STA */
+ /**
+ * type of destination device being ranged; one of RTT_PEER_TYPE_AP or RTT_PEER_TYPE_STA
+ */
public int deviceType;
- /** type of RTT being sought; one of RTT_TYPE_ONE_SIDED
- * RTT_TYPE_11_V or RTT_TYPE_11_MC or RTT_TYPE_UNSPECIFIED */
+ /**
+ * type of RTT measurement method; one of RTT_TYPE_ONE_SIDED or RTT_TYPE_TWO_SIDED.
+ */
public int requestType;
/** mac address of the device being ranged */
public String bssid;
- /** channel frequency that the device is on; optional */
+ /**
+ * The primary 20 MHz frequency (in MHz) of the channel over which the client is
+ * communicating with the access point.Similar as ScanResult.frequency
+ */
public int frequency;
- /** optional channel width. wider channels result in better accuracy,
- * but they take longer time, and even get aborted may times; use
- * RTT_CHANNEL_WIDTH_UNSPECIFIED if not specifying */
+ /**
+ * channel width used for RTT measurement. User need verify the highest BW the destination
+ * support (from scan result etc) before set this value. Wider channels result usually give
+ * better accuracy. However, the frame loss can increase. Similar as ScanResult.channelWidth
+ */
public int channelWidth;
- /** number of samples to be taken */
+ /**
+ * Not used if the AP bandwidth is 20 MHz
+ * If the AP use 40, 80 or 160 MHz, this is the center frequency
+ * if the AP use 80 + 80 MHz, this is the center frequency of the first segment
+ * similar as ScanResult.centerFreq0
+ */
+ public int centerFreq0;
+
+ /**
+ * Only used if the AP bandwidth is 80 + 80 MHz
+ * if the AP use 80 + 80 MHz, this is the center frequency of the second segment
+ * similar as ScanResult.centerFreq1
+ */
+ public int centerFreq1;
+ /**
+ * number of samples to be taken
+ * @deprecated It has been replaced by numSamplesPerBurst
+ */
+ @Deprecated
public int num_samples;
- /** number of retries if a sample fails */
+ /**
+ * number of retries if a sample fails
+ * @deprecated It has been replaced by numRetriesPerMeasurementFrame
+ */
+ @Deprecated
public int num_retries;
+
+ /** Number of burst. fixed to 1 for single side RTT*/
+ public int numberBurst;
+
+ /** valid only if numberBurst > 1, interval between burst(ms). Not used by singe side RTT */
+ public int interval;
+
+ /** number of samples to be taken in one burst*/
+ public int numSamplesPerBurst;
+
+ /** number of retries for each measurement frame if a sample fails
+ * Only used by single side RTT
+ */
+ public int numRetriesPerMeasurementFrame;
+
+ /** number of retries for FTMR frame if fails Only used by 80211MC double side RTT */
+ public int numRetriesPerFTMR;
+
+ /** Request LCI information */
+ public boolean LCIRequest;
+
+ /** Request LCR information */
+ public boolean LCRRequest;
+
+ /** Timeout for each burst, unit of 250 us*/
+ public int burstTimeout;
+
+ /** preamble used for RTT measurement
+ * should be one of PREAMBLE_LEGACY, PREAMBLE_HT, PREAMBLE_VHT
+ */
+ public int preamble;
+
+ /** bandWidth used for RTT measurement.User need verify the highest BW the destination
+ * support (from scan result etc) before set this value. Wider channels result usually give
+ * better accuracy. However, the frame loss can increase too.
+ * should be one of RTT_CHANNEL_WIDTH_20 to RTT_CHANNEL_WIDTH_80
+ */
+ public int bandwidth;
+
+ public RttParams() {
+ //provide initial value for RttParams
+ deviceType = RTT_PEER_TYPE_AP;
+ numberBurst = 1;
+ numSamplesPerBurst = 8;
+ numRetriesPerMeasurementFrame = 0;
+ burstTimeout = 40 + numSamplesPerBurst *4;
+ preamble = PREAMBLE_LEGACY;
+ bandwidth = RTT_CHANNEL_WIDTH_20;
+ }
}
/** pseudo-private class used to parcel arguments */
@@ -121,10 +367,20 @@ public class RttManager {
dest.writeInt(params.deviceType);
dest.writeInt(params.requestType);
dest.writeString(params.bssid);
- dest.writeInt(params.frequency);
dest.writeInt(params.channelWidth);
- dest.writeInt(params.num_samples);
- dest.writeInt(params.num_retries);
+ dest.writeInt(params.frequency);
+ dest.writeInt(params.centerFreq0);
+ dest.writeInt(params.centerFreq1);
+ dest.writeInt(params.numberBurst);
+ dest.writeInt(params.interval);
+ dest.writeInt(params.numSamplesPerBurst);
+ dest.writeInt(params.numRetriesPerMeasurementFrame);
+ dest.writeInt(params.numRetriesPerFTMR);
+ dest.writeInt(params.LCIRequest ? 1 : 0);
+ dest.writeInt(params.LCRRequest ? 1 : 0);
+ dest.writeInt(params.burstTimeout);
+ dest.writeInt(params.preamble);
+ dest.writeInt(params.bandwidth);
}
} else {
dest.writeInt(0);
@@ -148,11 +404,20 @@ public class RttManager {
params[i].deviceType = in.readInt();
params[i].requestType = in.readInt();
params[i].bssid = in.readString();
- params[i].frequency = in.readInt();
params[i].channelWidth = in.readInt();
- params[i].num_samples = in.readInt();
- params[i].num_retries = in.readInt();
-
+ params[i].frequency = in.readInt();
+ params[i].centerFreq0 = in.readInt();
+ params[i].centerFreq1 = in.readInt();
+ params[i].numberBurst = in.readInt();
+ params[i].interval = in.readInt();
+ params[i].numSamplesPerBurst = in.readInt();
+ params[i].numRetriesPerMeasurementFrame = in.readInt();
+ params[i].numRetriesPerFTMR = in.readInt();
+ params[i].LCIRequest = in.readInt() == 1 ? true : false;
+ params[i].LCRRequest = in.readInt() == 1 ? true : false;
+ params[i].burstTimeout = in.readInt();
+ params[i].preamble = in.readInt();
+ params[i].bandwidth = in.readInt();
}
ParcelableRttParams parcelableParams = new ParcelableRttParams(params);
@@ -165,46 +430,143 @@ public class RttManager {
};
}
+ public class wifiInformationElement {
+ /** Information Element ID*/
+ public int id;
+ public String data;
+ }
/** specifies RTT results */
public static class RttResult {
/** mac address of the device being ranged */
public String bssid;
+ /** # of burst for this measurement*/
+ public int burstNumber;
+
+ /** total number of measurement frames in this measurement*/
+ public int measurementFrameNumber;
+
+ /** total successful number of measurement frames in this measurement*/
+ public int successMeasurementFrameNumber;
+
+ /** Maximum number of frames per burst supported by peer */
+ public int frameNumberPerBurstPeer;
+
/** status of the request */
public int status;
- /** type of the request used */
+ /**
+ * type of the request used
+ * @deprecated It has been replaced by measurementType
+ */
+ @Deprecated
public int requestType;
+ /** RTT measurement method type used, shoudl be one of RTT_TYPE_ONE_SIDED or
+ * RTT_TYPE_TWO_SIDED.
+ */
+ public int measurementType;
+
+ /** please retry RTT measurement after this S since peer indicate busy at ths moment*/
+ public int retryAfterDuration;
+
/** timestamp of completion, in microsecond since boot */
public long ts;
- /** average RSSI observed */
+ /** average RSSI observed, unit of 0.5 dB */
public int rssi;
- /** RSSI spread (i.e. max - min) */
+ /**
+ * RSSI spread (i.e. max - min)
+ * @deprecated It has been replaced by rssi_spread
+ */
+ @Deprecated
public int rssi_spread;
- /** average transmit rate */
+ /**RSSI spread (i.e. max - min), unit of 0.5 dB */
+ public int rssiSpread;
+
+ /**
+ * average transmit rate
+ * @deprecated It has been replaced by txRate
+ */
+ @Deprecated
public int tx_rate;
- /** average round trip time in nano second */
+ /** average transmit rate */
+ public int txRate;
+
+ /** average receiving rate */
+ public int rxRate;
+
+ /**
+ * average round trip time in nano second
+ * @deprecated It has been replaced by rtt
+ */
+ @Deprecated
public long rtt_ns;
- /** standard deviation observed in round trip time */
+ /** average round trip time in 0.1 nano second */
+ public long rtt;
+
+ /**
+ * standard deviation observed in round trip time
+ * @deprecated It has been replaced by rttStandardDeviation
+ */
+ @Deprecated
public long rtt_sd_ns;
- /** spread (i.e. max - min) round trip time */
+ /** standard deviation of RTT in 0.1 ns */
+ public long rttStandardDeviation;
+
+ /**
+ * spread (i.e. max - min) round trip time
+ * @deprecated It has been replaced by rttSpread
+ */
+ @Deprecated
public long rtt_spread_ns;
- /** average distance in centimeter, computed based on rtt_ns */
+ /** spread (i.e. max - min) RTT in 0.1 ns */
+ public long rttSpread;
+
+ /**
+ * average distance in centimeter, computed based on rtt_ns
+ * @deprecated It has been replaced by distance
+ */
+ @Deprecated
public int distance_cm;
- /** standard deviation observed in distance */
+ /** average distance in cm, computed based on rtt */
+ public int distance;
+
+ /**
+ * standard deviation observed in distance
+ * @deprecated It has been replaced with distanceStandardDeviation
+ */
+ @Deprecated
public int distance_sd_cm;
- /** spread (i.e. max - min) distance */
+ /** standard deviation observed in distance in cm*/
+ public int distanceStandardDeviation;
+
+ /**
+ * spread (i.e. max - min) distance
+ * @deprecated It has been replaced by distanceSpread
+ */
+ @Deprecated
public int distance_spread_cm;
+
+ /** spread (i.e. max - min) distance in cm */
+ public int distanceSpread;
+
+ /** the duration of this measurement burst*/
+ public int burstDuration;
+
+ /** LCI information Element*/
+ wifiInformationElement LCI;
+
+ /** LCR information Element*/
+ wifiInformationElement LCR;
}
@@ -228,18 +590,28 @@ public class RttManager {
dest.writeInt(mResults.length);
for (RttResult result : mResults) {
dest.writeString(result.bssid);
+ dest.writeInt(result.burstNumber);
+ dest.writeInt(result.measurementFrameNumber);
+ dest.writeInt(result.successMeasurementFrameNumber);
+ dest.writeInt(result.frameNumberPerBurstPeer);
dest.writeInt(result.status);
- dest.writeInt(result.requestType);
+ dest.writeInt(result.measurementType);
+ dest.writeInt(result.retryAfterDuration);
dest.writeLong(result.ts);
dest.writeInt(result.rssi);
- dest.writeInt(result.rssi_spread);
- dest.writeInt(result.tx_rate);
- dest.writeLong(result.rtt_ns);
- dest.writeLong(result.rtt_sd_ns);
- dest.writeLong(result.rtt_spread_ns);
- dest.writeInt(result.distance_cm);
- dest.writeInt(result.distance_sd_cm);
- dest.writeInt(result.distance_spread_cm);
+ dest.writeInt(result.rssiSpread);
+ dest.writeInt(result.txRate);
+ dest.writeLong(result.rtt);
+ dest.writeLong(result.rttStandardDeviation);
+ dest.writeLong(result.rttSpread);
+ dest.writeInt(result.distance);
+ dest.writeInt(result.distanceStandardDeviation);
+ dest.writeInt(result.distanceSpread);
+ dest.writeInt(result.burstDuration);
+ //dest.writeInt(result.LCI.id);
+ //dest.writeString(result.LCI.data);
+ //dest.writeInt(result.LCR.id);
+ //dest.writeString(result.LCR.data);
}
} else {
dest.writeInt(0);
@@ -261,18 +633,28 @@ public class RttManager {
for (int i = 0; i < num; i++) {
results[i] = new RttResult();
results[i].bssid = in.readString();
+ results[i].burstNumber = in.readInt();
+ results[i].measurementFrameNumber = in.readInt();
+ results[i].successMeasurementFrameNumber = in.readInt();
+ results[i].frameNumberPerBurstPeer = in.readInt();
results[i].status = in.readInt();
- results[i].requestType = in.readInt();
+ results[i].measurementType = in.readInt();
+ results[i].retryAfterDuration = in.readInt();
results[i].ts = in.readLong();
results[i].rssi = in.readInt();
- results[i].rssi_spread = in.readInt();
- results[i].tx_rate = in.readInt();
- results[i].rtt_ns = in.readLong();
- results[i].rtt_sd_ns = in.readLong();
- results[i].rtt_spread_ns = in.readLong();
- results[i].distance_cm = in.readInt();
- results[i].distance_sd_cm = in.readInt();
- results[i].distance_spread_cm = in.readInt();
+ results[i].rssiSpread = in.readInt();
+ results[i].txRate = in.readInt();
+ results[i].rtt = in.readLong();
+ results[i].rttStandardDeviation = in.readLong();
+ results[i].rttSpread = in.readLong();
+ results[i].distance = in.readInt();
+ results[i].distanceStandardDeviation = in.readInt();
+ results[i].distanceSpread = in.readInt();
+ results[i].burstDuration = in.readInt();
+ //results[i].LCI.id = in.readInt();
+ //results[i].LCI.data = in.readString();
+ //results[i].LCR.id = in.readInt();
+ //results[i].LCR.data = in.readString();
}
ParcelableRttResults parcelableResults = new ParcelableRttResults(results);
@@ -292,7 +674,70 @@ public class RttManager {
public void onAborted();
}
+ private boolean rttParamSanity(RttParams params, int index) {
+ if (mRttCapabilities == null) {
+ if(getRttCapabilities() == null) {
+ Log.e(TAG, "Can not get RTT capabilities");
+ //throw new IllegalStateException("RTT chip is not working");
+ }
+ }
+
+ if (params.deviceType != RTT_PEER_TYPE_AP) {
+ return false;
+ } else if (params.requestType != RTT_TYPE_ONE_SIDED && params.requestType !=
+ RTT_TYPE_TWO_SIDED) {
+ Log.e(TAG, "Request " + index + ": Illegal Request Type: " + params.requestType);
+ return false;
+ } else if (params.requestType == RTT_TYPE_ONE_SIDED &&
+ !mRttCapabilities.oneSidedRttSupported) {
+ Log.e(TAG, "Request " + index + ": One side RTT is not supported");
+ return false;
+ } else if (params.requestType == RTT_TYPE_TWO_SIDED &&
+ !mRttCapabilities.twoSided11McRttSupported) {
+ Log.e(TAG, "Request " + index + ": two side RTT is not supported");
+ return false;
+ } else if ( params.numberBurst <= 0 ) {
+ Log.e(TAG, "Request " + index + ": Illegal number of burst: " + params.numberBurst);
+ return false;
+ } else if (params.numberBurst > 1 && params.interval <= 0) {
+ Log.e(TAG, "Request " + index + ": Illegal interval value: " + params.interval);
+ return false;
+ } else if (params.numSamplesPerBurst <= 0) {
+ Log.e(TAG, "Request " + index + ": Illegal sample number per burst: " +
+ params.numSamplesPerBurst);
+ return false;
+ } else if (params.numRetriesPerMeasurementFrame < 0 || params.numRetriesPerFTMR < 0) {
+ Log.e(TAG, "Request " + index + ": Illegal retry number");
+ return false;
+ } else if (params.LCIRequest && !mRttCapabilities.lciSupported) {
+ Log.e(TAG, "Request " + index + ": LCI is not supported");
+ return false;
+ } else if (params.LCRRequest && !mRttCapabilities.lcrSupported) {
+ Log.e(TAG, "Request " + index + ": LCR is not supported");
+ return false;
+ } else if (params.burstTimeout <= 0){
+ Log.e(TAG, "Request " + index + ": Illegal burst timeout: " + params.burstTimeout);
+ return false;
+ } else if ((params.preamble & mRttCapabilities.preambleSupported) == 0) {
+ Log.e(TAG, "Request " + index + ": Do not support this preamble: " + params.preamble);
+ return false;
+ } else if ((params.bandwidth & mRttCapabilities.bwSupported) == 0) {
+ Log.e(TAG, "Request " + index + ": Do not support this bandwidth: " + params.bandwidth);
+ return false;
+ }
+
+ return true;
+ }
+
public void startRanging(RttParams[] params, RttListener listener) {
+ int index = 0;
+ for(RttParams rttParam : params) {
+ if (!rttParamSanity(rttParam, index)) {
+ throw new IllegalArgumentException("RTT Request Parameter Illegal");
+ }
+ index++;
+ }
+
validateChannel();
ParcelableRttParams parcelableParams = new ParcelableRttParams(params);
sAsyncChannel.sendMessage(CMD_OP_START_RANGING,
@@ -315,12 +760,14 @@ public class RttManager {
private Context mContext;
private IRttManager mService;
+ private RttCapabilities mRttCapabilities;
private static final int INVALID_KEY = 0;
private static int sListenerKey = 1;
private static final SparseArray sListenerMap = new SparseArray();
private static final Object sListenerMapLock = new Object();
+ private static final Object sCapabilitiesLock = new Object();
private static AsyncChannel sAsyncChannel;
private static CountDownLatch sConnected;
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index b4f49276a1d6..e8a51e336f7d 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -16,8 +16,6 @@
package android.net.wifi;
-import android.net.wifi.passpoint.WifiPasspointInfo;
-import android.net.wifi.passpoint.WifiPasspointManager;
import android.os.Parcel;
import android.os.Parcelable;
@@ -215,11 +213,19 @@ public class ScanResult implements Parcelable {
public int distanceSdCm;
/**
- * Passpoint ANQP information. This is not fetched automatically.
- * Use {@link WifiPasspointManager#requestAnqpInfo} to request ANQP info.
- * {@hide}
+ * Indicates if the scan result represents a passpoint AP
+ */
+ public boolean passpointNetwork;
+
+ /**
+ * Indicates if venue name
+ */
+ public String venueName;
+
+ /**
+ * Indicates operator name
*/
- public WifiPasspointInfo passpoint;
+ public String operatorFriendlyName;
/**
* {@hide}
@@ -292,6 +298,7 @@ public class ScanResult implements Parcelable {
this.centerFreq0 = UNSPECIFIED;
this.centerFreq1 = UNSPECIFIED;
this.is80211McRTTResponder = false;
+ this.passpointNetwork = false;
}
/** {@hide} */
@@ -310,6 +317,7 @@ public class ScanResult implements Parcelable {
this.centerFreq0 = UNSPECIFIED;
this.centerFreq1 = UNSPECIFIED;
this.is80211McRTTResponder = false;
+ this.passpointNetwork = false;
}
/** {@hide} */
@@ -329,6 +337,7 @@ public class ScanResult implements Parcelable {
this.centerFreq0 = centerFreq0;
this.centerFreq1 = centerFreq1;
this.is80211McRTTResponder = is80211McRTTResponder;
+ this.passpointNetwork = false;
}
/** copy constructor {@hide} */
@@ -348,13 +357,15 @@ public class ScanResult implements Parcelable {
distanceCm = source.distanceCm;
distanceSdCm = source.distanceSdCm;
seen = source.seen;
- passpoint = source.passpoint;
autoJoinStatus = source.autoJoinStatus;
untrusted = source.untrusted;
numConnection = source.numConnection;
numUsage = source.numUsage;
numIpConfigFailures = source.numIpConfigFailures;
isAutoJoinCandidate = source.isAutoJoinCandidate;
+ passpointNetwork = source.passpointNetwork;
+ venueName = source.venueName;
+ operatorFriendlyName = source.operatorFriendlyName;
}
}
@@ -388,7 +399,7 @@ public class ScanResult implements Parcelable {
sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")).
append("(cm)");
- sb.append(", passpoint: ").append(passpoint != null ? "yes" : "no");
+ sb.append(", passpoint: ").append(passpointNetwork ? "yes" : "no");
if (autoJoinStatus != 0) {
sb.append(", status: ").append(autoJoinStatus);
}
@@ -431,12 +442,10 @@ public class ScanResult implements Parcelable {
dest.writeInt(numUsage);
dest.writeInt(numIpConfigFailures);
dest.writeInt(isAutoJoinCandidate);
- if (passpoint != null) {
- dest.writeInt(1);
- passpoint.writeToParcel(dest, flags);
- } else {
- dest.writeInt(0);
- }
+ dest.writeInt(passpointNetwork ? 1 : 0);
+ dest.writeString(venueName);
+ dest.writeString(operatorFriendlyName);
+
if (informationElements != null) {
dest.writeInt(informationElements.length);
for (int i = 0; i < informationElements.length; i++) {
@@ -478,9 +487,9 @@ public class ScanResult implements Parcelable {
sr.numUsage = in.readInt();
sr.numIpConfigFailures = in.readInt();
sr.isAutoJoinCandidate = in.readInt();
- if (in.readInt() == 1) {
- sr.passpoint = WifiPasspointInfo.CREATOR.createFromParcel(in);
- }
+ sr.passpointNetwork = in.readInt() == 1;
+ sr.venueName = in.readString();
+ sr.operatorFriendlyName = in.readString();
int n = in.readInt();
if (n != 0) {
sr.informationElements = new InformationElement[n];
diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
index 626346304437..928479652573 100644
--- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
+++ b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
@@ -26,12 +26,35 @@ import android.os.Parcelable;
* @hide
*/
public final class WifiActivityEnergyInfo implements Parcelable {
- private final long mTimestamp;
- private final int mStackState;
- private final int mControllerTxTimeMs;
- private final int mControllerRxTimeMs;
- private final int mControllerIdleTimeMs;
- private final int mControllerEnergyUsed;
+ /**
+ * @hide
+ */
+ public long mTimestamp;
+
+ /**
+ * @hide
+ */
+ public int mStackState;
+
+ /**
+ * @hide
+ */
+ public int mControllerTxTimeMs;
+
+ /**
+ * @hide
+ */
+ public int mControllerRxTimeMs;
+
+ /**
+ * @hide
+ */
+ public int mControllerIdleTimeMs;
+
+ /**
+ * @hide
+ */
+ public int mControllerEnergyUsed;
public static final int STACK_STATE_INVALID = 0;
public static final int STACK_STATE_STATE_ACTIVE = 1;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 7e04f2b1f081..11bdebb06811 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -973,13 +973,18 @@ public class WifiConfiguration implements Parcelable {
}
}
- if (FQDN != null) {
- /* must have a providerFriendlyName */
- if (providerFriendlyName == null) {
+ if (TextUtils.isEmpty(FQDN) == false) {
+ /* this is passpoint configuration; it must not have an SSID */
+ if (TextUtils.isEmpty(SSID) == false) {
+ return false;
+ }
+ /* this is passpoint configuration; it must have a providerFriendlyName */
+ if (TextUtils.isEmpty(providerFriendlyName)) {
return false;
}
/* this is passpoint configuration; it must have enterprise config */
- if (enterpriseConfig == null) {
+ if (enterpriseConfig == null
+ || enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.NONE ) {
return false;
}
}
@@ -989,6 +994,16 @@ public class WifiConfiguration implements Parcelable {
}
/**
+ * Identify if this configuration represents a passpoint network
+ */
+ public boolean isPasspoint() {
+ return !TextUtils.isEmpty(FQDN)
+ && !TextUtils.isEmpty(providerFriendlyName)
+ && enterpriseConfig != null
+ && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
+ }
+
+ /**
* Helper function, identify if a configuration is linked
* @hide
*/
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index b292c22c4e66..e1460efb58c2 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2598,6 +2598,27 @@ public class WifiManager {
}
}
+ /**
+ * Set setting for allowing Scans when infrastructure is associated
+ * @hide
+ */
+ public void setAllowScansWhileAssociated(boolean enabled) {
+ try {
+ mService.setAllowScansWhileAssociated(enabled);
+ } catch (RemoteException e) {
+ }
+ }
+ /**
+ * Get setting for allowing Scans when infrastructure is associated
+ * @hide
+ */
+ public boolean getAllowScansWhileAssociated() {
+ try {
+ return mService.getAllowScansWhileAssociated();
+ } catch (RemoteException e) {
+ }
+ return false;
+ }
}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
index b9b17ebedd04..0245a3d0617a 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
@@ -262,7 +262,7 @@ public class WifiPasspointManager {
for (ScanResult sr : mAnqpRequest)
if (sr.BSSID.equals(result.bssid)) {
Log.d(TAG, "find hit " + result.bssid);
- sr.passpoint = result;
+ /* sr.passpoint = result; */
mAnqpRequest.remove(sr);
Log.d(TAG, "mAnqpRequest.len=" + mAnqpRequest.size());
break;